feat(master): back to dixous 2.0.1

This commit is contained in:
2025-07-16 17:27:26 -06:00
parent 2d17aaa0e7
commit a371e21366
11 changed files with 584 additions and 7 deletions

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>

View File

@ -2,6 +2,29 @@
import ProjectsCard from './projectsCard.svelte';
let { independent_page = true } = $props();
let limitProjects = $derived(independent_page ? 0 : 8);
let projectsPromise = $state(null);
$effect(async () => {
try {
const res = await fetch(
`https://darkicewolf50cloud.bajacloud.duckdns.org/projects/${limitProjects}`
);
if (!res.ok) {
projectsPromise = null;
return;
}
const data = await res.json();
projectsPromise = Array.isArray(data) ? data : null;
} catch (e) {
console.error('Fetch error:', e);
projectsPromise = null;
}
});
$inspect(projectsPromise).with(console.trace);
</script>
{#if independent_page}
@ -12,6 +35,16 @@
<p>Top Featured and Recent Projects</p>
</div>
<div class="project-section">
<ProjectsCard
project_name="Portfolio Site Version 3.0.0"
website_link="https://darkicewolf50.pages.dev"
gitea_link="https://gitea.bajacloud.duckdns.org/darkicewolf50/darkicewolf50"
project_img="https://res.cloudinary.com/dpgrgsh7g/image/upload/v1745630861/Portfolio_site_k4mhmj.png"
techs_used={['JavaScript', 'CSS', 'SvelteKit', 'Git', 'Gitea']}
project_des="A conversion from Dioxus to Sveltekit is going to be worth it as it is significantly easier to add additional api calls.
This is not to mention the benefits of using ssg instead of a client side rendered app.
Overall this was a great way to dive into a great JavaScript framework."
/>
<ProjectsCard
project_name="Personal Backend"
gitea_link="https://gitea.bajacloud.duckdns.org/darkicewolf50/darkicewolf50Cloud"
@ -36,7 +69,7 @@
I was surprise how easy it was to set up a discord webhook using the 'reqwest' crate.
As I continue on I find myself struggling with how and why to use databases for content I generate.
I think using tools like disocrd webhooks and email notifications are great for users but certainly not great for reading data from.
I was very satisfied with serde, and comrak for converting markdown fiels into html.
I was very satisfied with serde, and comrak for converting markdown files into html.
I use this extensively for the blogs search menu and the blog itself to display the blog itself in a consistent way without needing to write a whole library."
/>
<ProjectsCard

View File

@ -18,6 +18,8 @@
return tech_to_return;
};
// https://darkicewolf50cloud.bajacloud.duckdns.org/home/skills
const TECH_TABLE = [
{
tech_name: 'Rust',
@ -35,7 +37,7 @@
{
tech_name: 'JavaScript',
tech_logo: 'https://www.svgrepo.com/show/303206/javascript-logo.svg',
project_site: 'https://www.python.org',
project_site: 'https://google.com',
skill_level: 60
},
@ -197,7 +199,7 @@
tech_name: 'SvelteKit',
tech_logo: 'https://svelte.dev/favicon.png',
project_site: 'https://svelte.dev',
skill_level: 1
skill_level: 70
},
{
tech_name: 'Mongodb',

View File

@ -1,11 +1,52 @@
<script>
import { page } from '$app/state';
console.log(page.status);
// $inspect(page.status);
</script>
<title>Brock Tomlinson - Not Found</title>
<div>
<h1>{page.status} Page not found</h1>
<h1>{page.status} - Page not found</h1>
<p>We are terribly sorry, but the page you requested doesn't exist.</p>
<a href="/"><button>Return Home Here</button></a>
</div>
<style>
div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 80svh;
}
h1 {
border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius);
}
button {
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
border: none;
color: inherit;
font-size: xx-large;
padding: 1rem;
}
button:hover {
cursor: pointer;
}
a {
text-decoration: none;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
color: inherit;
}
a:hover {
color: #91a4d2;
}
</style>

View File

@ -6,7 +6,7 @@
let languages = ['Rust', 'Python', 'YAML', 'HTML5', 'CSS', 'JavaScript', 'Markdown'];
let backend = ['Actix', 'FastAPI', 'Dioxus', 'Diesel'];
let frontend = ['React', 'Dioxus', 'Vue'];
let frontend = ['React', 'Dioxus', 'SvelteKit'];
let databases = ['Sqlite', 'PostgreSQL', 'Mongodb', 'DynamoDB'];
let tools = [
'Vs Code',

View File

@ -0,0 +1,163 @@
<script>
import { page } from '$app/state';
let blogTitle = $derived(page.params.slug);
$inspect(page.params.slug);
let blogPromise = $state(null);
$inspect(blogPromise);
// $effect(async () => {
// try {
// const res = await fetch(
// `https://darkicewolf50cloud.bajacloud.duckdns.org/blogs/blog/${blogTitle}`
// );
// if (!res.ok) {
// blogPromise = null;
// return;
// }
// const data = await res.json();
// blogPromise = data;
// } catch (e) {
// console.error('Fetch error:', e);
// blogPromise = null;
// }
// });
$effect(() => {
if (!blogTitle) {
blogPromise = null;
return;
}
blogPromise = fetch(
`https://darkicewolf50cloud.bajacloud.duckdns.org/blogs/blog/${blogTitle}`
).then((res) => {
if (!res.ok) throw new Error('Network error');
return res.json();
});
});
</script>
<title>Brock Tomlinson - {blogTitle}</title>
<meta name="author" content="Brock Tomlinson" />
<meta name="robots" content="noindex, nofollow" />
<div id="blog">
<a href="/blogs/0">Go Back</a>
{#await blogPromise}
<p>Loading...</p>
{:then blogContent}
{#if blogContent}
<article>
<header class="blog-info">
<h1>{blogContent.blog_title}</h1>
<div>
<ul>
{#each blogContent.tags as tag, tagIndex}
<li key={tag + tagIndex}>{tag}</li>
{/each}
</ul>
<p>{blogContent.date_last_edit}</p>
</div>
</header>
<section class="blog-content">{@html blogContent.html_blog_content}</section>
</article>
{:else}
<p>An Error has occurred or blog not found</p>
{/if}
{:catch}
<p>An Error has occurred</p>
{/await}
</div>
<style>
#blog {
margin-top: 2svh;
min-height: 80svh;
}
.blog-info {
display: flex;
flex-direction: column;
}
ul {
display: flex;
flex-direction: row;
list-style-type: none;
margin: 0px;
padding: 0px;
}
ul li {
background-color: rgba(128, 0, 128, 0.2);
border-radius: 1rem;
padding: 0.25svh 8px;
margin: 0svh 0.25svh;
height: fit-content;
}
.blog-info h1 {
padding: 1svh 1svw !important;
margin: 2svh 0svw !important;
margin-bottom: 0px !important;
font-size: 2em !important;
border-radius: 0px !important;
border-bottom: none !important;
}
.blog-info div {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 1svh 0svw;
border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius);
}
#blog a {
color: #ffffff;
margin-top: 50px;
text-decoration: underline;
}
#blog a:hover {
color: #91a4d2;
}
.blog-content {
padding: 2svh 0svw;
}
:global(.blog-content h1),
:global(.blog-content h2),
:global(.blog-content h3),
:global(.blog-content h4),
:global(.blog-content h5),
:global(.blog-content h6) {
margin: 0px;
padding: 1svh 0svw;
border-radius: 0px;
border-bottom: none;
}
h1 {
border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius);
margin: 1svh 2svw;
padding: 1svh 2svw;
display: flex;
}
p {
margin: 0px;
padding: 0px;
}
a {
text-decoration: none;
color: inherit;
}
a:hover {
color: #91a4d2;
}
</style>

View File

@ -0,0 +1,292 @@
<script>
import { page } from '$app/state';
let pageNum = $derived(page.params.slug);
let numLimit = $state(10);
// $inspect(page.params.slug);
// $inspect(numLimit);
let blogsPromise = $state(null);
$effect(async () => {
try {
const res = await fetch(
`https://darkicewolf50cloud.bajacloud.duckdns.org/blogs/${numLimit}/${pageNum}`
);
if (!res.ok) {
blogsPromise = null;
return;
}
const data = await res.json();
blogsPromise = Array.isArray(data) ? data : null;
} catch (e) {
console.error('Fetch error:', e);
blogsPromise = null;
}
});
</script>
<title>Brock Tomlinson - Blogs - {pageNum}</title>
<meta name="robots" content="noindex, nofollow" />
<!-- // document::Stylesheet { href: asset!("/assets/styling/blog.css") } -->
<div id="blogs">
<div id="blogs-title">
<h1>Blogs</h1>
<p>
This is a collection of blog posts, ranging from tutorials, technologies I found interesting,
and opinion pieces
</p>
<p>These blogs are my opinion and mine alone</p>
</div>
<div id="blogs-on-show">
{#await blogsPromise}
<div id="blog-loading"><p>Loading blogs...</p></div>
{:then blogs}
{#if blogs && blogs.length > 0}
{#each blogs as blog, blogIndex}
<a
class="blog-preview"
href={'/blog/' + blog.blog_file_name}
key={blog.blog_file_name + blogIndex}
>
<div class="blog-info">
<h1>{blog.blog_title}</h1>
<div>
<ul>
{#each blog.tags as tag, tagIndex}
<li key={tag + tagIndex}>{tag}</li>
{/each}
</ul>
<p>{blog.date_last_edit}</p>
</div>
</div>
<div class="blog_content">{@html blog.html_blog_content}</div>
<button>Read More Here</button>
</a>
{/each}
{:else}
<div id="blog-out-of">
<p>No more blogs available</p>
<a href="/blogs/0"><button>Go Back</button></a>
</div>
{/if}
{:catch error}
<div id="blog-loading"><p>An error has occurred</p></div>
{/await}
</div>
<div id="blog-nav">
{#if pageNum > 0}
<a href={'/blogs/' + (pageNum - 1)}><button>{'<-- Go Back'}</button></a>
{/if}
<div>
<label for="selectHowManyShow">display: </label>
<select name="selectHowManyShow" id="selectHowManyShow" bind:value={numLimit}>
<option value={10}>10</option>
<option value={25}>25</option>
<option value={50}>50</option>
<option value={100}>100</option>
</select>
</div>
<a href={'/blogs/' + (pageNum + 1)}>{'Next -->'}</a>
</div>
</div>
<style>
.blog-info {
display: flex;
flex-direction: column;
}
.blog-info p {
padding: 2svh 0svw;
margin: 0px;
}
.blog-info h1 {
padding: 1svh 1svw !important;
margin: 2svh 0svw !important;
margin-bottom: 0px !important;
font-size: 2em !important;
border-radius: 0px !important;
border-bottom: none !important;
}
.blog-info div {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 1svh 0svw;
border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius);
}
ul {
display: flex;
flex-direction: row;
list-style-type: none;
margin: 0px;
padding: 0px;
}
ul li {
background-color: rgba(128, 0, 128, 0.2);
border-radius: 1rem;
padding: 0.25svh 8px;
margin: 0svh 0.25svh;
height: fit-content;
}
#blogs {
display: flex;
flex-direction: column;
min-height: 80svh;
}
h1 {
border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius);
margin: 1svh 2svw;
padding: 1svh 2svw;
display: flex;
}
button {
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
border: none;
color: inherit;
font-size: x-large;
padding: 0.5rem;
margin: 1svh 0svw;
}
p {
margin: 0px;
padding: 0px;
}
a {
text-decoration: none;
color: inherit;
}
a:hover {
color: #91a4d2;
}
.blog-preview {
display: flex;
flex-direction: column;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
padding: 0svh 2svw;
max-width: 600px;
}
#blogs .blog-preview h1 {
border-bottom: none;
padding: 0svh 1svw;
margin: 0px;
}
.blog-preview button {
width: max-content;
border: 2px solid rgba(145, 164, 210, 0.4);
border-radius: var(--card-border-radius);
font-size: medium;
margin-top: auto;
margin-bottom: 4svh;
}
#blogs .blog-preview .blog-info div p:last-child {
margin-right: 0svh;
margin-left: 2svw;
padding: 0px;
}
#blogs-title {
display: flex;
flex-direction: column;
padding-bottom: 1svh;
}
#blogs-title p {
margin: 0svh 1svw;
padding: 1svh 0svw;
}
#blogs-on-show {
display: flex;
flex-flow: row wrap;
justify-content: center;
padding: 2svh 0svw;
row-gap: 2svh;
column-gap: 2svw;
}
#blog-loading {
display: flex;
flex-direction: column;
justify-self: center;
align-self: center;
justify-content: center;
align-items: center;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
padding: 2svh 2svw;
margin: 8svh 0svw;
}
#blog-out-of {
display: flex;
flex-direction: column;
justify-self: center;
align-self: center;
justify-content: center;
align-items: center;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
padding: 2svh 2svw;
margin: 8svh 0svw;
}
#blog-nav {
display: flex;
align-items: center;
position: relative;
padding: 0svh 2svw;
margin-top: auto;
margin-bottom: 2svh;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
}
#blog-nav a:last-child {
margin-left: auto;
}
#blog-nav div {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
justify-self: center;
margin: 1svh 0svw;
padding: 0.5rem;
column-gap: 1svw;
min-height: 28px;
font-size: large;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
position: relative;
left: 50%;
transform: translateX(-50%);
}
</style>

View File

@ -0,0 +1,44 @@
// src/routes/sitemap.xml/+server.ts (or +server.js)
import { format } from 'date-fns'; // Optional, if you want <lastmod> etc.
export async function GET() {
const baseUrl = 'https://yourdomain.com'; // Replace with your domain
const staticPages = [
'', // Home page
'contact',
'projects'
];
const urls = staticPages
.map(
(path) => `
<url>
<loc>${baseUrl}/${path}</loc>
<lastmod>${format(new Date(), 'yyyy-MM-dd')}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>`
)
.join('');
return new Response(
`
<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="https://www.w3.org/1999/xhtml"
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"
>
${urls}
</urlset>`.trim(),
{
headers: {
'Content-Type': 'application/xml'
}
}
);
}

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

2
static/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow: /blogs/