Files
Sveltey/README.md

16 KiB

🚀 Sveltey - SvelteKit SaaS Template

Sveltey SaaS Template

A modern, production-ready SaaS template built with SvelteKit 2, Svelte 5, Supabase, and Skeleton UI. Get your SaaS project up and running in hours, not months.

Features

🔐 Authentication & User Management

  • Supabase Auth Integration: Complete authentication flow with email/password and OAuth providers
  • Protected Routes: Automatic route protection and session management
  • User Profiles: Customizable user profile management
  • Password Reset: Secure password reset functionality

🎨 Modern UI/UX

  • Skeleton UI: Beautiful, accessible components out of the box
  • Dark/Light Mode: Built-in mode switching
  • Comprehensive Themes: 22 beautiful handmade themes
  • Responsive Design: Mobile-first, responsive layouts
  • Loading States: Elegant loading indicators and transitions
  • Toast Notifications: User-friendly feedback system

📝 Content Management

  • Blog System: Built-in blog with markdown support
  • SEO Optimized: Meta tags, Open Graph, and structured data

📊 Dashboard & Analytics - Planned

  • Admin Dashboard: Clean, intuitive admin interface
  • User Analytics: Basic user metrics and insights
  • Real-time Updates: Live data updates using Supabase real-time
  • Data Visualization: Charts and graphs for key metrics

💳 Payments & Subscriptions - Planned

  • Stripe Integration: Ready-to-use payment processing
  • Subscription Plans: Flexible pricing tiers
  • Billing Management: Customer billing portal
  • Webhook Handling: Secure webhook processing

🚀 Quick Start

# Clone the repository
git clone https://github.com/yourusername/sveltey.git
cd sveltey

# Install dependencies
npm install

# Set up environment variables
cp .env.example .env
# Edit .env with your Supabase and Stripe keys

# Start the development server
npm run dev

Visit http://localhost:5173 and start building your SaaS!

📦 Tech Stack

  • Framework: SvelteKit 2 with Svelte 5
  • Database: Supabase (PostgreSQL)
  • Authentication: Supabase Auth
  • UI Components: Skeleton UI
  • Styling: Tailwind CSS
  • Deployment: Vercel/Netlify ready
  • Language: TypeScript

📁 Project Structure

src/
├── lib/
│   ├── components/     # Reusable UI components
│   ├── stores/         # Svelte stores for state management
│   ├── utils/          # Utility functions
│   └── types/          # TypeScript type definitions
├── routes/
│   ├── (app)/          # App routes
|   |   ├── api         # API routes, security is handled at the endpoint level
|   |   ├── app         # App routes, security is handeled globally, all sub-routes are protected
|   |   └── auth        # Auth routes, used for login, logout, and password reset functionality
│   └── (marketing)/    # Public marketing pages
|       ├── blog        # API routes, security is handled at the endpoint level
|       ├── contact     # Contact page
|       ├── pricing     # Pricing page
|       ├── privacy     # Privacy policy page
|       └── terms       # Terms of service page
├── app.html            # App shell
├── app.css             # Global styles
└── hooks.server.ts     # Server hooks

🔧 Configuration

Environment Variables

Create a .env file in the root directory:

# Supabase
PUBLIC_SUPABASE_URL=your_supabase_url
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

# Stripe // coming soon
PUBLIC_STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_WEBHOOK_SECRET=your_webhook_secret

Supabase Setup

  1. Create a new Supabase project
  2. Copy the project URL and anon key
  3. Run the included SQL migrations
  4. Set up your authentication providers

Stripe Setup

  1. Create a Stripe account
  2. Copy your API keys
  3. Configure your products and pricing
  4. Set up webhooks for subscription events

🎯 Customization

Branding

  • Update app.html for favicon and meta tags
  • Modify src/lib/config.ts for app configuration
  • Customize colors in with a custom Skeleton UI theme
  • Replace logo

Components

  • All components are in src/lib/components/
  • Skeleton UI provides the base component library
  • Easy to theme and customize with CSS variables

🔍 SEO & Meta Tags

Sveltey comes with a comprehensive SEO system built on top of svelte-meta-tags that provides automatic meta tag management, OpenGraph support, and Twitter Card integration.

Understanding the Meta Tag System

The meta tag system in Sveltey uses a two-level approach:

  1. Base Meta Tags (src/routes/+layout.ts) - Global defaults for your entire site
  2. Page Meta Tags (src/routes/*/+page.ts) - Page-specific overrides and additions

Base Meta Tags Structure

The base meta tags are defined in src/routes/+layout.ts and include:

const baseMetaTags = Object.freeze({
  title: 'Sveltey - SvelteKit SaaS Template',
  titleTemplate: '%s | Sveltey',
  description: 'Your default site description...',
  canonical: new URL(url.pathname, url.origin).href,
  robots: 'index,follow',
  keywords: ['SvelteKit', 'SaaS', 'template'],
  
  openGraph: {
    type: 'website',
    url: new URL(url.pathname, url.origin).href,
    title: 'Sveltey - SvelteKit SaaS Template',
    description: 'Your OpenGraph description...',
    siteName: 'Sveltey',
    locale: 'en_US',
    images: [
      {
        url: `${url.origin}/og-image.jpg`,
        width: 1200,
        height: 630,
        alt: 'Sveltey - SvelteKit SaaS Template',
        type: 'image/jpeg'
      }
    ]
  },
  
  twitter: {
    cardType: 'summary_large_image',
    site: '@sveltey_dev',
    creator: '@sveltey_dev',
    title: 'Sveltey - SvelteKit SaaS Template',
    description: 'Your Twitter description...',
    image: `${url.origin}/og-image.jpg`,
    imageAlt: 'Sveltey - SvelteKit SaaS Template'
  }
}) satisfies MetaTagsProps;

Customizing Page Meta Tags

Each page can override and extend the base meta tags by exporting a load function in its +page.ts file:

// src/routes/your-page/+page.ts
import type { MetaTagsProps } from 'svelte-meta-tags';

export const load = () => {
  const pageMetaTags = Object.freeze({
    title: 'Your Page Title',
    description: 'Specific description for this page',
    keywords: ['additional', 'keywords', 'for', 'this', 'page'],
    
    openGraph: {
      title: 'Your Page Title - Brand Name',
      description: 'OpenGraph description for social sharing',
      type: 'article', // or 'website', 'product', etc.
      images: [
        {
          url: 'https://your-domain.com/specific-og-image.jpg',
          width: 1200,
          height: 630,
          alt: 'Description of your image'
        }
      ]
    },
    
    twitter: {
      title: 'Twitter-specific title',
      description: 'Twitter-specific description'
    },
    
    // Additional meta tags
    additionalMetaTags: [
      {
        name: 'author',
        content: 'Your Name'
      },
      {
        property: 'article:published_time',
        content: '2024-01-01T00:00:00Z'
      }
    ]
  }) satisfies MetaTagsProps;

  return {
    pageMetaTags
  };
};

Dynamic Meta Tags

For dynamic pages (like blog posts), you can generate meta tags based on content:

// src/routes/blog/[slug]/+page.server.ts
export const load = async ({ params, url }) => {
  const post = await getPostBySlug(params.slug);
  
  const pageMetaTags = Object.freeze({
    title: post.title,
    description: post.excerpt,
    canonical: new URL(`/blog/${params.slug}`, url.origin).href,
    
    openGraph: {
      type: 'article',
      title: post.title,
      description: post.excerpt,
      url: new URL(`/blog/${params.slug}`, url.origin).href,
      images: post.featuredImage ? [
        {
          url: post.featuredImage,
          width: 1200,
          height: 630,
          alt: post.title
        }
      ] : undefined,
      article: {
        publishedTime: post.publishedAt,
        authors: [post.author],
        section: 'Technology',
        tags: post.tags
      }
    }
  }) satisfies MetaTagsProps;
  
  return { post, pageMetaTags };
};

Robot Control

Control search engine indexing per page:

const pageMetaTags = {
  robots: 'noindex,nofollow', // Don't index this page
  // or
  robots: 'index,follow', // Index this page (default)
  // or
  robots: 'index,nofollow' // Index but don't follow links
};

🖼️ OpenGraph Images

OpenGraph images are crucial for social media sharing and SEO. Sveltey provides a flexible system for managing these images.

Setting Up OpenGraph Images

1. Default Site Image

Place your default OpenGraph image in the static folder:

static/
├── og-image.jpg        # Default 1200x630 image
├── og-image-square.jpg # Optional square variant
└── favicon.png

The default image is automatically referenced in your base meta tags:

// src/routes/+layout.ts
openGraph: {
  images: [
    {
      url: `${url.origin}/og-image.jpg`,
      width: 1200,
      height: 630,
      alt: 'Sveltey - SvelteKit SaaS Template',
      type: 'image/jpeg'
    }
  ]
}

2. Page-Specific Images

Override the default image for specific pages:

// src/routes/pricing/+page.ts
const pageMetaTags = {
  openGraph: {
    images: [
      {
        url: `${url.origin}/og-pricing.jpg`,
        width: 1200,
        height: 630,
        alt: 'Sveltey Pricing Plans',
        type: 'image/jpeg'
      }
    ]
  }
};

3. Dynamic Images for Blog Posts

For blog posts or dynamic content, you can generate or specify images dynamically:

// src/routes/blog/[slug]/+page.server.ts
const pageMetaTags = {
  openGraph: {
    images: post.featuredImage ? [
      {
        url: post.featuredImage,
        width: 1200,
        height: 630,
        alt: post.title,
        type: 'image/jpeg'
      }
    ] : [
      {
        url: `${url.origin}/og-blog-default.jpg`,
        width: 1200,
        height: 630,
        alt: 'Sveltey Blog',
        type: 'image/jpeg'
      }
    ]
  }
};

OpenGraph Image Best Practices

Image Specifications

  • Recommended Size: 1200x630 pixels (1.91:1 aspect ratio)
  • Minimum Size: 600x315 pixels
  • Maximum Size: 8MB
  • Format: JPG or PNG (JPG preferred for smaller file size)

Design Guidelines

// Example with multiple image variants
openGraph: {
  images: [
    {
      url: `${url.origin}/og-image-large.jpg`,
      width: 1200,
      height: 630,
      alt: 'Large image for Facebook, LinkedIn',
      type: 'image/jpeg'
    },
    {
      url: `${url.origin}/og-image-square.jpg`,
      width: 1080,
      height: 1080,
      alt: 'Square image for Instagram, Twitter',
      type: 'image/jpeg'
    }
  ]
}

Dynamic Image Generation

For advanced use cases, you can generate images dynamically:

// src/routes/api/og/[slug]/+server.ts
export async function GET({ params, url }) {
  const post = await getPostBySlug(params.slug);
  
  // Generate image using libraries like @vercel/og or canvas
  const image = await generateOGImage({
    title: post.title,
    author: post.author,
    template: 'blog-post'
  });
  
  return new Response(image, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=31536000, immutable'
    }
  });
}

Then reference it in your meta tags:

openGraph: {
  images: [
    {
      url: `${url.origin}/api/og/${params.slug}`,
      width: 1200,
      height: 630,
      alt: post.title,
      type: 'image/png'
    }
  ]
}

Testing OpenGraph Images

Use these tools to test your OpenGraph implementation:

Common OpenGraph Properties

openGraph: {
  type: 'website',           // website, article, product, etc.
  title: 'Page Title',       // Specific title for social sharing
  description: 'Description', // Social media description
  url: 'https://example.com', // Canonical URL
  siteName: 'Site Name',     // Your site/brand name
  locale: 'en_US',           // Language and region
  
  // For articles
  article: {
    publishedTime: '2024-01-01T00:00:00Z',
    modifiedTime: '2024-01-02T00:00:00Z',
    authors: ['Author Name'],
    section: 'Technology',
    tags: ['svelte', 'sveltekit']
  },
  
  // For products
  product: {
    price: {
      amount: '29.99',
      currency: 'USD'
    }
  }
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

🙏 Acknowledgments


Ready to launch your SaaS? Get started with Sveltey today!