aboutsummaryrefslogtreecommitdiff
path: root/src/pages
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/Blog.tsx38
-rw-r--r--src/pages/Post.tsx74
2 files changed, 48 insertions, 64 deletions
diff --git a/src/pages/Blog.tsx b/src/pages/Blog.tsx
index 5db87c8..fa9b609 100644
--- a/src/pages/Blog.tsx
+++ b/src/pages/Blog.tsx
@@ -1,5 +1,3 @@
-import { useMemo } from "react";
-import matter from "gray-matter";
import { Link } from "react-router-dom";
import CardLink from "../components/CardLink";
@@ -11,40 +9,36 @@ interface PostMeta {
cover?: string;
}
-export default function Blog() {
- const posts = useMemo<PostMeta[]>(() => {
- const files = import.meta.glob("../blog/*.md", {
- eager: true,
- query: "?raw",
- import: "default",
- }) as Record<string, string>;
+const postFiles = import.meta.glob("../blog/*.md", { eager: true }) as Record<
+ string,
+ { attributes: Omit<PostMeta, "slug"> }
+>;
- return Object.entries(files)
- .map(([path, raw]) => {
- const { data } = matter(raw);
- const slug = path.split("/").pop()!.replace(".md", "");
- return { slug, ...data } as PostMeta;
- })
- .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
- }, []);
+const posts: PostMeta[] = Object.entries(postFiles)
+ .map(([path, mod]) => ({
+ slug: path.split("/").pop()!.replace(".md", ""),
+ ...(mod.attributes as Omit<PostMeta, "slug">),
+ }))
+ .sort(
+ (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
+ );
+export default function Blog() {
return (
<section className="container mx-auto px-4 py-10">
<h1 className="text-4xl font-bold mb-8">Blog</h1>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{posts.map((post) => (
- /* 1) Link für internes Routing */
- /* 2) CardLink bekommt genau deine Prop-Namen */
<Link key={post.slug} to={`/blog/${post.slug}`} className="block">
<CardLink
title={post.title}
- body={post.excerpt} // <— body statt description
- imgSrc={post.cover} // <— imgSrc statt image
+ body={post.excerpt}
+ imgSrc={post.cover}
/>
</Link>
))}
</div>
</section>
);
-}
+} \ No newline at end of file
diff --git a/src/pages/Post.tsx b/src/pages/Post.tsx
index c17873c..5c0f0ca 100644
--- a/src/pages/Post.tsx
+++ b/src/pages/Post.tsx
@@ -1,40 +1,36 @@
-import { useEffect, useState } from "react";
import { useParams, Link } from "react-router-dom";
-import matter from "gray-matter";
-import ReactMarkdown from "react-markdown";
import CodeSnippet from "../components/CodeSnippet";
import LinkWithIcon from "../components/LinkWithIcon";
import NotFoundPage from "./404Page";
-interface PostMeta {
- title: string;
- date: string;
- cover?: string;
+interface PostFile {
+ attributes: {
+ title: string;
+ date: string;
+ cover?: string;
+ };
+ markdown: string;
+ ReactComponent: React.FC<any>;
}
+const posts = import.meta.glob("../blog/*.md", {
+ eager: true,
+}) as Record<string, PostFile>;
+
export default function Post() {
const { slug } = useParams<{ slug: string }>();
- const [meta, setMeta] = useState<PostMeta | null>(null);
- const [content, setContent] = useState("");
- const [notFound, setNotFound] = useState(false);
- useEffect(() => {
- import(`../blog/${slug}.md?raw`)
- .then((m) => {
- const { data, content } = matter(m.default);
- setMeta(data as PostMeta);
- setContent(content);
- })
- .catch(() => setNotFound(true));
- }, [slug]);
+ const match = Object.entries(posts).find(([path]) =>
+ path.endsWith(`${slug}.md`)
+ );
- if (!meta) return null;
- if (notFound) return <NotFoundPage />;
+ if (!match) return <NotFoundPage />;
+ const { attributes: meta, ReactComponent: Content } = match[1];
return (
<article className="prose prose-zinc dark:prose-invert mx-auto px-4 py-10">
<Link to="/blog" className="no-underline">
- ← Back
+ ← Back
</Link>
{meta.cover && (
@@ -49,27 +45,21 @@ export default function Post() {
<p className="text-sm text-zinc-500 mb-8">
{new Date(meta.date).toLocaleDateString("de-DE")}
</p>
-
- <article className="markdown-body">
- <ReactMarkdown
- components={{
- code({ children }) {
- const text = String(children).replace(/\n$/, "");
- return <CodeSnippet code={text} initialLines={5} />;
- },
- a({ href = "", children, ...props }) {
- return (
- <LinkWithIcon href={href} {...props}>
- {children}
- </LinkWithIcon>
- );
- },
- }}
- >
- {content}
- </ReactMarkdown>
- </article>
+ {/* The Markdown, already a React component */}
+ <Content
+ components={{
+ code({ children }: any) {
+ return (
+ <CodeSnippet
+ code={String(children).replace(/\n$/, "")}
+ initialLines={5}
+ />
+ );
+ },
+ a: LinkWithIcon,
+ }}
+ />
</article>
);
} \ No newline at end of file