generated from darkicewolf50/ssg-sveltekit-template
feat(master): back to dixous 2.0.1
This commit is contained in:
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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>
|
||||
|
@ -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',
|
||||
|
@ -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>
|
||||
|
292
src/routes/blogs/[slug]/+page.svelte
Normal file
292
src/routes/blogs/[slug]/+page.svelte
Normal 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>
|
44
src/routes/sitemap.xml/+server.js
Normal file
44
src/routes/sitemap.xml/+server.js
Normal 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
BIN
static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
2
static/robots.txt
Normal file
2
static/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /blogs/
|
Reference in New Issue
Block a user