[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.

add first api reference, update cli

Florian (Mar 29, 2025, 10:49 AM +0100) 2a3155da 43f8fbb4

+207 -83
+1 -1
package.json
··· 1 1 { 2 2 "name": "fuchs", 3 - "version": "0.0.27", 3 + "version": "0.0.28", 4 4 "type": "module", 5 5 "description": "Beautiful UI components built with Tailwind 4 and Svelte 5", 6 6 "homepage": "https://flo-bit.dev/ui-kit",
+4 -5
src/lib/cli.ts
··· 33 33 const __dirname = path.dirname(__filename); 34 34 const githubUser = 'flo-bit'; 35 35 const repoName = 'ui-kit'; 36 - const branch = 'main'; 37 - const zipUrl = `https://github.com/${githubUser}/${repoName}/archive/refs/heads/${branch}.zip`; 36 + const zipUrl = `https://github.com/${githubUser}/${repoName}/archive/refs/heads/${version}.zip`; 38 37 const tmpDir = path.join(__dirname, 'tmp'); 39 38 const zipPath = path.join(tmpDir, `repo-${version}.zip`); 40 39 ··· 44 43 .command('add') 45 44 .description('Add a new component to the project') 46 45 .argument('<component-name>', 'name of the component to add') 47 - .action((component) => { 48 - addComponent(component); 46 + .action((component: string) => { 47 + addComponent(component.toLowerCase()); 49 48 }); 50 49 51 50 program.parse(); ··· 134 133 log.info('Repository already downloaded'); 135 134 packageFolder = extractDir; 136 135 } 137 - packageFolder = path.join(packageFolder, `${repoName}-${branch}`); 136 + packageFolder = path.join(packageFolder, `${repoName}-${version}`); 138 137 139 138 const sourcePath = path.join(packageFolder, 'src', 'lib', relativePath); 140 139 if (!fs.existsSync(sourcePath)) {
+60 -27
src/docs/site-components/API.svelte
··· 1 1 <script lang="ts"> 2 2 import type { APISchema } from '$docs/types/schema'; 3 + import { Button, Popover, Tooltip } from '$lib'; 3 4 import Badge from '$lib/components/base/badge/Badge.svelte'; 4 5 5 - const props: APISchema = { 6 - title: 'Accordion', 7 - description: 'A component that displays a list of items in an accordion format.', 8 - props: { 9 - items: { 10 - type: 'array', 11 - description: 'An array of items to display in the accordion.', 12 - required: true 13 - }, 14 - open: { type: 'boolean', description: 'Whether the accordion is open.', bindable: true } 15 - } 16 - }; 6 + const { props }: { props: APISchema } = $props(); 7 + 8 + console.log(props); 17 9 </script> 18 10 19 - <table class="text-base-900 dark:text-base-50 not-prose divide-base-900 min-w-full divide-y"> 11 + <h4 class="not-prose text-base-900 dark:text-base-50 mt-12 mb-2 text-lg font-semibold"> 12 + {props.title} 13 + </h4> 14 + 15 + <table 16 + class="text-base-900 dark:text-base-50 not-prose divide-base-200 dark:divide-base-900 min-w-full divide-y" 17 + > 20 18 <thead> 21 19 <tr> 22 20 <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" 23 21 >Property</th 24 22 > 25 - <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" 23 + <th scope="col" class="hidden px-5 py-3.5 text-left text-sm font-semibold md:table-cell" 26 24 >Type</th 27 25 > 28 26 <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" ··· 30 28 > 31 29 </tr> 32 30 </thead> 33 - <tbody class="divide-base-900 divide-y text-sm"> 34 - {#each Object.entries(props.props) as [key, prop]} 31 + <tbody class="divide-base-200 dark:divide-base-900 divide-y text-sm"> 32 + {#each Object.entries(props.props ?? {}) as [key, prop]} 35 33 <tr class="flex flex-col py-2 md:table-row"> 36 - <td class="my-2 table-cell px-1 py-1.5 whitespace-nowrap"> 37 - <span class="mb-1 block font-semibold md:hidden">Property</span> 38 - 39 - <div class="flex flex-row gap-2 md:flex-col md:gap-1"> 40 - <span class="text-base-100">{key}</span> 34 + <td class="my-2 table-cell px-1 py-3 align-top"> 35 + <div class="flex flex-row gap-1 md:flex-col md:gap-1"> 36 + <span class="text-base-900 dark:text-base-100 text-base font-semibold md:text-sm" 37 + >{key}</span 38 + > 41 39 {#if prop.required} 42 40 <Badge variant="primary" class="w-fit">required</Badge> 43 41 {:else if prop.bindable} ··· 45 43 {/if} 46 44 </div> 47 45 </td> 48 - <td class="text-base-200 table-cell px-1 py-2 align-top whitespace-nowrap"> 49 - <span class="mb-1 block font-semibold md:hidden">Type</span> 46 + <td class="table-cell px-2 py-3 align-top md:px-6"> 47 + <span class="text-base-800 dark:text-base-200 mb-1 block font-medium md:hidden">Type</span 48 + > 50 49 51 - <span class="text-base-400">{prop.type}</span> 50 + <span class="text-base-600 dark:text-base-400 flex flex-row items-center gap-1"> 51 + {#if typeof prop.type === 'string'} 52 + <span>{prop.type}</span> 53 + {:else} 54 + <span class="hidden md:block">{prop.type.type}</span> 55 + <Popover> 56 + {#snippet child({ props })} 57 + <Button {...props} variant="link" class="hidden p-0 md:block"> 58 + <svg 59 + xmlns="http://www.w3.org/2000/svg" 60 + fill="none" 61 + viewBox="0 0 24 24" 62 + stroke-width="1.5" 63 + stroke="currentColor" 64 + class="size-6" 65 + > 66 + <path 67 + stroke-linecap="round" 68 + stroke-linejoin="round" 69 + d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" 70 + /> 71 + </svg> 72 + </Button> 73 + {/snippet} 74 + {prop.type.definition} 75 + </Popover> 76 + <span class="block md:hidden">{prop.type.definition}</span> 77 + {/if} 78 + </span> 79 + 80 + {#if prop.default} 81 + <Badge variant="primary_shift_2" class="w-fit">default: {prop.default}</Badge> 82 + {/if} 52 83 </td> 53 - <td class="text-base-200 table-cell px-1 py-2 align-top whitespace-nowrap"> 54 - <span class="mb-1 block font-semibold md:hidden">Description</span> 55 - <span class="text-base-400">{prop.description}</span> 84 + <td class="table-cell px-2 py-3 align-top"> 85 + <span class="text-base-800 dark:text-base-200 mb-1 block font-medium md:hidden" 86 + >Description</span 87 + > 88 + <span class="text-base-600 dark:text-base-400">{prop.description}</span> 56 89 </td> 57 90 </tr> 58 91 {/each}
+1 -1
src/docs/site-components/components_all.ts
··· 14 14 href: 'base' 15 15 }, 16 16 { 17 - name: 'Colors', 17 + name: 'Color components', 18 18 components: colorComponents, 19 19 href: 'colors' 20 20 },
-2
src/docs/types/schema.ts
··· 3 3 export type PropType = { 4 4 type: string; 5 5 definition: string | Component; 6 - stringDefinition: string; 7 6 }; 8 7 9 8 export type PropSchema = { ··· 23 22 24 23 export type APISchema<T = Record<string, unknown>> = { 25 24 title: string; 26 - description: string; 27 25 props?: PropObj<T>; 28 26 };
+2 -2
src/lib/components/base/prose/Prose.svelte
··· 7 7 </script> 8 8 9 9 <div 10 - class="prose prose-base prose-sm prose-a:no-underline prose-a:text-accent-600 dark:prose-a:text-accent-600 prose-pre:rounded-2xl w-full dark:hidden" 10 + class="prose prose-base prose-sm prose-a:no-underline prose-a:text-accent-600 dark:prose-a:text-accent-600 prose-pre:rounded-2xl w-full max-w-2xl dark:hidden" 11 11 > 12 12 {@render children?.()} 13 13 </div> 14 14 <div 15 - class="prose prose-sm prose-base-dark dark:prose-invert prose-a:no-underline prose-a:text-accent-600 dark:prose-a:text-accent-400 prose-pre:rounded-2xl hidden w-full dark:block" 15 + class="prose prose-sm prose-base-dark dark:prose-invert prose-a:no-underline prose-a:text-accent-600 dark:prose-a:text-accent-400 prose-pre:rounded-2xl hidden w-full max-w-2xl dark:block" 16 16 > 17 17 {@render children?.()} 18 18 </div>
+21 -17
src/routes/(main)/docs/philosophy/Philosophy.md
··· 11 11 This ui kit's main aim is to help you build webapps that look good very fast. 12 12 13 13 It's not designed to be super customizable, but instead offers you a 14 - bunch of good-looking-by-default components. 14 + bunch of good-looking-by-default components that are as easy to use as possible. 15 15 16 16 ## Two colors 17 17 18 - Still all apps looking the same is kinda boring, so there are is one easy and quick way to customize all components. 18 + Still all apps looking the same is kinda boring, so there is one easy and quick way to customize all components. 19 19 20 20 The main idea is having two colors (in all tailwind shades from 50 up to 950): 21 21 ··· 29 29 I'm a big fan of the philosophy of copying components (shadcn-style) for better customization, 30 30 but also I think the quickest way to build something is to just install the package and use it. 31 31 32 - So the plan is to have both options (currently only installing as a package is available, 33 - but you can copy what you need from the [source code](https://github.com/flo-bit/ui-kit/tree/main/src/lib/components/base) 34 - though some imports might need to be adjusted). 32 + So the plan is to have both options (usually you start by just using the package and if you 33 + eventually need to customize a component you add it to your project), 34 + currently the recommended way to use it is installing as a package, 35 + but a cli tool is in the works and can already be tested with the base components by running: 36 + 37 + ```bash 38 + npx fuchs add [component-name] 39 + ``` 40 + 41 + (Note: this still needs you to install `fuchs` as a package first). 35 42 36 43 ## Lots of components 37 44 38 - While currently only the base and some other components are visible, there are lots of components in the pipeline. 39 - The aim is to have a component library that has lots of components that are useful for building 40 - webapps/websites/games, all in a consistent style/theme. 45 + Contrary to other component libraries that offer only some base components and expect you to built the rest, 46 + this library is aiming to have a component library that has lots of different components that are 47 + useful for building webapps/websites/games, all in a consistent style/theme. 41 48 42 - See here for a few examples of work in progress components (some may be partially broken): 49 + Scroll down the sidebar or main page for examples of specialised components (section `Color`, `Extra` and `3D` components) 50 + 51 + Also see here for a few examples of work in progress components (some may be partially broken): 43 52 44 53 ### graphs 45 54 ··· 47 56 - [heatmap](/ui-kit/components/graphs/heatmap/) 48 57 - [line chart](/ui-kit/components/graphs/line-graph/) 49 58 50 - ### extras 51 - 52 - - [swiper cards](/ui-kit/components/extras/swiper-cards/) 53 - 54 59 ### social 55 60 56 61 - [github-corner](/ui-kit/components/social/github-corner/) 57 62 - [star rating](/ui-kit/components/social/star-rating/) 58 63 - [social media post](/ui-kit/components/social/post/) 59 64 60 - ### 3d 61 - 62 - - [model-picker](/ui-kit/components/3d/model-picker/) 65 + If you have a suggestion for a new component, please open an issue on [github](https://github.com/flo-bit/ui-kit/issues). 63 66 64 67 ## Works without javascript when possible & is accessible 65 68 ··· 92 95 93 96 ## Credits 94 97 95 - This ui kit is largely based on [bits-ui](https://bits-ui.com/). 98 + The base components of this ui kit are largely based on [bits-ui](https://bits-ui.com/) and I've taken lots of inspiration 99 + from [shadcn-svelte](https://www.shadcn-svelte.com/).
+22 -22
src/routes/(main)/docs/quick-start/QuickStart.md
··· 28 28 @source "../node_modules/fuchs"; 29 29 30 30 @theme { 31 - --color-base-50: var(--color-gray-50); 32 - --color-base-100: var(--color-gray-100); 33 - --color-base-200: var(--color-gray-200); 34 - --color-base-300: var(--color-gray-300); 35 - --color-base-400: var(--color-gray-400); 36 - --color-base-500: var(--color-gray-500); 37 - --color-base-600: var(--color-gray-600); 38 - --color-base-700: var(--color-gray-700); 39 - --color-base-800: var(--color-gray-800); 40 - --color-base-900: var(--color-gray-900); 41 - --color-base-950: var(--color-gray-950); 31 + --color-base-50: var(--color-zinc-50); 32 + --color-base-100: var(--color-zinc-100); 33 + --color-base-200: var(--color-zinc-200); 34 + --color-base-300: var(--color-zinc-300); 35 + --color-base-400: var(--color-zinc-400); 36 + --color-base-500: var(--color-zinc-500); 37 + --color-base-600: var(--color-zinc-600); 38 + --color-base-700: var(--color-zinc-700); 39 + --color-base-800: var(--color-zinc-800); 40 + --color-base-900: var(--color-zinc-900); 41 + --color-base-950: var(--color-zinc-950); 42 42 43 - --color-accent-50: var(--color-blue-50); 44 - --color-accent-100: var(--color-blue-100); 45 - --color-accent-200: var(--color-blue-200); 46 - --color-accent-300: var(--color-blue-300); 47 - --color-accent-400: var(--color-blue-400); 48 - --color-accent-500: var(--color-blue-500); 49 - --color-accent-600: var(--color-blue-600); 50 - --color-accent-700: var(--color-blue-700); 51 - --color-accent-800: var(--color-blue-800); 52 - --color-accent-900: var(--color-blue-900); 53 - --color-accent-950: var(--color-blue-950); 43 + --color-accent-50: var(--color-emerald-50); 44 + --color-accent-100: var(--color-emerald-100); 45 + --color-accent-200: var(--color-emerald-200); 46 + --color-accent-300: var(--color-emerald-300); 47 + --color-accent-400: var(--color-emerald-400); 48 + --color-accent-500: var(--color-emerald-500); 49 + --color-accent-600: var(--color-emerald-600); 50 + --color-accent-700: var(--color-emerald-700); 51 + --color-accent-800: var(--color-emerald-800); 52 + --color-accent-900: var(--color-emerald-900); 53 + --color-accent-950: var(--color-emerald-950); 54 54 } 55 55 ``` 56 56
+11 -4
src/routes/(main)/components/base/accordion/Accordion.md
··· 1 1 <script lang="ts"> 2 2 import AccordionExample from './Example.svelte'; 3 - 4 - import Api from '$docs/site-components/API.svelte'; 3 + import AccordionProps from './Props.svelte'; 5 4 </script> 6 5 7 6 # Accordion ··· 18 17 </script> 19 18 20 19 <Accordion type="single"> 21 - <AccordionItem value="item-1" title="Is it accessible?"> 20 + <AccordionItem title="Is it accessible?"> 22 21 Yes. It adheres to the WAI-ARIA design pattern. 23 22 </AccordionItem> 24 - <AccordionItem value="item-2" title="Are you sure?"> 23 + <AccordionItem title="Are you sure?"> 25 24 I mean, I hope so? It's based on the bits-ui accordion component, so if not it's not my fault 😅 26 25 </AccordionItem> 27 26 </Accordion> 28 27 ``` 28 + 29 + ## API Reference 30 + 31 + <AccordionProps /> 32 + 33 + ## Credits 34 + 35 + This component is based on the [bits-ui accordion component](https://bits-ui.com/docs/components/accordion).
+2 -2
src/routes/(main)/components/base/accordion/Example.svelte
··· 3 3 </script> 4 4 5 5 <Accordion type="single"> 6 - <AccordionItem value="item-1" title="Is it accessible?"> 6 + <AccordionItem title="Is it accessible?"> 7 7 Yes. It adheres to the WAI-ARIA design pattern. 8 8 </AccordionItem> 9 - <AccordionItem value="item-2" title="Are you sure?"> 9 + <AccordionItem title="Are you sure?"> 10 10 I mean, I hope so? It's based on the <a 11 11 href="https://bits-ui.com/docs/components/accordion" 12 12 target="_blank">bits-ui accordion component</a
+83
src/routes/(main)/components/base/accordion/Props.svelte
··· 1 + <script> 2 + import Api from '$docs/site-components/API.svelte'; 3 + </script> 4 + 5 + <Api 6 + props={{ 7 + title: 'Accordion', 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 + 49 + <Api 50 + props={{ 51 + title: 'AccordionItem', 52 + props: { 53 + title: { 54 + type: 'string', 55 + description: 56 + 'The title of the accordion item, displayed both when the item is closed or open.', 57 + required: true 58 + }, 59 + children: { 60 + type: 'Snippet', 61 + description: 62 + 'The children content to render. The content is displayed when the item is open.', 63 + required: true 64 + }, 65 + value: { 66 + type: 'string', 67 + description: 68 + '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.' 69 + }, 70 + disabled: { 71 + type: 'boolean', 72 + description: 'Whether the accordion item is disabled.', 73 + default: 'false' 74 + }, 75 + ref: { 76 + type: 'HTMLDivElement', 77 + description: 78 + 'The underlying DOM element being rendered. You can bind to this to get a reference to the element.', 79 + bindable: true 80 + } 81 + } 82 + }} 83 + />