init blog
This commit is contained in:
26
src/components/ArticleBlockquote.tsx
Normal file
26
src/components/ArticleBlockquote.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
|
||||
interface BlockquoteProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Blockquote: React.FC<BlockquoteProps> = ({ children, className = '' }) => (
|
||||
<blockquote className={`border-l-4 border-slate-400 pl-4 italic text-slate-600 my-6 ${className}`}>
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
|
||||
export const CodeBlock: React.FC<{ children: React.ReactNode; className?: string }> = ({ children, className = '' }) => (
|
||||
<pre className={`bg-slate-900 text-slate-100 p-4 rounded-lg overflow-x-auto mb-4 ${className}`}>
|
||||
<code className="font-mono text-sm">
|
||||
{children}
|
||||
</code>
|
||||
</pre>
|
||||
);
|
||||
|
||||
export const InlineCode: React.FC<{ children: React.ReactNode; className?: string }> = ({ children, className = '' }) => (
|
||||
<code className={`bg-slate-200 text-slate-900 px-1 py-0.5 rounded font-mono text-sm ${className}`}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
24
src/components/ArticleHeading.tsx
Normal file
24
src/components/ArticleHeading.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
interface HeadingProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const H1: React.FC<HeadingProps> = ({ children, className = '' }) => (
|
||||
<h1 className={`text-4xl font-bold text-slate-900 mb-4 mt-8 leading-tight ${className}`}>
|
||||
{children}
|
||||
</h1>
|
||||
);
|
||||
|
||||
export const H2: React.FC<HeadingProps> = ({ children, className = '' }) => (
|
||||
<h2 className={`text-3xl font-bold text-slate-900 mb-4 mt-8 leading-snug ${className}`}>
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
|
||||
export const H3: React.FC<HeadingProps> = ({ children, className = '' }) => (
|
||||
<h3 className={`text-2xl font-bold text-slate-900 mb-4 mt-8 leading-relaxed ${className}`}>
|
||||
{children}
|
||||
</h3>
|
||||
);
|
||||
24
src/components/ArticleList.tsx
Normal file
24
src/components/ArticleList.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
interface ListProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const UL: React.FC<ListProps> = ({ children, className = '' }) => (
|
||||
<ul className={`list-disc list-inside text-slate-700 leading-relaxed mb-4 ml-4 ${className}`}>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
|
||||
export const OL: React.FC<ListProps> = ({ children, className = '' }) => (
|
||||
<ol className={`list-decimal list-inside text-slate-700 leading-relaxed mb-4 ml-4 ${className}`}>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
|
||||
export const LI: React.FC<ListProps> = ({ children, className = '' }) => (
|
||||
<li className={`mb-1 ${className}`}>
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
18
src/components/ArticleParagraph.tsx
Normal file
18
src/components/ArticleParagraph.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
interface ParagraphProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Paragraph: React.FC<ParagraphProps> = ({ children, className = '' }) => (
|
||||
<p className={`text-slate-700 leading-relaxed mb-4 ${className}`}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
|
||||
export const LeadParagraph: React.FC<ParagraphProps> = ({ children, className = '' }) => (
|
||||
<p className={`text-xl text-slate-700 leading-relaxed mb-6 ${className}`}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
48
src/components/BlogPostCard.tsx
Normal file
48
src/components/BlogPostCard.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
|
||||
interface BlogPostCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
slug: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export const BlogPostCard: React.FC<BlogPostCardProps> = ({
|
||||
title,
|
||||
description,
|
||||
date,
|
||||
slug,
|
||||
tags = []
|
||||
}) => {
|
||||
const formattedDate = new Date(date).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
|
||||
return (
|
||||
<article className="border border-slate-200 rounded-lg p-6 hover:shadow-lg transition-shadow">
|
||||
<a href={`/blog/${slug}`} className="block">
|
||||
<h2 className="text-2xl font-bold text-slate-900 mb-2 hover:text-slate-700">
|
||||
{title}
|
||||
</h2>
|
||||
<p className="text-slate-600 mb-3 leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
<div className="flex items-center justify-between text-sm text-slate-500">
|
||||
<time dateTime={date}>{formattedDate}</time>
|
||||
{tags.length > 0 && (
|
||||
<div className="flex gap-2">
|
||||
{tags.map(tag => (
|
||||
<span key={tag} className="bg-slate-100 text-slate-700 px-2 py-1 rounded">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
</article>
|
||||
);
|
||||
};
|
||||
23
src/components/Container.tsx
Normal file
23
src/components/Container.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
|
||||
interface ContainerProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
maxWidth?: string;
|
||||
}
|
||||
|
||||
export const Container: React.FC<ContainerProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
maxWidth = 'max-w-4xl'
|
||||
}) => (
|
||||
<div className={`mx-auto px-4 ${maxWidth} ${className}`}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ArticleContainer: React.FC<ContainerProps> = ({ children, className = '' }) => (
|
||||
<Container maxWidth="max-w-3xl" className={`py-8 ${className}`}>
|
||||
{children}
|
||||
</Container>
|
||||
);
|
||||
24
src/data/blogPosts.ts
Normal file
24
src/data/blogPosts.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export interface BlogPost {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
slug: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export const blogPosts: BlogPost[] = [
|
||||
{
|
||||
title: "Starting this blog",
|
||||
description: "Why I'm writing things down in public",
|
||||
date: "2024-01-15",
|
||||
slug: "first-note",
|
||||
tags: ["meta", "learning"]
|
||||
},
|
||||
{
|
||||
title: "Debugging with print statements",
|
||||
description: "When printf debugging is actually the right tool",
|
||||
date: "2024-01-20",
|
||||
slug: "debugging-tips",
|
||||
tags: ["debugging", "tools"]
|
||||
}
|
||||
];
|
||||
100
src/layouts/BaseLayout.astro
Normal file
100
src/layouts/BaseLayout.astro
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const { title, description = "Technical problem solver's blog - practical insights and learning notes" } = Astro.props;
|
||||
|
||||
// About info from context
|
||||
const aboutInfo = {
|
||||
name: "Marc Mintel",
|
||||
role: "Technical problem solver",
|
||||
email: "marc@mintel.me",
|
||||
location: "Vulkaneifel, Germany"
|
||||
};
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{title} | {aboutInfo.name}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-white text-slate-900 font-sans antialiased">
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<!-- Header with About Info -->
|
||||
<header class="bg-white border-b border-slate-200 sticky top-0 z-10">
|
||||
<div class="max-w-4xl mx-auto px-4 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-xl font-bold text-slate-900">
|
||||
<a href="/" class="hover:text-slate-700">{aboutInfo.name}</a>
|
||||
</h1>
|
||||
<p class="text-sm text-slate-600">{aboutInfo.role}</p>
|
||||
</div>
|
||||
<div class="text-right text-sm text-slate-600 hidden sm:block">
|
||||
<p>{aboutInfo.email}</p>
|
||||
<p>{aboutInfo.location}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-grow">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="border-t border-slate-200 bg-slate-50">
|
||||
<div class="max-w-4xl mx-auto px-4 py-6">
|
||||
<p class="text-sm text-slate-600 text-center">
|
||||
A public notebook of things I figured out, mistakes I made, and tools I tested.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2563eb;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Smooth scrolling */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Focus styles for accessibility */
|
||||
a:focus,
|
||||
button:focus {
|
||||
outline: 2px solid #2563eb;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
133
src/layouts/BlogLayout.astro
Normal file
133
src/layouts/BlogLayout.astro
Normal file
@@ -0,0 +1,133 @@
|
||||
---
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
import BaseLayout from './BaseLayout.astro';
|
||||
|
||||
interface Props {
|
||||
post: CollectionEntry<'blog'>;
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { title, description, date, tags } = post.data;
|
||||
const formattedDate = new Date(date).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description}>
|
||||
<article class="max-w-3xl mx-auto px-4 py-8">
|
||||
<header class="mb-8">
|
||||
<h1 class="text-4xl font-bold text-slate-900 mb-4 leading-tight">
|
||||
{title}
|
||||
</h1>
|
||||
<div class="flex items-center justify-between text-sm text-slate-500 mb-4">
|
||||
<time datetime={date}>{formattedDate}</time>
|
||||
{tags && tags.length > 0 && (
|
||||
<div class="flex gap-2">
|
||||
{tags.map(tag => (
|
||||
<span key={tag} class="bg-slate-100 text-slate-700 px-2 py-1 rounded text-xs">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<p class="text-xl text-slate-600 leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="prose prose-slate max-w-none">
|
||||
<slot />
|
||||
</div>
|
||||
</article>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.prose {
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #0f172a;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #0f172a;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
margin-bottom: 1.25rem;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.prose ul, .prose ol {
|
||||
margin-bottom: 1.25rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.prose li {
|
||||
margin-bottom: 0.5rem;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.prose ul li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.prose ol li {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
border-left: 4px solid #94a3b8;
|
||||
padding-left: 1rem;
|
||||
font-style: italic;
|
||||
color: #475569;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.prose code {
|
||||
background-color: #f1f5f9;
|
||||
color: #0f172a;
|
||||
padding: 0.125rem 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875em;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.prose pre {
|
||||
background-color: #0f172a;
|
||||
color: #f1f5f9;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.prose pre code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
color: #2563eb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.prose a:hover {
|
||||
color: #1d4ed8;
|
||||
}
|
||||
</style>
|
||||
79
src/pages/blog/debugging-tips.astro
Normal file
79
src/pages/blog/debugging-tips.astro
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
import BlogLayout from '../../layouts/BlogLayout.astro';
|
||||
import { H2, H3 } from '../../components/ArticleHeading';
|
||||
import { Paragraph, LeadParagraph } from '../../components/ArticleParagraph';
|
||||
import { UL, LI } from '../../components/ArticleList';
|
||||
import { CodeBlock, InlineCode } from '../../components/ArticleBlockquote';
|
||||
|
||||
const post = {
|
||||
data: {
|
||||
title: "Debugging with print statements",
|
||||
description: "When printf debugging is actually the right tool",
|
||||
date: new Date("2024-01-20"),
|
||||
tags: ["debugging", "tools"]
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<BlogLayout post={post}>
|
||||
<LeadParagraph>
|
||||
Sometimes the simplest debugging tool is the best one. Print statements get a bad reputation, but they're often exactly what you need.
|
||||
</LeadParagraph>
|
||||
|
||||
<H2>Why print statements work</H2>
|
||||
|
||||
<Paragraph>
|
||||
Debuggers are powerful, but they change how your code runs. Print statements don't. They let you see what's actually happening in the real execution flow.
|
||||
</Paragraph>
|
||||
|
||||
<H3>When to use them</H3>
|
||||
|
||||
<UL>
|
||||
<LI>Quick investigation of unexpected behavior</LI>
|
||||
<LI>Understanding data flow through multiple functions</LI>
|
||||
<LI>Checking state at specific points in time</LI>
|
||||
<LI>When setting up a debugger feels like overkill</LI>
|
||||
</UL>
|
||||
|
||||
<H2>Make them useful</H2>
|
||||
|
||||
<Paragraph>
|
||||
Bad print statements create noise. Good ones tell you exactly what you need to know.
|
||||
</Paragraph>
|
||||
|
||||
<CodeBlock>
|
||||
{`def process_data(data):
|
||||
# Bad: What does this even mean?
|
||||
print("debug 1")
|
||||
|
||||
# Good: Clear context and value
|
||||
print(f"Processing {len(data)} items")
|
||||
|
||||
result = expensive_operation(data)
|
||||
|
||||
# Good: Show the important intermediate result
|
||||
print(f"Operation result: {result}")
|
||||
|
||||
return result`}
|
||||
</CodeBlock>
|
||||
|
||||
<H3>What to print</H3>
|
||||
|
||||
<UL>
|
||||
<LI>Variable values at key points</LI>
|
||||
<LI>Function entry/exit with parameters</LI>
|
||||
<LI>Loop iterations with counters</LI>
|
||||
<LI>Conditional branches taken</LI>
|
||||
<LI>Timing information for performance</LI>
|
||||
</UL>
|
||||
|
||||
<H2>Temporary by design</H2>
|
||||
|
||||
<Paragraph>
|
||||
The beauty of print statements is that they're temporary. Add them, get your answer, remove them. No setup, no cleanup, no commitment.
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
Sometimes the most sophisticated tool is the one you can use in 5 seconds and throw away in 10.
|
||||
</Paragraph>
|
||||
</BlogLayout>
|
||||
69
src/pages/blog/first-note.astro
Normal file
69
src/pages/blog/first-note.astro
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
import BlogLayout from '../../layouts/BlogLayout.astro';
|
||||
import { H2, H3 } from '../../components/ArticleHeading';
|
||||
import { Paragraph, LeadParagraph } from '../../components/ArticleParagraph';
|
||||
import { UL, LI } from '../../components/ArticleList';
|
||||
import { Blockquote, InlineCode } from '../../components/ArticleBlockquote';
|
||||
|
||||
const post = {
|
||||
data: {
|
||||
title: "Starting this blog",
|
||||
description: "Why I'm writing things down in public",
|
||||
date: new Date("2024-01-15"),
|
||||
tags: ["meta", "learning"]
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<BlogLayout post={post}>
|
||||
<LeadParagraph>
|
||||
This blog is a public notebook. It's where I document things I learn, problems I solve, and tools I test.
|
||||
</LeadParagraph>
|
||||
|
||||
<H2>Why write in public?</H2>
|
||||
|
||||
<Paragraph>
|
||||
I forget things. Writing them down helps. Making them public helps me think more clearly and might help someone else.
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
The goal isn't to teach or impress. It's to document. If you find something useful here, great. If not, that's fine too.
|
||||
</Paragraph>
|
||||
|
||||
<H2>What to expect</H2>
|
||||
|
||||
<UL>
|
||||
<LI>Short entries, usually under 500 words</LI>
|
||||
<LI>Practical solutions to specific problems</LI>
|
||||
<LI>Notes on tools and workflows</LI>
|
||||
<LI>Mistakes and what I learned</LI>
|
||||
<LI>Occasional deep dives when needed</LI>
|
||||
</UL>
|
||||
|
||||
<H2>How I work</H2>
|
||||
|
||||
<Paragraph>
|
||||
My process is simple:
|
||||
</Paragraph>
|
||||
|
||||
<UL>
|
||||
<LI>I try things</LI>
|
||||
<LI>I break things</LI>
|
||||
<LI>I fix things</LI>
|
||||
<LI>I write down what I learned</LI>
|
||||
</UL>
|
||||
|
||||
<Blockquote>
|
||||
Understanding doesn't expire. Finished projects do.
|
||||
</Blockquote>
|
||||
|
||||
<H3>Tools I use</H3>
|
||||
|
||||
<Paragraph>
|
||||
Mostly standard Unix tools, Python, shell scripts, and whatever gets the job done. I prefer <InlineCode>simple</InlineCode> over <InlineCode>clever</InlineCode>.
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
If you're building things and solving problems, maybe you'll find something useful here. If not, thanks for reading anyway.
|
||||
</Paragraph>
|
||||
</BlogLayout>
|
||||
49
src/pages/index.astro
Normal file
49
src/pages/index.astro
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { BlogPostCard } from '../components/BlogPostCard';
|
||||
import { blogPosts } from '../data/blogPosts';
|
||||
|
||||
// Sort posts by date
|
||||
const posts = [...blogPosts].sort((a, b) =>
|
||||
new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout title="Blog" description="Technical problem solving blog - practical insights and learning notes">
|
||||
<div class="max-w-4xl mx-auto px-4 py-8">
|
||||
<!-- About Section -->
|
||||
<section class="mb-12 pb-8 border-b border-slate-200">
|
||||
<p class="text-lg text-slate-700 leading-relaxed">
|
||||
I work on technical problems and build tools, scripts, and systems to solve them.
|
||||
Sometimes that means code, sometimes automation, sometimes AI, sometimes something else.
|
||||
The tool is secondary. The problem comes first.
|
||||
</p>
|
||||
<p class="text-sm text-slate-500 mt-4">
|
||||
Topics: Vibe coding with AI • Debugging • Mac tools • Automation • Small scripts • Learning notes • FOSS
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Blog Posts -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold text-slate-900 mb-6">Recent Notes</h2>
|
||||
|
||||
{posts.length === 0 ? (
|
||||
<div class="text-center py-12">
|
||||
<p class="text-slate-500">No posts yet. Check back soon!</p>
|
||||
</div>
|
||||
) : (
|
||||
<div class="space-y-4">
|
||||
{posts.map(post => (
|
||||
<BlogPostCard
|
||||
title={post.title}
|
||||
description={post.description}
|
||||
date={post.date}
|
||||
slug={post.slug}
|
||||
tags={post.tags}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
Reference in New Issue
Block a user