@neynar/ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/components/ui/accordion.d.ts +229 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +247 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert.d.ts +187 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.d.ts +94 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/avatar.d.ts +244 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +163 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +281 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +129 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/calendar.d.ts +169 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/card.d.ts +365 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/carousel.d.ts +369 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/chart.d.ts +442 -0
- package/dist/components/ui/chart.d.ts.map +1 -0
- package/dist/components/ui/checkbox.d.ts +88 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/collapsible.d.ts +182 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/combobox.d.ts +270 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/command.d.ts +355 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/container.d.ts +102 -0
- package/dist/components/ui/container.d.ts.map +1 -0
- package/dist/components/ui/context-menu.d.ts +339 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/date-picker.d.ts +145 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -0
- package/dist/components/ui/dialog.d.ts +322 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/drawer.d.ts +154 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +349 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/empty-state.d.ts +133 -0
- package/dist/components/ui/empty-state.d.ts.map +1 -0
- package/dist/components/ui/hover-card.d.ts +109 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/input.d.ts +89 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/label.d.ts +93 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/menubar.d.ts +306 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.d.ts +318 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/pagination.d.ts +343 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/popover.d.ts +178 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/progress.d.ts +64 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/radio-group.d.ts +144 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/resizable.d.ts +164 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +82 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/select.d.ts +316 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/separator.d.ts +80 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/sheet.d.ts +346 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sidebar.d.ts +1561 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/skeleton.d.ts +66 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/slider.d.ts +95 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/sonner.d.ts +101 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/stack.d.ts +192 -0
- package/dist/components/ui/stack.d.ts.map +1 -0
- package/dist/components/ui/stories/accordion.stories.d.ts +71 -0
- package/dist/components/ui/stories/accordion.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/alert-dialog.stories.d.ts +39 -0
- package/dist/components/ui/stories/alert-dialog.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/alert.stories.d.ts +48 -0
- package/dist/components/ui/stories/alert.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts +53 -0
- package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/avatar.stories.d.ts +49 -0
- package/dist/components/ui/stories/avatar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/badge.stories.d.ts +64 -0
- package/dist/components/ui/stories/badge.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/breadcrumb.stories.d.ts +27 -0
- package/dist/components/ui/stories/breadcrumb.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/button.stories.d.ts +92 -0
- package/dist/components/ui/stories/button.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/calendar.stories.d.ts +94 -0
- package/dist/components/ui/stories/calendar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/card.stories.d.ts +29 -0
- package/dist/components/ui/stories/card.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/carousel.stories.d.ts +42 -0
- package/dist/components/ui/stories/carousel.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/chart.stories.d.ts +51 -0
- package/dist/components/ui/stories/chart.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/checkbox.stories.d.ts +72 -0
- package/dist/components/ui/stories/checkbox.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/cn.stories.d.ts +19 -0
- package/dist/components/ui/stories/cn.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/collapsible.stories.d.ts +51 -0
- package/dist/components/ui/stories/collapsible.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/colors.stories.d.ts +31 -0
- package/dist/components/ui/stories/colors.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/combobox.stories.d.ts +89 -0
- package/dist/components/ui/stories/combobox.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/command.stories.d.ts +69 -0
- package/dist/components/ui/stories/command.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/container.stories.d.ts +42 -0
- package/dist/components/ui/stories/container.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/context-menu.stories.d.ts +32 -0
- package/dist/components/ui/stories/context-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/date-picker.stories.d.ts +67 -0
- package/dist/components/ui/stories/date-picker.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/dialog.stories.d.ts +48 -0
- package/dist/components/ui/stories/dialog.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/drawer.stories.d.ts +33 -0
- package/dist/components/ui/stories/drawer.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/dropdown-menu.stories.d.ts +31 -0
- package/dist/components/ui/stories/dropdown-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/empty-state.stories.d.ts +74 -0
- package/dist/components/ui/stories/empty-state.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/hover-card.stories.d.ts +35 -0
- package/dist/components/ui/stories/hover-card.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/input.stories.d.ts +69 -0
- package/dist/components/ui/stories/input.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/label.stories.d.ts +47 -0
- package/dist/components/ui/stories/label.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/menubar.stories.d.ts +39 -0
- package/dist/components/ui/stories/menubar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/navigation-menu.stories.d.ts +44 -0
- package/dist/components/ui/stories/navigation-menu.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/pagination.stories.d.ts +33 -0
- package/dist/components/ui/stories/pagination.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/popover.stories.d.ts +36 -0
- package/dist/components/ui/stories/popover.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/progress.stories.d.ts +38 -0
- package/dist/components/ui/stories/progress.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/radio-group.stories.d.ts +76 -0
- package/dist/components/ui/stories/radio-group.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/resizable.stories.d.ts +49 -0
- package/dist/components/ui/stories/resizable.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/scroll-area.stories.d.ts +35 -0
- package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/select.stories.d.ts +51 -0
- package/dist/components/ui/stories/select.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/separator.stories.d.ts +58 -0
- package/dist/components/ui/stories/separator.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sheet.stories.d.ts +43 -0
- package/dist/components/ui/stories/sheet.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sidebar.stories.d.ts +60 -0
- package/dist/components/ui/stories/sidebar.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/skeleton.stories.d.ts +42 -0
- package/dist/components/ui/stories/skeleton.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/slider.stories.d.ts +99 -0
- package/dist/components/ui/stories/slider.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/sonner.stories.d.ts +9 -0
- package/dist/components/ui/stories/sonner.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/stack.stories.d.ts +39 -0
- package/dist/components/ui/stories/stack.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/switch.stories.d.ts +71 -0
- package/dist/components/ui/stories/switch.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/table.stories.d.ts +40 -0
- package/dist/components/ui/stories/table.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/tabs.stories.d.ts +62 -0
- package/dist/components/ui/stories/tabs.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/text-field.stories.d.ts +78 -0
- package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/textarea.stories.d.ts +57 -0
- package/dist/components/ui/stories/textarea.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/theme-toggle.stories.d.ts +71 -0
- package/dist/components/ui/stories/theme-toggle.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/theme.stories.d.ts +51 -0
- package/dist/components/ui/stories/theme.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/toggle-group.stories.d.ts +71 -0
- package/dist/components/ui/stories/toggle-group.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/toggle.stories.d.ts +78 -0
- package/dist/components/ui/stories/toggle.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/tooltip.stories.d.ts +37 -0
- package/dist/components/ui/stories/tooltip.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/typography.stories.d.ts +137 -0
- package/dist/components/ui/stories/typography.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/use-mobile.stories.d.ts +20 -0
- package/dist/components/ui/stories/use-mobile.stories.d.ts.map +1 -0
- package/dist/components/ui/stories/use-theme.stories.d.ts +23 -0
- package/dist/components/ui/stories/use-theme.stories.d.ts.map +1 -0
- package/dist/components/ui/switch.d.ts +84 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/table.d.ts +321 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/tabs.d.ts +260 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/text-field.d.ts +157 -0
- package/dist/components/ui/text-field.d.ts.map +1 -0
- package/dist/components/ui/textarea.d.ts +84 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/theme-toggle.d.ts +105 -0
- package/dist/components/ui/theme-toggle.d.ts.map +1 -0
- package/dist/components/ui/theme.d.ts +110 -0
- package/dist/components/ui/theme.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +133 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle.d.ts +84 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/tooltip.d.ts +202 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/typography.d.ts +287 -0
- package/dist/components/ui/typography.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts +74 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-theme.d.ts +142 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27498 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +43 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/llm/colors.md +273 -0
- package/docs/llm/components/buttons.md +68 -0
- package/docs/llm/components/cards.md +53 -0
- package/docs/llm/components/display.md +134 -0
- package/docs/llm/components/feedback.md +96 -0
- package/docs/llm/components/forms.md +90 -0
- package/docs/llm/components/layout.md +59 -0
- package/docs/llm/components/menus.md +70 -0
- package/docs/llm/components/navigation.md +80 -0
- package/docs/llm/components/overlays.md +83 -0
- package/docs/llm/components/tables.md +73 -0
- package/docs/llm/components/typography.md +199 -0
- package/docs/llm/components/utilities.md +114 -0
- package/docs/llm/guide.md +165 -0
- package/llms.txt +122 -0
- package/package.json +104 -0
- package/src/components/ui/accordion.tsx +285 -0
- package/src/components/ui/alert-dialog.tsx +387 -0
- package/src/components/ui/alert.tsx +243 -0
- package/src/components/ui/aspect-ratio.tsx +99 -0
- package/src/components/ui/avatar.tsx +288 -0
- package/src/components/ui/badge.tsx +205 -0
- package/src/components/ui/breadcrumb.tsx +378 -0
- package/src/components/ui/button.tsx +195 -0
- package/src/components/ui/calendar.tsx +371 -0
- package/src/components/ui/card.tsx +447 -0
- package/src/components/ui/carousel.tsx +624 -0
- package/src/components/ui/chart.tsx +802 -0
- package/src/components/ui/checkbox.tsx +113 -0
- package/src/components/ui/collapsible.tsx +207 -0
- package/src/components/ui/combobox.tsx +373 -0
- package/src/components/ui/command.tsx +518 -0
- package/src/components/ui/container.tsx +114 -0
- package/src/components/ui/context-menu.tsx +563 -0
- package/src/components/ui/date-picker.tsx +213 -0
- package/src/components/ui/dialog.tsx +447 -0
- package/src/components/ui/drawer.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +578 -0
- package/src/components/ui/empty-state.tsx +145 -0
- package/src/components/ui/hover-card.tsx +144 -0
- package/src/components/ui/input.tsx +106 -0
- package/src/components/ui/label.tsx +110 -0
- package/src/components/ui/menubar.tsx +553 -0
- package/src/components/ui/navigation-menu.tsx +471 -0
- package/src/components/ui/pagination.tsx +456 -0
- package/src/components/ui/popover.tsx +216 -0
- package/src/components/ui/progress.tsx +88 -0
- package/src/components/ui/radio-group.tsx +183 -0
- package/src/components/ui/resizable.tsx +209 -0
- package/src/components/ui/scroll-area.tsx +132 -0
- package/src/components/ui/select.tsx +485 -0
- package/src/components/ui/separator.tsx +101 -0
- package/src/components/ui/sheet.tsx +495 -0
- package/src/components/ui/sidebar.tsx +2211 -0
- package/src/components/ui/skeleton.tsx +76 -0
- package/src/components/ui/slider.tsx +147 -0
- package/src/components/ui/sonner.tsx +120 -0
- package/src/components/ui/stack.tsx +180 -0
- package/src/components/ui/stories/accordion.stories.tsx +429 -0
- package/src/components/ui/stories/alert-dialog.stories.tsx +519 -0
- package/src/components/ui/stories/alert.stories.tsx +228 -0
- package/src/components/ui/stories/aspect-ratio.stories.tsx +200 -0
- package/src/components/ui/stories/avatar.stories.tsx +317 -0
- package/src/components/ui/stories/badge.stories.tsx +260 -0
- package/src/components/ui/stories/breadcrumb.stories.tsx +482 -0
- package/src/components/ui/stories/button.stories.tsx +266 -0
- package/src/components/ui/stories/calendar.stories.tsx +375 -0
- package/src/components/ui/stories/card.stories.tsx +308 -0
- package/src/components/ui/stories/carousel.stories.tsx +328 -0
- package/src/components/ui/stories/chart.stories.tsx +430 -0
- package/src/components/ui/stories/checkbox.stories.tsx +297 -0
- package/src/components/ui/stories/cn.stories.tsx +433 -0
- package/src/components/ui/stories/collapsible.stories.tsx +256 -0
- package/src/components/ui/stories/colors.stories.tsx +502 -0
- package/src/components/ui/stories/combobox.stories.tsx +301 -0
- package/src/components/ui/stories/command.stories.tsx +632 -0
- package/src/components/ui/stories/container.stories.tsx +250 -0
- package/src/components/ui/stories/context-menu.stories.tsx +446 -0
- package/src/components/ui/stories/date-picker.stories.tsx +378 -0
- package/src/components/ui/stories/dialog.stories.tsx +535 -0
- package/src/components/ui/stories/drawer.stories.tsx +364 -0
- package/src/components/ui/stories/dropdown-menu.stories.tsx +374 -0
- package/src/components/ui/stories/empty-state.stories.tsx +244 -0
- package/src/components/ui/stories/hover-card.stories.tsx +355 -0
- package/src/components/ui/stories/input.stories.tsx +289 -0
- package/src/components/ui/stories/label.stories.tsx +294 -0
- package/src/components/ui/stories/menubar.stories.tsx +764 -0
- package/src/components/ui/stories/navigation-menu.stories.tsx +539 -0
- package/src/components/ui/stories/pagination.stories.tsx +604 -0
- package/src/components/ui/stories/popover.stories.tsx +392 -0
- package/src/components/ui/stories/progress.stories.tsx +218 -0
- package/src/components/ui/stories/radio-group.stories.tsx +400 -0
- package/src/components/ui/stories/resizable.stories.tsx +417 -0
- package/src/components/ui/stories/scroll-area.stories.tsx +180 -0
- package/src/components/ui/stories/select.stories.tsx +389 -0
- package/src/components/ui/stories/separator.stories.tsx +192 -0
- package/src/components/ui/stories/sheet.stories.tsx +468 -0
- package/src/components/ui/stories/sidebar.stories.tsx +731 -0
- package/src/components/ui/stories/skeleton.stories.tsx +216 -0
- package/src/components/ui/stories/slider.stories.tsx +321 -0
- package/src/components/ui/stories/sonner.stories.tsx +373 -0
- package/src/components/ui/stories/stack.stories.tsx +222 -0
- package/src/components/ui/stories/switch.stories.tsx +202 -0
- package/src/components/ui/stories/table.stories.tsx +541 -0
- package/src/components/ui/stories/tabs.stories.tsx +544 -0
- package/src/components/ui/stories/text-field.stories.tsx +280 -0
- package/src/components/ui/stories/textarea.stories.tsx +245 -0
- package/src/components/ui/stories/theme-toggle.stories.tsx +275 -0
- package/src/components/ui/stories/theme.stories.tsx +412 -0
- package/src/components/ui/stories/toggle-group.stories.tsx +337 -0
- package/src/components/ui/stories/toggle.stories.tsx +325 -0
- package/src/components/ui/stories/tooltip.stories.tsx +444 -0
- package/src/components/ui/stories/typography.stories.tsx +1586 -0
- package/src/components/ui/stories/use-mobile.stories.tsx +420 -0
- package/src/components/ui/stories/use-theme.stories.tsx +531 -0
- package/src/components/ui/switch.tsx +106 -0
- package/src/components/ui/table.tsx +424 -0
- package/src/components/ui/tabs.tsx +316 -0
- package/src/components/ui/text-field.tsx +206 -0
- package/src/components/ui/textarea.tsx +98 -0
- package/src/components/ui/theme-toggle.tsx +185 -0
- package/src/components/ui/theme.tsx +148 -0
- package/src/components/ui/toggle-group.tsx +196 -0
- package/src/components/ui/toggle.tsx +115 -0
- package/src/components/ui/tooltip.tsx +253 -0
- package/src/components/ui/typography.tsx +468 -0
- package/src/hooks/use-mobile.ts +91 -0
- package/src/hooks/use-theme.ts +319 -0
- package/src/index.ts +77 -0
- package/src/lib/utils.ts +57 -0
- package/src/styles/globals.css +160 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { ThemeToggle } from "../theme-toggle";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ThemeToggle component stories for design system documentation
|
|
6
|
+
*
|
|
7
|
+
* This story file demonstrates the ThemeToggle component's capabilities through three focused stories:
|
|
8
|
+
* - Interactive: Playground for testing all props and custom theme configurations
|
|
9
|
+
* - Variants: Systematic showcase of all available styles, sizes, and theme combinations
|
|
10
|
+
* - InContext: Real-world usage examples for business and design teams
|
|
11
|
+
*/
|
|
12
|
+
const meta = {
|
|
13
|
+
title: "Theme/ThemeToggle",
|
|
14
|
+
component: ThemeToggle,
|
|
15
|
+
parameters: {
|
|
16
|
+
layout: "centered",
|
|
17
|
+
docs: {
|
|
18
|
+
description: {
|
|
19
|
+
component:
|
|
20
|
+
"An advanced theme toggle component that supports custom themes, visual styling, and color-coded indicators. Built on top of the framework-agnostic useTheme hook for maximum compatibility across different React environments.",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
argTypes: {
|
|
26
|
+
variant: {
|
|
27
|
+
control: { type: "select" },
|
|
28
|
+
options: [
|
|
29
|
+
"default",
|
|
30
|
+
"destructive",
|
|
31
|
+
"outline",
|
|
32
|
+
"secondary",
|
|
33
|
+
"ghost",
|
|
34
|
+
"link",
|
|
35
|
+
],
|
|
36
|
+
description: "Visual style variant for the toggle button",
|
|
37
|
+
},
|
|
38
|
+
size: {
|
|
39
|
+
control: { type: "select" },
|
|
40
|
+
options: ["default", "sm", "lg", "icon"],
|
|
41
|
+
description:
|
|
42
|
+
"Size of the toggle button - icon shows only icon, others include text",
|
|
43
|
+
},
|
|
44
|
+
className: {
|
|
45
|
+
control: "text",
|
|
46
|
+
description: "Additional CSS classes to apply to the button",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
args: {
|
|
50
|
+
variant: "outline",
|
|
51
|
+
size: "icon",
|
|
52
|
+
},
|
|
53
|
+
} satisfies Meta<typeof ThemeToggle>;
|
|
54
|
+
|
|
55
|
+
export default meta;
|
|
56
|
+
type Story = StoryObj<typeof meta>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Interactive Playground Story
|
|
60
|
+
*
|
|
61
|
+
* Use this story to test all ThemeToggle props and configurations through Storybook controls.
|
|
62
|
+
* Perfect for designers and developers to experiment with custom themes and styling options.
|
|
63
|
+
*/
|
|
64
|
+
export const Interactive: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
variant: "outline",
|
|
67
|
+
size: "icon",
|
|
68
|
+
showLabel: false,
|
|
69
|
+
align: "end",
|
|
70
|
+
},
|
|
71
|
+
parameters: {
|
|
72
|
+
docs: {
|
|
73
|
+
description: {
|
|
74
|
+
story:
|
|
75
|
+
"Interactive playground for testing all ThemeToggle properties. Use the controls panel to experiment with custom themes, colors, variants, and visual options. The component will persist theme changes using cookies.",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Variants Showcase Story
|
|
83
|
+
*
|
|
84
|
+
* Systematic display of all available ThemeToggle variants, sizes, and custom theme configurations.
|
|
85
|
+
* Helps design teams understand the full range of available options and styling capabilities.
|
|
86
|
+
*/
|
|
87
|
+
export const Variants: Story = {
|
|
88
|
+
render: () => (
|
|
89
|
+
<div className="space-y-8">
|
|
90
|
+
{/* Size Variants */}
|
|
91
|
+
<div className="space-y-4">
|
|
92
|
+
<h3 className="text-lg font-semibold">Size Variants</h3>
|
|
93
|
+
<div className="flex items-center gap-4">
|
|
94
|
+
<div className="space-y-2">
|
|
95
|
+
<div className="text-sm text-muted-foreground">Icon</div>
|
|
96
|
+
<ThemeToggle size="icon" />
|
|
97
|
+
</div>
|
|
98
|
+
<div className="space-y-2">
|
|
99
|
+
<div className="text-sm text-muted-foreground">Small</div>
|
|
100
|
+
<ThemeToggle size="sm" />
|
|
101
|
+
</div>
|
|
102
|
+
<div className="space-y-2">
|
|
103
|
+
<div className="text-sm text-muted-foreground">Default</div>
|
|
104
|
+
<ThemeToggle size="default" />
|
|
105
|
+
</div>
|
|
106
|
+
<div className="space-y-2">
|
|
107
|
+
<div className="text-sm text-muted-foreground">Large</div>
|
|
108
|
+
<ThemeToggle size="lg" />
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
{/* Visual Variants */}
|
|
114
|
+
<div className="space-y-4">
|
|
115
|
+
<h3 className="text-lg font-semibold">Visual Variants</h3>
|
|
116
|
+
<div className="flex flex-wrap gap-3">
|
|
117
|
+
<ThemeToggle variant="default" size="sm" />
|
|
118
|
+
<ThemeToggle variant="outline" size="sm" />
|
|
119
|
+
<ThemeToggle variant="secondary" size="sm" />
|
|
120
|
+
<ThemeToggle variant="ghost" size="sm" />
|
|
121
|
+
<ThemeToggle variant="link" size="sm" />
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* Custom Themes */}
|
|
126
|
+
<div className="space-y-4">
|
|
127
|
+
<h3 className="text-lg font-semibold">Custom Themes</h3>
|
|
128
|
+
<div className="space-y-3">
|
|
129
|
+
<div className="space-y-2">
|
|
130
|
+
<div className="text-sm text-muted-foreground">
|
|
131
|
+
Basic Custom Themes
|
|
132
|
+
</div>
|
|
133
|
+
<ThemeToggle size="default" />
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div className="space-y-2">
|
|
137
|
+
<div className="text-sm text-muted-foreground">
|
|
138
|
+
With Color Indicators
|
|
139
|
+
</div>
|
|
140
|
+
<ThemeToggle size="default" />
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div className="space-y-2">
|
|
144
|
+
<div className="text-sm text-muted-foreground">
|
|
145
|
+
System-Respecting Theme
|
|
146
|
+
</div>
|
|
147
|
+
<ThemeToggle size="default" />
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
{/* Advanced Styling */}
|
|
153
|
+
<div className="space-y-4">
|
|
154
|
+
<h3 className="text-lg font-semibold">Advanced Styling</h3>
|
|
155
|
+
<div className="flex flex-wrap gap-3">
|
|
156
|
+
<ThemeToggle variant="outline" size="default" className="border-2" />
|
|
157
|
+
|
|
158
|
+
<ThemeToggle variant="secondary" size="lg" className="border-2" />
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
),
|
|
163
|
+
parameters: {
|
|
164
|
+
layout: "padded",
|
|
165
|
+
docs: {
|
|
166
|
+
description: {
|
|
167
|
+
story:
|
|
168
|
+
"Complete showcase of all ThemeToggle variants, sizes, custom theme configurations, and styling options. Use this as a reference for what's available in the design system and how custom themes work.",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Real-world Context Story
|
|
176
|
+
*
|
|
177
|
+
* Demonstrates the ThemeToggle component in realistic UI scenarios.
|
|
178
|
+
* Helps business teams and designers understand practical usage patterns and integration approaches.
|
|
179
|
+
*/
|
|
180
|
+
export const InContext: Story = {
|
|
181
|
+
render: () => (
|
|
182
|
+
<div className="space-y-8 max-w-2xl">
|
|
183
|
+
{/* Application Header */}
|
|
184
|
+
<div className="space-y-4">
|
|
185
|
+
<h3 className="text-lg font-semibold">Application Header</h3>
|
|
186
|
+
<div className="flex items-center justify-between p-4 border rounded-lg bg-card">
|
|
187
|
+
<div className="flex items-center gap-3">
|
|
188
|
+
<div className="h-8 w-8 rounded-full bg-primary" />
|
|
189
|
+
<h2 className="font-semibold">My Application</h2>
|
|
190
|
+
</div>
|
|
191
|
+
<div className="flex items-center gap-2">
|
|
192
|
+
<button className="px-3 py-1.5 text-sm rounded-md hover:bg-muted">
|
|
193
|
+
Profile
|
|
194
|
+
</button>
|
|
195
|
+
<ThemeToggle variant="ghost" size="icon" />
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
{/* Settings Panel */}
|
|
201
|
+
<div className="space-y-4">
|
|
202
|
+
<h3 className="text-lg font-semibold">Settings Panel</h3>
|
|
203
|
+
<div className="p-6 border rounded-lg bg-card space-y-4">
|
|
204
|
+
<h4 className="font-medium">Appearance</h4>
|
|
205
|
+
<div className="space-y-3">
|
|
206
|
+
<div className="flex items-center justify-between">
|
|
207
|
+
<div>
|
|
208
|
+
<div className="font-medium">Theme</div>
|
|
209
|
+
<div className="text-sm text-muted-foreground">
|
|
210
|
+
Choose your preferred color scheme
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
<ThemeToggle size="default" variant="outline" />
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
{/* Design System Demo */}
|
|
220
|
+
<div className="space-y-4">
|
|
221
|
+
<h3 className="text-lg font-semibold">Design System Customization</h3>
|
|
222
|
+
<div className="p-6 border rounded-lg bg-card space-y-4">
|
|
223
|
+
<h4 className="font-medium">Brand Themes</h4>
|
|
224
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
225
|
+
<div className="space-y-2">
|
|
226
|
+
<div className="text-sm font-medium">Marketing Site</div>
|
|
227
|
+
<ThemeToggle size="sm" variant="secondary" />
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div className="space-y-2">
|
|
231
|
+
<div className="text-sm font-medium">Creative Tools</div>
|
|
232
|
+
<ThemeToggle size="sm" variant="outline" />
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
{/* Mobile Layout */}
|
|
239
|
+
<div className="space-y-4">
|
|
240
|
+
<h3 className="text-lg font-semibold">Mobile Navigation</h3>
|
|
241
|
+
<div className="max-w-sm mx-auto border rounded-lg bg-card">
|
|
242
|
+
<div className="p-4 border-b">
|
|
243
|
+
<div className="flex items-center justify-between">
|
|
244
|
+
<h4 className="font-medium">Settings</h4>
|
|
245
|
+
<ThemeToggle size="icon" variant="ghost" />
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
<div className="p-4 space-y-3">
|
|
249
|
+
<div className="flex items-center justify-between py-2">
|
|
250
|
+
<span>Notifications</span>
|
|
251
|
+
<div className="w-10 h-6 bg-primary rounded-full" />
|
|
252
|
+
</div>
|
|
253
|
+
<div className="flex items-center justify-between py-2">
|
|
254
|
+
<span>Theme</span>
|
|
255
|
+
<ThemeToggle size="sm" variant="outline" />
|
|
256
|
+
</div>
|
|
257
|
+
<div className="flex items-center justify-between py-2">
|
|
258
|
+
<span>Language</span>
|
|
259
|
+
<span className="text-sm text-muted-foreground">English</span>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
),
|
|
266
|
+
parameters: {
|
|
267
|
+
layout: "padded",
|
|
268
|
+
docs: {
|
|
269
|
+
description: {
|
|
270
|
+
story:
|
|
271
|
+
"Real-world usage examples showing how ThemeToggle integrates into common UI patterns like application headers, settings panels, and mobile layouts. These patterns demonstrate practical implementation approaches for different use cases.",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
};
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Theme } from "../theme";
|
|
3
|
+
import { ThemeToggle } from "../theme-toggle";
|
|
4
|
+
import { Card, CardHeader, CardTitle, CardContent } from "../card";
|
|
5
|
+
import { Button } from "../button";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Theme stories demonstrate FOUC prevention and theming system setup
|
|
9
|
+
*
|
|
10
|
+
* The Theme component prevents flash of unstyled content (FOUC) by applying
|
|
11
|
+
* the user's preferred theme before the page renders. It should be placed once
|
|
12
|
+
* at the root of your application for optimal theming experience.
|
|
13
|
+
*
|
|
14
|
+
* These stories showcase:
|
|
15
|
+
* - Basic Theme component setup
|
|
16
|
+
* - Integration with ThemeToggle for user controls
|
|
17
|
+
* - Multiple synchronized theme toggles
|
|
18
|
+
* - Framework-agnostic theming patterns
|
|
19
|
+
*/
|
|
20
|
+
const meta = {
|
|
21
|
+
title: "Theme/Theme",
|
|
22
|
+
component: Theme,
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: "fullscreen",
|
|
25
|
+
docs: {
|
|
26
|
+
description: {
|
|
27
|
+
component: `
|
|
28
|
+
The Theme component prevents flash of unstyled content (FOUC) by injecting a small script that applies the correct theme before the page renders.
|
|
29
|
+
|
|
30
|
+
**Key Features:**
|
|
31
|
+
- ⚡ Prevents FOUC (flash of unstyled content)
|
|
32
|
+
- 🌐 Framework agnostic (Next.js, Vite, Remix, etc.)
|
|
33
|
+
- 🔄 Perfect synchronization across multiple theme toggles
|
|
34
|
+
- 🍪 Persistent theme storage via cookies
|
|
35
|
+
- 🎨 System theme detection and following
|
|
36
|
+
- ⚙️ Zero configuration required
|
|
37
|
+
|
|
38
|
+
**Usage:**
|
|
39
|
+
Place the Theme component once at the root of your application, ideally in the document head or at the very top of your app component.
|
|
40
|
+
`,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
tags: ["autodocs"],
|
|
45
|
+
} satisfies Meta<typeof Theme>;
|
|
46
|
+
|
|
47
|
+
export default meta;
|
|
48
|
+
type Story = StoryObj<typeof meta>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Basic usage showing the Theme component with a simple themed interface.
|
|
52
|
+
* The Theme component should be placed at the top of your application to prevent FOUC.
|
|
53
|
+
*/
|
|
54
|
+
export const Basic: Story = {
|
|
55
|
+
render: () => (
|
|
56
|
+
<div className="min-h-screen bg-background text-foreground p-8">
|
|
57
|
+
<Theme />
|
|
58
|
+
|
|
59
|
+
<div className="max-w-2xl mx-auto space-y-6">
|
|
60
|
+
<div className="text-center space-y-2">
|
|
61
|
+
<h1 className="text-3xl font-bold">Theme Setup Demo</h1>
|
|
62
|
+
<p className="text-muted-foreground">
|
|
63
|
+
The Theme component prevents FOUC and enables theming system
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<Card>
|
|
68
|
+
<CardHeader>
|
|
69
|
+
<CardTitle>Themed Content</CardTitle>
|
|
70
|
+
</CardHeader>
|
|
71
|
+
<CardContent className="space-y-4">
|
|
72
|
+
<p className="text-sm text-muted-foreground">
|
|
73
|
+
This content is themed correctly without any flash of unstyled
|
|
74
|
+
content. The Theme component loads the user's preferred theme
|
|
75
|
+
before first paint.
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
<div className="flex items-center justify-center">
|
|
79
|
+
<ThemeToggle />
|
|
80
|
+
</div>
|
|
81
|
+
</CardContent>
|
|
82
|
+
</Card>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Demonstrates multiple synchronized theme toggles working together.
|
|
90
|
+
* All toggles stay perfectly in sync through the custom event system.
|
|
91
|
+
*/
|
|
92
|
+
export const MultipleSynchronizedToggles: Story = {
|
|
93
|
+
render: () => (
|
|
94
|
+
<div className="min-h-screen bg-background text-foreground">
|
|
95
|
+
<Theme />
|
|
96
|
+
|
|
97
|
+
{/* Header with theme toggle */}
|
|
98
|
+
<header className="border-b p-4">
|
|
99
|
+
<div className="max-w-4xl mx-auto flex items-center justify-between">
|
|
100
|
+
<h1 className="text-xl font-semibold">My App</h1>
|
|
101
|
+
<ThemeToggle />
|
|
102
|
+
</div>
|
|
103
|
+
</header>
|
|
104
|
+
|
|
105
|
+
{/* Main content */}
|
|
106
|
+
<main className="p-8">
|
|
107
|
+
<div className="max-w-4xl mx-auto grid gap-6 md:grid-cols-2">
|
|
108
|
+
<Card>
|
|
109
|
+
<CardHeader>
|
|
110
|
+
<div className="flex items-center justify-between">
|
|
111
|
+
<CardTitle>Settings Panel</CardTitle>
|
|
112
|
+
<ThemeToggle variant="ghost" size="sm" />
|
|
113
|
+
</div>
|
|
114
|
+
</CardHeader>
|
|
115
|
+
<CardContent className="space-y-4">
|
|
116
|
+
<p className="text-sm text-muted-foreground">
|
|
117
|
+
This toggle is synchronized with all other theme toggles on the
|
|
118
|
+
page. Try switching themes and watch how they all update
|
|
119
|
+
together.
|
|
120
|
+
</p>
|
|
121
|
+
<Button variant="outline">Configure Settings</Button>
|
|
122
|
+
</CardContent>
|
|
123
|
+
</Card>
|
|
124
|
+
|
|
125
|
+
<Card>
|
|
126
|
+
<CardHeader>
|
|
127
|
+
<div className="flex items-center justify-between">
|
|
128
|
+
<CardTitle>User Profile</CardTitle>
|
|
129
|
+
<ThemeToggle variant="secondary" showLabel />
|
|
130
|
+
</div>
|
|
131
|
+
</CardHeader>
|
|
132
|
+
<CardContent className="space-y-4">
|
|
133
|
+
<p className="text-sm text-muted-foreground">
|
|
134
|
+
All theme toggles use the same underlying state via cookies and
|
|
135
|
+
custom events. This ensures perfect synchronization without any
|
|
136
|
+
providers or context.
|
|
137
|
+
</p>
|
|
138
|
+
<Button>Update Profile</Button>
|
|
139
|
+
</CardContent>
|
|
140
|
+
</Card>
|
|
141
|
+
</div>
|
|
142
|
+
</main>
|
|
143
|
+
|
|
144
|
+
{/* Footer with another toggle */}
|
|
145
|
+
<footer className="border-t mt-8 p-4">
|
|
146
|
+
<div className="max-w-4xl mx-auto flex items-center justify-between">
|
|
147
|
+
<p className="text-sm text-muted-foreground">
|
|
148
|
+
Footer content with synchronized theme
|
|
149
|
+
</p>
|
|
150
|
+
<ThemeToggle variant="outline" size="sm" />
|
|
151
|
+
</div>
|
|
152
|
+
</footer>
|
|
153
|
+
</div>
|
|
154
|
+
),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Framework integration examples showing how to use Theme with different React frameworks.
|
|
159
|
+
* This story demonstrates the setup patterns for Next.js, Vite, and other frameworks.
|
|
160
|
+
*/
|
|
161
|
+
export const FrameworkIntegration: Story = {
|
|
162
|
+
render: () => (
|
|
163
|
+
<div className="min-h-screen bg-background text-foreground p-8">
|
|
164
|
+
<Theme />
|
|
165
|
+
|
|
166
|
+
<div className="max-w-4xl mx-auto space-y-8">
|
|
167
|
+
<div className="text-center space-y-2">
|
|
168
|
+
<h1 className="text-3xl font-bold">Framework Integration</h1>
|
|
169
|
+
<p className="text-muted-foreground">
|
|
170
|
+
Theme component works with any React framework
|
|
171
|
+
</p>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
175
|
+
<Card>
|
|
176
|
+
<CardHeader>
|
|
177
|
+
<CardTitle>Next.js App Router</CardTitle>
|
|
178
|
+
</CardHeader>
|
|
179
|
+
<CardContent>
|
|
180
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
|
|
181
|
+
{`// app/layout.tsx
|
|
182
|
+
import { Theme } from "@neynar/ui";
|
|
183
|
+
|
|
184
|
+
export default function RootLayout({ children }) {
|
|
185
|
+
return (
|
|
186
|
+
<html suppressHydrationWarning>
|
|
187
|
+
<head>
|
|
188
|
+
<Theme /> {/* Prevents FOUC */}
|
|
189
|
+
</head>
|
|
190
|
+
<body>{children}</body>
|
|
191
|
+
</html>
|
|
192
|
+
);
|
|
193
|
+
}`}
|
|
194
|
+
</pre>
|
|
195
|
+
</CardContent>
|
|
196
|
+
</Card>
|
|
197
|
+
|
|
198
|
+
<Card>
|
|
199
|
+
<CardHeader>
|
|
200
|
+
<CardTitle>Vite + React</CardTitle>
|
|
201
|
+
</CardHeader>
|
|
202
|
+
<CardContent>
|
|
203
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
|
|
204
|
+
{`// App.tsx
|
|
205
|
+
import { Theme } from "@neynar/ui";
|
|
206
|
+
|
|
207
|
+
function App() {
|
|
208
|
+
return (
|
|
209
|
+
<>
|
|
210
|
+
<Theme /> {/* Place at the top */}
|
|
211
|
+
<div className="app">
|
|
212
|
+
{/* Your content */}
|
|
213
|
+
</div>
|
|
214
|
+
</>
|
|
215
|
+
);
|
|
216
|
+
}`}
|
|
217
|
+
</pre>
|
|
218
|
+
</CardContent>
|
|
219
|
+
</Card>
|
|
220
|
+
|
|
221
|
+
<Card>
|
|
222
|
+
<CardHeader>
|
|
223
|
+
<CardTitle>Next.js Pages Router</CardTitle>
|
|
224
|
+
</CardHeader>
|
|
225
|
+
<CardContent>
|
|
226
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
|
|
227
|
+
{`// pages/_document.tsx
|
|
228
|
+
import { Theme } from "@neynar/ui";
|
|
229
|
+
|
|
230
|
+
export default function Document() {
|
|
231
|
+
return (
|
|
232
|
+
<Html>
|
|
233
|
+
<Head>
|
|
234
|
+
<Theme /> {/* In document head */}
|
|
235
|
+
</Head>
|
|
236
|
+
<body>
|
|
237
|
+
<Main />
|
|
238
|
+
<NextScript />
|
|
239
|
+
</body>
|
|
240
|
+
</Html>
|
|
241
|
+
);
|
|
242
|
+
}`}
|
|
243
|
+
</pre>
|
|
244
|
+
</CardContent>
|
|
245
|
+
</Card>
|
|
246
|
+
|
|
247
|
+
<Card>
|
|
248
|
+
<CardHeader>
|
|
249
|
+
<CardTitle>Remix</CardTitle>
|
|
250
|
+
</CardHeader>
|
|
251
|
+
<CardContent>
|
|
252
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
|
|
253
|
+
{`// app/root.tsx
|
|
254
|
+
import { Theme } from "@neynar/ui";
|
|
255
|
+
|
|
256
|
+
export default function Root() {
|
|
257
|
+
return (
|
|
258
|
+
<html>
|
|
259
|
+
<head>
|
|
260
|
+
<Theme /> {/* Before other head content */}
|
|
261
|
+
<Meta />
|
|
262
|
+
<Links />
|
|
263
|
+
</head>
|
|
264
|
+
<body>
|
|
265
|
+
<Outlet />
|
|
266
|
+
<ScrollRestoration />
|
|
267
|
+
<Scripts />
|
|
268
|
+
</body>
|
|
269
|
+
</html>
|
|
270
|
+
);
|
|
271
|
+
}`}
|
|
272
|
+
</pre>
|
|
273
|
+
</CardContent>
|
|
274
|
+
</Card>
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
<Card>
|
|
278
|
+
<CardHeader>
|
|
279
|
+
<CardTitle>Live Demo</CardTitle>
|
|
280
|
+
</CardHeader>
|
|
281
|
+
<CardContent className="space-y-4">
|
|
282
|
+
<p className="text-sm text-muted-foreground">
|
|
283
|
+
The Theme component is already active on this page, preventing
|
|
284
|
+
FOUC and enabling the theme system to work correctly. Use the
|
|
285
|
+
toggle below to test theme switching.
|
|
286
|
+
</p>
|
|
287
|
+
|
|
288
|
+
<div className="flex items-center justify-center">
|
|
289
|
+
<ThemeToggle showLabel />
|
|
290
|
+
</div>
|
|
291
|
+
</CardContent>
|
|
292
|
+
</Card>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
),
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Technical implementation details showing how the Theme component works internally.
|
|
300
|
+
* This story provides insight into the script content and architecture.
|
|
301
|
+
*/
|
|
302
|
+
export const TechnicalDetails: Story = {
|
|
303
|
+
render: () => (
|
|
304
|
+
<div className="min-h-screen bg-background text-foreground p-8">
|
|
305
|
+
<Theme />
|
|
306
|
+
|
|
307
|
+
<div className="max-w-4xl mx-auto space-y-6">
|
|
308
|
+
<div className="text-center space-y-2">
|
|
309
|
+
<h1 className="text-3xl font-bold">How Theme Works</h1>
|
|
310
|
+
<p className="text-muted-foreground">
|
|
311
|
+
Under the hood technical details
|
|
312
|
+
</p>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<div className="grid gap-6">
|
|
316
|
+
<Card>
|
|
317
|
+
<CardHeader>
|
|
318
|
+
<CardTitle>Script Content</CardTitle>
|
|
319
|
+
</CardHeader>
|
|
320
|
+
<CardContent>
|
|
321
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
322
|
+
The Theme component injects a small inline script that executes
|
|
323
|
+
before React hydration:
|
|
324
|
+
</p>
|
|
325
|
+
<pre className="text-xs bg-muted p-3 rounded overflow-x-auto max-h-60">
|
|
326
|
+
{`// Injected script content (minified in production)
|
|
327
|
+
(function() {
|
|
328
|
+
try {
|
|
329
|
+
// Read theme preference from cookie
|
|
330
|
+
var cookie = document.cookie.match(/theme=([^;]*)/);
|
|
331
|
+
var stored = cookie ? JSON.parse(decodeURIComponent(cookie[1])) : null;
|
|
332
|
+
var preference = stored ? stored.preference : 'system';
|
|
333
|
+
var mode;
|
|
334
|
+
|
|
335
|
+
// Determine active theme mode
|
|
336
|
+
if (preference === 'system') {
|
|
337
|
+
mode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
338
|
+
} else {
|
|
339
|
+
mode = preference;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Apply theme to document root
|
|
343
|
+
if (mode === 'dark') {
|
|
344
|
+
document.documentElement.classList.add('dark');
|
|
345
|
+
} else {
|
|
346
|
+
document.documentElement.classList.remove('dark');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Set color-scheme for native elements
|
|
350
|
+
document.documentElement.style.colorScheme = mode;
|
|
351
|
+
} catch (e) {
|
|
352
|
+
// Graceful fallback - default to light theme
|
|
353
|
+
document.documentElement.classList.remove('dark');
|
|
354
|
+
document.documentElement.style.colorScheme = 'light';
|
|
355
|
+
}
|
|
356
|
+
})();`}
|
|
357
|
+
</pre>
|
|
358
|
+
</CardContent>
|
|
359
|
+
</Card>
|
|
360
|
+
|
|
361
|
+
<Card>
|
|
362
|
+
<CardHeader>
|
|
363
|
+
<CardTitle>Synchronization Architecture</CardTitle>
|
|
364
|
+
</CardHeader>
|
|
365
|
+
<CardContent className="space-y-4">
|
|
366
|
+
<p className="text-sm text-muted-foreground">
|
|
367
|
+
Multiple theme toggles stay perfectly synchronized through
|
|
368
|
+
custom events:
|
|
369
|
+
</p>
|
|
370
|
+
|
|
371
|
+
<div className="space-y-3">
|
|
372
|
+
<div className="flex items-center gap-3">
|
|
373
|
+
<div className="w-2 h-2 bg-blue-500 rounded-full" />
|
|
374
|
+
<span className="text-sm">
|
|
375
|
+
Cookie stores theme preference (single source of truth)
|
|
376
|
+
</span>
|
|
377
|
+
</div>
|
|
378
|
+
<div className="flex items-center gap-3">
|
|
379
|
+
<div className="w-2 h-2 bg-green-500 rounded-full" />
|
|
380
|
+
<span className="text-sm">
|
|
381
|
+
Custom 'theme-change' events broadcast changes
|
|
382
|
+
</span>
|
|
383
|
+
</div>
|
|
384
|
+
<div className="flex items-center gap-3">
|
|
385
|
+
<div className="w-2 h-2 bg-purple-500 rounded-full" />
|
|
386
|
+
<span className="text-sm">
|
|
387
|
+
All useTheme hooks listen and update in sync
|
|
388
|
+
</span>
|
|
389
|
+
</div>
|
|
390
|
+
<div className="flex items-center gap-3">
|
|
391
|
+
<div className="w-2 h-2 bg-orange-500 rounded-full" />
|
|
392
|
+
<span className="text-sm">
|
|
393
|
+
DOM updates happen immediately (no React re-render delay)
|
|
394
|
+
</span>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div className="flex items-center justify-center pt-4">
|
|
399
|
+
<div className="flex gap-2">
|
|
400
|
+
<ThemeToggle variant="default" size="sm" />
|
|
401
|
+
<ThemeToggle variant="outline" size="sm" />
|
|
402
|
+
<ThemeToggle variant="ghost" size="sm" />
|
|
403
|
+
<ThemeToggle variant="secondary" size="sm" />
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
</CardContent>
|
|
407
|
+
</Card>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
),
|
|
412
|
+
};
|