This commit is contained in:
32
src/lib/components/PostCard.svelte
Normal file
32
src/lib/components/PostCard.svelte
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
interface PostCardProps {
|
||||||
|
slug: string;
|
||||||
|
title: string;
|
||||||
|
date: string;
|
||||||
|
excerpt: string;
|
||||||
|
image?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { slug, title, date, excerpt, image }: PostCardProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<article class="group overflow-hidden rounded-lg border border-gray-200 transition hover:shadow-lg">
|
||||||
|
<a href="/posts/{slug}" class="block">
|
||||||
|
{#if image}
|
||||||
|
<div class="aspect-video w-full overflow-hidden bg-gray-100">
|
||||||
|
<img
|
||||||
|
src={image}
|
||||||
|
alt={title}
|
||||||
|
class="h-full w-full object-cover transition duration-300 group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="p-6">
|
||||||
|
<h2 class="mb-2 text-2xl font-semibold transition group-hover:text-electric-violet-800">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<p class="mb-2 text-gray-600">{date}</p>
|
||||||
|
<p class="text-gray-700">{excerpt}</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import PostCard from '$lib/components/PostCard.svelte';
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
</script>
|
</script>
|
||||||
@@ -13,15 +14,13 @@
|
|||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
{#each data.posts as post}
|
{#each data.posts as post}
|
||||||
<article class="border-b pb-6">
|
<PostCard
|
||||||
<a href="/posts/{post.slug}" class="group">
|
slug={post.slug}
|
||||||
<h2 class="mb-2 text-2xl font-semibold transition group-hover:text-electric-violet-800">
|
title={post.title}
|
||||||
{post.title}
|
date={post.date}
|
||||||
</h2>
|
excerpt={post.excerpt}
|
||||||
<p class="mb-2 text-gray-600">{post.date}</p>
|
image={post.image}
|
||||||
<p class="text-gray-700">{post.excerpt}</p>
|
/>
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
|
|
||||||
export const load: PageLoad = async () => {
|
export const load: PageLoad = async () => {
|
||||||
const postFiles = import.meta.glob<{ metadata: { title: string; date: string; excerpt: string } }>(
|
const postFiles = import.meta.glob<{
|
||||||
'./posts/*.md',
|
metadata: { title: string; date: string; excerpt: string; image?: string };
|
||||||
{ eager: true }
|
}>('./posts/*.md', { eager: true });
|
||||||
);
|
|
||||||
|
|
||||||
const posts = Object.entries(postFiles).map(([path, post]) => {
|
const posts = Object.entries(postFiles).map(([path, post]) => {
|
||||||
const slug = path.replace('./posts/', '').replace('.md', '');
|
const slug = path.replace('./posts/', '').replace('.md', '');
|
||||||
@@ -13,7 +12,8 @@ export const load: PageLoad = async () => {
|
|||||||
slug,
|
slug,
|
||||||
title: post.metadata.title,
|
title: post.metadata.title,
|
||||||
date: post.metadata.date,
|
date: post.metadata.date,
|
||||||
excerpt: post.metadata.excerpt
|
excerpt: post.metadata.excerpt,
|
||||||
|
image: post.metadata.image
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,16 @@
|
|||||||
<p class="text-gray-600">{data.metadata.date}</p>
|
<p class="text-gray-600">{data.metadata.date}</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
{#if data.metadata.image}
|
||||||
|
<div class="mb-8 -mx-4 md:mx-0">
|
||||||
|
<img
|
||||||
|
src={data.metadata.image}
|
||||||
|
alt={data.metadata.title}
|
||||||
|
class="w-full rounded-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="prose-headings:font-semibold prose-a:text-electric-violet-800 prose-a:no-underline hover:prose-a:underline"
|
class="prose-headings:font-semibold prose-a:text-electric-violet-800 prose-a:no-underline hover:prose-a:underline"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
title: "How It's Made - The Homelab (if I can call it that)"
|
title: "How It's Made - The Homelab (if I can call it that)"
|
||||||
date: "2025-12-22"
|
date: "2025-12-22"
|
||||||
excerpt: "How I bought an office PC at a protest and turned it into t h e c l o u d over the course of a weekend."
|
excerpt: "How I bought an office PC at a protest and turned it into t h e c l o u d over the course of a weekend."
|
||||||
|
image: "/images/posts/homelab-hp-prodesk.jpeg"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Set And Setting
|
## Set And Setting
|
||||||
|
|||||||
BIN
static/images/posts/homelab-hp-prodesk.jpeg
Normal file
BIN
static/images/posts/homelab-hp-prodesk.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Reference in New Issue
Block a user