# svelte-standard-site Examples
This file contains comprehensive examples of using svelte-standard-site in various scenarios.
## Table of Contents
- [Basic Setup](#basic-setup)
- [Simple Blog](#simple-blog)
- [Using Utility Components](#using-utility-components)
- [Building Custom Cards](#building-custom-cards)
- [Multi-Publication Site](#multi-publication-site)
- [Custom Styling](#custom-styling)
- [Custom Layout](#custom-layout)
- [Programmatic Theme Control](#programmatic-theme-control)
- [Internationalization](#internationalization)
- [Server-Side Rendering](#server-side-rendering)
## Basic Setup
### 1. Install and Configure
```bash
pnpm add svelte-standard-site
```
Create `.env`:
```env
PUBLIC_ATPROTO_DID=did:plc:your-did-here
```
### 2. Root Layout
```svelte
{@render children()}
```
### 3. Home Page
```svelte
Welcome!
{#each data.publications as publication}
{/each}
```
## Simple Blog
### Load Function
```typescript
// src/routes/blog/+page.server.ts
import { createClient } from 'svelte-standard-site';
import { getConfigFromEnv } from 'svelte-standard-site/config/env';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch }) => {
const config = getConfigFromEnv();
if (!config) {
throw new Error('Missing AT Proto configuration');
}
const client = createClient(config);
const documents = await client.fetchAllDocuments(fetch);
return {
posts: documents
};
};
```
### Blog Index Page
```svelte
Blog Posts
Thoughts, tutorials, and updates
{#each data.posts as post}
{/each}
```
### Individual Post Page
```typescript
// src/routes/blog/[pub_rkey]/[doc_rkey]/+page.server.ts
import { createClient } from 'svelte-standard-site';
import { getConfigFromEnv } from 'svelte-standard-site/config/env';
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, fetch }) => {
const config = getConfigFromEnv();
if (!config) {
throw new Error('Missing configuration');
}
const client = createClient(config);
const document = await client.fetchDocument(params.doc_rkey, fetch);
if (!document) {
throw error(404, 'Post not found');
}
return {
post: document
};
};
```
```svelte
{post.title} - My Blog
{#if post.description}
{/if}
{#if post.coverImage}
{/if}
{post.title}
{formatDate(post.publishedAt)}
{#if post.updatedAt}
Updated: {formatDate(post.updatedAt)}
{/if}
{#if post.tags && post.tags.length > 0}
{#each post.tags as tag}
{tag}
{/each}
{/if}
{@html post.content || post.textContent || ''}
```
## Using Utility Components
The modular utility components make it easy to build consistent, theme-aware UIs.
### Using DateDisplay
```svelte
{data.post.value.title}
```
### Using TagList
```svelte
```
### Using ThemedText
```svelte
{data.post.value.title}
{data.post.value.description}
Read more →
```
### Combining Utility Components
```svelte
{data.post.value.title}
{data.post.value.description}
{#if data.post.value.updatedAt}
{/if}
{@html data.post.value.content}
```
## Building Custom Cards
Use ThemedCard and utility components to build custom card layouts.
### Blog Post Card
```svelte
{#if value.coverImage}
{/if}
{value.title}
{#if value.description}
{value.description}
{/if}
{#if value.tags?.length}
{/if}
```
### Author Card
```svelte
{#if avatar}
{/if}
{name}
{bio}
```
### Feature Card with Icon
```svelte
{@render icon()}
{title}
{description}
```
## Internationalization
### Automatic Locale Detection
The DateDisplay component automatically detects the user's browser locale.
```svelte
```
### Explicit Locale Override
```svelte
```
### Multi-Language Blog
```svelte
{data.post.value.title}
{@html data.post.value.content}
```
## Multi-Publication Site
```typescript
// src/routes/+page.server.ts
import { createClient } from 'svelte-standard-site';
import { getConfigFromEnv } from 'svelte-standard-site/config/env';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch }) => {
const config = getConfigFromEnv();
if (!config) {
return { error: 'Configuration missing', publications: [], documents: [] };
}
const client = createClient(config);
const [publications, documents] = await Promise.all([
client.fetchAllPublications(fetch),
client.fetchAllDocuments(fetch)
]);
// Group documents by publication
const documentsByPub = new Map();
for (const doc of documents) {
const pubUri = doc.value.site;
if (!documentsByPub.has(pubUri)) {
documentsByPub.set(pubUri, []);
}
documentsByPub.get(pubUri).push(doc);
}
return {
publications,
documents,
documentsByPub: Object.fromEntries(documentsByPub)
};
};
```
```svelte
{#each data.publications as publication}
Recent from {publication.value.name}
{#if data.documentsByPub[publication.uri]}
{#each data.documentsByPub[publication.uri].slice(0, 5) as document}
{/each}
{:else}
No documents yet
{/if}
{/each}
```
## Custom Styling
### Override Theme Colors
```css
/* src/app.css or src/lib/styles/custom.css */
@import 'svelte-standard-site/styles/base.css';
/* Override primary color */
:root {
--color-primary-50: oklch(18.2% 0.018 280);
--color-primary-100: oklch(26.5% 0.03 280);
--color-primary-200: oklch(40.5% 0.048 280);
--color-primary-300: oklch(54% 0.065 280);
--color-primary-400: oklch(66.5% 0.08 280);
--color-primary-500: oklch(78.5% 0.095 280);
--color-primary-600: oklch(82.2% 0.078 280);
--color-primary-700: oklch(86.5% 0.062 280);
--color-primary-800: oklch(91% 0.042 280);
--color-primary-900: oklch(95.8% 0.022 280);
--color-primary-950: oklch(98% 0.012 280);
}
```
### Custom Component Styles
```svelte
```
## Custom Layout
### Full Custom Layout with Theme Support
```svelte
```
## Programmatic Theme Control
### Theme Toggle Button
```svelte
themeStore.toggle()} class="bg-primary-600 rounded-lg px-4 py-2 text-white">
Switch to {isDark ? 'Light' : 'Dark'} Mode
```
### System Preference Detection
```svelte
setTheme('light')}
class="rounded px-4 py-2 {currentTheme === 'light'
? 'bg-primary-600 text-white'
: 'bg-canvas-200'}"
>
Light
setTheme('dark')}
class="rounded px-4 py-2 {currentTheme === 'dark'
? 'bg-primary-600 text-white'
: 'bg-canvas-200'}"
>
Dark
setTheme('system')}
class="rounded px-4 py-2 {currentTheme === 'system'
? 'bg-primary-600 text-white'
: 'bg-canvas-200'}"
>
System
```
## Server-Side Rendering
### Pre-render Static Pages
```typescript
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: null,
precompress: false
}),
prerender: {
entries: ['*']
}
}
};
```
### Generate Dynamic Routes
```typescript
// src/routes/blog/[pub_rkey]/[doc_rkey]/+page.server.ts
import { createClient } from 'svelte-standard-site';
import { getConfigFromEnv } from 'svelte-standard-site/config/env';
import { error } from '@sveltejs/kit';
import type { PageServerLoad, EntryGenerator } from './$types';
export const load: PageServerLoad = async ({ params, fetch }) => {
const config = getConfigFromEnv();
if (!config) throw error(500, 'Configuration missing');
const client = createClient(config);
const document = await client.fetchDocument(params.doc_rkey, fetch);
if (!document) throw error(404, 'Post not found');
return { post: document };
};
export const entries: EntryGenerator = async () => {
const config = getConfigFromEnv();
if (!config) return [];
const client = createClient(config);
const documents = await client.fetchAllDocuments();
return documents.map((doc) => {
const pubRkey = doc.value.site.split('/').pop() || '';
const docRkey = doc.uri.split('/').pop() || '';
return { pub_rkey: pubRkey, doc_rkey: docRkey };
});
};
```
## Tips and Best Practices
1. **Always import base.css** in your root layout for consistent styling
2. **Use the ThemeToggle component** or manage theme with themeStore
3. **Leverage utility components** - Use DateDisplay, TagList, ThemedText, etc. for consistency
4. **Follow DRY principles** - Don't manually format dates or apply theme colors repeatedly
5. **Leverage the design tokens** (ink, canvas, primary, etc.) for consistency
6. **Pass custom classes** to components for one-off customizations
7. **Use server-side rendering** for better SEO and performance
8. **Cache aggressively** - the library has built-in caching
9. **Handle errors gracefully** - always check for null/undefined data
10. **Test dark mode** - all components support it out of the box
11. **Embrace locale-aware dates** - DateDisplay automatically formats for user's locale
For more examples and detailed documentation, visit the [GitHub repository](https://github.com/ewanc26/svelte-standard-site).