[READ-ONLY] Mirror of https://github.com/flo-bit/ui-kit. 🦊 fox ui, svelte 5 and tailwind 4 flo-bit.dev/ui-kit/
svelte tailwindcss ui-components
0

Configure Feed

Select the types of activity you want to include in your feed.

refactor docs pt2

Florian (Mar 6, 2026, 7:12 AM +0100) 56a08d96 a4f22818

+369 -629
-10
apps/docs/src/lib/site-components/components_3d.ts
··· 1 - import depth3d from '$lib/docs/3d/depth-3d'; 2 - import voxelArt from '$lib/docs/3d/voxel-art'; 3 - import modelPicker from '$lib/docs/3d/model-picker'; 4 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 5 - 6 - export const threeDComponents: ComponentCard[] = [ 7 - depth3d, 8 - voxelArt, 9 - modelPicker, 10 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
+33 -42
apps/docs/src/lib/site-components/components_all.ts
··· 1 - import type { ComponentCard } from '$lib/types/schema'; 2 - import { baseComponents } from './components_base'; 3 - import { colorsComponents } from './components_colors'; 4 - import { socialComponents } from './components_social'; 5 - import { textComponents } from './components_text'; 6 - import { timeComponents } from './components_time'; 7 - import { visualComponents } from './components_visual'; 1 + import type { ComponentDoc } from '$lib/types/schema'; 2 + import type { Component } from 'svelte'; 8 3 9 - export const components: { 10 - name: string; 11 - components: ComponentCard[]; 12 - href: string; 13 - }[] = [ 14 - { 15 - name: 'Core', 16 - components: baseComponents, 17 - href: 'core' 18 - }, 19 - { 20 - name: 'Colors', 21 - components: colorsComponents, 22 - href: 'colors' 23 - }, 24 - { 25 - name: 'Social', 26 - components: socialComponents, 27 - href: 'social' 28 - }, 29 - { 30 - name: 'Text', 31 - components: textComponents, 32 - href: 'text' 33 - }, 34 - { 35 - name: 'Visual', 36 - components: visualComponents, 37 - href: 'visual' 38 - }, 39 - { 40 - name: 'Time', 41 - components: timeComponents, 42 - href: 'time' 43 - } 4 + const categories = [ 5 + { slug: 'core', label: 'Core' }, 6 + { slug: 'colors', label: 'Colors' }, 7 + { slug: 'social', label: 'Social' }, 8 + { slug: 'text', label: 'Text' }, 9 + { slug: 'visual', label: 'Visual' }, 10 + { slug: 'time', label: 'Time' } 44 11 ]; 12 + 13 + const modules = import.meta.glob('/src/lib/docs/*/*/index.ts', { eager: true }) as Record< 14 + string, 15 + { default: ComponentDoc } 16 + >; 17 + 18 + export const components = categories.map((category) => { 19 + const comps = Object.entries(modules) 20 + .filter(([path]) => path.startsWith(`/src/lib/docs/${category.slug}/`)) 21 + .map(([, mod]) => mod.default) 22 + .filter((doc) => doc.card) 23 + .sort((a, b) => a.title.localeCompare(b.title)) 24 + .map((doc) => ({ 25 + component: doc.card as Component, 26 + label: doc.title, 27 + href: doc.slug 28 + })); 29 + 30 + return { 31 + name: category.label, 32 + href: category.slug, 33 + components: comps 34 + }; 35 + });
-60
apps/docs/src/lib/site-components/components_base.ts
··· 1 - import accordion from '$lib/docs/core/accordion'; 2 - import alert from '$lib/docs/core/alert'; 3 - import avatar from '$lib/docs/core/avatar'; 4 - import badge from '$lib/docs/core/badge'; 5 - import box from '$lib/docs/core/box'; 6 - import button from '$lib/docs/core/button'; 7 - import cards from '$lib/docs/core/cards'; 8 - import chatBubble from '$lib/docs/core/chat-bubble'; 9 - import checkbox from '$lib/docs/core/checkbox'; 10 - import head from '$lib/docs/core/head'; 11 - import image from '$lib/docs/core/image'; 12 - import input from '$lib/docs/core/input'; 13 - import modal from '$lib/docs/core/modal'; 14 - import popover from '$lib/docs/core/popover'; 15 - import prose from '$lib/docs/core/prose'; 16 - import scrollArea from '$lib/docs/core/scroll-area'; 17 - import select from '$lib/docs/core/select'; 18 - import sidebar from '$lib/docs/core/sidebar'; 19 - import slider from '$lib/docs/core/slider'; 20 - import sonner from '$lib/docs/core/sonner'; 21 - import switchDoc from '$lib/docs/core/switch'; 22 - import tabs from '$lib/docs/core/tabs'; 23 - import textarea from '$lib/docs/core/textarea'; 24 - import themeToggle from '$lib/docs/core/theme-toggle'; 25 - import toggle from '$lib/docs/core/toggle'; 26 - import toggleGroup from '$lib/docs/core/toggle-group'; 27 - import tooltip from '$lib/docs/core/tooltip'; 28 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 29 - 30 - export type { ComponentCard }; 31 - 32 - export const baseComponents: ComponentCard[] = [ 33 - accordion, 34 - alert, 35 - avatar, 36 - badge, 37 - box, 38 - button, 39 - cards, 40 - chatBubble, 41 - checkbox, 42 - head, 43 - image, 44 - input, 45 - modal, 46 - popover, 47 - prose, 48 - scrollArea, 49 - select, 50 - sidebar, 51 - slider, 52 - sonner, 53 - switchDoc, 54 - tabs, 55 - textarea, 56 - themeToggle, 57 - toggle, 58 - toggleGroup, 59 - tooltip, 60 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
-10
apps/docs/src/lib/site-components/components_colors.ts
··· 1 - import colorPicker from '$lib/docs/colors/color-picker'; 2 - import colorSelect from '$lib/docs/colors/color-select'; 3 - import colorGradientPicker from '$lib/docs/colors/color-gradient-picker'; 4 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 5 - 6 - export const colorsComponents: ComponentCard[] = [ 7 - colorPicker, 8 - colorSelect, 9 - colorGradientPicker, 10 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
-22
apps/docs/src/lib/site-components/components_social.ts
··· 1 - import cardSwiper from '$lib/docs/social/card-swiper'; 2 - import userProfile from '$lib/docs/social/user-profile'; 3 - import githubCorner from '$lib/docs/social/github-corner'; 4 - import atprotoLogin from '$lib/docs/social/atproto-login'; 5 - import starRating from '$lib/docs/social/star-rating'; 6 - import emojiPicker from '$lib/docs/social/emoji-picker'; 7 - import post from '$lib/docs/social/post'; 8 - import linkCard from '$lib/docs/social/link-card'; 9 - import atprotoHandlePopup from '$lib/docs/social/atproto-handle-popup'; 10 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 11 - 12 - export const socialComponents: ComponentCard[] = [ 13 - cardSwiper, 14 - userProfile, 15 - githubCorner, 16 - atprotoLogin, 17 - starRating, 18 - emojiPicker, 19 - post, 20 - linkCard, 21 - atprotoHandlePopup, 22 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
-10
apps/docs/src/lib/site-components/components_text.ts
··· 1 - import plainTextEditor from '$lib/docs/text/plain-text-editor'; 2 - import richTextEditor from '$lib/docs/text/rich-text-editor'; 3 - import advancedTextArea from '$lib/docs/text/advanced-text-area'; 4 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 5 - 6 - export const textComponents: ComponentCard[] = [ 7 - plainTextEditor, 8 - richTextEditor, 9 - advancedTextArea, 10 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
-10
apps/docs/src/lib/site-components/components_time.ts
··· 1 - import timer from '$lib/docs/time/timer'; 2 - import stopwatch from '$lib/docs/time/stopwatch'; 3 - import relativeTime from '$lib/docs/time/relative-time'; 4 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 5 - 6 - export const timeComponents: ComponentCard[] = [ 7 - timer, 8 - stopwatch, 9 - relativeTime, 10 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
-16
apps/docs/src/lib/site-components/components_visual.ts
··· 1 - import excalidraw from '$lib/docs/visual/excalidraw'; 2 - import phone from '$lib/docs/visual/phone'; 3 - import quote from '$lib/docs/visual/quote'; 4 - import undraw from '$lib/docs/visual/undraw'; 5 - import imageMasonry from '$lib/docs/visual/image-masonry'; 6 - import confetti from '$lib/docs/visual/confetti'; 7 - import { toComponentCard, type ComponentCard } from '$lib/types/schema'; 8 - 9 - export const visualComponents: ComponentCard[] = [ 10 - excalidraw, 11 - phone, 12 - quote, 13 - undraw, 14 - imageMasonry, 15 - confetti, 16 - ].map(toComponentCard).sort((a, b) => a.label.localeCompare(b.label));
+8 -14
apps/docs/src/lib/types/schema.ts
··· 26 26 props?: PropObj<T>; 27 27 }; 28 28 29 + export type ComponentSource = { 30 + href: string; 31 + label: string; 32 + package?: string; 33 + component?: string; 34 + }; 35 + 29 36 export type ComponentDoc = { 30 37 slug: string; 31 38 title: string; ··· 33 40 example?: Component; 34 41 card?: Component; 35 42 api?: APISchema[]; 43 + sources?: ComponentSource[]; 36 44 }; 37 45 38 - // Used by Cards.svelte and Sidebar.svelte for rendering 39 - export type ComponentCard = { 40 - component?: Component; 41 - label: string; 42 - href: string; 43 - }; 44 - 45 - export function toComponentCard(doc: ComponentDoc): ComponentCard { 46 - return { 47 - component: doc.card, 48 - label: doc.title, 49 - href: doc.slug 50 - }; 51 - }
+1 -5
apps/docs/src/lib/docs/3d/model-picker/Documentation.md
··· 7 7 console.log(path, label); 8 8 }} 9 9 /> 10 - ``` 11 - 12 - ## Credits 13 - 14 - - Models from [Toy Car Kit](https://kenney.nl/assets/toy-car-kit) by [Kenney](https://kenney.nl) 10 + ```
+6
apps/docs/src/lib/docs/3d/model-picker/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://kenney.nl/assets/toy-car-kit', 14 + label: 'Toy Car Kit by Kenney' 15 + } 16 + ] 11 17 };
+1 -5
apps/docs/src/lib/docs/3d/voxel-art/Documentation.md
··· 20 20 '505050': 'var(--color-accent-500)' 21 21 }} 22 22 /> 23 - ``` 24 - 25 - ## Credits 26 - 27 - - inspired by [this article](https://tympanus.net/codrops/2025/03/03/css-meets-voxel-art-building-a-rendering-engine-with-stacked-grids/) 23 + ```
+6
apps/docs/src/lib/docs/3d/voxel-art/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://tympanus.net/codrops/2025/03/03/css-meets-voxel-art-building-a-rendering-engine-with-stacked-grids/', 14 + label: 'CSS Meets Voxel Art (Codrops)' 15 + } 16 + ] 11 17 };
+1 -5
apps/docs/src/lib/docs/core/accordion/Documentation.md
··· 9 9 I mean, I hope so? It's based on the bits-ui accordion component, so if not it's not my fault 😅 10 10 </AccordionItem> 11 11 </Accordion> 12 - ``` 13 - 14 - ## Credits 15 - 16 - This component is based on the [bits-ui accordion component](https://bits-ui.com/docs/components/accordion). 12 + ```
+81
apps/docs/src/lib/docs/core/accordion/api.ts
··· 1 + import type { APISchema } from '$lib/types/schema'; 2 + 3 + export default [ 4 + { 5 + title: 'Accordion', 6 + description: 7 + 'A vertically stacked set of interactive headings that each reveal a section of content.', 8 + props: { 9 + children: { 10 + type: 'Snippet', 11 + description: 12 + 'The children content to render. Should be a list of AccordionItem components.', 13 + required: true 14 + }, 15 + type: { 16 + type: { type: 'enum', definition: "'single' | 'multiple'" }, 17 + description: 18 + "If set to 'multiple', the accordion will allow multiple items to be open at the same time. If set to single, the accordion will only allow a single item to be open.", 19 + required: true 20 + }, 21 + value: { 22 + type: { type: 'union', definition: 'string | string[]' }, 23 + description: 24 + 'The value of the accordion item that is currently open. If type is set to "multiple", this will be an array of strings. If type is set to "single", this will be a string.', 25 + bindable: true 26 + }, 27 + onValueChange: { 28 + type: { 29 + type: 'function', 30 + definition: '(value: string) => void | (value: string[]) => void' 31 + }, 32 + description: 'A function that is called when the value of the accordion item changes.' 33 + }, 34 + disabled: { 35 + type: 'boolean', 36 + description: 'Whether the accordion is disabled.', 37 + default: 'false' 38 + }, 39 + ref: { 40 + type: 'HTMLDivElement', 41 + description: 42 + 'The underlying DOM element being rendered. You can bind to this to get a reference to the element.', 43 + bindable: true 44 + } 45 + } 46 + }, 47 + { 48 + title: 'AccordionItem', 49 + description: 'A single collapsible section within the accordion.', 50 + props: { 51 + title: { 52 + type: 'string', 53 + description: 54 + 'The title of the accordion item, displayed both when the item is closed or open.', 55 + required: true 56 + }, 57 + children: { 58 + type: 'Snippet', 59 + description: 60 + 'The children content to render. The content is displayed when the item is open.', 61 + required: true 62 + }, 63 + value: { 64 + type: 'string', 65 + description: 66 + 'The value of the accordion item. This is used to identify when the item is open or closed. If not provided, a unique ID will be generated for this value.' 67 + }, 68 + disabled: { 69 + type: 'boolean', 70 + description: 'Whether the accordion item is disabled.', 71 + default: 'false' 72 + }, 73 + ref: { 74 + type: 'HTMLDivElement', 75 + description: 76 + 'The underlying DOM element being rendered. You can bind to this to get a reference to the element.', 77 + bindable: true 78 + } 79 + } 80 + } 81 + ] satisfies APISchema[];
+8 -78
apps/docs/src/lib/docs/core/accordion/index.ts
··· 1 - import type { APISchema } from '$lib/types/schema'; 2 1 import Docs from './Documentation.md'; 3 2 import Example from './Example.svelte'; 4 3 import Card from './Card.svelte'; 4 + import api from './api'; 5 5 6 6 export default { 7 7 slug: 'accordion', ··· 9 9 docs: Docs, 10 10 example: Example, 11 11 card: Card, 12 - api: [ 12 + api, 13 + sources: [ 13 14 { 14 - title: 'Accordion', 15 - description: 16 - 'A vertically stacked set of interactive headings that each reveal a section of content.', 17 - props: { 18 - children: { 19 - type: 'Snippet', 20 - description: 21 - 'The children content to render. Should be a list of AccordionItem components.', 22 - required: true 23 - }, 24 - type: { 25 - type: { type: 'enum', definition: "'single' | 'multiple'" }, 26 - description: 27 - "If set to 'multiple', the accordion will allow multiple items to be open at the same time. If set to single, the accordion will only allow a single item to be open.", 28 - required: true 29 - }, 30 - value: { 31 - type: { type: 'union', definition: 'string | string[]' }, 32 - description: 33 - 'The value of the accordion item that is currently open. If type is set to "multiple", this will be an array of strings. If type is set to "single", this will be a string.', 34 - bindable: true 35 - }, 36 - onValueChange: { 37 - type: { 38 - type: 'function', 39 - definition: '(value: string) => void | (value: string[]) => void' 40 - }, 41 - description: 'A function that is called when the value of the accordion item changes.' 42 - }, 43 - disabled: { 44 - type: 'boolean', 45 - description: 'Whether the accordion is disabled.', 46 - default: 'false' 47 - }, 48 - ref: { 49 - type: 'HTMLDivElement', 50 - description: 51 - 'The underlying DOM element being rendered. You can bind to this to get a reference to the element.', 52 - bindable: true 53 - } 54 - } 55 - }, 56 - { 57 - title: 'AccordionItem', 58 - description: 'A single collapsible section within the accordion.', 59 - props: { 60 - title: { 61 - type: 'string', 62 - description: 63 - 'The title of the accordion item, displayed both when the item is closed or open.', 64 - required: true 65 - }, 66 - children: { 67 - type: 'Snippet', 68 - description: 69 - 'The children content to render. The content is displayed when the item is open.', 70 - required: true 71 - }, 72 - value: { 73 - type: 'string', 74 - description: 75 - 'The value of the accordion item. This is used to identify when the item is open or closed. If not provided, a unique ID will be generated for this value.' 76 - }, 77 - disabled: { 78 - type: 'boolean', 79 - description: 'Whether the accordion item is disabled.', 80 - default: 'false' 81 - }, 82 - ref: { 83 - type: 'HTMLDivElement', 84 - description: 85 - 'The underlying DOM element being rendered. You can bind to this to get a reference to the element.', 86 - bindable: true 87 - } 88 - } 15 + href: 'https://bits-ui.com/docs/components/accordion', 16 + label: 'bits-ui accordion', 17 + package: 'bits-ui', 18 + component: 'Accordion' 89 19 } 90 - ] satisfies APISchema[] 20 + ] 91 21 };
+1 -5
apps/docs/src/lib/docs/core/number-input/Documentation.md
··· 2 2 3 3 ```svelte 4 4 <NumberInput min={0} max={100} bind:value /> 5 - ``` 6 - 7 - ## Credits 8 - 9 - - Adapted from an example of [number-flow](https://number-flow.barvian.me/) 5 + ```
+6
apps/docs/src/lib/docs/core/number-input/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://number-flow.barvian.me/', 14 + label: 'number-flow' 15 + } 16 + ] 11 17 };
+1 -5
apps/docs/src/lib/docs/core/theme-toggle/Documentation.md
··· 8 8 9 9 ## Accessibility 10 10 11 - - If javascript is disabled, the theme toggle will not be shown. 12 - 13 - ## Credits 14 - 15 - Based on [mode-watcher](https://github.com/svecosystem/mode-watcher), also exports all functions and stores from the package. 11 + - If javascript is disabled, the theme toggle will not be shown.
+6
apps/docs/src/lib/docs/core/theme-toggle/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://github.com/svecosystem/mode-watcher', 14 + label: 'mode-watcher' 15 + } 16 + ] 11 17 };
+1 -5
apps/docs/src/lib/docs/time/relative-time/Documentation.md
··· 9 9 10 10 ```svelte 11 11 <RelativeTime date={new Date(Date.now() - 10000)} locale="en-US" /> 12 - ``` 13 - 14 - ## Credits 15 - 16 - - Based on [svelte-relative-time](https://github.com/CaptainCodeman/svelte-relative-time) 12 + ```
+6
apps/docs/src/lib/docs/time/relative-time/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://github.com/CaptainCodeman/svelte-relative-time', 14 + label: 'svelte-relative-time' 15 + } 16 + ] 11 17 };
+1 -6
apps/docs/src/lib/docs/time/stopwatch/Documentation.md
··· 4 4 <Stopwatch bind:stopwatch /> 5 5 6 6 <Button onclick={() => stopwatch?.start()}>Start</Button> 7 - ``` 8 - 9 - ## Credits 10 - 11 - - Stopwatch state based on [svelte-reactive-timer](https://github.com/joshnuss/svelte-reactive-timer) 12 - - Moving numbers component from [number-flow](https://number-flow.barvian.me/) 7 + ```
+10
apps/docs/src/lib/docs/time/stopwatch/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://github.com/joshnuss/svelte-reactive-timer', 14 + label: 'svelte-reactive-timer' 15 + }, 16 + { 17 + href: 'https://number-flow.barvian.me/', 18 + label: 'number-flow' 19 + } 20 + ] 11 21 };
+1 -6
apps/docs/src/lib/docs/time/timer/Documentation.md
··· 4 4 <Timer bind:timer /> 5 5 6 6 <Button onclick={() => timer.start()}>Start</Button> 7 - ``` 8 - 9 - ## Credits 10 - 11 - - Timer state based on [svelte-reactive-timer](https://github.com/joshnuss/svelte-reactive-timer) 12 - - Moving numbers component from [number-flow](https://number-flow.barvian.me/) 7 + ```
+10
apps/docs/src/lib/docs/time/timer/index.ts
··· 8 8 docs: Docs, 9 9 example: Example, 10 10 card: Card, 11 + sources: [ 12 + { 13 + href: 'https://github.com/joshnuss/svelte-reactive-timer', 14 + label: 'svelte-reactive-timer' 15 + }, 16 + { 17 + href: 'https://number-flow.barvian.me/', 18 + label: 'number-flow' 19 + } 20 + ] 11 21 };
+41
apps/docs/src/routes/(main)/components/llms.txt/+server.ts
··· 1 + import type { ComponentDoc } from '$lib/types/schema'; 2 + 3 + const BASE_URL = 'https://flo-bit.dev/ui-kit'; 4 + 5 + const categories = [ 6 + { slug: 'core', label: 'Core' }, 7 + { slug: 'colors', label: 'Colors' }, 8 + { slug: 'social', label: 'Social' }, 9 + { slug: 'text', label: 'Text' }, 10 + { slug: 'visual', label: 'Visual' }, 11 + { slug: 'time', label: 'Time' }, 12 + { slug: '3d', label: '3D' } 13 + ]; 14 + 15 + const modules = import.meta.glob('/src/lib/docs/*/*/index.ts', { eager: true }) as Record< 16 + string, 17 + { default: ComponentDoc } 18 + >; 19 + 20 + export function GET() { 21 + const lines: string[] = []; 22 + 23 + for (const category of categories) { 24 + lines.push(`${category.label}:`); 25 + 26 + const comps = Object.entries(modules) 27 + .filter(([path]) => path.startsWith(`/src/lib/docs/${category.slug}/`)) 28 + .map(([, mod]) => mod.default) 29 + .sort((a, b) => a.title.localeCompare(b.title)); 30 + 31 + for (const comp of comps) { 32 + lines.push(`${comp.title} (${BASE_URL}/components/${category.slug}/${comp.slug}/llms.txt)`); 33 + } 34 + 35 + lines.push(''); 36 + } 37 + 38 + return new Response(lines.join('\n').trim(), { 39 + headers: { 'Content-Type': 'text/plain' } 40 + }); 41 + }
-45
apps/docs/src/routes/(main)/components/3d/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/3d/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/3d/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
+48
apps/docs/src/routes/(main)/components/[category]/[slug]/+page.svelte
··· 1 + <script lang="ts"> 2 + import { page } from '$app/state'; 3 + import { error } from '@sveltejs/kit'; 4 + import { Prose, Button } from '@foxui/all'; 5 + import Api from '$lib/site-components/API.svelte'; 6 + import type { ComponentDoc } from '$lib/types/schema'; 7 + 8 + type ModuleEntry = { 9 + default: ComponentDoc; 10 + }; 11 + 12 + const modules = import.meta.glob('/src/lib/docs/*/*/index.ts', { eager: true }) as Record< 13 + string, 14 + ModuleEntry 15 + >; 16 + 17 + let category = $derived(page.params.category); 18 + let slug = $derived(page.params.slug); 19 + 20 + let componentDoc = $derived.by(() => { 21 + const mod = modules[`/src/lib/docs/${category}/${slug}/index.ts`]; 22 + if (!mod) error(404, 'Component not found'); 23 + return mod.default; 24 + }); 25 + </script> 26 + 27 + <Prose> 28 + <div class="flex items-end gap-4"> 29 + <h1 class="!my-0">{componentDoc.title}</h1> 30 + <Button size="sm" class="not-prose mb-1" variant="secondary" href="/components/{category}/{slug}/llms.txt" target="_blank"> 31 + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="m5 16-3 3 3 3"/><path d="m9 22 3-3-3-3"/></svg> 32 + <span class="sr-only">open llms.txt</span> 33 + </Button> 34 + </div> 35 + {#if componentDoc.example} 36 + {@const Example = componentDoc.example} 37 + <h2>Example</h2> 38 + <Example /> 39 + {/if} 40 + {@const Doc = componentDoc.docs} 41 + <Doc /> 42 + {#if componentDoc.api?.length} 43 + <h2>API Reference</h2> 44 + {#each componentDoc.api as schema (schema.title)} 45 + <Api props={schema} /> 46 + {/each} 47 + {/if} 48 + </Prose>
-45
apps/docs/src/routes/(main)/components/colors/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/colors/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/colors/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
-45
apps/docs/src/routes/(main)/components/core/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/core/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/core/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
-45
apps/docs/src/routes/(main)/components/social/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/social/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/social/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
-45
apps/docs/src/routes/(main)/components/text/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/text/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/text/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
-45
apps/docs/src/routes/(main)/components/time/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/time/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/time/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
-45
apps/docs/src/routes/(main)/components/visual/[slug]/+page.svelte
··· 1 - <script lang="ts"> 2 - import { page } from '$app/state'; 3 - import { error } from '@sveltejs/kit'; 4 - import { Prose } from '@foxui/all'; 5 - import Api from '$lib/site-components/API.svelte'; 6 - import type { Component } from 'svelte'; 7 - import type { APISchema } from '$lib/types/schema'; 8 - 9 - type ComponentDoc = { 10 - default: { 11 - title: string; 12 - docs: Component; 13 - example?: Component; 14 - card?: Component; 15 - api?: APISchema[]; 16 - }; 17 - }; 18 - 19 - const modules = import.meta.glob('/src/lib/docs/visual/*/index.ts', { eager: true }) as Record<string, ComponentDoc>; 20 - 21 - let slug = $derived(page.params.slug); 22 - 23 - let componentDoc = $derived.by(() => { 24 - const mod = modules[`/src/lib/docs/visual/${slug}/index.ts`]; 25 - if (!mod) error(404, 'Component not found'); 26 - return mod.default; 27 - }); 28 - </script> 29 - 30 - <Prose> 31 - <h1>{componentDoc.title}</h1> 32 - {#if componentDoc.example} 33 - {@const Example = componentDoc.example} 34 - <h2>Example</h2> 35 - <Example /> 36 - {/if} 37 - {@const Doc = componentDoc.docs} 38 - <Doc /> 39 - {#if componentDoc.api?.length} 40 - <h2>API Reference</h2> 41 - {#each componentDoc.api as schema} 42 - <Api props={schema} /> 43 - {/each} 44 - {/if} 45 - </Prose>
+92
apps/docs/src/routes/(main)/components/[category]/[slug]/llms.txt/+server.ts
··· 1 + import { error } from '@sveltejs/kit'; 2 + import type { RequestHandler } from './$types'; 3 + import type { ComponentDoc, APISchema, PropType } from '$lib/types/schema'; 4 + 5 + const modules = import.meta.glob('/src/lib/docs/*/*/index.ts', { eager: true }) as Record< 6 + string, 7 + { default: ComponentDoc } 8 + >; 9 + 10 + const rawDocs = import.meta.glob('/src/lib/docs/*/*/Documentation.md', { 11 + query: '?raw', 12 + eager: true 13 + }) as Record<string, { default: string }>; 14 + 15 + const rawExamples = import.meta.glob('/src/lib/docs/*/*/Example.svelte', { 16 + query: '?raw', 17 + eager: true 18 + }) as Record<string, { default: string }>; 19 + 20 + function formatType(type: string | PropType): string { 21 + if (typeof type === 'string') return type; 22 + return type.definition as string; 23 + } 24 + 25 + function formatApiSchema(schema: APISchema): string { 26 + const lines: string[] = []; 27 + lines.push(`### ${schema.title}`); 28 + if (schema.description) lines.push(schema.description); 29 + 30 + if (schema.props) { 31 + lines.push(''); 32 + lines.push('| Prop | Type | Default | Description |'); 33 + lines.push('|------|------|---------|-------------|'); 34 + 35 + for (const [name, prop] of Object.entries(schema.props)) { 36 + const type = formatType(prop.type); 37 + const def = prop.default ?? '-'; 38 + const tags: string[] = []; 39 + if (prop.required) tags.push('required'); 40 + if (prop.bindable) tags.push('bindable'); 41 + const desc = prop.description + (tags.length ? ` (${tags.join(', ')})` : ''); 42 + lines.push(`| ${name} | \`${type}\` | \`${def}\` | ${desc} |`); 43 + } 44 + } 45 + 46 + return lines.join('\n'); 47 + } 48 + 49 + export const GET: RequestHandler = ({ params }) => { 50 + const { category, slug } = params; 51 + const basePath = `/src/lib/docs/${category}/${slug}`; 52 + 53 + const mod = modules[`${basePath}/index.ts`]; 54 + if (!mod) error(404, 'Component not found'); 55 + 56 + const comp = mod.default; 57 + const sections: string[] = []; 58 + 59 + sections.push(`# ${comp.title}`); 60 + 61 + const rawExample = rawExamples[`${basePath}/Example.svelte`]; 62 + if (rawExample) { 63 + sections.push('## Example\n\n```svelte\n' + rawExample.default.trim() + '\n```'); 64 + } 65 + 66 + const rawDoc = rawDocs[`${basePath}/Documentation.md`]; 67 + if (rawDoc) { 68 + sections.push('## Documentation\n\n' + rawDoc.default.trim()); 69 + } 70 + 71 + if (comp.sources?.length) { 72 + const sourceLines: string[] = []; 73 + for (const source of comp.sources) { 74 + if (source.package === 'bits-ui') { 75 + sourceLines.push( 76 + `This component uses the bits-ui component: ${source.component ?? source.label}, see here for the documentation for that: ${source.href}/llms.txt` 77 + ); 78 + } else { 79 + sourceLines.push(`Based on "${source.label}" (${source.href})`); 80 + } 81 + } 82 + sections.push('## Sources\n\n' + sourceLines.join('\n')); 83 + } 84 + 85 + if (comp.api?.length) { 86 + sections.push('## API Reference\n\n' + comp.api.map(formatApiSchema).join('\n\n')); 87 + } 88 + 89 + return new Response(sections.join('\n\n') + '\n', { 90 + headers: { 'Content-Type': 'text/plain; charset=utf-8' } 91 + }); 92 + };