[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 popover, some refactor, formating, prepare api section

Florian (Mar 24, 2025, 2:12 AM +0100) cd3089cd 849ac64d

+348 -201
+1 -1
package.json
··· 1 1 { 2 2 "name": "fuchs", 3 - "version": "0.0.14", 3 + "version": "0.0.15", 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 -4
.github/workflows/deploy_all.yml
··· 3 3 on: 4 4 push: 5 5 branches: 6 - - publish 6 + - main 7 7 8 8 jobs: 9 9 build_site: ··· 12 12 permissions: 13 13 contents: read 14 14 id-token: write 15 - 15 + 16 16 steps: 17 17 - name: Checkout 18 18 uses: actions/checkout@v4 ··· 37 37 uses: actions/upload-pages-artifact@v3 38 38 with: 39 39 path: 'build/' 40 - 40 + 41 41 - name: Publish npm package 42 42 env: 43 - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 43 + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 44 44 run: npm publish --provenance --access public 45 45 46 46 deploy:
+2 -2
.github/workflows/deploy_docs.yml
··· 3 3 on: 4 4 push: 5 5 branches: 6 - - main 6 + - docs 7 7 8 8 jobs: 9 9 build_site: ··· 31 31 uses: actions/upload-pages-artifact@v3 32 32 with: 33 33 path: 'build/' 34 - 34 + 35 35 deploy: 36 36 needs: build_site 37 37 runs-on: ubuntu-latest
+1 -1
src/lib/index.ts
··· 51 51 export { default as ModalModelPicker } from '$lib/components/3d/model-picker/modal/ModalModelPicker.svelte'; 52 52 export { default as PopoverModelPicker } from '$lib/components/3d/model-picker/popover/PopoverModelPicker.svelte'; 53 53 export { default as Depth3D } from '$lib/components/3d/depth3d/Depth3D.svelte'; 54 - export { default as VoxelArt } from '$lib/components/3d/voxel-art/VoxelArt.svelte'; 54 + export { default as VoxelArt } from '$lib/components/3d/voxel-art/VoxelArt.svelte';
+5 -1
src/docs/preview/ColorPickerPreview.svelte
··· 6 6 import Button from '$lib/components/base/button/Button.svelte'; 7 7 import PopoverColorPicker from '$lib/components/extra/color-picker/popover/PopoverColorPicker.svelte'; 8 8 import { ThemeWatcher } from '$lib/helper/ThemeWatcher.svelte'; 9 - import { hex_to_rgb, oklch_string_to_oklch, oklch_to_rgb } from '$lib/components/extra/color-picker/base/color'; 9 + import { 10 + hex_to_rgb, 11 + oklch_string_to_oklch, 12 + oklch_to_rgb 13 + } from '$lib/components/extra/color-picker/base/color'; 10 14 11 15 let rgb = $state({ 12 16 r: 0,
+60
src/docs/site-components/API.svelte
··· 1 + <script lang="ts"> 2 + import type { APISchema } from '$docs/types/schema'; 3 + import Badge from '$lib/components/base/badge/Badge.svelte'; 4 + 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 + }; 17 + </script> 18 + 19 + <table class="text-base-900 dark:text-base-50 not-prose divide-base-900 min-w-full divide-y"> 20 + <thead> 21 + <tr> 22 + <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" 23 + >Property</th 24 + > 25 + <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" 26 + >Type</th 27 + > 28 + <th scope="col" class="hidden px-1 py-3.5 text-left text-sm font-semibold md:table-cell" 29 + >Description</th 30 + > 31 + </tr> 32 + </thead> 33 + <tbody class="divide-base-900 divide-y text-sm"> 34 + {#each Object.entries(props.props) as [key, prop]} 35 + <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> 41 + {#if prop.required} 42 + <Badge variant="primary" class="w-fit">required</Badge> 43 + {:else if prop.bindable} 44 + <Badge variant="primary_shift" class="w-fit">bindable</Badge> 45 + {/if} 46 + </div> 47 + </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> 50 + 51 + <span class="text-base-400">{prop.type}</span> 52 + </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> 56 + </td> 57 + </tr> 58 + {/each} 59 + </tbody> 60 + </table>
+1 -1
src/docs/site-components/SelectTheme.svelte
··· 75 75 if (typeof previous === 'string' || typeof color === 'string') { 76 76 return; 77 77 } 78 - 78 + 79 79 document.documentElement.classList.remove(previous.label.toLowerCase()); 80 80 document.documentElement.classList.add(color.label.toLowerCase()); 81 81
-1
src/docs/site-components/Sidebar.svelte
··· 93 93 {/each} 94 94 </AccordionItem> 95 95 {/each} 96 - 97 96 </Accordion> 98 97 </div> 99 98 </Sidebar>
+28
src/docs/types/schema.ts
··· 1 + import type { Component } from 'svelte'; 2 + 3 + export type PropType = { 4 + type: string; 5 + definition: string | Component; 6 + stringDefinition: string; 7 + }; 8 + 9 + export type PropSchema = { 10 + default?: string; 11 + type: PropType | string; 12 + description: string; 13 + required?: boolean; 14 + bindable?: boolean; 15 + linked?: boolean; 16 + href?: string; 17 + tooltipContent?: string; 18 + }; 19 + 20 + export type PropObj<T> = { 21 + [K in keyof T]-?: PropSchema; 22 + }; 23 + 24 + export type APISchema<T = Record<string, unknown>> = { 25 + title: string; 26 + description: string; 27 + props?: PropObj<T>; 28 + };
+1 -1
src/docs/cards/3d/CardModelPicker.svelte
··· 8 8 import image3 from '$docs/assets/models/vehicle-racer-low.png'; 9 9 </script> 10 10 11 - <div class="h-44 w-full max-h-44 max-w-full flex items-center justify-center gap-6"> 11 + <div class="flex h-44 max-h-44 w-full max-w-full items-center justify-center gap-6"> 12 12 <Image src={image} alt="Vehicle Monster Truck" class="scale-125" /> 13 13 <Image src={image2} alt="Vehicle Racer" class="scale-125" /> 14 14 <Image src={image3} alt="Vehicle Racer Low" class="scale-125" />
+1 -1
src/docs/cards/3d/CardVoxelArt.svelte
··· 3 3 import data from '$docs/assets/model-apple.json'; 4 4 </script> 5 5 6 - <div class="flex h-full w-full items-center justify-center -mt-8"> 6 + <div class="-mt-8 flex h-full w-full items-center justify-center"> 7 7 <VoxelArt 8 8 {data} 9 9 colorMap={{
+1 -2
src/docs/cards/base/CardAvatar.svelte
··· 2 2 import { Avatar, AvatarGroup } from '$lib/components/base/avatar'; 3 3 </script> 4 4 5 - 6 5 <div class="flex items-center gap-2"> 7 6 <Avatar fallback="AB" class="size-16 text-xl font-semibold" /> 8 7 <Avatar class="size-16" /> 9 - <Avatar src="https://github.com/flo-bit.png" alt="flo-bit" fallback="FB" class="size-16" /> 8 + <Avatar src="https://github.com/flo-bit.png" alt="flo-bit" fallback="FB" class="size-16" /> 10 9 </div>
+15 -6
src/docs/cards/colors/CardColorGradientPicker.svelte
··· 1 - <div class="px-8 w-full"> 2 - <div class="gradient-background h-4 w-full rounded-2xl relative border border-base-500"> 3 - <div class="absolute size-6 bg-accent-500 rounded-full border border-base-500 -top-3" style="left: calc(0% - 12px);"></div> 4 - <div class="absolute size-6 bg-accent-500 rounded-full border border-base-500 -top-3" style="left: calc(50% - 12px); background: oklch(from var(--color-accent-500) l c calc(h + 30));"></div> 5 - <div class="absolute size-6 bg-accent-500 rounded-full border border-base-500 -top-3" style="left: calc(100% - 12px); background: oklch(from var(--color-accent-500) l c calc(h + 60));"></div> 6 - </div> 1 + <div class="w-full px-8"> 2 + <div class="gradient-background border-base-500 relative h-4 w-full rounded-2xl border"> 3 + <div 4 + class="bg-accent-500 border-base-500 absolute -top-3 size-6 rounded-full border" 5 + style="left: calc(0% - 12px);" 6 + ></div> 7 + <div 8 + class="bg-accent-500 border-base-500 absolute -top-3 size-6 rounded-full border" 9 + style="left: calc(50% - 12px); background: oklch(from var(--color-accent-500) l c calc(h + 30));" 10 + ></div> 11 + <div 12 + class="bg-accent-500 border-base-500 absolute -top-3 size-6 rounded-full border" 13 + style="left: calc(100% - 12px); background: oklch(from var(--color-accent-500) l c calc(h + 60));" 14 + ></div> 15 + </div> 7 16 </div> 8 17 9 18 <style>
+8 -4
src/docs/cards/colors/CardColorPicker.svelte
··· 1 1 <script lang="ts"> 2 2 import { ColorPicker } from '$lib'; 3 - import { oklch_string_to_oklch, oklch_to_rgb } from '$lib/components/colors/color-picker/base/color'; 3 + import { 4 + oklch_string_to_oklch, 5 + oklch_to_rgb 6 + } from '$lib/components/colors/color-picker/base/color'; 4 7 import { ThemeWatcher } from '$lib/helper/ThemeWatcher.svelte'; 5 8 import { onMount } from 'svelte'; 6 9 ··· 22 25 }); 23 26 </script> 24 27 25 - <div class="h-full w-full flex items-center justify-center"> 26 - <!-- inline version --> 27 - <ColorPicker bind:rgb class="scale-[0.6] -ml-2" /></div> 28 + <div class="flex h-full w-full items-center justify-center"> 29 + <!-- inline version --> 30 + <ColorPicker bind:rgb class="-ml-2 scale-[0.6]" /> 31 + </div>
+6 -4
src/docs/cards/colors/CardColorSelect.svelte
··· 1 1 <div class={'group flex flex-wrap items-center gap-2'}> 2 - <div class="rounded-full flex items-center justify-center text-accent-700"> 2 + <div class="text-accent-700 flex items-center justify-center rounded-full"> 3 3 <div class="size-8 rounded-full bg-current"></div> 4 4 </div> 5 - <div class="rounded-full flex items-center justify-center text-accent-500 ring-accent-500 p-0.5 ring-3"> 5 + <div 6 + class="text-accent-500 ring-accent-500 flex items-center justify-center rounded-full p-0.5 ring-3" 7 + > 6 8 <div class="size-8 rounded-full bg-current"></div> 7 9 </div> 8 - <div class="rounded-full flex items-center justify-center text-accent-300"> 10 + <div class="text-accent-300 flex items-center justify-center rounded-full"> 9 11 <div class="size-8 rounded-full bg-current"></div> 10 12 </div> 11 - <div class="rounded-full flex items-center justify-center text-accent-100"> 13 + <div class="text-accent-100 flex items-center justify-center rounded-full"> 12 14 <div class="size-8 rounded-full bg-current"></div> 13 15 </div> 14 16 </div>
+5 -3
src/docs/cards/extras/CardPhone.svelte
··· 4 4 5 5 <div class="-mt-20 h-full w-full scale-50"> 6 6 <Phone class=""> 7 - <div class="bg-accent-200 flex h-full w-full justify-center p-8 bg-gradient-to-b from-accent-200 via-accent-300"> 8 - <div class="text-3xl font-bold text-black mt-20 text-center">Hello there</div> 7 + <div 8 + class="bg-accent-200 from-accent-200 via-accent-300 flex h-full w-full justify-center bg-gradient-to-b p-8" 9 + > 10 + <div class="mt-20 text-center text-3xl font-bold text-black">Hello there</div> 9 11 </div> 10 12 </Phone> 11 - </div> 13 + </div>
+1 -1
src/docs/cards/extras/CardQuote.svelte
··· 8 8 author={{ 9 9 name: 'Einstein', 10 10 role: 'Scientist', 11 - src: einstein, 11 + src: einstein 12 12 }} 13 13 useThemeColor 14 14 class="scale-75"
+11 -9
src/docs/cards/extras/CardUndraw.svelte
··· 4 4 import svg from '$docs/assets/undraw_wireframing.svg?raw'; 5 5 </script> 6 6 7 - 8 7 <div class="max-h-full"> 9 - <Undraw svg={svg} alt="Undraw" colorMap={{ 10 - '#3f3d56': 'fill-base-950 dark:fill-base-600', 11 - '#2f2e41': 'fill-base-800 dark:fill-base-800', 12 - '#e4e4e4': 'fill-base-300 dark:fill-base-700', 13 - '#cacaca': 'fill-base-400 dark:fill-base-600', 14 - }} /> 15 - </div> 16 - 8 + <Undraw 9 + {svg} 10 + alt="Undraw" 11 + colorMap={{ 12 + '#3f3d56': 'fill-base-950 dark:fill-base-600', 13 + '#2f2e41': 'fill-base-800 dark:fill-base-800', 14 + '#e4e4e4': 'fill-base-300 dark:fill-base-700', 15 + '#cacaca': 'fill-base-400 dark:fill-base-600' 16 + }} 17 + /> 18 + </div>
+2 -2
src/docs/wip/pdf-viewer/PDFViewer.svelte
··· 52 52 }); 53 53 </script> 54 54 55 - <div class="relative max-w-full mx-auto"> 56 - <canvas bind:this={canvas} class="max-w-full max-h-[calc(100vh-8rem)] dark:invert"></canvas> 55 + <div class="relative mx-auto max-w-full"> 56 + <canvas bind:this={canvas} class="max-h-[calc(100vh-8rem)] max-w-full dark:invert"></canvas> 57 57 58 58 {#if loaded} 59 59 <Button
+4
src/lib/components/base/badge/Badge.svelte
··· 8 8 variant: { 9 9 primary: 10 10 'border border-accent-500/20 dark:border-accent-500/20 bg-accent-500/10 dark:bg-accent-500/10 text-accent-700 dark:text-accent-400', 11 + primary_shift: 12 + 'border border-[oklch(from_var(--color-accent-500)_l_c_calc(h+35)_/_0.2)] dark:border-[oklch(from_var(--color-accent-500)_l_c_calc(h+35)_/_0.2)] bg-[oklch(from_var(--color-accent-500)_l_c_calc(h+35)_/_0.1)] text-[oklch(from_var(--color-accent-700)_l_c_calc(h+35))] dark:text-[oklch(from_var(--color-accent-400)_l_c_calc(h+35))]', 13 + primary_shift_2: 14 + 'border border-[oklch(from_var(--color-accent-500)_l_c_calc(h+70)_/_0.2)] dark:border-[oklch(from_var(--color-accent-500)_l_c_calc(h+70)_/_0.2)] bg-[oklch(from_var(--color-accent-500)_l_c_calc(h+70)_/_0.1)] text-[oklch(from_var(--color-accent-700)_l_c_calc(h+70))] dark:text-[oklch(from_var(--color-accent-400)_l_c_calc(h+70))]', 11 15 secondary: 12 16 'bg-base-300/30 dark:bg-base-800/50 text-base-900 dark:text-base-50 border border-base-300/50 dark:border-base-700/30', 13 17
+1 -1
src/lib/components/base/copy-code-button/CopyCodeButton.svelte
··· 24 24 {#if !copied} 25 25 <button 26 26 class={cn( 27 - 'not-prose cursor-pointer focus-visible:outline-base-600 dark:focus-visible:outline-base-400 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2', 27 + 'not-prose focus-visible:outline-base-600 dark:focus-visible:outline-base-400 cursor-pointer focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2', 28 28 'bg-base-200 inline-flex size-8 items-center justify-center p-1 transition-opacity duration-150 group-hover:opacity-100 [@media(pointer:fine)]:opacity-0', 29 29 'dark:bg-base-800 border-base-400 dark:border-base-700 dark:hover:bg-base-700 hover:bg-base-300 absolute top-3 right-3 rounded-2xl border' 30 30 )}
+6 -9
src/lib/components/base/image/Image.svelte
··· 58 58 )} 59 59 {...restProps} 60 60 onload={(evt) => { 61 - loaded = true 62 - if(restProps.onload) { 63 - restProps.onload(evt) 61 + loaded = true; 62 + if (restProps.onload) { 63 + restProps.onload(evt); 64 64 } 65 65 }} 66 66 /> ··· 76 76 )} 77 77 width={restProps.width ? Number(restProps.width) : undefined} 78 78 height={restProps.height ? Number(restProps.height) : undefined} 79 - 80 79 loading={restProps.loading ?? 'lazy'} 81 80 decoding={restProps.decoding ?? 'async'} 82 - 83 81 sizes={restProps.sizes ?? undefined} 84 - 85 82 onload={(evt) => { 86 - loaded = true 87 - if(restProps.onload) { 88 - restProps.onload(evt) 83 + loaded = true; 84 + if (restProps.onload) { 85 + restProps.onload(evt); 89 86 } 90 87 }} 91 88 />
+2 -4
src/lib/components/base/popover/Popover.svelte
··· 4 4 import * as Popover from '$lib/components/base/popover'; 5 5 import { Popover as PopoverPrimitive } from 'bits-ui'; 6 6 7 - 8 7 type Props = PopoverPrimitive.RootProps & { 9 8 triggerProps?: PopoverPrimitive.TriggerProps; 10 9 text?: string; ··· 15 14 triggerSize?: ButtonSize; 16 15 17 16 triggerRef?: HTMLButtonElement | null; 18 - 19 - } & PopoverPrimitive.ContentProps & PopoverPrimitive.TriggerProps; 20 - 17 + } & PopoverPrimitive.ContentProps & 18 + PopoverPrimitive.TriggerProps; 21 19 22 20 let { 23 21 open = $bindable(false),
+1 -1
src/lib/components/base/scroll-area/BodyScrollArea.svelte
··· 1 1 <script lang="ts"> 2 2 import './style.css'; 3 - </script> 3 + </script>
+1 -1
src/lib/components/base/scroll-area/style.css
··· 38 38 39 39 .dark body::-webkit-scrollbar-thumb:hover { 40 40 background-color: var(--color-base-700); 41 - } 41 + }
+1 -5
src/lib/components/base/select/Select.svelte
··· 27 27 } 28 28 </script> 29 29 30 - <Toolbar.Root 31 - bind:ref 32 - class={className} 33 - {...restProps} 34 - > 30 + <Toolbar.Root bind:ref class={className} {...restProps}> 35 31 <Toolbar.Group bind:value={selected} type="single" class="flex items-center gap-x-1 text-sm"> 36 32 {#each items as item} 37 33 <Toolbar.GroupItem
+1 -1
src/lib/components/base/slider/Slider.svelte
··· 8 8 orientation = 'horizontal', 9 9 class: className, 10 10 tabindex = undefined, 11 - type = 'single', 11 + type = 'single' 12 12 }: WithoutChildrenOrChild<SliderPrimitive.RootProps> = $props(); 13 13 </script> 14 14
+1 -1
src/lib/components/base/slider/SliderNumber.svelte
··· 22 22 locales="en-US" 23 23 format={{ useGrouping: false }} 24 24 aria-hidden="true" 25 - class="pointer-events-none min-w-6 text-right text-lg font-semibold text-base-900 dark:text-base-100" 25 + class="text-base-900 dark:text-base-100 pointer-events-none min-w-6 text-right text-lg font-semibold" 26 26 willChange 27 27 /> 28 28 </div>
+23 -20
src/lib/components/colors/color-gradient-picker/ColorGradientPicker.svelte
··· 12 12 import { DragGesture } from '@use-gesture/vanilla'; 13 13 import Button from '$lib/components/base/button/Button.svelte'; 14 14 15 - 16 15 type ColorStop = { rgb: RGB; position: number }; 17 16 18 17 let initialColors: ColorStop[] = $state([ ··· 58 57 if (!ref) return; 59 58 60 59 gestures.push( 61 - new DragGesture(ref, (state) => { 62 - const { delta } = state; 60 + new DragGesture( 61 + ref, 62 + (state) => { 63 + const { delta } = state; 63 64 64 - const newPosition = delta[0] / (gradientRef?.clientWidth ?? 1); 65 + const newPosition = delta[0] / (gradientRef?.clientWidth ?? 1); 65 66 66 - colors[i].position += newPosition; 67 - colors[i].position = Math.max(0, Math.min(1, colors[i].position)); 67 + colors[i].position += newPosition; 68 + colors[i].position = Math.max(0, Math.min(1, colors[i].position)); 68 69 69 - if (Math.abs(state.offset[0]) > 10) { 70 - isDragging[i] = state.active; 71 - } else { 72 - isDragging[i] = state.active; 70 + if (Math.abs(state.offset[0]) > 10) { 71 + isDragging[i] = state.active; 72 + } else { 73 + isDragging[i] = state.active; 74 + } 75 + 76 + if (state.tap) { 77 + allOpen[i] = !allOpen[i]; 78 + } 79 + }, 80 + { 81 + preventDefault: true, 82 + eventOptions: { 83 + passive: false 84 + } 73 85 } 74 - 75 - if (state.tap) { 76 - allOpen[i] = !allOpen[i]; 77 - } 78 - }, { 79 - preventDefault: true, 80 - eventOptions: { 81 - passive: false 82 - } 83 - }) 86 + ) 84 87 ); 85 88 }); 86 89
+1 -4
src/lib/components/colors/color-select/ColorSelect.svelte
··· 76 76 checked={getLabel(selected) === getLabel(color)} 77 77 /> 78 78 79 - <span 80 - aria-hidden="true" 81 - class="size-8 rounded-full bg-current" 82 - ></span> 79 + <span aria-hidden="true" class="size-8 rounded-full bg-current"></span> 83 80 </label> 84 81 {/each} 85 82 </div>
+1 -6
src/lib/components/extra/countdown/Countdown.svelte
··· 37 37 style="font-variant-numeric: tabular-nums;" 38 38 {...restProps} 39 39 > 40 - 41 40 {#if showSeconds} 42 - <NumberFlow 43 - value={ss} 44 - trend={-1} 45 - digits={{ 1: { max: 5 } }} 46 - /> 41 + <NumberFlow value={ss} trend={-1} digits={{ 1: { max: 5 } }} /> 47 42 {/if} 48 43 </div> 49 44 </NumberFlowGroup>
-1
src/lib/components/extra/excalidraw/Excalidraw.svelte
··· 50 50 51 51 return loadedSvg.html(); 52 52 } 53 - 54 53 </script> 55 54 56 55 <figure
+1 -1
src/lib/components/extra/phone/Phone.svelte
··· 7 7 8 8 <div 9 9 class={cn( 10 - 'isolate bg-accent-500 relative h-[712px] w-[350px] max-w-full rounded-[60px] aspect-[350/712]', 10 + 'bg-accent-500 relative isolate aspect-[350/712] h-[712px] w-[350px] max-w-full rounded-[60px]', 11 11 className 12 12 )} 13 13 >
+1 -1
src/lib/components/extra/quote/Quote.svelte
··· 52 52 fallback={author?.fallback} 53 53 src={author?.src} 54 54 alt={author?.alt} 55 - class="size-24 rounded-2xl text-3xl md:size-32 object-cover" 55 + class="size-24 rounded-2xl object-cover text-3xl md:size-32" 56 56 /> 57 57 </div> 58 58 <div class="flex flex-col gap-2">
+3 -3
src/lib/components/extra/swiper-cards/CardSwiper.svelte
··· 1 1 <script lang="ts"> 2 2 // TODO: fix types 3 - 3 + 4 4 import { onMount, type Snippet } from 'svelte'; 5 5 import { DragGesture, type FullGestureState } from '@use-gesture/vanilla'; 6 6 import type { CardData, Direction, SwipeEventData } from '.'; ··· 195 195 {#key image} 196 196 {#if image} 197 197 <Image 198 - containerClasses="absolute inset-0 h-full w-full rounded-2xl" 198 + containerClasses="absolute inset-0 h-full w-full rounded-2xl" 199 199 src={image} 200 200 alt={title ?? ''} 201 201 loading="eager" ··· 206 206 <div 207 207 class="from-base-50/80 dark:from-base-950/80 absolute inset-0 rounded-b-xl bg-gradient-to-t via-transparent" 208 208 ></div> 209 - <div class="absolute bottom-0 flex w-full justify-start px-3 sm:px-12 py-16"> 209 + <div class="absolute bottom-0 flex w-full justify-start px-3 py-16 sm:px-12"> 210 210 <div class="flex flex-col"> 211 211 <h3 class="text-base-900 dark:text-base-50 pb-2 text-3xl font-bold">{title}</h3> 212 212 <p class="text-base-800 dark:text-base-200 text-sm">{description}</p>
+2 -6
src/lib/components/extra/undraw/Undraw.svelte
··· 26 26 27 27 function applyClasses(loadedSvg: CheerioAPI, el: any) { 28 28 let fill = loadedSvg(el).attr('fill'); 29 - if(!fill) return; 29 + if (!fill) return; 30 30 31 31 if (fill === '#6c63ff') { 32 32 loadedSvg(el).removeAttr('fill'); 33 33 loadedSvg(el).addClass('fill-accent-600 dark:fill-accent-500'); 34 - } else if ( 35 - fill.startsWith('#') && 36 - !fill.includes('url') && 37 - autoInvert 38 - ) { 34 + } else if (fill.startsWith('#') && !fill.includes('url') && autoInvert) { 39 35 loadedSvg(el).addClass('dark:invert dark:hue-rotate-180'); 40 36 } else if (colorMap[fill]) { 41 37 loadedSvg(el).removeAttr('fill');
+8 -8
src/routes/(main)/docs/philosophy/Philosophy.md
··· 26 26 27 27 ## Copying components vs installing packages 28 28 29 - I'm a big fan of the philosophy of copying components (shadcn-style) for better customization, 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) 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 34 though some imports might need to be adjusted). 35 35 36 36 ## Lots of components 37 37 38 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 39 + The aim is to have a component library that has lots of components that are useful for building 40 40 webapps/websites/games, all in a consistent style/theme. 41 41 42 42 See here for a few examples of work in progress components (some may be partially broken): ··· 63 63 64 64 ## Works without javascript when possible & is accessible 65 65 66 - Whenever possible components should work without javascript. 67 - Also all components should be accessible (to the best of my knowledge). 66 + Whenever possible components should work without javascript. 67 + Also all components should be accessible (to the best of my knowledge). 68 68 Please let me know [if you find any issues there](https://github.com/flo-bit/ui-kit/issues). 69 69 70 70 ## Dark mode 71 71 72 - This ui kit is designed to be used in both light and dark mode 72 + This ui kit is designed to be used in both light and dark mode 73 73 (and switch automatically depending on system settings). 74 74 If you want to disable dark mode, add the following to your app.css: 75 75 ··· 92 92 93 93 ## Credits 94 94 95 - This ui kit is largely based on [bits-ui](https://bits-ui.com/). 95 + This ui kit is largely based on [bits-ui](https://bits-ui.com/).
+1 -1
src/lib/components/3d/model-picker/base/ModelPickerScene.svelte
··· 28 28 stop(); 29 29 } 30 30 }); 31 - 31 + 32 32 const { renderer } = useThrelte(); 33 33 34 34 onMount(() => {
+1 -1
src/lib/components/3d/model-picker/popover/PopoverModelPicker.svelte
··· 31 31 <Popover.Content 32 32 side={'top'} 33 33 sideOffset={10} 34 - class="max-h-[60dvh] w-full max-w-[calc(100vw-1rem)] overflow-y-scroll mx-2" 34 + class="mx-2 max-h-[60dvh] w-full max-w-[calc(100vw-1rem)] overflow-y-scroll" 35 35 > 36 36 <ModelPicker 37 37 {items}
+2 -2
src/lib/components/colors/color-picker/popover/PopoverColorPicker.svelte
··· 61 61 style={`background-color: rgb(${internalColor.r * 255}, ${internalColor.g * 255}, ${internalColor.b * 255});`} 62 62 ></div> 63 63 </Popover.Trigger> 64 - <Popover.Content side={side} sideOffset={sideOffset}> 65 - <ColorPicker bind:rgb bind:oklab bind:okhsv class={className} onchange={onchange} /> 64 + <Popover.Content {side} {sideOffset}> 65 + <ColorPicker bind:rgb bind:oklab bind:okhsv class={className} {onchange} /> 66 66 </Popover.Content> 67 67 </Popover.Root>
-1
src/routes/(main)/components/3d/depth-3d/Depth3D.md
··· 29 29 }} 30 30 /> 31 31 ``` 32 -
+1 -1
src/routes/(main)/components/3d/model-picker/Example.svelte
··· 1 1 <script lang="ts"> 2 2 import { base } from '$app/paths'; 3 3 import { toast } from 'svelte-sonner'; 4 - 4 + 5 5 import { ModelPicker } from '$lib'; 6 6 import ModalModelPicker from '$lib/components/3d/model-picker/modal/ModalModelPicker.svelte'; 7 7 import PopoverModelPicker from '$lib/components/3d/model-picker/popover/PopoverModelPicker.svelte';
+6 -4
src/routes/(main)/components/3d/model-picker/ModelPicker.md
··· 16 16 17 17 const items = [ 18 18 { 19 - path:'/path/to/model.gltf', 19 + path: '/path/to/model.gltf', 20 20 label: 'Model A' 21 21 }, 22 22 { 23 23 path: '/path/to/model.gltf', 24 24 label: 'Model B' 25 25 } 26 - ] 26 + ]; 27 27 </script> 28 28 29 - <ModelPicker items={items} onselect={({ path, label }) => { 29 + <ModelPicker 30 + {items} 31 + onselect={({ path, label }) => { 30 32 console.log(path, label); 31 33 }} 32 34 /> ··· 34 36 35 37 ## Credits 36 38 37 - - Models from [Toy Car Kit](https://kenney.nl/assets/toy-car-kit) by [Kenney](https://kenney.nl) 39 + - Models from [Toy Car Kit](https://kenney.nl/assets/toy-car-kit) by [Kenney](https://kenney.nl)
+12 -9
src/routes/(main)/components/3d/voxel-art/VoxelArt.md
··· 25 25 You can also pass a `colorMap` prop to the component to change the colors of the voxel art, e.g. like this: 26 26 27 27 ```svelte 28 - <VoxelArt {data} colorMap={{ 29 - '050505': 'var(--color-accent-50)', 30 - '101010': 'var(--color-accent-100)', 31 - '202020': 'var(--color-accent-200)', 32 - '303030': 'var(--color-accent-300)', 33 - '404040': 'var(--color-accent-400)', 34 - '505050': 'var(--color-accent-500)', 35 - }} /> 28 + <VoxelArt 29 + {data} 30 + colorMap={{ 31 + '050505': 'var(--color-accent-50)', 32 + '101010': 'var(--color-accent-100)', 33 + '202020': 'var(--color-accent-200)', 34 + '303030': 'var(--color-accent-300)', 35 + '404040': 'var(--color-accent-400)', 36 + '505050': 'var(--color-accent-500)' 37 + }} 38 + /> 36 39 ``` 37 40 38 41 ## Credits 39 42 40 - - inspired by [this article](https://tympanus.net/codrops/2025/03/03/css-meets-voxel-art-building-a-rendering-engine-with-stacked-grids/) 43 + - inspired by [this article](https://tympanus.net/codrops/2025/03/03/css-meets-voxel-art-building-a-rendering-engine-with-stacked-grids/)
+7 -10
src/routes/(main)/components/base/accordion/Accordion.md
··· 1 1 <script lang="ts"> 2 - import { Accordion, AccordionItem } from '$lib/components/base/accordion'; 2 + import AccordionExample from './Example.svelte'; 3 + 4 + import Api from '$docs/site-components/API.svelte'; 3 5 </script> 4 6 5 7 # Accordion 6 8 7 9 ## Example 8 10 9 - <Accordion type="single"> 10 - <AccordionItem value="item-1" title="Is it accessible?"> 11 - Yes. It adheres to the WAI-ARIA design pattern. 12 - </AccordionItem> 13 - <AccordionItem value="item-2" title="Are you sure?"> 14 - I mean, I hope so? 15 - </AccordionItem> 16 - </Accordion> 11 + <AccordionExample /> 17 12 18 13 ## Usage 19 14 ··· 26 21 <AccordionItem value="item-1" title="Is it accessible?"> 27 22 Yes. It adheres to the WAI-ARIA design pattern. 28 23 </AccordionItem> 29 - <AccordionItem value="item-2" title="Are you sure?">I mean, I hope so?</AccordionItem> 24 + <AccordionItem value="item-2" title="Are you sure?"> 25 + I mean, I hope so? It's based on the bits-ui accordion component, so if not it's not my fault 😅 26 + </AccordionItem> 30 27 </Accordion> 31 28 ```
+15
src/routes/(main)/components/base/accordion/Example.svelte
··· 1 + <script lang="ts"> 2 + import { Accordion, AccordionItem } from '$lib'; 3 + </script> 4 + 5 + <Accordion type="single"> 6 + <AccordionItem value="item-1" title="Is it accessible?"> 7 + Yes. It adheres to the WAI-ARIA design pattern. 8 + </AccordionItem> 9 + <AccordionItem value="item-2" title="Are you sure?"> 10 + I mean, I hope so? It's based on the <a 11 + href="https://bits-ui.com/docs/components/accordion" 12 + target="_blank">bits-ui accordion component</a 13 + >, so if not it's not my fault 😅 14 + </AccordionItem> 15 + </Accordion>
+1 -1
src/routes/(main)/components/base/number-input/NumberInput.md
··· 23 23 24 24 ## Credits 25 25 26 - - Adapted from an example of [number-flow](https://number-flow.barvian.me/) 26 + - Adapted from an example of [number-flow](https://number-flow.barvian.me/)
+25 -11
src/routes/(main)/components/base/popover/Example.svelte
··· 2 2 import { Popover, ColorSelect, Button, toast } from '$lib'; 3 3 4 4 let open = $state(false); 5 - let selected: string = $state('red'); 5 + 6 + let colors = [ 7 + { label: '1', value: 'oklch(from var(--color-accent-500) l c h)' }, 8 + { label: '2', value: 'oklch(from var(--color-accent-500) l c calc(h + 40))' }, 9 + { label: '3', value: 'oklch(from var(--color-accent-500) l c calc(h + 80))' } 10 + ]; 11 + 12 + let selected: { label: string; value: string } = $state(colors[0]); 6 13 </script> 7 14 8 15 <h3>Default trigger</h3> ··· 11 18 <div class="flex items-center justify-between gap-2"> 12 19 <div>Are you sure?</div> 13 20 <div> 14 - <Button variant="secondary" size="iconSm" onclick={() => { 15 - open = !open; 16 - toast('Fair enough!'); 17 - }}> 21 + <Button 22 + variant="secondary" 23 + size="iconSm" 24 + onclick={() => { 25 + open = !open; 26 + toast('Fair enough!'); 27 + }} 28 + > 18 29 <svg 19 30 xmlns="http://www.w3.org/2000/svg" 20 31 fill="none" ··· 27 38 </svg> 28 39 </Button> 29 40 30 - <Button size="iconSm" onclick={() => { 31 - open = !open; 32 - toast('Good choice!'); 33 - }}> 41 + <Button 42 + size="iconSm" 43 + onclick={() => { 44 + open = !open; 45 + toast('Good choice!'); 46 + }} 47 + > 34 48 <svg 35 49 xmlns="http://www.w3.org/2000/svg" 36 50 fill="none" ··· 53 67 <button 54 68 {...props} 55 69 class="mt-2 size-8 cursor-pointer rounded-full" 56 - style="background-color: {selected}" 70 + style="background-color: {selected.value}" 57 71 ></button> 58 72 {/snippet} 59 73 60 74 Select a color: 61 75 62 - <ColorSelect colors={['red', 'green', 'blue']} bind:selected class="mt-2" /> 76 + <ColorSelect {colors} bind:selected class="mt-2" /> 63 77 </Popover>
+2 -2
src/routes/(main)/components/base/popover/Popover.md
··· 21 21 <!-- custom trigger --> 22 22 <Popover> 23 23 {#snippet child({ props })} 24 - <button {...props} class="bg-accent-500 size-8 rounded-full cursor-pointer mt-2"></button> 24 + <button {...props} class="bg-accent-500 mt-2 size-8 cursor-pointer rounded-full"></button> 25 25 {/snippet} 26 26 Content of the popover here 27 27 </Popover> 28 - ``` 28 + ```
+1 -1
src/routes/(main)/components/base/progress/+page.svelte
··· 13 13 14 14 <Subheading class="mb-8">Progress</Subheading> 15 15 16 - <Progress {progress} /> 16 + <Progress {progress} />
+1 -1
src/routes/(main)/components/base/slider/Example.svelte
··· 10 10 <Slider bind:value /> 11 11 12 12 <h3>With Number</h3> 13 - <SliderNumber bind:value={value2} /> 13 + <SliderNumber bind:value={value2} />
+1 -1
src/routes/(main)/components/base/slider/Slider.md
··· 20 20 <Slider bind:value min={0} max={100} /> 21 21 22 22 <!-- With Number --> 23 - <SliderNumber bind:value={value} /> 23 + <SliderNumber bind:value /> 24 24 ```
-1
src/routes/(main)/components/colors/color-gradient-picker/ColorGradientPicker.md
··· 23 23 24 24 <ColorGradientPicker bind:colors /> 25 25 ``` 26 -
+1 -1
src/routes/(main)/components/colors/color-picker/ColorPicker.md
··· 30 30 31 31 ### Credits 32 32 33 - - Adapted from [svelte-color-select](https://github.com/CaptainCodeman/svelte-color-select). 33 + - Adapted from [svelte-color-select](https://github.com/CaptainCodeman/svelte-color-select).
+5 -2
src/routes/(main)/components/colors/color-picker/Example.svelte
··· 1 1 <script lang="ts"> 2 2 import { ColorPicker, PopoverColorPicker } from '$lib'; 3 3 import { ThemeWatcher } from '$lib/helper/ThemeWatcher.svelte'; 4 - import { oklch_string_to_oklch, oklch_to_rgb } from '$lib/components/colors/color-picker/base/color'; 4 + import { 5 + oklch_string_to_oklch, 6 + oklch_to_rgb 7 + } from '$lib/components/colors/color-picker/base/color'; 5 8 import { onMount } from 'svelte'; 6 9 7 10 let rgb = $state({ ··· 28 31 29 32 <h3>Popover Color Picker</h3> 30 33 31 - <PopoverColorPicker bind:rgb /> 34 + <PopoverColorPicker bind:rgb />
+1 -1
src/routes/(main)/components/colors/color-select/Example.svelte
··· 7 7 { class: 'text-accent-500', label: '1' }, 8 8 { label: '2', value: 'oklch(from var(--color-accent-500) l c calc(h + 20))' }, 9 9 { label: '3', value: 'oklch(from var(--color-accent-500) l c calc(h + 40))' }, 10 - { label: '4', value: 'oklch(from var(--color-accent-500) l c calc(h + 60))' }, 10 + { label: '4', value: 'oklch(from var(--color-accent-500) l c calc(h + 60))' } 11 11 ]} 12 12 />
+1 -1
src/routes/(main)/components/extras/excalidraw/Excalidraw.md
··· 22 22 </script> 23 23 24 24 <Excalidraw {svg} alt="Excalidraw Demo" caption="This is a demo of the Excalidraw component." /> 25 - ``` 25 + ```
+3 -2
src/routes/(main)/components/extras/pdf-viewer/+page.svelte
··· 1 1 <script> 2 - import PdfViewer from "$docs/wip/pdf-viewer/PDFViewer.svelte"; 2 + import PdfViewer from '$docs/wip/pdf-viewer/PDFViewer.svelte'; 3 3 </script> 4 - <PdfViewer /> 4 + 5 + <PdfViewer />
+1 -1
src/routes/(main)/components/extras/phone/Phone.md
··· 20 20 <div class="text-3xl font-bold text-black">Hello there</div> 21 21 </div> 22 22 </Phone> 23 - ``` 23 + ```
+1 -1
src/routes/(main)/components/extras/quote/Example.svelte
··· 8 8 author={{ 9 9 name: 'Albert Einstein', 10 10 role: 'Scientist', 11 - src: einstein, 11 + src: einstein 12 12 }} 13 13 useThemeColor 14 14 class="not-prose"
+1 -1
src/routes/(main)/components/extras/quote/Quote.md
··· 20 20 author={{ 21 21 name: 'Albert Einstein', 22 22 role: 'Scientist', 23 - src: './einstein.png', 23 + src: './einstein.png' 24 24 }} 25 25 useThemeColor 26 26 />
+1 -1
src/routes/(main)/components/extras/stopwatch/Example.svelte
··· 13 13 <Stopwatch bind:stopwatch class="sm:text-7xl" /> 14 14 </Box> 15 15 16 - <div class="flex w-full justify-center gap-2 mt-2"> 16 + <div class="mt-2 flex w-full justify-center gap-2"> 17 17 <Button 18 18 onclick={() => { 19 19 if (stopwatch?.isRunning) {
+1 -1
src/routes/(main)/components/extras/stopwatch/Stopwatch.md
··· 25 25 ## Credits 26 26 27 27 - Stopwatch state based on [svelte-reactive-timer](https://github.com/joshnuss/svelte-reactive-timer) 28 - - Moving numbers component from [number-flow](https://number-flow.barvian.me/) 28 + - Moving numbers component from [number-flow](https://number-flow.barvian.me/)
+40 -19
src/routes/(main)/components/extras/swiper-cards/+page.svelte
··· 15 15 import profile10 from '$docs/assets/profiles/9.webp?as=run'; 16 16 import Image from '$lib/components/base/image/Image.svelte'; 17 17 18 - const profiles = [profile1, profile2, profile3, profile4, profile5, profile6, profile7, profile8, profile9, profile10]; 18 + const profiles = [ 19 + profile1, 20 + profile2, 21 + profile3, 22 + profile4, 23 + profile5, 24 + profile6, 25 + profile7, 26 + profile8, 27 + profile9, 28 + profile10 29 + ]; 19 30 20 31 let swipe: (direction: 'left' | 'right') => void; 21 32 </script> 22 33 23 - <div class="h-[70vh] w-full relative"> 34 + <div class="relative h-[70vh] w-full"> 24 35 <CardSwiper 25 36 cardData={(i) => ({ 26 37 title: `Card ${i}`, ··· 28 39 image: profiles[i % profiles.length] 29 40 })} 30 41 bind:swipe 31 - > 32 - </CardSwiper> 42 + ></CardSwiper> 33 43 34 - <div class="w-full flex justify-between absolute bottom-2 px-2"> 35 - <Button onclick={() => swipe('left')} size="iconLg"> 36 - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" class="size-6"> 37 - <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> 38 - </svg> 39 - 40 - 41 - </Button> 42 - <Button onclick={() => swipe('right')} size="iconLg"> 43 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"> 44 - <path d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z" /> 45 - </svg> 46 - 47 - </Button> 48 - </div> 44 + <div class="absolute bottom-2 flex w-full justify-between px-2"> 45 + <Button onclick={() => swipe('left')} size="iconLg"> 46 + <svg 47 + xmlns="http://www.w3.org/2000/svg" 48 + fill="none" 49 + viewBox="0 0 24 24" 50 + stroke-width="2.5" 51 + stroke="currentColor" 52 + class="size-6" 53 + > 54 + <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> 55 + </svg> 56 + </Button> 57 + <Button onclick={() => swipe('right')} size="iconLg"> 58 + <svg 59 + xmlns="http://www.w3.org/2000/svg" 60 + viewBox="0 0 24 24" 61 + fill="currentColor" 62 + class="size-6" 63 + > 64 + <path 65 + d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z" 66 + /> 67 + </svg> 68 + </Button> 69 + </div> 49 70 </div>
+1 -1
src/routes/(main)/components/extras/timer/Example.svelte
··· 13 13 <Timer bind:timer class="sm:text-7xl" /> 14 14 </Box> 15 15 16 - <div class="flex w-full justify-center gap-2 mt-2"> 16 + <div class="mt-2 flex w-full justify-center gap-2"> 17 17 <Button 18 18 onclick={() => { 19 19 if (timer?.isRunning) {
+1 -1
src/routes/(main)/components/extras/timer/Timer.md
··· 25 25 ## Credits 26 26 27 27 - Timer state based on [svelte-reactive-timer](https://github.com/joshnuss/svelte-reactive-timer) 28 - - Moving numbers component from [number-flow](https://number-flow.barvian.me/) 28 + - Moving numbers component from [number-flow](https://number-flow.barvian.me/)
+1 -1
src/routes/(main)/components/extras/undraw/Example.svelte
··· 4 4 import svg from '$docs/assets/undraw_yoga.svg?raw'; 5 5 </script> 6 6 7 - <div class="w-full max-w-md mx-auto"> 7 + <div class="mx-auto w-full max-w-md"> 8 8 <Undraw 9 9 {svg} 10 10 alt="Undraw"
+2 -3
src/routes/(main)/components/extras/undraw/Undraw.md
··· 17 17 </span> 18 18 </Alert> 19 19 20 - 21 20 1. Download a svg illustration from [undraw](https://undraw.co/illustrations) leaving the theme color as it is (#6c63ff). 22 21 2. Import that svg with the `?raw` extension and use it with the undraw component. The theme color will automatically change to your theme color, all other colors will have to be manually changed using the `colorMap` prop (or if not using dark mode, leave as is). 23 22 24 23 ```svelte 25 24 <script lang="ts"> 26 - import { Undraw } from 'fuchs'; 25 + import { Undraw } from 'fuchs'; 27 26 28 27 import svg from './your-illustration.svg?raw'; 29 28 </script> ··· 39 38 '#f2f2f2': 'fill-base-200 dark:fill-base-800' 40 39 }} 41 40 /> 42 - ``` 41 + ```