mirror of
https://github.com/LukeHagar/Sveltey.git
synced 2025-12-06 04:21:38 +00:00
Overhaul
This commit is contained in:
191
docs/AUTHENTICATION_SETUP.md
Normal file
191
docs/AUTHENTICATION_SETUP.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# SvelteKit Supabase Authentication Setup
|
||||
|
||||
This project uses Supabase for authentication with full server-side rendering (SSR) support through SvelteKit hooks.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Email/Password authentication
|
||||
- ✅ GitHub OAuth integration
|
||||
- ✅ Server-side authentication with `hooks.server.ts`
|
||||
- ✅ Protected routes with automatic redirects
|
||||
- ✅ Session management across client and server
|
||||
- ✅ TypeScript support with proper types
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Environment Variables
|
||||
|
||||
Create a `.env.local` file in your project root:
|
||||
|
||||
```bash
|
||||
PUBLIC_SUPABASE_URL=your_supabase_project_url
|
||||
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
|
||||
```
|
||||
|
||||
Get these values from your Supabase project dashboard under Settings > API.
|
||||
|
||||
### 2. Supabase Configuration
|
||||
|
||||
#### Enable GitHub OAuth Provider
|
||||
|
||||
1. Go to your Supabase project dashboard
|
||||
2. Navigate to **Authentication > Providers**
|
||||
3. Enable the **GitHub** provider
|
||||
4. Add your GitHub OAuth credentials:
|
||||
- **Client ID**: From your GitHub OAuth app
|
||||
- **Client Secret**: From your GitHub OAuth app
|
||||
|
||||
#### GitHub OAuth App Setup
|
||||
|
||||
1. Go to GitHub Settings > Developer settings > OAuth Apps
|
||||
2. Click "New OAuth App"
|
||||
3. Fill in the details:
|
||||
- **Application name**: Your app name
|
||||
- **Homepage URL**: `http://localhost:5173` (for development)
|
||||
- **Authorization callback URL**: `https://your-project-ref.supabase.co/auth/v1/callback`
|
||||
4. Note the Client ID and Client Secret for Supabase configuration
|
||||
|
||||
### 3. Supabase Authentication Settings
|
||||
|
||||
In your Supabase project settings:
|
||||
|
||||
1. Go to **Authentication > Settings**
|
||||
2. Add your site URLs:
|
||||
- **Site URL**: `http://localhost:5173` (development) / `https://yourdomain.com` (production)
|
||||
- **Redirect URLs**: Add both your local and production URLs
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Server-Side Authentication (`hooks.server.ts`)
|
||||
|
||||
The authentication is handled through SvelteKit hooks:
|
||||
|
||||
```typescript
|
||||
// src/hooks.server.ts
|
||||
export const handle: Handle = sequence(supabase, authGuard);
|
||||
```
|
||||
|
||||
#### Features:
|
||||
- **`supabase` hook**: Creates server-side Supabase client with cookie management
|
||||
- **`authGuard` hook**: Protects routes and handles redirects
|
||||
- **Session validation**: Validates JWTs on every request
|
||||
- **Cookie management**: Automatic token refresh and cookie handling
|
||||
|
||||
### Protected Routes
|
||||
|
||||
Routes are automatically protected based on path patterns:
|
||||
|
||||
- **`/dashboard/*`**: Requires authentication, redirects to `/auth/login` if not authenticated
|
||||
- **`/auth/*`**: Redirects authenticated users to `/dashboard`
|
||||
|
||||
### Client-Side Integration (`+layout.svelte`)
|
||||
|
||||
The root layout handles client-side authentication state:
|
||||
|
||||
```typescript
|
||||
// Syncs server-side session with client-side
|
||||
$effect(() => {
|
||||
session = data.session;
|
||||
});
|
||||
|
||||
// Handles auth state changes
|
||||
supabase.auth.onAuthStateChange((event, newSession) => {
|
||||
if (newSession?.expires_at !== session?.expires_at) {
|
||||
invalidateAll();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── hooks.server.ts # Server-side authentication hooks
|
||||
├── app.d.ts # TypeScript definitions for Supabase
|
||||
├── lib/
|
||||
│ ├── index.ts # Exports (toaster)
|
||||
│ └── supabaseClient.ts # Browser Supabase client
|
||||
├── routes/
|
||||
│ ├── +layout.svelte # Root layout with auth state
|
||||
│ ├── +layout.server.ts # Server layout with session data
|
||||
│ ├── auth/
|
||||
│ │ ├── login/+page.svelte # Login page with GitHub OAuth
|
||||
│ │ ├── signup/+page.svelte # Signup page with GitHub OAuth
|
||||
│ │ └── logout/+page.server.ts # Logout action
|
||||
│ └── dashboard/
|
||||
│ ├── +layout.server.ts # Dashboard layout (protected)
|
||||
│ └── +page.svelte # Dashboard page
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Login Page Features
|
||||
|
||||
- Email/password authentication
|
||||
- GitHub OAuth login
|
||||
- Form validation and error handling
|
||||
- Loading states
|
||||
- Automatic redirect after login
|
||||
|
||||
### Signup Page Features
|
||||
|
||||
- Email/password registration
|
||||
- GitHub OAuth signup
|
||||
- Email confirmation handling
|
||||
- Error handling with toast notifications
|
||||
|
||||
### Dashboard Protection
|
||||
|
||||
The dashboard is automatically protected and will:
|
||||
- Redirect unauthenticated users to login
|
||||
- Display user information for authenticated users
|
||||
- Handle session expiration gracefully
|
||||
|
||||
## TypeScript Support
|
||||
|
||||
Full TypeScript support with proper types:
|
||||
|
||||
```typescript
|
||||
// app.d.ts
|
||||
interface Locals {
|
||||
supabase: SupabaseClient;
|
||||
safeGetSession(): Promise<{ session: Session | null; user: User | null }>;
|
||||
session: Session | null;
|
||||
user: User | null;
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
1. Start your development server:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
2. Test authentication:
|
||||
- Visit `/auth/signup` to create an account
|
||||
- Try GitHub OAuth login
|
||||
- Visit `/dashboard` to see protected content
|
||||
- Test logout functionality
|
||||
|
||||
## Security Features
|
||||
|
||||
- **JWT validation**: Server-side validation of authentication tokens
|
||||
- **Automatic refresh**: Tokens are refreshed automatically
|
||||
- **Secure cookies**: HTTP-only cookies for session management
|
||||
- **Route protection**: Server-side route guards
|
||||
- **CSRF protection**: Built into Supabase auth flow
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **"Cannot redirect during render"**: Usually caused by trying to redirect in a `load` function without throwing the redirect
|
||||
2. **OAuth callback errors**: Check your GitHub OAuth app callback URL matches Supabase settings
|
||||
3. **Session not persisting**: Ensure cookies are configured correctly in `hooks.server.ts`
|
||||
|
||||
### Debug Tips
|
||||
|
||||
- Check browser Network tab for auth requests
|
||||
- Verify Supabase project settings match your configuration
|
||||
- Test OAuth flow in incognito mode to avoid cached sessions
|
||||
392
docs/BLOG_SETUP.md
Normal file
392
docs/BLOG_SETUP.md
Normal file
@@ -0,0 +1,392 @@
|
||||
# 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
|
||||
<!-- In the blog post page -->
|
||||
{#if post.component}
|
||||
<svelte:component this={post.component} />
|
||||
{:else}
|
||||
<p>Content not available.</p>
|
||||
{/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
|
||||
<title>My Blog Post | Blog</title>
|
||||
<meta name="description" content="Post excerpt here" />
|
||||
<meta property="og:title" content="My Blog Post" />
|
||||
<meta property="og:description" content="Post excerpt here" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="article:published_time" content="2024-01-30" />
|
||||
<meta property="article:author" content="Author Name" />
|
||||
<meta property="article:tag" content="tutorial" />
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 1. Create New Post
|
||||
|
||||
```bash
|
||||
# Create new post file
|
||||
touch src/lib/posts/my-new-post.md
|
||||
|
||||
# Add frontmatter and content
|
||||
# The post will automatically appear in the blog
|
||||
```
|
||||
|
||||
### 2. Preview Posts
|
||||
|
||||
Posts are automatically available at:
|
||||
- Blog index: `/blog`
|
||||
- Individual post: `/blog/your-post-slug`
|
||||
|
||||
### 3. Manage Content
|
||||
|
||||
- Posts are automatically sorted by publication date
|
||||
- Only posts with `publishedAt` dates in the past are shown
|
||||
- Featured posts appear in a special section
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom Components in Markdown
|
||||
|
||||
You can use Svelte components in your markdown:
|
||||
|
||||
```markdown
|
||||
<script>
|
||||
import MyComponent from '$lib/components/MyComponent.svelte';
|
||||
</script>
|
||||
|
||||
# My Post
|
||||
|
||||
Here's a custom component:
|
||||
|
||||
<MyComponent prop="value" />
|
||||
```
|
||||
|
||||
### Dynamic Imports
|
||||
|
||||
Posts are loaded dynamically using Vite's `import.meta.glob()`:
|
||||
|
||||
```typescript
|
||||
const allPostFiles = import.meta.glob('/src/lib/posts/*.md');
|
||||
```
|
||||
|
||||
### Build-Time Processing
|
||||
|
||||
All markdown processing happens at build time, ensuring:
|
||||
- Fast page loads
|
||||
- SEO-friendly static HTML
|
||||
- No runtime markdown parsing overhead
|
||||
|
||||
## Svelte 5 Compatibility
|
||||
|
||||
### Key Differences from Previous Versions
|
||||
|
||||
1. **Component-based rendering**: Instead of HTML strings, posts are Svelte components
|
||||
2. **No server-side rendering of content**: Content is rendered client-side as components
|
||||
3. **Simplified architecture**: No need to handle HTML content strings
|
||||
|
||||
### Migration from HTML-based Systems
|
||||
|
||||
If migrating from an HTML-content based blog:
|
||||
|
||||
1. Update blog post interface to use `component` instead of `content`
|
||||
2. Replace `{@html post.content}` with `<svelte:component this={post.component} />`
|
||||
3. Remove any server-side HTML rendering logic
|
||||
|
||||
## Deployment
|
||||
|
||||
The markdown blog works with any SvelteKit deployment target:
|
||||
|
||||
- **Static**: Pre-rendered at build time
|
||||
- **Server**: Rendered on demand
|
||||
- **Hybrid**: Mix of static and server rendering
|
||||
|
||||
All posts are processed at build time, so they work perfectly with static deployment.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Consistent Naming**: Use kebab-case for slugs and filenames
|
||||
2. **Descriptive Excerpts**: Write compelling excerpts for better SEO
|
||||
3. **Meaningful Tags**: Use consistent, meaningful tags
|
||||
4. **Proper Dates**: Always use YYYY-MM-DD format for dates
|
||||
5. **Image Optimization**: Optimize images before including in posts
|
||||
6. **Internal Linking**: Use relative links for internal content
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Post not appearing**: Check `publishedAt` date is not in the future
|
||||
2. **Styling issues**: Ensure prose classes are applied correctly
|
||||
3. **Build errors**: Validate frontmatter YAML syntax
|
||||
4. **Component not rendering**: Verify the markdown file has proper frontmatter
|
||||
|
||||
### Debug Mode
|
||||
|
||||
In development, check the browser console for any post loading errors. The system will log issues with individual posts without breaking the entire blog.
|
||||
|
||||
### Svelte 5 Specific Issues
|
||||
|
||||
- **Component rendering errors**: Check that the markdown files are properly processed by mdsvex
|
||||
- **Missing syntax highlighting**: Ensure shiki is properly configured
|
||||
- **Layout issues**: Verify the MDXLayout component is correctly set in svelte.config.js
|
||||
|
||||
---
|
||||
|
||||
This Svelte 5 compatible markdown blog system provides a powerful, flexible, and maintainable solution for content management while leveraging the full power of Svelte's component system!
|
||||
Reference in New Issue
Block a user