# Markdown Blog Setup with MDSvex (Svelte 5 Compatible)
This project uses a static markdown-based blog system powered by MDSvex for SvelteKit. This implementation is optimized for Svelte 5 and uses component-based rendering instead of HTML content strings.
## Features
- ✅ **Markdown Support**: Write posts in markdown with full syntax support
- ✅ **Frontmatter Metadata**: YAML frontmatter for post metadata
- ✅ **Featured Posts**: Mark posts as featured for special display
- ✅ **Tags & Categories**: Organize posts with tags
- ✅ **SEO Optimized**: Automatic meta tags and Open Graph support
- ✅ **Responsive Design**: Mobile-friendly blog layout
- ✅ **Syntax Highlighting**: Code blocks with Shiki highlighting
- ✅ **Table of Contents**: Automatic TOC generation
- ✅ **Svelte 5 Compatible**: Uses component-based rendering
## File Structure
```
src/
├── lib/
│ ├── posts/ # Markdown blog posts
│ │ ├── getting-started.md
│ │ ├── advanced-features.md
│ │ └── building-integrations.md
│ ├── components/
│ │ └── MDXLayout.svelte # Layout for mdx content
│ ├── blog.ts # Blog utilities and types
│ └── blog-utils.ts # Helper functions
├── routes/
│ └── blog/
│ ├── +page.svelte # Blog index page
│ ├── +page.server.ts # Load all posts
│ └── [slug]/
│ ├── +page.svelte # Individual post page
│ └── +page.server.ts # Load single post
└── docs/
└── BLOG_SETUP.md # This documentation
```
## Creating Blog Posts
### 1. Create a New Markdown File
Create a new `.md` file in `src/lib/posts/`:
```bash
touch src/lib/posts/my-new-post.md
```
### 2. Add Frontmatter
Start your post with YAML frontmatter:
```markdown
---
title: "My Awesome Blog Post"
slug: "my-awesome-blog-post"
excerpt: "A compelling description of your blog post that will appear in listings and meta tags."
publishedAt: "2024-01-30"
author: "Your Name"
tags: ["tutorial", "sveltekit", "web-development"]
featured: true
---
# My Awesome Blog Post
Your content goes here...
```
### 3. Write Your Content
Use standard Markdown syntax for your blog post content:
```markdown
## Section Heading
This is a paragraph with **bold** and *italic* text.
### Code Examples
```javascript
const example = () => {
console.log('Hello from my blog!');
};
```
### Lists
- Item 1
- Item 2
- Item 3
### Links
Check out [SvelteKit](https://kit.svelte.dev) for more information.
```
## Frontmatter Reference
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | string | ✅ | Post title displayed in listings and page title |
| `slug` | string | ✅ | URL-friendly identifier for the post |
| `excerpt` | string | ✅ | Short description for listings and meta tags |
| `publishedAt` | string | ✅ | Publication date in YYYY-MM-DD format |
| `author` | string | ✅ | Author name |
| `tags` | array | ✅ | Array of tags for categorization |
| `featured` | boolean | ❌ | Whether to feature this post (default: false) |
## Svelte 5 Integration
### Component-Based Rendering
This implementation uses Svelte 5's component system. Each markdown file is compiled to a Svelte component:
```typescript
export interface BlogPost {
title: string;
slug: string;
excerpt: string;
publishedAt: string;
author: string;
tags: string[];
featured: boolean;
component?: any; // The Svelte component for rendering
}
```
### Rendering Posts
Posts are rendered using `svelte:component`:
```svelte
{#if post.component}
Content not available.
{/if} ``` ## Blog Utilities ### Available Functions The blog system provides several utility functions in `src/lib/blog.ts`: ```typescript // Get all published posts const posts = await getAllPosts(); // Get a specific post by slug const post = await getPostBySlug('my-post-slug'); // Get featured posts only const featured = await getFeaturedPosts(); // Get posts with a specific tag const tagged = await getPostsByTag('tutorial'); // Get all unique tags const tags = await getAllTags(); ``` ### Helper Functions Additional utilities in `src/lib/blog-utils.ts`: ```typescript // Generate URL-friendly slug from title const slug = generateSlug('My Blog Post Title'); // Create a new post template const template = createPostTemplate('New Post', 'Author Name'); // Validate post metadata const errors = validatePostMetadata(postData); // Search posts const results = searchPosts(allPosts, 'keyword'); // Get related posts const related = getRelatedPosts(currentPost, allPosts, 3); ``` ## Styling and Layout ### Custom Prose Styles The blog uses Tailwind's typography plugin with custom styling: ```css .prose { @apply text-surface-900-50-token max-w-none; } .prose h1 { @apply text-3xl font-bold mb-6; } .prose code { @apply bg-surface-200 dark:bg-surface-700 px-1 py-0.5 rounded; } ``` ### MDX Layout Component The `MDXLayout.svelte` component provides consistent styling for markdown content and can be customized for your design needs. ## Configuration ### MDSvex Configuration The markdown processing is configured in `svelte.config.js`: ```javascript const mdsvexOptions = { extensions: ['.md'], layout: { _: './src/lib/components/MDXLayout.svelte' }, remarkPlugins: [remarkUnwrapImages, remarkToc, remarkAbbr], rehypePlugins: [rehypeSlug], highlight: { highlighter: async (code, lang) => { const shiki = await import('shiki'); const highlighter = await shiki.getHighlighter({ themes: ['github-dark', 'github-light'], langs: ['javascript', 'typescript', 'html', 'css', 'svelte', 'bash', 'json', 'yaml', 'python', 'rust', 'go'] }); const html = highlighter.codeToHtml(code, { lang, themes: { light: 'github-light', dark: 'github-dark' } }); return html; } } }; ``` ### Available Plugins - **remark-unwrap-images**: Removes paragraph wrappers around images - **remark-toc**: Generates table of contents from headings - **remark-abbr**: Processes abbreviation definitions - **rehype-slug**: Adds IDs to headings for anchor links - **shiki**: Syntax highlighting for code blocks ## SEO Features ### Automatic Meta Tags Each blog post automatically generates: - Page title with post title - Meta description from excerpt - Open Graph tags for social sharing - Article metadata (published date, author, tags) ### Example Generated Meta Tags ```html