Compare commits

...

3 Commits

6 changed files with 126 additions and 78 deletions

View File

@@ -1,32 +1,50 @@
<script lang="ts"> <script lang="ts">
let { let {
title, title,
date = "", date = "", // date posted
dateUpdated = "",
subtitle = "", subtitle = "",
banner = "", banner = "",
bannerAlt = "", bannerAlt = "",
tags = [],
pixelated, pixelated,
}: { }: {
title: string; title: string;
date?: string; date?: string;
dateUpdated?: string;
subtitle?: string; subtitle?: string;
banner?: string; banner?: string;
bannerAlt?: string; bannerAlt?: string;
tags?: string[];
pixelated?: boolean; pixelated?: boolean;
} = $props(); } = $props();
</script> </script>
{#snippet titles({title, subtitle, date}: {title: string, subtitle: string, date: string})} {#snippet titles({title, subtitle, date}: {title: string, subtitle: string, date: string})}
<div class="title-container">
<h1 class="title">{title}</h1> <h1 class="title">{title}</h1>
<div class="title-container">
<div class="title-text-container">
{#if subtitle} {#if subtitle}
<p class="subtitle">[ {subtitle} ]</p> <p class="subtitle">[ {subtitle} ]</p>
{/if} {/if}
{#if tags.length}
<div class="tag-container">
{#each tags as tag}
<span class="post-tag">{tag}</span>
{/each}
</div>
{/if}
</div> </div>
{#if date} {#if date}
<p class="date">» {date}</p> <div class="date-container">
<p class="date">posted :: {date}</p>
{#if dateUpdated}
<p class="date">last updated :: {dateUpdated}</p>
{/if} {/if}
</div>
{/if}
</div>
{/snippet} {/snippet}
<div class="container"> <div class="container">
@@ -55,26 +73,48 @@
.title-container { .title-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: flex-end; /* align-items: flex-end; */
gap: 12px; gap: 16px;
margin: var(--margin-header-top) 0 var(--margin-header-bottom) 0; margin: 8px 0;
} }
.title-container + hr { .title-text-container {
/* Add top margin if no date element exists */ width: fit-content;
margin-top: 16px; display: flex;
flex-direction: column;
flex: 1;
gap: 8px;
}
.tag-container {
display: flex;
gap: 4px;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 4px;
}
.date-container {
width: fit-content;
display: flex;
flex-direction: column;
align-items: flex-end;
} }
.title { .title {
box-sizing: border-box; box-sizing: border-box;
height: fit-content; height: fit-content;
margin: 0; margin: 0;
margin-top: var(--margin-header-top);
} }
.date { .date {
font-weight:700; font-weight: 500;
font-size: 1.3rem; font-family: var(--font-mono);
margin-top: 0; font-size: 1.0rem;
line-height: 1.4rem;
font-style: italic;
margin: 0;
color: var(--color-highlight); color: var(--color-highlight);
} }
@@ -82,6 +122,7 @@
font-family: var(--font-mono); font-family: var(--font-mono);
font-weight: 500; font-weight: 500;
font-size: 1.0rem; font-size: 1.0rem;
line-height: 1.4rem;
margin: 0; margin: 0;
} }

View File

@@ -148,7 +148,7 @@
--font-lightyears: 'LIGHTYEARS', sans-serif; --font-lightyears: 'LIGHTYEARS', sans-serif;
--font-size-h1: 2.0rem; --font-size-h1: 2.2rem;
--font-size-h2: 1.5rem; --font-size-h2: 1.5rem;
--font-size-h3: 1.3rem; --font-size-h3: 1.3rem;
--font-size-h4: 1.2rem; --font-size-h4: 1.2rem;

View File

@@ -98,8 +98,8 @@
<hr> <hr>
<div class="split-intro-container">
<div> <div>
<img class="me-img pixelated-img" src="me.webp" alt="Pixelated mirror selfie of the website creator wearing a green shirt, fitting the website theme. The face is obscured." title="hi!"> <img class="me-img pixelated-img" src="me.webp" alt="Pixelated mirror selfie of the website creator wearing a green shirt, fitting the website theme. The face is obscured." title="hi!">
<p>Hi! I'm Deniz. Welcome to my website! I keep rewriting this introduction but I'm REALLY bad at this type of stuff.</p> <p>Hi! I'm Deniz. Welcome to my website! I keep rewriting this introduction but I'm REALLY bad at this type of stuff.</p>
@@ -108,30 +108,34 @@
<p>irl I am from 🇩🇪 Northern Germany and studying to become a secondary school teacher.</p> <p>irl I am from 🇩🇪 Northern Germany and studying to become a secondary school teacher.</p>
</div> </div>
<div class="split-container"> <div>
<div class="meta-vertical-container"> <div class="sidebox-container">
<div class="meta-container info-container"> <h4 class="sidebox-header">heads-up</h4>
<a class="status-header-link" href="/"><h4 class="update-header">latest status</h4></a>
<p class="status-content">{latestStatusContent}</p>
<span class="status-timestamp">:: {latestStatusTimestamp}</span>
</div>
<div class="meta-container info-container">
<h4 class="update-header">heads-up</h4>
<p>This website works best on Firefox and other Gecko-based browsers! All pages <i>should</i> be responsive and work on mobile.</p> <p>This website works best on Firefox and other Gecko-based browsers! All pages <i>should</i> be responsive and work on mobile.</p>
<hr>
<a class="sidebox-header-link" href="/"><h4 class="sidebox-header">latest status</h4></a>
<p class="status-content">"{latestStatusContent}"</p>
<span class="status-timestamp">:: {latestStatusTimestamp}</span>
<!-- <hr>
<a class="sidebox-header-link" href="/meta/updates"><h4 class="sidebox-header">website updates <span class="small-supertext">(new!)</span></h4></a>
{#each updateEntriesTrimmed as entry}
<UpdateEntry {entry} />
{/each} -->
</div>
</div> </div>
</div> </div>
<div class="meta-container update-container"> <hr>
<a class="update-header-link" href="/meta/updates"><h4 class="update-header">website updates <span class="small-supertext">(new!)</span></h4></a>
{#each updateEntriesTrimmed as entry}
<UpdateEntry {entry} />
{/each}
</div>
</div>
<GalleryRow entries={galleryTopRow} /> <GalleryRow entries={galleryTopRow} />
<GalleryRow entries={galleryBottomRow} /> <GalleryRow entries={galleryBottomRow} />
<hr>
<div class="split-container"> <div class="split-container">
<div class="webring-container"> <div class="webring-container">
<h4 class="update-header">webrings</h4> <h4 class="update-header">webrings</h4>
@@ -174,6 +178,11 @@
</Content> </Content>
<style> <style>
.split-intro-container {
display: grid;
grid-template-columns: 3fr 1fr;
}
.split-container { .split-container {
width: 100%; width: 100%;
display: flex; display: flex;
@@ -219,36 +228,24 @@
margin-right: 12px; margin-right: 12px;
} }
.meta-vertical-container { .sidebox-container {
flex: 3;
display: flex;
flex-direction: column;
gap: 8px;
}
.meta-container {
padding: 8px 24px; padding: 8px 24px;
backdrop-filter: blur(var(--blur-radius-background)); backdrop-filter: blur(var(--blur-radius-background));
border-width: var(--border-dash-size); border-width: var(--border-dash-size);
border-style: var(--border-style); border-style: var(--border-style);
border-color: var(--color-highlight-alt);
/* transition: border-radius var(--duration-animation) var(--anim-curve); */ /* transition: border-radius var(--duration-animation) var(--anim-curve); */
/* border-radius: var(--border-radius); */ /* border-radius: var(--border-radius); */
} }
.info-container { .sidebox-container hr {
border-color: var(--color-highlight-alt); border-color: var(--color-highlight-alt);
} margin: 16px 0;
.info-container p, .info-container a {
font-size: 1.0rem;
line-height: 1.4rem;
}
.info-container > h4 {
color: var(--color-highlight-alt);
} }
.update-container { .sidebox-container p, .sidebox-container a {
border-color: var(--color-highlight); font-size: 0.9rem;
flex: 4; line-height: 1.3rem;
} }
.status-content { .status-content {
@@ -278,27 +275,23 @@
padding-bottom: 16px; padding-bottom: 16px;
} }
.update-header-link, .status-header-link { .sidebox-header {
text-decoration: none; font-size: 1.0rem;
} line-height: 1.0rem;
.update-header-link:hover { margin-top: 8px;
text-decoration-color: var(--color-highlight);
}
.status-header-link:hover {
text-decoration-color: var(--color-highlight-alt);
}
.update-header-link:hover, .status-header-link:hover {
text-decoration-line: underline;
text-decoration-style: dashed;
text-decoration-thickness: var(--border-dash-size);
}
.status-header-link .update-header {
color: var(--color-highlight-alt); color: var(--color-highlight-alt);
} }
.update-header { .sidebox-header-link {
margin-top: 8px; text-decoration: none;
}
.sidebox-header-link:hover {
text-decoration-color: var(--color-highlight-alt);
}
.sidebox-header-link:hover {
text-decoration-line: underline;
text-decoration-style: dashed;
text-decoration-thickness: var(--border-dash-size);
} }
.gradient-title { .gradient-title {

View File

@@ -15,9 +15,12 @@
<Content> <Content>
<Banner2 <Banner2
title="{data.title}" title="{data.title}"
date="{data.date}, {data.time}" subtitle="{data.subtitle}"
date="{data.date}"
dateUpdated="{data.dateUpdated}"
banner="{data.banner}" banner="{data.banner}"
bannerAlt="Banner for blog post '{data.title}'" /> bannerAlt="Banner for blog post '{data.title}'"
tags={data.tags} />
<TableOfContents /> <TableOfContents />

View File

@@ -1,24 +1,30 @@
import { posts, type BlogPostLink } from '../../posts'; import { BlogPostTag, posts, type BlogPostLink } from '../../posts';
export async function load({ params }) { export async function load({ params }) {
const post = await import(`../../${params.year}/${params.date}.md`); const post = await import(`../../${params.year}/${params.date}.md`);
const tag: string = `${params.year}/${params.date}`; const tag: string = `${params.year}/${params.date}`; // link to the page. not to be confused with tags. i know it's confusing naming
const postValues = posts.find((v: BlogPostLink) => v.key == tag)?.post; const postValues = posts.find((v: BlogPostLink) => v.key == tag)?.post;
const content = post.default; const content = post.default;
const title: string = postValues?.title ?? ""; const title: string = postValues?.title ?? "";
const subtitle: string = postValues?.subtitle ?? "";
const date: string = postValues?.date ?? ""; const date: string = postValues?.date ?? "";
const dateUpdated: string = postValues?.dateUpdated ?? "";
const time: string = postValues?.time ?? ""; const time: string = postValues?.time ?? "";
const banner: string = postValues?.banner ?? ""; const banner: string = postValues?.banner ?? "";
const description: string = postValues?.description ?? ""; const description: string = postValues?.description ?? "";
const tags: BlogPostTag[] = postValues?.tags ?? []; // blog post tags. should be renamed 'keywords'
return { return {
content, content,
title, title,
subtitle,
banner, banner,
date, date,
dateUpdated,
time, time,
tag, tag,
tags,
description, description,
}; };
} }

View File

@@ -4,11 +4,14 @@ export interface BlogPostDetails {
// Format: HH:mm // Format: HH:mm
time: string; time: string;
dateUpdated?: string;
// Banner image title. If empty, defaults to banner.webp // Banner image title. If empty, defaults to banner.webp
banner: string; banner: string;
bannerAlt: string; bannerAlt: string;
title: string; title: string;
subtitle?: string;
/** /**
* Description to be used in page's metadata. * Description to be used in page's metadata.
@@ -67,6 +70,7 @@ export const posts: BlogPostLink[] = [
post: { post: {
date: "2026-03-17", date: "2026-03-17",
time: "17:00", time: "17:00",
dateUpdated: "2026-03-25",
banner: "banner.webp", banner: "banner.webp",
bannerAlt: "A Microsoft Surface Pro 8 displaying a Blue Screen of Death.", bannerAlt: "A Microsoft Surface Pro 8 displaying a Blue Screen of Death.",
title: "How To: Set Up SvelteKit Frontend + PostgreSQL Backend", title: "How To: Set Up SvelteKit Frontend + PostgreSQL Backend",
@@ -110,6 +114,7 @@ export const posts: BlogPostLink[] = [
post: { post: {
date: "2026-02-05", date: "2026-02-05",
time: "22:55", time: "22:55",
dateUpdated: "2026-03-05",
banner: "banner.webp", banner: "banner.webp",
bannerAlt: "A Leuchtturm-branded notebook with a copper-coloured cover. An eraser, a pencil sharpener, and a Faber-Castell pencil are lying on top.", bannerAlt: "A Leuchtturm-branded notebook with a copper-coloured cover. An eraser, a pencil sharpener, and a Faber-Castell pencil are lying on top.",
title: "Drawing Challenge", title: "Drawing Challenge",