├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── components.json ├── package.json ├── postcss.config.js ├── src ├── app.css ├── app.d.ts ├── app.html ├── content │ ├── customize.md │ ├── examples.md │ ├── features.md │ ├── index.md │ └── styling │ │ ├── syntax-highlighting.md │ │ └── theme.md ├── lib │ ├── components │ │ ├── app-sidebar.svelte │ │ ├── breadcrumb.svelte │ │ ├── dark-mode-toggle.svelte │ │ ├── doc-navigation.svelte.ts │ │ ├── doc-search.svelte.ts │ │ ├── document │ │ │ ├── doc-content.svelte │ │ │ ├── doc-header.svelte │ │ │ ├── doc-renderer.svelte │ │ │ ├── mobile-table-of-contents.svelte │ │ │ ├── promo-card.svelte │ │ │ ├── table-of-contents.svelte │ │ │ └── toc.svelte.ts │ │ ├── home │ │ │ ├── features.svelte │ │ │ ├── footer.svelte │ │ │ ├── hero.svelte │ │ │ └── nav.svelte │ │ ├── search-bar.svelte │ │ ├── sidebar-page.svelte │ │ ├── social-media.svelte │ │ └── ui │ │ │ ├── avatar │ │ │ ├── avatar-fallback.svelte │ │ │ ├── avatar-image.svelte │ │ │ ├── avatar.svelte │ │ │ └── index.ts │ │ │ ├── badge │ │ │ ├── badge.svelte │ │ │ └── index.ts │ │ │ ├── breadcrumb │ │ │ ├── breadcrumb-ellipsis.svelte │ │ │ ├── breadcrumb-item.svelte │ │ │ ├── breadcrumb-link.svelte │ │ │ ├── breadcrumb-list.svelte │ │ │ ├── breadcrumb-page.svelte │ │ │ ├── breadcrumb-separator.svelte │ │ │ ├── breadcrumb.svelte │ │ │ └── index.ts │ │ │ ├── button │ │ │ ├── button.svelte │ │ │ └── index.ts │ │ │ ├── card │ │ │ ├── card-content.svelte │ │ │ ├── card-description.svelte │ │ │ ├── card-footer.svelte │ │ │ ├── card-header.svelte │ │ │ ├── card-title.svelte │ │ │ ├── card.svelte │ │ │ └── index.ts │ │ │ ├── collapsible │ │ │ └── index.ts │ │ │ ├── command │ │ │ ├── command-dialog.svelte │ │ │ ├── command-empty.svelte │ │ │ ├── command-group.svelte │ │ │ ├── command-input.svelte │ │ │ ├── command-item.svelte │ │ │ ├── command-list.svelte │ │ │ ├── command-separator.svelte │ │ │ ├── command-shortcut.svelte │ │ │ ├── command.svelte │ │ │ └── index.ts │ │ │ ├── dialog │ │ │ ├── dialog-content.svelte │ │ │ ├── dialog-description.svelte │ │ │ ├── dialog-footer.svelte │ │ │ ├── dialog-header.svelte │ │ │ ├── dialog-overlay.svelte │ │ │ ├── dialog-portal.svelte │ │ │ ├── dialog-title.svelte │ │ │ └── index.ts │ │ │ ├── dropdown-menu │ │ │ ├── dropdown-menu-checkbox-item.svelte │ │ │ ├── dropdown-menu-content.svelte │ │ │ ├── dropdown-menu-group-heading.svelte │ │ │ ├── dropdown-menu-item.svelte │ │ │ ├── dropdown-menu-label.svelte │ │ │ ├── dropdown-menu-radio-item.svelte │ │ │ ├── dropdown-menu-separator.svelte │ │ │ ├── dropdown-menu-shortcut.svelte │ │ │ ├── dropdown-menu-sub-content.svelte │ │ │ ├── dropdown-menu-sub-trigger.svelte │ │ │ └── index.ts │ │ │ ├── input │ │ │ ├── index.ts │ │ │ └── input.svelte │ │ │ ├── label │ │ │ ├── index.ts │ │ │ └── label.svelte │ │ │ ├── scroll-area │ │ │ ├── index.ts │ │ │ ├── scroll-area-scrollbar.svelte │ │ │ └── scroll-area.svelte │ │ │ ├── separator │ │ │ ├── index.ts │ │ │ └── separator.svelte │ │ │ ├── sheet │ │ │ ├── index.ts │ │ │ ├── sheet-content.svelte │ │ │ ├── sheet-description.svelte │ │ │ ├── sheet-footer.svelte │ │ │ ├── sheet-header.svelte │ │ │ ├── sheet-overlay.svelte │ │ │ └── sheet-title.svelte │ │ │ ├── sidebar │ │ │ ├── constants.ts │ │ │ ├── context.svelte.ts │ │ │ ├── index.ts │ │ │ ├── sidebar-content.svelte │ │ │ ├── sidebar-footer.svelte │ │ │ ├── sidebar-group-action.svelte │ │ │ ├── sidebar-group-content.svelte │ │ │ ├── sidebar-group-label.svelte │ │ │ ├── sidebar-group.svelte │ │ │ ├── sidebar-header.svelte │ │ │ ├── sidebar-input.svelte │ │ │ ├── sidebar-inset.svelte │ │ │ ├── sidebar-menu-action.svelte │ │ │ ├── sidebar-menu-badge.svelte │ │ │ ├── sidebar-menu-button.svelte │ │ │ ├── sidebar-menu-item.svelte │ │ │ ├── sidebar-menu-skeleton.svelte │ │ │ ├── sidebar-menu-sub-button.svelte │ │ │ ├── sidebar-menu-sub-item.svelte │ │ │ ├── sidebar-menu-sub.svelte │ │ │ ├── sidebar-menu.svelte │ │ │ ├── sidebar-provider.svelte │ │ │ ├── sidebar-rail.svelte │ │ │ ├── sidebar-separator.svelte │ │ │ ├── sidebar-trigger.svelte │ │ │ └── sidebar.svelte │ │ │ ├── skeleton │ │ │ ├── index.ts │ │ │ └── skeleton.svelte │ │ │ ├── sonner │ │ │ ├── index.ts │ │ │ └── sonner.svelte │ │ │ └── tooltip │ │ │ ├── index.ts │ │ │ └── tooltip-content.svelte │ ├── config.ts │ ├── hooks │ │ └── is-mobile.svelte.ts │ ├── index.ts │ ├── types │ │ ├── config.ts │ │ ├── docs.ts │ │ └── nav.ts │ └── utils.ts └── routes │ ├── +layout.svelte │ ├── +page.svelte │ └── docs │ ├── +layout.svelte │ ├── +layout.ts │ ├── +page.svelte │ ├── +page.ts │ └── [...slug] │ ├── +page.svelte │ └── +page.ts ├── static ├── favicon.png ├── hero-bg-dark.svg ├── hero-bg.svg ├── logo-white.svg └── logo.svg ├── svelte.config.js ├── tailwind.config.ts ├── tsconfig.json ├── vite.config.ts └── wrangler.toml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | .netlify 7 | .wrangler 8 | /.svelte-kit 9 | /build 10 | 11 | # OS 12 | .DS_Store 13 | Thumbs.db 14 | 15 | # Env 16 | .env 17 | .env.* 18 | !.env.example 19 | !.env.test 20 | 21 | # Vite 22 | vite.config.js.timestamp-* 23 | vite.config.ts.timestamp-* 24 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 7 | "overrides": [ 8 | { 9 | "files": "*.svelte", 10 | "options": { 11 | "parser": "svelte" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Documentation Template 2 | 3 | A modern documentation template built with Svelte 5, MDSvex, and Tailwind CSS. 4 | 5 | [Template Preview](https://svelte-docs.codegio.com/) 6 | 7 | ## Overview 8 | 9 | Create beautiful, modern documentation sites with minimal setup. This template combines the power of Svelte 5 with the flexibility of Markdown to deliver a superior documentation experience. 10 | 11 | ## Features 12 | 13 | - **📚 MDSvex Integration** - Write documentation in Markdown with Svelte components 14 | - **🎨 Modern Design** - Built with Tailwind CSS and shadcn/ui components 15 | - **🌙 Dark Mode** - Automatic dark mode with system preference detection 16 | - **🔍 Search** - Built-in search functionality powered by FlexSearch 17 | - **📱 Responsive** - Mobile-first design that works on all devices 18 | - **📑 Auto-Navigation** - Automatic documentation structure generation 19 | - **📖 Table of Contents** - Dynamic table of contents for each page 20 | - **⚡ Fast** - Optimized for speed and performance 21 | - **🔒 Type Safe** - Full TypeScript support 22 | 23 | ## Quick Start 24 | 25 | 1. Click the green "Use this template" button 26 | 2. Create a new repository 27 | 3. Clone your repository: 28 | ```bash 29 | git clone https://github.com/yourusername/your-repo-name.git 30 | ``` 31 | 4. Install dependencies: 32 | ```bash 33 | cd your-repo-name 34 | npm install 35 | ``` 36 | 5. Start the development server: 37 | ```bash 38 | npm run dev 39 | ``` 40 | 41 | ## Project Structure 42 | 43 | ``` 44 | your-project/ 45 | ├── src/ 46 | │ ├── content/ # Documentation markdown files 47 | │ ├── lib/ 48 | │ │ ├── components/ # Core components 49 | │ │ │ ├── document/ # Document-related components 50 | │ │ │ ├── home/ # Home page components 51 | │ │ │ └── ui/ # UI components 52 | │ │ ├── hooks/ # Custom hooks 53 | │ │ ├── types/ # TypeScript type definitions 54 | │ │ ├── config.ts # Site configuration 55 | │ │ ├── index.ts # Library exports 56 | │ │ └── utils.ts # Utility functions 57 | │ ├── routes/ # SvelteKit routes 58 | │ ├── app.css # Global styles 59 | │ ├── app.d.ts # TypeScript declarations 60 | │ └── app.html # HTML template 61 | └── static/ # Static assets 62 | ``` 63 | 64 | ## Writing Documentation 65 | 66 | Place your markdown files in the `src/content` directory. The folder structure will automatically generate the navigation. 67 | 68 | ```markdown 69 | --- 70 | title: Getting Started 71 | description: Learn how to use this template 72 | --- 73 | 74 | # Getting Started 75 | 76 | Write your documentation here... 77 | ``` 78 | 79 | ## Customization 80 | 81 | ### Themes 82 | Modify the theme in `src/app.css` or use pre-built themes from [shadcn-svelte](https://next.shadcn-svelte.com/themes). 83 | 84 | ### Components 85 | Customize components in `src/lib/components` to match your brand. 86 | 87 | ### Configuration 88 | Update site settings in `src/lib/config`: 89 | ```typescript 90 | export const siteConfig = { 91 | title: 'Your Documentation', 92 | description: 'Your site description', 93 | // ...other settings 94 | }; 95 | ``` 96 | 97 | ## Development 98 | 99 | ```bash 100 | # Start development server 101 | npm run dev 102 | 103 | # Build for production 104 | npm run build 105 | 106 | # Preview production build 107 | npm run preview 108 | ``` 109 | 110 | ## Deployment 111 | 112 | This template can be deployed to any static hosting platform: 113 | 114 | - Vercel 115 | - Netlify 116 | - GitHub Pages 117 | - Cloudflare Pages 118 | 119 | ## Contributing 120 | 121 | Contributions are welcome! Please feel free to submit a Pull Request. 122 | 123 | ## License 124 | 125 | MIT License - use this template for any project. 126 | 127 | ## Acknowledgments 128 | 129 | - [Svelte](https://svelte.dev) 130 | - [shadcn-svelte](https://next.shadcn-svelte.com) 131 | - [Tailwind CSS](https://tailwindcss.com) 132 | - [MDSvex](https://mdsvex.com) 133 | 134 | ## Support 135 | 136 | Need help with your documentation? [Contact us](mailto:info@codegio.com). -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://next.shadcn-svelte.com/schema.json", 3 | "style": "new-york", 4 | "tailwind": { 5 | "config": "tailwind.config.ts", 6 | "css": "src/app.css", 7 | "baseColor": "slate" 8 | }, 9 | "aliases": { 10 | "components": "$lib/components", 11 | "utils": "$lib/utils", 12 | "ui": "$lib/components/ui", 13 | "hooks": "$lib/hooks" 14 | }, 15 | "typescript": true, 16 | "registry": "https://next.shadcn-svelte.com/registry" 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "documentation", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite dev", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 | "format": "prettier --write .", 13 | "lint": "prettier --check ." 14 | }, 15 | "devDependencies": { 16 | "@sveltejs/adapter-auto": "^3.0.0", 17 | "@sveltejs/adapter-cloudflare": "^4.9.0", 18 | "@sveltejs/kit": "^2.9.0", 19 | "@sveltejs/vite-plugin-svelte": "^5.0.0", 20 | "@tailwindcss/typography": "^0.5.15", 21 | "autoprefixer": "^10.4.20", 22 | "bits-ui": "^1.0.0-next.74", 23 | "clsx": "^2.1.1", 24 | "cmdk-sv": "^0.0.18", 25 | "lucide-svelte": "^0.468.0", 26 | "mode-watcher": "^0.5.0", 27 | "prettier": "^3.3.2", 28 | "prettier-plugin-svelte": "^3.2.6", 29 | "prettier-plugin-tailwindcss": "^0.6.5", 30 | "shiki": "^1.24.3", 31 | "svelte": "^5.0.0", 32 | "svelte-check": "^4.0.0", 33 | "svelte-sonner": "^0.3.28", 34 | "tailwind-merge": "^2.5.5", 35 | "tailwind-variants": "^0.3.0", 36 | "tailwindcss": "^3.4.9", 37 | "tailwindcss-animate": "^1.0.7", 38 | "typescript": "^5.0.0", 39 | "vite": "^6.0.0" 40 | }, 41 | "dependencies": { 42 | "flexsearch": "^0.7.43", 43 | "mdsvex": "^0.12.3" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 84% 4.9%; 9 | --card: 0 0% 100%; 10 | --card-foreground: 222.2 84% 4.9%; 11 | --popover: 0 0% 100%; 12 | --popover-foreground: 222.2 84% 4.9%; 13 | --primary: 221.2 83.2% 53.3%; 14 | --primary-foreground: 210 40% 98%; 15 | --secondary: 210 40% 96.1%; 16 | --secondary-foreground: 222.2 47.4% 11.2%; 17 | --muted: 210 40% 96.1%; 18 | --muted-foreground: 215.4 16.3% 46.9%; 19 | --accent: 210 40% 96.1%; 20 | --accent-foreground: 222.2 47.4% 11.2%; 21 | --destructive: 0 72.22% 50.59%; 22 | --destructive-foreground: 210 40% 98%; 23 | --border: 214.3 31.8% 91.4%; 24 | --input: 214.3 31.8% 91.4%; 25 | --ring: 221.2 83.2% 53.3%; 26 | --radius: 0.5rem; 27 | } 28 | .dark { 29 | --background: 222.2 84% 4.9%; 30 | --foreground: 210 40% 98%; 31 | --card: 222.2 84% 4.9%; 32 | --card-foreground: 210 40% 98%; 33 | --popover: 222.2 84% 4.9%; 34 | --popover-foreground: 210 40% 98%; 35 | --primary: 217.2 91.2% 59.8%; 36 | --primary-foreground: 222.2 47.4% 11.2%; 37 | --secondary: 217.2 32.6% 17.5%; 38 | --secondary-foreground: 210 40% 98%; 39 | --muted: 217.2 32.6% 17.5%; 40 | --muted-foreground: 215 20.2% 65.1%; 41 | --accent: 217.2 32.6% 17.5%; 42 | --accent-foreground: 210 40% 98%; 43 | --destructive: 0 62.8% 30.6%; 44 | --destructive-foreground: 210 40% 98%; 45 | --border: 217.2 32.6% 17.5%; 46 | --input: 217.2 32.6% 17.5%; 47 | --ring: 224.3 76.3% 48%; 48 | } 49 | } 50 | @layer base { 51 | :root { 52 | --sidebar-background: 0 0% 98%; 53 | --sidebar-foreground: 240 5.3% 26.1%; 54 | --sidebar-primary: 240 5.9% 10%; 55 | --sidebar-primary-foreground: 0 0% 98%; 56 | --sidebar-accent: 240 4.8% 95.9%; 57 | --sidebar-accent-foreground: 240 5.9% 10%; 58 | --sidebar-border: 220 13% 91%; 59 | --sidebar-ring: 217.2 91.2% 59.8%; 60 | } 61 | 62 | .dark { 63 | --sidebar-background: 240 5.9% 10%; 64 | --sidebar-foreground: 240 4.8% 95.9%; 65 | --sidebar-primary: 224.3 76.3% 48%; 66 | --sidebar-primary-foreground: 0 0% 100%; 67 | --sidebar-accent: 240 3.7% 15.9%; 68 | --sidebar-accent-foreground: 240 4.8% 95.9%; 69 | --sidebar-border: 240 3.7% 15.9%; 70 | --sidebar-ring: 217.2 91.2% 59.8%; 71 | } 72 | } 73 | 74 | @layer base { 75 | * { 76 | @apply border-border; 77 | } 78 | 79 | body { 80 | @apply bg-background text-foreground; 81 | } 82 | } 83 | 84 | @layer utilities { 85 | .prose { 86 | --tw-prose-pre-bg: transparent; 87 | } 88 | 89 | .prose pre { 90 | background-color: transparent !important; 91 | margin: 0 !important; 92 | padding: 0 !important; 93 | } 94 | 95 | .prose :not(pre)>code { 96 | background-color: hsl(var(--muted)); 97 | color: hsl(var(--foreground)); 98 | padding: 0.25rem 0.375rem; 99 | border-radius: 0.25rem; 100 | font-weight: 400; 101 | font-size: 0.875em; 102 | } 103 | 104 | .prose code::before, 105 | .prose code::after { 106 | content: "" !important; 107 | } 108 | } 109 | 110 | html { 111 | scroll-padding-top: 6rem; 112 | scroll-behavior: smooth; 113 | } -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://svelte.dev/docs/kit/types#app.d.ts 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | interface Platform { 10 | env: { 11 | COUNTER: DurableObjectNamespace; 12 | }; 13 | context: { 14 | waitUntil(promise: Promise): void; 15 | }; 16 | caches: CacheStorage & { default: Cache } 17 | } 18 | } 19 | } 20 | 21 | export { }; 22 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/content/customize.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Customization Guide 3 | description: Learn how to customize your documentation site to match your brand and requirements 4 | --- 5 | 6 | 7 | This guide will walk you through the various ways you can customize your documentation site to match your brand identity and specific needs. All customizations are type-safe, providing excellent IDE support and a reliable development experience. 8 | 9 | ## Site Configuration 10 | 11 | The primary way to customize your site is through the `siteConfig.ts` file. The configuration follows the `SiteConfig` interface: 12 | 13 | ```typescript 14 | interface SiteConfig { 15 | /** Current version of the documentation/project */ 16 | version: string; 17 | 18 | /** Main title of the documentation site */ 19 | title: string; 20 | 21 | /** Detailed description of the project/documentation */ 22 | description: string; 23 | 24 | /** GitHub repository URL */ 25 | github: string; 26 | 27 | /** NPM package name */ 28 | npm: string; 29 | 30 | /** Array of quick navigation links */ 31 | quickLinks: QuickLink[]; 32 | 33 | /** Path to the main logo (light theme) */ 34 | logo: string; 35 | 36 | /** Path to the dark theme logo (optional) */ 37 | logoDark?: string; 38 | 39 | /** Path to the site favicon */ 40 | favicon: string; 41 | } 42 | ``` 43 | 44 | Example configuration: 45 | 46 | ```typescript 47 | export const siteConfig: SiteConfig = { 48 | version: '0.0.1', 49 | title: 'Documentation', 50 | description: 'Comprehensive documentation for your project', 51 | github: 'https://github.com/yourusername/your-repo', 52 | npm: 'your-package-name', 53 | quickLinks: [ 54 | { title: 'Customize', href: '/docs/customize' }, 55 | { title: 'Examples', href: '/docs/examples' } 56 | ], 57 | logo: '/logo.svg', 58 | logoDark: '/logo-white.svg', 59 | favicon: '/favicon.png', 60 | }; 61 | ``` 62 | 63 | ## Feature Highlights 64 | 65 | Features are defined using the `Feature` interface, which requires an icon from Lucide, a title, and a description: 66 | 67 | ```typescript 68 | interface Feature { 69 | icon: typeof IconType; 70 | title: string; 71 | description: string; 72 | } 73 | ``` 74 | 75 | Example feature configuration: 76 | 77 | ```typescript 78 | import { Boxes, Workflow, Paintbrush, Zap } from 'lucide-svelte'; 79 | 80 | export const features: Feature[] = [ 81 | { 82 | icon: Boxes, 83 | title: 'Component Library', 84 | description: 'Built on top of shadcn/ui, offering comprehensive accessible components' 85 | }, 86 | { 87 | icon: Workflow, 88 | title: 'Type Safe', 89 | description: 'Fully typed with TypeScript for excellent IDE support' 90 | }, 91 | // Add more features as needed 92 | ]; 93 | ``` 94 | 95 | ## Promotional Section 96 | 97 | The promotional section is configured using the `PromoConfig` interface: 98 | 99 | ```typescript 100 | interface PromoConfig { 101 | title: string; 102 | description: string; 103 | ctaText: string; 104 | ctaLink: string; 105 | lightImage?: string; 106 | darkImage?: string; 107 | } 108 | ``` 109 | 110 | Example promotional configuration: 111 | 112 | ```typescript 113 | export let promoConfig: PromoConfig = { 114 | title: 'Need help with your project?', 115 | description: 'Custom development services and technical guidance for your web applications', 116 | ctaText: "Let's work together", 117 | ctaLink: 'mailto:your@email.com', 118 | lightImage: '/images/promo-light.jpg', 119 | darkImage: '/images/promo-dark.jpg' 120 | }; 121 | ``` 122 | 123 | ## Quick Links 124 | 125 | Quick links are typed using the `QuickLink` interface imported from the nav types: 126 | 127 | ```typescript 128 | import type { QuickLink } from "$lib/types/nav"; 129 | 130 | export const quickLinks: QuickLink[] = [ 131 | { title: 'Customize', href: '/docs/customize' }, 132 | { title: 'Examples', href: '/docs/examples' } 133 | ]; 134 | ``` 135 | 136 | Each quick link requires a title and href property, providing easy navigation to key sections of your documentation. 137 | 138 | Remember to rebuild your site after making configuration changes to see the updates take effect. -------------------------------------------------------------------------------- /src/content/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Example Sites 3 | description: Showcase of websites and documentation built with our documentation template 4 | --- 5 | 6 | 7 | Discover how different projects are using this documentation template to create beautiful, functional documentation sites. 8 | 9 | ## Featured Examples 10 | 11 | ### Svelte FireKit 12 | **[firekit.codegio.com](https://firekit.codegio.com/)** 13 | 14 | Svelte FireKit is a comprehensive Firebase integration library designed specifically for Svelte applications. Their documentation showcases how to effectively present complex technical content while maintaining clean design and excellent usability. 15 | 16 | 17 | ## Add Your Site 18 | 19 | Are you using this documentation template for your project? We'd love to feature your site here! 20 | 21 | To have your site added to this showcase: 22 | 1. Ensure your site is publicly accessible 23 | 2. Send us an email at [info@codegio.com](mailto:info@codegio.com) with: 24 | - Your site's URL 25 | - A brief description of your project 26 | - How you've customized the template 27 | - Any notable features or modifications 28 | 29 | ## Showcase Guidelines 30 | 31 | To be featured in our examples, sites should: 32 | - Be built using this documentation template 33 | - Maintain good performance 34 | - Follow accessibility best practices 35 | - Demonstrate unique customizations or use cases 36 | 37 | ## Coming Soon 38 | 39 | We're constantly adding new examples to this showcase. Check back regularly to see more implementations and creative uses of our documentation template. 40 | 41 | --- 42 | 43 | *Want to be featured here? [Contact me](mailto:info@codegio.com) to submit your site for consideration.* -------------------------------------------------------------------------------- /src/content/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Features 3 | description: Explore the powerful features that make this documentation template stand out 4 | --- 5 | 6 | # Features 7 | 8 | Our documentation template comes with powerful built-in features designed to enhance both the developer and user experience. 9 | 10 | ## Automatic Documentation Navigation 11 | 12 | The template automatically generates a navigation structure from your markdown files using an intelligent singleton pattern. 13 | 14 | ### How It Works 15 | - Automatically scans your `/src/content` directory for markdown files 16 | - Creates a nested navigation structure based on your folder hierarchy 17 | - Supports customization through frontmatter metadata 18 | - Handles special cases like index files and single-file folders 19 | - Maintains a clean, organized sidebar structure 20 | 21 | ```typescript 22 | // Example markdown frontmatter 23 | --- 24 | title: Getting Started 25 | description: Quick start guide 26 | disabled: false 27 | external: false 28 | label: New 29 | --- 30 | ``` 31 | 32 | ## Dynamic Table of Contents 33 | 34 | Every documentation page automatically generates a table of contents from your markdown headings. 35 | 36 | ### Features 37 | - Automatically extracts h1-h6 headings 38 | - Generates unique IDs for each heading 39 | - Updates in real-time as content changes 40 | - Supports smooth scrolling to sections 41 | - Provides both desktop and mobile views 42 | - Maintains active section highlighting 43 | 44 | The table of contents is implemented using a reactive system that: 45 | - Watches for DOM changes 46 | - Updates navigation states automatically 47 | - Provides smooth scrolling behavior 48 | - Supports dynamic content updates 49 | 50 | ## Document Search 51 | 52 | Built-in search functionality powered by FlexSearch provides fast and accurate content discovery. 53 | 54 | ### Search Features 55 | - Full-text search across all documentation 56 | - Real-time search results 57 | - Search through titles and content 58 | - Fuzzy matching support 59 | - Type-ahead suggestions 60 | - Relevant result highlighting 61 | - Mobile-friendly search interface 62 | 63 | ```typescript 64 | // Example search usage 65 | const results = await docsSearch.search("authentication"); 66 | ``` 67 | 68 | ## Dark Mode Support 69 | 70 | The template includes a fully functional dark mode with system preference detection. 71 | 72 | ### Dark Mode Features 73 | - System preference detection 74 | - Manual toggle option 75 | - Persistent preference storage 76 | - Smooth theme transitions 77 | - Consistent styling across components 78 | - Dark mode optimized syntax highlighting 79 | 80 | ## Responsive Design 81 | 82 | The documentation template is fully responsive and optimized for all device sizes. 83 | 84 | ### Responsive Features 85 | - Mobile-first approach 86 | - Adaptive navigation 87 | - Responsive tables and code blocks 88 | - Touch-friendly interactions 89 | - Optimized reading experience 90 | - Collapsible sidebar on mobile 91 | 92 | ## Promotional Components 93 | 94 | Built-in promotional components help you highlight important information or calls-to-action. 95 | 96 | ### Promo Features 97 | - Customizable promo cards 98 | - Strategic placement options 99 | - Responsive design 100 | - Dark mode support 101 | - Call-to-action buttons 102 | - Custom imagery support 103 | 104 | ## Full Customization 105 | 106 | The template is designed to be fully customizable to match your brand and requirements. 107 | 108 | ### Customization Options 109 | - Theme customization 110 | - Typography settings 111 | - Layout modifications 112 | - Component styling 113 | - Navigation structure 114 | - Search behavior 115 | - Promotional content 116 | - Syntax highlighting 117 | 118 | ## Quick Reference 119 | 120 | ```typescript 121 | // Initialize documentation features 122 | await docsNavigation.generateNavigation(); 123 | await docsSearch.initializeSearchIndex(); 124 | const toc = TableOfContents.getInstance(contentRef); 125 | ``` 126 | 127 | All features are implemented using singleton patterns for efficient state management and consistent behavior across your documentation site. -------------------------------------------------------------------------------- /src/content/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get Started 3 | description: Learn how to set up and start using our modern documentation template built with Svelte 5, MDSvex, and Tailwind CSS. 4 | --- 5 | 6 | # Getting Started 7 | 8 | Create beautiful, modern documentation for your project in minutes with our Svelte-powered documentation template. 9 | 10 | ## Prerequisites 11 | 12 | Before you begin, ensure you have: 13 | - Node.js 18+ installed 14 | - Git installed 15 | - A GitHub account 16 | - Basic familiarity with Markdown 17 | 18 | ## Quick Start 19 | 20 | 1. Go to [GitHub](https://github.com/code-gio/svelte-docs-starter) click the green **"Use this template"** button at the top of this page 21 | 2. Select **"Create a new repository"** 22 | 3. Name your repository and choose its visibility 23 | 4. Click **"Create repository from template"** 24 | 5. Clone your new repository: 25 | ```bash 26 | git clone https://github.com/yourusername/your-repo-name.git 27 | ``` 28 | 6. Install dependencies: 29 | ```bash 30 | cd your-repo-name 31 | npm install 32 | ``` 33 | 7. Start the development server: 34 | ```bash 35 | npm run dev 36 | ``` 37 | 38 | Your documentation site is now running at `http://localhost:5173`! 39 | 40 | ## Core Features 41 | 42 | Our template combines powerful tools to create an exceptional documentation experience: 43 | 44 | - **Component Library**: Built on shadcn/ui for beautiful, accessible components 45 | - **Type Safety**: Full TypeScript support for reliable development 46 | - **Modern Stack**: Powered by Svelte 5, MDSvex, and TailwindCSS 47 | - **Customizable**: Easy theming and layout modifications 48 | 49 | ## Adding Content 50 | 51 | ### Creating Pages 52 | 53 | 1. Add new `.md` files in the `src/docs` directory 54 | 2. Include frontmatter at the top of your markdown files: 55 | ```markdown 56 | --- 57 | title: Your Page Title 58 | description: A brief description of the page 59 | --- 60 | ``` 61 | 3. Write your content using Markdown and MDSvex features 62 | 63 | ### Using Components 64 | 65 | Import and use Svelte components directly in your markdown: 66 | 67 | ```markdown 68 | 71 | 72 | # My Page 73 | 74 | 75 | This is a custom component in markdown! 76 | 77 | ``` 78 | 79 | ## Next Steps 80 | 81 | - Browse the [Examples](/docs/examples) to see what you can build 82 | - Learn about customization in our [Customization Guide](/docs/customize) 83 | - Check out our [Component Styling](/docs/styling/theme) 84 | 85 | ## Need Help? 86 | 87 | - Browse our [documentation](/docs) 88 | - Report issues on [GitHub](https://github.com/code-gio/svelte-docs-starter/issues) 89 | - Check out the [examples](/docs/examples) for inspiration -------------------------------------------------------------------------------- /src/content/styling/syntax-highlighting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Syntax Highlighting 3 | description: Learn how to customize code syntax highlighting using Shiki 4 | --- 5 | 6 | 7 | The documentation template uses [Shiki](https://shiki.matsu.io/) for syntax highlighting. This guide explains how to customize themes and add support for additional programming languages. 8 | 9 | ## Adding Custom Themes 10 | 11 | ### Step 1: Import Themes 12 | In your `doc-render.svelte` component, modify the `createHighlighter` configuration to include your preferred themes: 13 | 14 | ```typescript 15 | highlighter = await createHighlighter({ 16 | themes: [ 17 | 'github-dark', // Default dark theme 18 | 'github-light', // Default light theme 19 | 'dracula', // Add more themes 20 | 'nord', 21 | 'material-theme' 22 | ], 23 | langs: [ ... ] 24 | }); 25 | ``` 26 | 27 | ### Available Built-in Themes 28 | Shiki includes many popular themes out of the box: 29 | - `'github-dark'` 30 | - `'github-light'` 31 | - `'dracula'` 32 | - `'nord'` 33 | - `'monokai'` 34 | - `'material-theme'` 35 | - `'one-dark-pro'` 36 | - And [many more](https://github.com/shikijs/shiki/blob/main/docs/themes.md) 37 | 38 | ## Adding Programming Languages 39 | 40 | ### Step 1: Update Language Support 41 | Modify the `langs` array in the `createHighlighter` configuration: 42 | 43 | ```typescript 44 | highlighter = await createHighlighter({ 45 | themes: ['github-dark', 'github-light'], 46 | langs: [ 47 | // Currently supported languages 48 | 'typescript', 49 | 'javascript', 50 | 'bash', 51 | 'markdown', 52 | 'json', 53 | 'html', 54 | 'css', 55 | 'svelte', 56 | 'shell', 57 | 'tsx', 58 | // Add more languages 59 | 'python', 60 | 'rust', 61 | 'go', 62 | 'java', 63 | 'php', 64 | 'ruby', 65 | 'yaml' 66 | ] 67 | }); 68 | ``` 69 | 70 | ### Available Languages 71 | Shiki supports a wide range of programming languages. Here are some popular ones: 72 | - Web: `html`, `css`, `javascript`, `typescript`, `jsx`, `tsx` 73 | - Backend: `python`, `ruby`, `php`, `java`, `rust`, `go` 74 | - Data: `json`, `yaml`, `toml` 75 | - Shell: `bash`, `shell`, `powershell` 76 | - And [many more](https://github.com/shikijs/shiki/blob/main/docs/languages.md) 77 | 78 | ## Customizing Styles 79 | 80 | ### Code Block Wrapper 81 | Modify the wrapper styles in the component's ` 125 | -------------------------------------------------------------------------------- /src/lib/components/document/mobile-table-of-contents.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | On This Page 16 | 17 | 18 | 19 | On this page 20 | 21 | 22 |
    23 | {#each toc.headings as heading} 24 |
  • 25 | 37 |
  • 38 | {/each} 39 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /src/lib/components/document/promo-card.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 |

10 | {promoConfig.title} 11 |

12 |

13 | {promoConfig.description} 14 |

15 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/lib/components/document/table-of-contents.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 |
14 | On this page 15 |
16 | 33 |
34 | -------------------------------------------------------------------------------- /src/lib/components/document/toc.svelte.ts: -------------------------------------------------------------------------------- 1 | export class TableOfContents { 2 | contentRef: HTMLElement | undefined; 3 | headings: Array<{ id: string; text: string; level: number }> = $state([]); 4 | private observer: MutationObserver | null = null; 5 | private static instance: TableOfContents 6 | 7 | private constructor(contentRef: HTMLElement | undefined) { 8 | this.contentRef = contentRef; 9 | if (contentRef) { 10 | this.initializeObserver(); 11 | } 12 | } 13 | 14 | static getInstance(contentRef?: HTMLElement): TableOfContents { 15 | if (!TableOfContents.instance) { 16 | TableOfContents.instance = new TableOfContents(contentRef); 17 | } else if (contentRef) { 18 | TableOfContents.instance.updateContentRef(contentRef); 19 | } 20 | return TableOfContents.instance; 21 | } 22 | 23 | updateContentRef(newRef: HTMLElement | undefined) { 24 | this.observer?.disconnect(); 25 | this.contentRef = newRef; 26 | if (newRef) { 27 | this.initializeObserver(); 28 | } else { 29 | this.headings = []; 30 | } 31 | } 32 | 33 | private extractHeadings() { 34 | if (!this.contentRef) return; 35 | const headingElements = this.contentRef.querySelectorAll('h1, h2, h3, h4, h5, h6'); 36 | 37 | this.headings = Array.from(headingElements) 38 | .map((heading) => { 39 | const level = parseInt(heading.tagName.charAt(1)); 40 | const text = heading.textContent || ''; 41 | const id = heading.id || text.toLowerCase().replace(/[^a-z0-9]+/g, '-'); 42 | 43 | if (!heading.id) heading.id = id; 44 | 45 | return { id, text, level }; 46 | }) 47 | .filter((heading): heading is { id: string; text: string; level: number } => 48 | heading.text !== null && heading.text !== '' 49 | ); 50 | } 51 | 52 | private initializeObserver() { 53 | this.extractHeadings(); 54 | 55 | this.observer = new MutationObserver(() => this.extractHeadings()); 56 | if (!this.contentRef) return; 57 | this.observer.observe(this.contentRef, { 58 | childList: true, 59 | subtree: true 60 | }); 61 | } 62 | 63 | destroy() { 64 | this.observer?.disconnect(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/lib/components/home/features.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 | {#each features as feature} 8 | 9 |
10 |
13 | 14 |
15 |
16 |

17 | {feature.title} 18 |

19 |

20 | {feature.description} 21 |

22 |
23 |
24 | 25 | {/each} 26 |
27 |
28 | -------------------------------------------------------------------------------- /src/lib/components/home/footer.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 33 | -------------------------------------------------------------------------------- /src/lib/components/home/hero.svelte: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 |
29 |
30 | 31 | 43 | 44 | 45 |
46 |

49 | {siteConfig.title} 50 |

51 |
52 | 53 | 54 |
55 |

56 | {siteConfig.description} 57 |

58 |
59 | 60 | 61 |
62 | 66 | 67 | {#if siteConfig.npm !== ''} 68 | 78 | {/if} 79 |
80 | 81 | 82 |
83 | Quick links: 84 | {#each siteConfig.quickLinks as link} 85 | 89 | 90 | {#if link !== siteConfig.quickLinks[siteConfig.quickLinks.length - 1]} 91 | 92 | {/if} 93 | {/each} 94 |
95 |
96 |
97 | -------------------------------------------------------------------------------- /src/lib/components/home/nav.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
16 | 96 |
97 | -------------------------------------------------------------------------------- /src/lib/components/search-bar.svelte: -------------------------------------------------------------------------------- 1 | 45 | 46 | 60 | 61 | 62 |
63 | 64 |
65 | 66 | 67 | {#if searchQuery === ''} 68 | 69 | Start typing to search documentation... 70 | 71 | {:else if searchResults.length === 0} 72 | 73 | No results found for "{searchQuery}" 74 | 75 | {:else if searchResults.length > 0} 76 | 77 | {#each searchResults as result} 78 | handleResultClick(result.slug)} 80 | class="flex items-start gap-2 px-2 py-3" 81 | > 82 | 83 |
84 | {result.title} 85 | 86 | {result.description} 87 | 88 |
89 |
90 | {/each} 91 |
92 | {/if} 93 | 94 | {#if searchQuery === '' || searchResults.length > 0} 95 | 96 | handleResultClick('')}> 97 | 98 | Browse All Documentation 99 | 100 | 101 | {/if} 102 |
103 |
104 | -------------------------------------------------------------------------------- /src/lib/components/sidebar-page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | 17 | 20 | 25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /src/lib/components/social-media.svelte: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 28 |
29 | {#each socialLinks as { title, href, icon }} 30 | 49 | {/each} 50 |
51 | 52 | 53 | 54 | 60 | -------------------------------------------------------------------------------- /src/lib/components/ui/avatar/avatar-fallback.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/avatar/avatar-image.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /src/lib/components/ui/avatar/avatar.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /src/lib/components/ui/avatar/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./avatar.svelte"; 2 | import Image from "./avatar-image.svelte"; 3 | import Fallback from "./avatar-fallback.svelte"; 4 | 5 | export { 6 | Root, 7 | Image, 8 | Fallback, 9 | // 10 | Root as Avatar, 11 | Image as AvatarImage, 12 | Fallback as AvatarFallback, 13 | }; 14 | -------------------------------------------------------------------------------- /src/lib/components/ui/badge/badge.svelte: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | 41 | 48 | {@render children?.()} 49 | 50 | -------------------------------------------------------------------------------- /src/lib/components/ui/badge/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Badge } from "./badge.svelte"; 2 | export { badgeVariants, type BadgeVariant } from "./badge.svelte"; 3 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-item.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
  • 15 | {@render children?.()} 16 |
  • 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-link.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | {#if child} 26 | {@render child({ props: attrs })} 27 | {:else} 28 | 29 | {@render children?.()} 30 | 31 | {/if} 32 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-list.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
      22 | {@render children?.()} 23 |
    24 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | {@render children?.()} 23 | 24 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/breadcrumb.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/lib/components/ui/breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./breadcrumb.svelte"; 2 | import Ellipsis from "./breadcrumb-ellipsis.svelte"; 3 | import Item from "./breadcrumb-item.svelte"; 4 | import Separator from "./breadcrumb-separator.svelte"; 5 | import Link from "./breadcrumb-link.svelte"; 6 | import List from "./breadcrumb-list.svelte"; 7 | import Page from "./breadcrumb-page.svelte"; 8 | 9 | export { 10 | Root, 11 | Ellipsis, 12 | Item, 13 | Separator, 14 | Link, 15 | List, 16 | Page, 17 | // 18 | Root as Breadcrumb, 19 | Ellipsis as BreadcrumbEllipsis, 20 | Item as BreadcrumbItem, 21 | Separator as BreadcrumbSeparator, 22 | Link as BreadcrumbLink, 23 | List as BreadcrumbList, 24 | Page as BreadcrumbPage, 25 | }; 26 | -------------------------------------------------------------------------------- /src/lib/components/ui/button/button.svelte: -------------------------------------------------------------------------------- 1 | 41 | 42 | 56 | 57 | {#if href} 58 | 64 | {@render children?.()} 65 | 66 | {:else} 67 | 75 | {/if} 76 | -------------------------------------------------------------------------------- /src/lib/components/ui/button/index.ts: -------------------------------------------------------------------------------- 1 | import Root, { 2 | type ButtonProps, 3 | type ButtonSize, 4 | type ButtonVariant, 5 | buttonVariants, 6 | } from "./button.svelte"; 7 | 8 | export { 9 | Root, 10 | type ButtonProps as Props, 11 | // 12 | Root as Button, 13 | buttonVariants, 14 | type ButtonProps, 15 | type ButtonSize, 16 | type ButtonVariant, 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card-content.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    15 | {@render children?.()} 16 |
    17 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card-description.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |

    15 | {@render children?.()} 16 |

    17 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card-footer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    15 | {@render children?.()} 16 |
    17 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card-header.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    15 | {@render children?.()} 16 |
    17 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card-title.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
    24 | {@render children?.()} 25 |
    26 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/card.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    19 | {@render children?.()} 20 |
    21 | -------------------------------------------------------------------------------- /src/lib/components/ui/card/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./card.svelte"; 2 | import Content from "./card-content.svelte"; 3 | import Description from "./card-description.svelte"; 4 | import Footer from "./card-footer.svelte"; 5 | import Header from "./card-header.svelte"; 6 | import Title from "./card-title.svelte"; 7 | 8 | export { 9 | Root, 10 | Content, 11 | Description, 12 | Footer, 13 | Header, 14 | Title, 15 | // 16 | Root as Card, 17 | Content as CardContent, 18 | Description as CardDescription, 19 | Footer as CardFooter, 20 | Header as CardHeader, 21 | Title as CardTitle, 22 | }; 23 | -------------------------------------------------------------------------------- /src/lib/components/ui/collapsible/index.ts: -------------------------------------------------------------------------------- 1 | import { Collapsible as CollapsiblePrimitive } from "bits-ui"; 2 | 3 | const Root: typeof CollapsiblePrimitive.Root = CollapsiblePrimitive.Root; 4 | const Trigger: typeof CollapsiblePrimitive.Trigger = CollapsiblePrimitive.Trigger; 5 | const Content: typeof CollapsiblePrimitive.Content = CollapsiblePrimitive.Content; 6 | 7 | export { 8 | Root, 9 | Content, 10 | Trigger, 11 | // 12 | Root as Collapsible, 13 | Content as CollapsibleContent, 14 | Trigger as CollapsibleTrigger, 15 | }; 16 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-dialog.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-empty.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-group.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-input.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 | 15 | 23 |
    24 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-item.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-list.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-separator.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command-shortcut.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/command.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/lib/components/ui/command/index.ts: -------------------------------------------------------------------------------- 1 | import { Command as CommandPrimitive } from "cmdk-sv"; 2 | 3 | import Root from "./command.svelte"; 4 | import Dialog from "./command-dialog.svelte"; 5 | import Empty from "./command-empty.svelte"; 6 | import Group from "./command-group.svelte"; 7 | import Item from "./command-item.svelte"; 8 | import Input from "./command-input.svelte"; 9 | import List from "./command-list.svelte"; 10 | import Separator from "./command-separator.svelte"; 11 | import Shortcut from "./command-shortcut.svelte"; 12 | 13 | const Loading = CommandPrimitive.Loading; 14 | 15 | export { 16 | Root, 17 | Dialog, 18 | Empty, 19 | Group, 20 | Item, 21 | Input, 22 | List, 23 | Separator, 24 | Shortcut, 25 | Loading, 26 | // 27 | Root as Command, 28 | Dialog as CommandDialog, 29 | Empty as CommandEmpty, 30 | Group as CommandGroup, 31 | Item as CommandItem, 32 | Input as CommandInput, 33 | List as CommandList, 34 | Separator as CommandSeparator, 35 | Shortcut as CommandShortcut, 36 | Loading as CommandLoading, 37 | }; 38 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-content.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 30 | {@render children?.()} 31 | 34 | 35 | Close 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-description.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-footer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    19 | {@render children?.()} 20 |
    21 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-header.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    19 | {@render children?.()} 20 |
    21 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-overlay.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-portal.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/dialog-title.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/dialog/index.ts: -------------------------------------------------------------------------------- 1 | import { Dialog as DialogPrimitive } from "bits-ui"; 2 | 3 | import Title from "./dialog-title.svelte"; 4 | import Footer from "./dialog-footer.svelte"; 5 | import Header from "./dialog-header.svelte"; 6 | import Overlay from "./dialog-overlay.svelte"; 7 | import Content from "./dialog-content.svelte"; 8 | import Description from "./dialog-description.svelte"; 9 | 10 | const Root: typeof DialogPrimitive.Root = DialogPrimitive.Root; 11 | const Trigger: typeof DialogPrimitive.Trigger = DialogPrimitive.Trigger; 12 | const Close: typeof DialogPrimitive.Close = DialogPrimitive.Close; 13 | const Portal: typeof DialogPrimitive.Portal = DialogPrimitive.Portal; 14 | 15 | export { 16 | Root, 17 | Title, 18 | Portal, 19 | Footer, 20 | Header, 21 | Trigger, 22 | Overlay, 23 | Content, 24 | Description, 25 | Close, 26 | // 27 | Root as Dialog, 28 | Title as DialogTitle, 29 | Portal as DialogPortal, 30 | Footer as DialogFooter, 31 | Header as DialogHeader, 32 | Trigger as DialogTrigger, 33 | Overlay as DialogOverlay, 34 | Content as DialogContent, 35 | Description as DialogDescription, 36 | Close as DialogClose, 37 | }; 38 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 30 | {#snippet children({ checked, indeterminate })} 31 | 32 | {#if indeterminate} 33 | 34 | {:else} 35 | 36 | {/if} 37 | 38 | {@render childrenProp?.()} 39 | {/snippet} 40 | 41 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | svg]:size-4 [&>svg]:shrink-0", 19 | inset && "pl-8", 20 | className 21 | )} 22 | {...restProps} 23 | /> 24 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
    22 | {@render children?.()} 23 |
    24 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | {#snippet children({ checked })} 23 | 24 | {#if checked} 25 | 26 | {/if} 27 | 28 | {@render childrenProp?.({ checked })} 29 | {/snippet} 30 | 31 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 19 | {@render children?.()} 20 | 21 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 26 | {@render children?.()} 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/lib/components/ui/dropdown-menu/index.ts: -------------------------------------------------------------------------------- 1 | import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; 2 | import CheckboxItem from "./dropdown-menu-checkbox-item.svelte"; 3 | import Content from "./dropdown-menu-content.svelte"; 4 | import GroupHeading from "./dropdown-menu-group-heading.svelte"; 5 | import Item from "./dropdown-menu-item.svelte"; 6 | import Label from "./dropdown-menu-label.svelte"; 7 | import RadioItem from "./dropdown-menu-radio-item.svelte"; 8 | import Separator from "./dropdown-menu-separator.svelte"; 9 | import Shortcut from "./dropdown-menu-shortcut.svelte"; 10 | import SubContent from "./dropdown-menu-sub-content.svelte"; 11 | import SubTrigger from "./dropdown-menu-sub-trigger.svelte"; 12 | 13 | const Sub = DropdownMenuPrimitive.Sub; 14 | const Root = DropdownMenuPrimitive.Root; 15 | const Trigger = DropdownMenuPrimitive.Trigger; 16 | const Group = DropdownMenuPrimitive.Group; 17 | const RadioGroup = DropdownMenuPrimitive.RadioGroup; 18 | 19 | export { 20 | CheckboxItem, 21 | Content, 22 | Root as DropdownMenu, 23 | CheckboxItem as DropdownMenuCheckboxItem, 24 | Content as DropdownMenuContent, 25 | Group as DropdownMenuGroup, 26 | GroupHeading as DropdownMenuGroupHeading, 27 | Item as DropdownMenuItem, 28 | Label as DropdownMenuLabel, 29 | RadioGroup as DropdownMenuRadioGroup, 30 | RadioItem as DropdownMenuRadioItem, 31 | Separator as DropdownMenuSeparator, 32 | Shortcut as DropdownMenuShortcut, 33 | Sub as DropdownMenuSub, 34 | SubContent as DropdownMenuSubContent, 35 | SubTrigger as DropdownMenuSubTrigger, 36 | Trigger as DropdownMenuTrigger, 37 | Group, 38 | GroupHeading, 39 | Item, 40 | Label, 41 | RadioGroup, 42 | RadioItem, 43 | Root, 44 | Separator, 45 | Shortcut, 46 | Sub, 47 | SubContent, 48 | SubTrigger, 49 | Trigger, 50 | }; 51 | -------------------------------------------------------------------------------- /src/lib/components/ui/input/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./input.svelte"; 2 | 3 | export { 4 | Root, 5 | // 6 | Root as Input, 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/components/ui/input/input.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /src/lib/components/ui/label/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./label.svelte"; 2 | 3 | export { 4 | Root, 5 | // 6 | Root as Label, 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/components/ui/label/label.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /src/lib/components/ui/scroll-area/index.ts: -------------------------------------------------------------------------------- 1 | import Scrollbar from "./scroll-area-scrollbar.svelte"; 2 | import Root from "./scroll-area.svelte"; 3 | 4 | export { 5 | Root, 6 | Scrollbar, 7 | //, 8 | Root as ScrollArea, 9 | Scrollbar as ScrollAreaScrollbar, 10 | }; 11 | -------------------------------------------------------------------------------- /src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 25 | {@render children?.()} 26 | 29 | 30 | -------------------------------------------------------------------------------- /src/lib/components/ui/scroll-area/scroll-area.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 | {@render children?.()} 24 | 25 | {#if orientation === "vertical" || orientation === "both"} 26 | 27 | {/if} 28 | {#if orientation === "horizontal" || orientation === "both"} 29 | 30 | {/if} 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/lib/components/ui/separator/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./separator.svelte"; 2 | 3 | export { 4 | Root, 5 | // 6 | Root as Separator, 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/components/ui/separator/separator.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/index.ts: -------------------------------------------------------------------------------- 1 | import { Dialog as SheetPrimitive } from "bits-ui"; 2 | 3 | import Overlay from "./sheet-overlay.svelte"; 4 | import Content from "./sheet-content.svelte"; 5 | import Header from "./sheet-header.svelte"; 6 | import Footer from "./sheet-footer.svelte"; 7 | import Title from "./sheet-title.svelte"; 8 | import Description from "./sheet-description.svelte"; 9 | 10 | const Root = SheetPrimitive.Root; 11 | const Close = SheetPrimitive.Close; 12 | const Trigger = SheetPrimitive.Trigger; 13 | const Portal = SheetPrimitive.Portal; 14 | 15 | export { 16 | Root, 17 | Close, 18 | Trigger, 19 | Portal, 20 | Overlay, 21 | Content, 22 | Header, 23 | Footer, 24 | Title, 25 | Description, 26 | // 27 | Root as Sheet, 28 | Close as SheetClose, 29 | Trigger as SheetTrigger, 30 | Portal as SheetPortal, 31 | Overlay as SheetOverlay, 32 | Content as SheetContent, 33 | Header as SheetHeader, 34 | Footer as SheetFooter, 35 | Title as SheetTitle, 36 | Description as SheetDescription, 37 | }; 38 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-content.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | 42 | 43 | 44 | 45 | 46 | {@render children?.()} 47 | 50 | 51 | Close 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-description.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-footer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    19 | {@render children?.()} 20 |
    21 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-header.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    19 | {@render children?.()} 20 |
    21 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-overlay.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /src/lib/components/ui/sheet/sheet-title.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/constants.ts: -------------------------------------------------------------------------------- 1 | export const SIDEBAR_COOKIE_NAME = "sidebar:state"; 2 | export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; 3 | export const SIDEBAR_WIDTH = "16rem"; 4 | export const SIDEBAR_WIDTH_MOBILE = "18rem"; 5 | export const SIDEBAR_WIDTH_ICON = "3rem"; 6 | export const SIDEBAR_KEYBOARD_SHORTCUT = "b"; 7 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/context.svelte.ts: -------------------------------------------------------------------------------- 1 | import { IsMobile } from "$lib/hooks/is-mobile.svelte.js"; 2 | import { getContext, setContext } from "svelte"; 3 | import { SIDEBAR_KEYBOARD_SHORTCUT } from "./constants.js"; 4 | 5 | type Getter = () => T; 6 | 7 | export type SidebarStateProps = { 8 | /** 9 | * A getter function that returns the current open state of the sidebar. 10 | * We use a getter function here to support `bind:open` on the `Sidebar.Provider` 11 | * component. 12 | */ 13 | open: Getter; 14 | 15 | /** 16 | * A function that sets the open state of the sidebar. To support `bind:open`, we need 17 | * a source of truth for changing the open state to ensure it will be synced throughout 18 | * the sub-components and any `bind:` references. 19 | */ 20 | setOpen: (open: boolean) => void; 21 | }; 22 | 23 | class SidebarState { 24 | readonly props: SidebarStateProps; 25 | open = $derived.by(() => this.props.open()); 26 | openMobile = $state(false); 27 | setOpen: SidebarStateProps["setOpen"]; 28 | #isMobile: IsMobile; 29 | state = $derived.by(() => (this.open ? "expanded" : "collapsed")); 30 | 31 | constructor(props: SidebarStateProps) { 32 | this.setOpen = props.setOpen; 33 | this.#isMobile = new IsMobile(); 34 | this.props = props; 35 | } 36 | 37 | // Convenience getter for checking if the sidebar is mobile 38 | // without this, we would need to use `sidebar.isMobile.current` everywhere 39 | get isMobile() { 40 | return this.#isMobile.current; 41 | } 42 | 43 | // Event handler to apply to the `` 44 | handleShortcutKeydown = (e: KeyboardEvent) => { 45 | if (e.key === SIDEBAR_KEYBOARD_SHORTCUT && (e.metaKey || e.ctrlKey)) { 46 | e.preventDefault(); 47 | this.toggle(); 48 | } 49 | }; 50 | 51 | setOpenMobile = (value: boolean) => { 52 | this.openMobile = value; 53 | }; 54 | 55 | toggle = () => { 56 | return this.#isMobile.current 57 | ? (this.openMobile = !this.openMobile) 58 | : this.setOpen(!this.open); 59 | }; 60 | } 61 | 62 | const SYMBOL_KEY = "scn-sidebar"; 63 | 64 | /** 65 | * Instantiates a new `SidebarState` instance and sets it in the context. 66 | * 67 | * @param props The constructor props for the `SidebarState` class. 68 | * @returns The `SidebarState` instance. 69 | */ 70 | export function setSidebar(props: SidebarStateProps): SidebarState { 71 | return setContext(Symbol.for(SYMBOL_KEY), new SidebarState(props)); 72 | } 73 | 74 | /** 75 | * Retrieves the `SidebarState` instance from the context. This is a class instance, 76 | * so you cannot destructure it. 77 | * @returns The `SidebarState` instance. 78 | */ 79 | export function useSidebar(): SidebarState { 80 | return getContext(Symbol.for(SYMBOL_KEY)); 81 | } 82 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/index.ts: -------------------------------------------------------------------------------- 1 | import { useSidebar } from "./context.svelte.js"; 2 | import Content from "./sidebar-content.svelte"; 3 | import Footer from "./sidebar-footer.svelte"; 4 | import GroupAction from "./sidebar-group-action.svelte"; 5 | import GroupContent from "./sidebar-group-content.svelte"; 6 | import GroupLabel from "./sidebar-group-label.svelte"; 7 | import Group from "./sidebar-group.svelte"; 8 | import Header from "./sidebar-header.svelte"; 9 | import Input from "./sidebar-input.svelte"; 10 | import Inset from "./sidebar-inset.svelte"; 11 | import MenuAction from "./sidebar-menu-action.svelte"; 12 | import MenuBadge from "./sidebar-menu-badge.svelte"; 13 | import MenuButton from "./sidebar-menu-button.svelte"; 14 | import MenuItem from "./sidebar-menu-item.svelte"; 15 | import MenuSkeleton from "./sidebar-menu-skeleton.svelte"; 16 | import MenuSubButton from "./sidebar-menu-sub-button.svelte"; 17 | import MenuSubItem from "./sidebar-menu-sub-item.svelte"; 18 | import MenuSub from "./sidebar-menu-sub.svelte"; 19 | import Menu from "./sidebar-menu.svelte"; 20 | import Provider from "./sidebar-provider.svelte"; 21 | import Rail from "./sidebar-rail.svelte"; 22 | import Separator from "./sidebar-separator.svelte"; 23 | import Trigger from "./sidebar-trigger.svelte"; 24 | import Root from "./sidebar.svelte"; 25 | 26 | export { 27 | Content, 28 | Footer, 29 | Group, 30 | GroupAction, 31 | GroupContent, 32 | GroupLabel, 33 | Header, 34 | Input, 35 | Inset, 36 | Menu, 37 | MenuAction, 38 | MenuBadge, 39 | MenuButton, 40 | MenuItem, 41 | MenuSkeleton, 42 | MenuSub, 43 | MenuSubButton, 44 | MenuSubItem, 45 | Provider, 46 | Rail, 47 | Root, 48 | Separator, 49 | // 50 | Root as Sidebar, 51 | Content as SidebarContent, 52 | Footer as SidebarFooter, 53 | Group as SidebarGroup, 54 | GroupAction as SidebarGroupAction, 55 | GroupContent as SidebarGroupContent, 56 | GroupLabel as SidebarGroupLabel, 57 | Header as SidebarHeader, 58 | Input as SidebarInput, 59 | Inset as SidebarInset, 60 | Menu as SidebarMenu, 61 | MenuAction as SidebarMenuAction, 62 | MenuBadge as SidebarMenuBadge, 63 | MenuButton as SidebarMenuButton, 64 | MenuItem as SidebarMenuItem, 65 | MenuSkeleton as SidebarMenuSkeleton, 66 | MenuSub as SidebarMenuSub, 67 | MenuSubButton as SidebarMenuSubButton, 68 | MenuSubItem as SidebarMenuSubItem, 69 | Provider as SidebarProvider, 70 | Rail as SidebarRail, 71 | Separator as SidebarSeparator, 72 | Trigger as SidebarTrigger, 73 | Trigger, 74 | useSidebar, 75 | }; 76 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-content.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    23 | {@render children?.()} 24 |
    25 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-footer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    20 | {@render children?.()} 21 |
    22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-group-action.svelte: -------------------------------------------------------------------------------- 1 | 29 | 30 | {#if child} 31 | {@render child({ props: propObj })} 32 | {:else} 33 | 36 | {/if} 37 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-group-content.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    20 | {@render children?.()} 21 |
    22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-group-label.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 | {#if child} 29 | {@render child({ props: mergedProps })} 30 | {:else} 31 |
    32 | {@render children?.()} 33 |
    34 | {/if} 35 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-group.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    20 | {@render children?.()} 21 |
    22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-header.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    20 | {@render children?.()} 21 |
    22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-input.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-inset.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    23 | {@render children?.()} 24 |
    25 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-action.svelte: -------------------------------------------------------------------------------- 1 | 36 | 37 | {#if child} 38 | {@render child({ props: mergedProps })} 39 | {:else} 40 | 43 | {/if} 44 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-badge.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    28 | {@render children?.()} 29 |
    30 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-button.svelte: -------------------------------------------------------------------------------- 1 | 29 | 30 | 68 | 69 | {#snippet Button({ props }: { props?: Record })} 70 | {@const mergedProps = mergeProps(buttonProps, props)} 71 | {#if child} 72 | {@render child({ props: mergedProps })} 73 | {:else} 74 | 77 | {/if} 78 | {/snippet} 79 | 80 | {#if !tooltipContent} 81 | {@render Button({})} 82 | {:else} 83 | 84 | 85 | {#snippet child({ props })} 86 | {@render Button({ props })} 87 | {/snippet} 88 | 89 | 97 | {/if} 98 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-item.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
  • 20 | {@render children?.()} 21 |
  • 22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 |
    27 | {#if showIcon} 28 | 29 | {/if} 30 | 35 | {@render children?.()} 36 |
    37 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte: -------------------------------------------------------------------------------- 1 | 36 | 37 | {#if child} 38 | {@render child({ props: mergedProps })} 39 | {:else} 40 | 41 | {@render children?.()} 42 | 43 | {/if} 44 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
  • 13 | {@render children?.()} 14 |
  • 15 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu-sub.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
      24 | {@render children?.()} 25 |
    26 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-menu.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
      20 | {@render children?.()} 21 |
    22 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-provider.svelte: -------------------------------------------------------------------------------- 1 | 44 | 45 | 46 | 47 | 48 |
    57 | {@render children?.()} 58 |
    59 |
    60 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-rail.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 37 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-separator.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar-trigger.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 35 | -------------------------------------------------------------------------------- /src/lib/components/ui/sidebar/sidebar.svelte: -------------------------------------------------------------------------------- 1 | 25 | 26 | {#if collapsible === "none"} 27 |
    35 | {@render children?.()} 36 |
    37 | {:else if sidebar.isMobile} 38 | 44 | 51 |
    52 | {@render children?.()} 53 |
    54 |
    55 |
    56 | {:else} 57 | 98 | {/if} 99 | -------------------------------------------------------------------------------- /src/lib/components/ui/skeleton/index.ts: -------------------------------------------------------------------------------- 1 | import Root from "./skeleton.svelte"; 2 | 3 | export { 4 | Root, 5 | // 6 | Root as Skeleton, 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/components/ui/skeleton/skeleton.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    18 | -------------------------------------------------------------------------------- /src/lib/components/ui/sonner/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Toaster } from "./sonner.svelte"; 2 | -------------------------------------------------------------------------------- /src/lib/components/ui/sonner/sonner.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 21 | -------------------------------------------------------------------------------- /src/lib/components/ui/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import { Tooltip as TooltipPrimitive } from "bits-ui"; 2 | import Content from "./tooltip-content.svelte"; 3 | 4 | const Root = TooltipPrimitive.Root; 5 | const Trigger = TooltipPrimitive.Trigger; 6 | const Provider = TooltipPrimitive.Provider; 7 | 8 | export { 9 | Root, 10 | Trigger, 11 | Content, 12 | Provider, 13 | // 14 | Root as Tooltip, 15 | Content as TooltipContent, 16 | Trigger as TooltipTrigger, 17 | Provider as TooltipProvider, 18 | }; 19 | -------------------------------------------------------------------------------- /src/lib/components/ui/tooltip/tooltip-content.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /src/lib/config.ts: -------------------------------------------------------------------------------- 1 | 2 | import type { NavItem, SocialLink } from "$lib/types/nav"; 3 | 4 | import { 5 | Boxes, 6 | Paintbrush, 7 | Workflow, 8 | Zap 9 | } from 'lucide-svelte'; 10 | import type { Feature, PromoConfig, SiteConfig } from "./types/config"; 11 | 12 | 13 | export const siteConfig: SiteConfig = { 14 | version: '0.0.1', 15 | title: 'Documentation', 16 | description: 17 | 'Comprehensive documentation for your project. Built with Svelte 5, MDSvex, Tailwind CSS, and shadcn/ui components.', 18 | github: 'https://github.com/code-gio/svelte-firekit-docs', 19 | npm: '', 20 | 21 | quickLinks: [ 22 | { title: 'Customize', href: '/docs/customize' }, 23 | { title: 'Examples', href: '/docs/examples' } 24 | ], 25 | logo: '/logo.svg', 26 | logoDark: '/logo-white.svg', 27 | favicon: '/favicon.png', 28 | }; 29 | 30 | 31 | export let navItems: NavItem[] = [ 32 | { 33 | title: 'Docs', 34 | href: '/docs' 35 | }, 36 | 37 | ]; 38 | 39 | export let socialLinks: SocialLink[] = [ 40 | 41 | { 42 | title: 'LinkedIn', 43 | href: 'https://www.linkedin.com/in/giovanirodriguez26/', 44 | icon: 'linkedin' 45 | }, 46 | { 47 | title: 'GitHub', 48 | href: 'https://github.com/code-gio', 49 | icon: 'github' 50 | }, 51 | 52 | ]; 53 | 54 | 55 | export const features: Feature[] = [ 56 | { 57 | icon: Boxes, 58 | title: 'Component Library', 59 | description: 'Built on top of shadcn/ui, offering comprehensive accessible components with complete documentation' 60 | }, 61 | { 62 | icon: Workflow, 63 | title: 'Type Safe', 64 | description: 'Fully typed with TypeScript, providing excellent IDE support and reliable development experience' 65 | }, 66 | { 67 | icon: Paintbrush, 68 | title: 'Fully Customizable', 69 | description: 'Easily customize themes, layouts, and components to match your brand identity and requirements' 70 | }, 71 | { 72 | icon: Zap, 73 | title: 'Fast & Modern', 74 | description: 'Powered by Svelte 5, MDSvex, and TailwindCSS for optimal performance and developer experience' 75 | } 76 | ]; 77 | 78 | export let promoConfig: PromoConfig = { 79 | title: 'Need help with your project?', 80 | description: 81 | 'I offer custom development services, consulting, and technical guidance for your web applications.', 82 | ctaText: "Let's work together", 83 | ctaLink: 'mailto:info@codegio.com', 84 | lightImage: '/images/dev-services-light.jpg', 85 | darkImage: '/images/dev-services-dark.jpg' 86 | }; -------------------------------------------------------------------------------- /src/lib/hooks/is-mobile.svelte.ts: -------------------------------------------------------------------------------- 1 | import { untrack } from "svelte"; 2 | 3 | const MOBILE_BREAKPOINT = 768; 4 | 5 | export class IsMobile { 6 | #current = $state(false); 7 | 8 | constructor() { 9 | $effect(() => { 10 | return untrack(() => { 11 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); 12 | const onChange = () => { 13 | this.#current = window.innerWidth < MOBILE_BREAKPOINT; 14 | }; 15 | mql.addEventListener("change", onChange); 16 | onChange(); 17 | return () => { 18 | mql.removeEventListener("change", onChange); 19 | }; 20 | }); 21 | }); 22 | } 23 | 24 | get current() { 25 | return this.#current; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /src/lib/types/config.ts: -------------------------------------------------------------------------------- 1 | import type { QuickLink } from "$lib/types/nav"; 2 | import { 3 | type Icon as IconType, 4 | 5 | } from 'lucide-svelte'; 6 | 7 | export interface Feature { 8 | icon: typeof IconType; 9 | title: string; 10 | description: string; 11 | } 12 | 13 | export interface SiteConfig { 14 | /** Current version of the documentation/project */ 15 | version: string; 16 | 17 | /** Main title of the documentation site */ 18 | title: string; 19 | 20 | /** Detailed description of the project/documentation */ 21 | description: string; 22 | 23 | /** GitHub repository URL */ 24 | github: string; 25 | 26 | /** NPM package name */ 27 | npm: string; 28 | 29 | /** Array of quick navigation links */ 30 | quickLinks: QuickLink[]; 31 | 32 | /** Path to the main logo (light theme) */ 33 | logo: string; 34 | 35 | /** Path to the dark theme logo (optional) */ 36 | logoDark?: string; 37 | 38 | /** Path to the site favicon */ 39 | favicon: string; 40 | } 41 | export interface PromoConfig { 42 | title: string; 43 | description: string; 44 | ctaText: string; 45 | ctaLink: string; 46 | lightImage?: string; 47 | darkImage?: string; 48 | } -------------------------------------------------------------------------------- /src/lib/types/docs.ts: -------------------------------------------------------------------------------- 1 | import type { Component } from "svelte"; 2 | 3 | export type Metadata = { 4 | title: string; 5 | description: string; 6 | openGraph: { 7 | title: string; 8 | description: string; 9 | type: 'article'; 10 | url: string; 11 | images: [ 12 | { 13 | url: string; 14 | width: number; 15 | height: number; 16 | alt: string; 17 | } 18 | ]; 19 | }; 20 | twitter: { 21 | card: 'summary_large_image'; 22 | title: string; 23 | description: string; 24 | images: string[]; 25 | creator: string; 26 | }; 27 | }; 28 | 29 | export type DocMeta = { 30 | title: string; 31 | description: string; 32 | slug: string; 33 | component: boolean; 34 | source: string; 35 | bits?: string; 36 | icon?: string 37 | label?: string 38 | disabled?: false 39 | external?: false 40 | }; 41 | 42 | export type DocFile = { 43 | default: Component 44 | metadata: DocMeta; 45 | }; 46 | 47 | export type DocResolver = () => Promise; 48 | 49 | export type TableOfContentsItem = { 50 | title: string; 51 | url: string; 52 | items?: TableOfContentsItem[]; 53 | }; 54 | 55 | export type TableOfContents = { 56 | items: TableOfContentsItem[]; 57 | }; -------------------------------------------------------------------------------- /src/lib/types/nav.ts: -------------------------------------------------------------------------------- 1 | import { type Icon as IconType } from 'lucide-svelte'; 2 | 3 | 4 | export interface NavItem { 5 | title: string; 6 | href?: string; 7 | disabled?: boolean; 8 | external?: boolean; 9 | icon?: typeof IconType; 10 | label?: string; 11 | items?: NavItem[]; 12 | }; 13 | 14 | export interface SocialLink { 15 | title: string; 16 | href: string; 17 | icon: keyof Icons; 18 | } 19 | 20 | export interface Icons { 21 | twitter: string; 22 | github: string; 23 | facebook: string; 24 | instagram: string; 25 | linkedin: string; 26 | youtube: string; 27 | tiktok: string; 28 | snapchat: string; 29 | } 30 | 31 | 32 | export interface QuickLink { 33 | title: string; 34 | href: string; 35 | } -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { error } from "@sveltejs/kit"; 2 | import { type ClassValue, clsx } from "clsx"; 3 | import { twMerge } from "tailwind-merge"; 4 | import type { DocResolver } from "./types/docs"; 5 | import type { NavItem } from "./types/nav"; 6 | import type { TransitionConfig } from "svelte/transition"; 7 | import { cubicOut } from "svelte/easing"; 8 | 9 | export function cn(...inputs: ClassValue[]) { 10 | return twMerge(clsx(inputs)); 11 | } 12 | type FlyAndScaleParams = { 13 | y?: number; 14 | x?: number; 15 | start?: number; 16 | duration?: number; 17 | }; 18 | 19 | type Modules = Record Promise>; 20 | 21 | export function styleToString(style: Record): string { 22 | return Object.keys(style).reduce((str, key) => { 23 | if (style[key] === undefined) return str; 24 | return `${str}${key}:${style[key]};`; 25 | }, ""); 26 | } 27 | 28 | 29 | export function flyAndScale( 30 | node: Element, 31 | params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } 32 | ): TransitionConfig { 33 | const style = getComputedStyle(node); 34 | const transform = style.transform === "none" ? "" : style.transform; 35 | 36 | const scaleConversion = ( 37 | valueA: number, 38 | scaleA: [number, number], 39 | scaleB: [number, number] 40 | ) => { 41 | const [minA, maxA] = scaleA; 42 | const [minB, maxB] = scaleB; 43 | 44 | const percentage = (valueA - minA) / (maxA - minA); 45 | const valueB = percentage * (maxB - minB) + minB; 46 | 47 | return valueB; 48 | }; 49 | 50 | return { 51 | duration: params.duration ?? 200, 52 | delay: 0, 53 | css: (t) => { 54 | const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); 55 | const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); 56 | const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); 57 | 58 | return styleToString({ 59 | transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, 60 | opacity: t, 61 | }); 62 | }, 63 | easing: cubicOut, 64 | }; 65 | } 66 | 67 | export function slugFromPath(path: string) { 68 | return path.replace('/src/content/', '').replace('.md', ''); 69 | } 70 | 71 | export async function getDoc(slug: string) { 72 | const modules = import.meta.glob(`/src/content/**/*.md`); 73 | const match = findMatch(slug, modules); 74 | const doc = await match?.resolver?.(); 75 | 76 | if (!doc || !doc.metadata) { 77 | error(404); 78 | } 79 | 80 | return doc; 81 | } 82 | 83 | function findMatch(slug: string, modules: Modules) { 84 | let match: { path?: string; resolver?: DocResolver } = {}; 85 | 86 | for (const [path, resolver] of Object.entries(modules)) { 87 | if (slugFromPath(path) === slug) { 88 | match = { path, resolver: resolver as unknown as DocResolver }; 89 | break; 90 | } 91 | } 92 | if (!match.path) { 93 | match = getIndexDocIfExists(slug, modules); 94 | } 95 | 96 | return match; 97 | } 98 | 99 | export function slugFromPathname(pathname: string) { 100 | return pathname.split('/').pop() ?? ''; 101 | } 102 | 103 | function getIndexDocIfExists(slug: string, modules: Modules) { 104 | let match: { path?: string; resolver?: DocResolver } = {}; 105 | 106 | for (const [path, resolver] of Object.entries(modules)) { 107 | if (path.includes(`/${slug}/index.md`)) { 108 | match = { path, resolver: resolver as unknown as DocResolver }; 109 | break; 110 | } 111 | } 112 | 113 | return match; 114 | } 115 | -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 |
    11 | {@render children()} 12 |
    13 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |