@mkbabb/glass-ui 0.2.0

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.
Files changed (335) hide show
  1. package/README.md +172 -0
  2. package/dist/glass-ui.css +1 -0
  3. package/dist/glass-ui.js +10019 -0
  4. package/dist/index.d.ts +6619 -0
  5. package/package.json +65 -0
  6. package/src/components/custom/aurora/Aurora.vue +34 -0
  7. package/src/components/custom/aurora/composables/color.ts +122 -0
  8. package/src/components/custom/aurora/composables/useAurora.ts +355 -0
  9. package/src/components/custom/aurora/index.ts +8 -0
  10. package/src/components/custom/confirm-dialog/ConfirmDialog.vue +88 -0
  11. package/src/components/custom/confirm-dialog/index.ts +1 -0
  12. package/src/components/custom/controls/DarkModeToggle.vue +96 -0
  13. package/src/components/custom/controls/index.ts +1 -0
  14. package/src/components/custom/dock/DockLayerGroup.vue +21 -0
  15. package/src/components/custom/dock/DockPopover.vue +263 -0
  16. package/src/components/custom/dock/GlassDock.vue +276 -0
  17. package/src/components/custom/dock/composables/index.ts +16 -0
  18. package/src/components/custom/dock/composables/isTeleportedTarget.ts +19 -0
  19. package/src/components/custom/dock/composables/useDockActionBar.ts +33 -0
  20. package/src/components/custom/dock/composables/useDockState.ts +301 -0
  21. package/src/components/custom/dock/composables/useDockTransition.ts +146 -0
  22. package/src/components/custom/dock/composables/useLayerTransition.ts +135 -0
  23. package/src/components/custom/dock/composables/usePopupMutex.ts +83 -0
  24. package/src/components/custom/dock/index.ts +9 -0
  25. package/src/components/custom/expandable-container/ExpandableContainer.vue +64 -0
  26. package/src/components/custom/expandable-container/index.ts +1 -0
  27. package/src/components/custom/glass-panel/GlassPanel.vue +98 -0
  28. package/src/components/custom/glass-panel/index.ts +2 -0
  29. package/src/components/custom/icon-tooltip/IconTooltip.vue +20 -0
  30. package/src/components/custom/icon-tooltip/index.ts +1 -0
  31. package/src/components/custom/index.ts +15 -0
  32. package/src/components/custom/infinite-scroll/InfiniteScroll.vue +55 -0
  33. package/src/components/custom/infinite-scroll/composables/index.ts +2 -0
  34. package/src/components/custom/infinite-scroll/composables/types.ts +23 -0
  35. package/src/components/custom/infinite-scroll/composables/useInfiniteScroll.ts +73 -0
  36. package/src/components/custom/infinite-scroll/index.ts +1 -0
  37. package/src/components/custom/labeled-field/LabeledInput.vue +29 -0
  38. package/src/components/custom/labeled-field/LabeledSelect.vue +59 -0
  39. package/src/components/custom/labeled-field/LabeledSlider.vue +32 -0
  40. package/src/components/custom/labeled-field/LabeledSwitch.vue +27 -0
  41. package/src/components/custom/labeled-field/index.ts +4 -0
  42. package/src/components/custom/metaballs/MetaballCanvas.vue +23 -0
  43. package/src/components/custom/metaballs/index.ts +4 -0
  44. package/src/components/custom/metaballs/shaders.ts +63 -0
  45. package/src/components/custom/metaballs/types.ts +29 -0
  46. package/src/components/custom/metaballs/useMetaballs.ts +252 -0
  47. package/src/components/custom/search/FuzzySearch.vue +589 -0
  48. package/src/components/custom/search/SearchBar.vue +44 -0
  49. package/src/components/custom/search/composables/fuzzySearchIndex.ts +224 -0
  50. package/src/components/custom/search/composables/index.ts +5 -0
  51. package/src/components/custom/search/composables/types.ts +34 -0
  52. package/src/components/custom/search/composables/useFuzzySearch.ts +115 -0
  53. package/src/components/custom/search/index.ts +7 -0
  54. package/src/components/custom/sidebar/ProgressiveSidebar.vue +256 -0
  55. package/src/components/custom/sidebar/composables/index.ts +6 -0
  56. package/src/components/custom/sidebar/composables/useScrollTracker.ts +242 -0
  57. package/src/components/custom/sidebar/composables/useSidebarFollow.ts +247 -0
  58. package/src/components/custom/sidebar/composables/useSidebarState.ts +72 -0
  59. package/src/components/custom/sidebar/composables/useTreeIndex.ts +152 -0
  60. package/src/components/custom/sidebar/index.ts +15 -0
  61. package/src/components/custom/sidebar/types.ts +50 -0
  62. package/src/components/custom/tabs/BouncyTabs.vue +39 -0
  63. package/src/components/custom/tabs/BouncyToggle.vue +352 -0
  64. package/src/components/custom/tabs/UnderlineTabs.vue +115 -0
  65. package/src/components/custom/tabs/index.ts +5 -0
  66. package/src/components/custom/timeline/GlassTimeline.vue +174 -0
  67. package/src/components/custom/timeline/index.ts +1 -0
  68. package/src/components/custom/typewriter/TypewriterText.vue +239 -0
  69. package/src/components/custom/typewriter/composables/index.ts +1 -0
  70. package/src/components/custom/typewriter/composables/useTypewriter.ts +413 -0
  71. package/src/components/custom/typewriter/index.ts +7 -0
  72. package/src/components/custom/typewriter/types.ts +159 -0
  73. package/src/components/custom/typewriter/utils/keyboard.ts +213 -0
  74. package/src/components/custom/typewriter/utils/pausePatterns.ts +55 -0
  75. package/src/components/custom/typewriter/utils/timing.ts +104 -0
  76. package/src/components/custom/typewriter/utils/typoStateMachine.ts +197 -0
  77. package/src/components/index.ts +2 -0
  78. package/src/components/ui/accordion/Accordion.vue +19 -0
  79. package/src/components/ui/accordion/AccordionContent.vue +24 -0
  80. package/src/components/ui/accordion/AccordionItem.vue +24 -0
  81. package/src/components/ui/accordion/AccordionTrigger.vue +39 -0
  82. package/src/components/ui/accordion/index.ts +4 -0
  83. package/src/components/ui/alert/Alert.vue +20 -0
  84. package/src/components/ui/alert/AlertDescription.vue +17 -0
  85. package/src/components/ui/alert/AlertTitle.vue +17 -0
  86. package/src/components/ui/alert/index.ts +23 -0
  87. package/src/components/ui/avatar/Avatar.vue +21 -0
  88. package/src/components/ui/avatar/AvatarFallback.vue +11 -0
  89. package/src/components/ui/avatar/AvatarImage.vue +9 -0
  90. package/src/components/ui/avatar/index.ts +24 -0
  91. package/src/components/ui/badge/Badge.vue +16 -0
  92. package/src/components/ui/badge/index.ts +25 -0
  93. package/src/components/ui/button/Button.vue +26 -0
  94. package/src/components/ui/button/index.ts +43 -0
  95. package/src/components/ui/card/Card.vue +28 -0
  96. package/src/components/ui/card/CardContent.vue +14 -0
  97. package/src/components/ui/card/CardDescription.vue +14 -0
  98. package/src/components/ui/card/CardFooter.vue +14 -0
  99. package/src/components/ui/card/CardHeader.vue +14 -0
  100. package/src/components/ui/card/CardTitle.vue +21 -0
  101. package/src/components/ui/card/index.ts +6 -0
  102. package/src/components/ui/carousel/Carousel.vue +53 -0
  103. package/src/components/ui/carousel/CarouselContent.vue +35 -0
  104. package/src/components/ui/carousel/CarouselItem.vue +24 -0
  105. package/src/components/ui/carousel/CarouselNext.vue +40 -0
  106. package/src/components/ui/carousel/CarouselPrevious.vue +40 -0
  107. package/src/components/ui/carousel/index.ts +10 -0
  108. package/src/components/ui/carousel/interface.ts +26 -0
  109. package/src/components/ui/carousel/useCarousel.ts +56 -0
  110. package/src/components/ui/checkbox/Checkbox.vue +33 -0
  111. package/src/components/ui/checkbox/index.ts +1 -0
  112. package/src/components/ui/collapsible/Collapsible.vue +15 -0
  113. package/src/components/ui/collapsible/CollapsibleContent.vue +11 -0
  114. package/src/components/ui/collapsible/CollapsibleTrigger.vue +11 -0
  115. package/src/components/ui/collapsible/index.ts +3 -0
  116. package/src/components/ui/combobox/Combobox.vue +17 -0
  117. package/src/components/ui/combobox/ComboboxAnchor.vue +23 -0
  118. package/src/components/ui/combobox/ComboboxEmpty.vue +21 -0
  119. package/src/components/ui/combobox/ComboboxGroup.vue +27 -0
  120. package/src/components/ui/combobox/ComboboxInput.vue +41 -0
  121. package/src/components/ui/combobox/ComboboxItem.vue +24 -0
  122. package/src/components/ui/combobox/ComboboxItemIndicator.vue +23 -0
  123. package/src/components/ui/combobox/ComboboxList.vue +29 -0
  124. package/src/components/ui/combobox/ComboboxSeparator.vue +21 -0
  125. package/src/components/ui/combobox/ComboboxViewport.vue +23 -0
  126. package/src/components/ui/combobox/index.ts +12 -0
  127. package/src/components/ui/command/Command.vue +30 -0
  128. package/src/components/ui/command/CommandDialog.vue +21 -0
  129. package/src/components/ui/command/CommandEmpty.vue +20 -0
  130. package/src/components/ui/command/CommandGroup.vue +29 -0
  131. package/src/components/ui/command/CommandInput.vue +33 -0
  132. package/src/components/ui/command/CommandItem.vue +26 -0
  133. package/src/components/ui/command/CommandList.vue +27 -0
  134. package/src/components/ui/command/CommandSeparator.vue +23 -0
  135. package/src/components/ui/command/CommandShortcut.vue +14 -0
  136. package/src/components/ui/command/index.ts +9 -0
  137. package/src/components/ui/context-menu/ContextMenu.vue +15 -0
  138. package/src/components/ui/context-menu/ContextMenuCheckboxItem.vue +40 -0
  139. package/src/components/ui/context-menu/ContextMenuContent.vue +36 -0
  140. package/src/components/ui/context-menu/ContextMenuGroup.vue +11 -0
  141. package/src/components/ui/context-menu/ContextMenuItem.vue +34 -0
  142. package/src/components/ui/context-menu/ContextMenuLabel.vue +25 -0
  143. package/src/components/ui/context-menu/ContextMenuPortal.vue +11 -0
  144. package/src/components/ui/context-menu/ContextMenuRadioGroup.vue +19 -0
  145. package/src/components/ui/context-menu/ContextMenuRadioItem.vue +40 -0
  146. package/src/components/ui/context-menu/ContextMenuSeparator.vue +20 -0
  147. package/src/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
  148. package/src/components/ui/context-menu/ContextMenuSub.vue +19 -0
  149. package/src/components/ui/context-menu/ContextMenuSubContent.vue +35 -0
  150. package/src/components/ui/context-menu/ContextMenuSubTrigger.vue +34 -0
  151. package/src/components/ui/context-menu/ContextMenuTrigger.vue +13 -0
  152. package/src/components/ui/context-menu/index.ts +14 -0
  153. package/src/components/ui/data-table/DataTable.vue +167 -0
  154. package/src/components/ui/data-table/DataTablePagination.vue +112 -0
  155. package/src/components/ui/data-table/index.ts +3 -0
  156. package/src/components/ui/data-table/types.ts +48 -0
  157. package/src/components/ui/dialog/Dialog.vue +14 -0
  158. package/src/components/ui/dialog/DialogClose.vue +11 -0
  159. package/src/components/ui/dialog/DialogContent.vue +61 -0
  160. package/src/components/ui/dialog/DialogDescription.vue +24 -0
  161. package/src/components/ui/dialog/DialogFooter.vue +19 -0
  162. package/src/components/ui/dialog/DialogHeader.vue +16 -0
  163. package/src/components/ui/dialog/DialogScrollContent.vue +65 -0
  164. package/src/components/ui/dialog/DialogTitle.vue +29 -0
  165. package/src/components/ui/dialog/DialogTrigger.vue +11 -0
  166. package/src/components/ui/dialog/index.ts +9 -0
  167. package/src/components/ui/drawer/Drawer.vue +19 -0
  168. package/src/components/ui/drawer/DrawerContent.vue +28 -0
  169. package/src/components/ui/drawer/DrawerDescription.vue +20 -0
  170. package/src/components/ui/drawer/DrawerFooter.vue +14 -0
  171. package/src/components/ui/drawer/DrawerHeader.vue +14 -0
  172. package/src/components/ui/drawer/DrawerOverlay.vue +18 -0
  173. package/src/components/ui/drawer/DrawerTitle.vue +20 -0
  174. package/src/components/ui/drawer/index.ts +8 -0
  175. package/src/components/ui/dropdown-menu/DropdownMenu.vue +14 -0
  176. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +40 -0
  177. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +44 -0
  178. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
  179. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +28 -0
  180. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +24 -0
  181. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +19 -0
  182. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  183. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +22 -0
  184. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  185. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  186. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +36 -0
  187. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +33 -0
  188. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +13 -0
  189. package/src/components/ui/dropdown-menu/index.ts +16 -0
  190. package/src/components/ui/hover-card/HoverCard.vue +14 -0
  191. package/src/components/ui/hover-card/HoverCardContent.vue +41 -0
  192. package/src/components/ui/hover-card/HoverCardTrigger.vue +11 -0
  193. package/src/components/ui/hover-card/index.ts +3 -0
  194. package/src/components/ui/index.ts +41 -0
  195. package/src/components/ui/input/Input.vue +24 -0
  196. package/src/components/ui/input/index.ts +1 -0
  197. package/src/components/ui/label/Label.vue +27 -0
  198. package/src/components/ui/label/index.ts +1 -0
  199. package/src/components/ui/multi-select/MultiSelect.vue +141 -0
  200. package/src/components/ui/multi-select/index.ts +7 -0
  201. package/src/components/ui/notification/Notification.vue +85 -0
  202. package/src/components/ui/notification/index.ts +1 -0
  203. package/src/components/ui/number-field/NumberField.vue +23 -0
  204. package/src/components/ui/number-field/NumberFieldContent.vue +14 -0
  205. package/src/components/ui/number-field/NumberFieldDecrement.vue +25 -0
  206. package/src/components/ui/number-field/NumberFieldIncrement.vue +25 -0
  207. package/src/components/ui/number-field/NumberFieldInput.vue +8 -0
  208. package/src/components/ui/number-field/index.ts +5 -0
  209. package/src/components/ui/popover/Popover.vue +15 -0
  210. package/src/components/ui/popover/PopoverContent.vue +61 -0
  211. package/src/components/ui/popover/PopoverTrigger.vue +11 -0
  212. package/src/components/ui/popover/index.ts +3 -0
  213. package/src/components/ui/progress/Progress.vue +39 -0
  214. package/src/components/ui/progress/index.ts +1 -0
  215. package/src/components/ui/radio-group/RadioGroup.vue +25 -0
  216. package/src/components/ui/radio-group/RadioGroupItem.vue +39 -0
  217. package/src/components/ui/radio-group/index.ts +2 -0
  218. package/src/components/ui/scroll-area/ScrollArea.vue +29 -0
  219. package/src/components/ui/scroll-area/ScrollBar.vue +30 -0
  220. package/src/components/ui/scroll-area/index.ts +2 -0
  221. package/src/components/ui/scroll-pane/ScrollPane.vue +25 -0
  222. package/src/components/ui/scroll-pane/ScrollPaneHeader.vue +75 -0
  223. package/src/components/ui/scroll-pane/index.ts +2 -0
  224. package/src/components/ui/select/Select.vue +15 -0
  225. package/src/components/ui/select/SelectContent.vue +57 -0
  226. package/src/components/ui/select/SelectGroup.vue +19 -0
  227. package/src/components/ui/select/SelectItem.vue +47 -0
  228. package/src/components/ui/select/SelectItemText.vue +11 -0
  229. package/src/components/ui/select/SelectLabel.vue +13 -0
  230. package/src/components/ui/select/SelectScrollDownButton.vue +24 -0
  231. package/src/components/ui/select/SelectScrollUpButton.vue +24 -0
  232. package/src/components/ui/select/SelectSeparator.vue +17 -0
  233. package/src/components/ui/select/SelectTrigger.vue +45 -0
  234. package/src/components/ui/select/SelectValue.vue +11 -0
  235. package/src/components/ui/select/index.ts +11 -0
  236. package/src/components/ui/separator/Separator.vue +35 -0
  237. package/src/components/ui/separator/index.ts +1 -0
  238. package/src/components/ui/sheet/Sheet.vue +14 -0
  239. package/src/components/ui/sheet/SheetClose.vue +11 -0
  240. package/src/components/ui/sheet/SheetContent.vue +56 -0
  241. package/src/components/ui/sheet/SheetDescription.vue +22 -0
  242. package/src/components/ui/sheet/SheetFooter.vue +19 -0
  243. package/src/components/ui/sheet/SheetHeader.vue +16 -0
  244. package/src/components/ui/sheet/SheetTitle.vue +22 -0
  245. package/src/components/ui/sheet/SheetTrigger.vue +11 -0
  246. package/src/components/ui/sheet/index.ts +31 -0
  247. package/src/components/ui/skeleton/Skeleton.vue +14 -0
  248. package/src/components/ui/skeleton/index.ts +1 -0
  249. package/src/components/ui/slider/Slider.vue +66 -0
  250. package/src/components/ui/slider/index.ts +1 -0
  251. package/src/components/ui/switch/Switch.vue +37 -0
  252. package/src/components/ui/switch/index.ts +1 -0
  253. package/src/components/ui/table/Table.vue +16 -0
  254. package/src/components/ui/table/TableBody.vue +14 -0
  255. package/src/components/ui/table/TableCaption.vue +14 -0
  256. package/src/components/ui/table/TableCell.vue +14 -0
  257. package/src/components/ui/table/TableEmpty.vue +39 -0
  258. package/src/components/ui/table/TableFooter.vue +16 -0
  259. package/src/components/ui/table/TableHead.vue +21 -0
  260. package/src/components/ui/table/TableHeader.vue +14 -0
  261. package/src/components/ui/table/TableRow.vue +21 -0
  262. package/src/components/ui/table/index.ts +9 -0
  263. package/src/components/ui/tabs/Tabs.vue +15 -0
  264. package/src/components/ui/tabs/TabsContent.vue +22 -0
  265. package/src/components/ui/tabs/TabsIndicator.vue +22 -0
  266. package/src/components/ui/tabs/TabsList.vue +25 -0
  267. package/src/components/ui/tabs/TabsTrigger.vue +29 -0
  268. package/src/components/ui/tabs/index.ts +5 -0
  269. package/src/components/ui/tags-input/TagsInput.vue +22 -0
  270. package/src/components/ui/tags-input/TagsInputInput.vue +19 -0
  271. package/src/components/ui/tags-input/TagsInputItem.vue +22 -0
  272. package/src/components/ui/tags-input/TagsInputItemDelete.vue +24 -0
  273. package/src/components/ui/tags-input/TagsInputItemText.vue +19 -0
  274. package/src/components/ui/tags-input/index.ts +5 -0
  275. package/src/components/ui/textarea/Textarea.vue +24 -0
  276. package/src/components/ui/textarea/index.ts +1 -0
  277. package/src/components/ui/toast/Toast.vue +57 -0
  278. package/src/components/ui/toast/ToastAction.vue +30 -0
  279. package/src/components/ui/toast/ToastClose.vue +31 -0
  280. package/src/components/ui/toast/ToastDescription.vue +25 -0
  281. package/src/components/ui/toast/ToastTitle.vue +25 -0
  282. package/src/components/ui/toast/Toaster.vue +31 -0
  283. package/src/components/ui/toast/index.ts +8 -0
  284. package/src/components/ui/toast/use-toast.ts +136 -0
  285. package/src/components/ui/toggle/Toggle.vue +35 -0
  286. package/src/components/ui/toggle/index.ts +27 -0
  287. package/src/components/ui/toggle-group/ToggleGroup.vue +34 -0
  288. package/src/components/ui/toggle-group/ToggleGroupItem.vue +35 -0
  289. package/src/components/ui/toggle-group/index.ts +2 -0
  290. package/src/components/ui/tooltip/Tooltip.vue +14 -0
  291. package/src/components/ui/tooltip/TooltipContent.vue +31 -0
  292. package/src/components/ui/tooltip/TooltipProvider.vue +11 -0
  293. package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
  294. package/src/components/ui/tooltip/index.ts +4 -0
  295. package/src/composables/glass/index.ts +8 -0
  296. package/src/composables/glass/useGlassRenderer.ts +252 -0
  297. package/src/composables/glass/webgl/frostShader.ts +221 -0
  298. package/src/composables/glass/webgpu/glassShader.wgsl +173 -0
  299. package/src/composables/index.ts +32 -0
  300. package/src/composables/infinite-scroll/index.ts +2 -0
  301. package/src/composables/infinite-scroll/types.ts +25 -0
  302. package/src/composables/infinite-scroll/useInfiniteScroll.ts +101 -0
  303. package/src/composables/interaction/index.ts +5 -0
  304. package/src/composables/interaction/useHeightTransition.ts +82 -0
  305. package/src/composables/interaction/useHoverPopover.ts +64 -0
  306. package/src/composables/interaction/useHoverToggle.ts +103 -0
  307. package/src/composables/interaction/useLeaveTimer.ts +17 -0
  308. package/src/composables/interaction/useTouchGate.ts +207 -0
  309. package/src/composables/pagination/index.ts +2 -0
  310. package/src/composables/pagination/useOffsetPagination.ts +70 -0
  311. package/src/composables/prng.ts +32 -0
  312. package/src/composables/useCharSplit.ts +31 -0
  313. package/src/composables/useClipboard.ts +46 -0
  314. package/src/composables/useGlobalDark.ts +61 -0
  315. package/src/composables/useKeyboardShortcuts.ts +205 -0
  316. package/src/composables/useWatercolorBlob.ts +136 -0
  317. package/src/composables/virtual/index.ts +22 -0
  318. package/src/composables/virtual/useVirtualSectionWindow.ts +338 -0
  319. package/src/composables/virtual/useWindowedStore.ts +86 -0
  320. package/src/composables/virtual/virtualSectionLayout.ts +212 -0
  321. package/src/index.ts +9 -0
  322. package/src/styles/animations.css +233 -0
  323. package/src/styles/cards.css +66 -0
  324. package/src/styles/dock.css +221 -0
  325. package/src/styles/floating-panel.css +49 -0
  326. package/src/styles/glass.css +266 -0
  327. package/src/styles/index.css +26 -0
  328. package/src/styles/scroll-pane.css +10 -0
  329. package/src/styles/theme.css +138 -0
  330. package/src/styles/tokens.css +333 -0
  331. package/src/styles/transitions.css +226 -0
  332. package/src/styles/typography.css +277 -0
  333. package/src/styles/utilities.css +697 -0
  334. package/src/utils/cn.ts +6 -0
  335. package/src/utils/index.ts +1 -0
@@ -0,0 +1,173 @@
1
+ // glass-ui WebGPU glass shader
2
+ // Features: variable blur, real-time refraction, caustics, dynamic specular
3
+ //
4
+ // This shader is designed to be used with a full-screen quad.
5
+ // It reads from a background texture and applies glass effects
6
+ // for each registered glass panel.
7
+
8
+ struct Uniforms {
9
+ resolution: vec2f, // Canvas resolution
10
+ glass_bounds: vec4f, // Glass panel rect (x, y, w, h) in UV space
11
+ blur_radius: f32, // Base blur radius
12
+ refraction_strength: f32, // Snell's law displacement strength
13
+ chromatic_aberration: f32, // Edge chromatic aberration strength
14
+ caustic_intensity: f32, // Caustic light pattern intensity
15
+ light_pos: vec2f, // Virtual light source position (UV)
16
+ time: f32, // Animation time (seconds)
17
+ _pad: f32, // Alignment padding
18
+ };
19
+
20
+ @group(0) @binding(0) var<uniform> u: Uniforms;
21
+ @group(0) @binding(1) var background_texture: texture_2d<f32>;
22
+ @group(0) @binding(2) var background_sampler: sampler;
23
+
24
+ // Pseudo-random hash for noise generation
25
+ fn hash21(p: vec2f) -> f32 {
26
+ var p3 = fract(vec3f(p.xyx) * 0.1031);
27
+ p3 += dot(p3, p3.yzx + 33.33);
28
+ return fract((p3.x + p3.y) * p3.z);
29
+ }
30
+
31
+ // Simplex-style noise for caustics
32
+ fn noise(p: vec2f) -> f32 {
33
+ let i = floor(p);
34
+ let f = fract(p);
35
+ let u_curve = f * f * (3.0 - 2.0 * f);
36
+
37
+ return mix(
38
+ mix(hash21(i), hash21(i + vec2f(1.0, 0.0)), u_curve.x),
39
+ mix(hash21(i + vec2f(0.0, 1.0)), hash21(i + vec2f(1.0, 1.0)), u_curve.x),
40
+ u_curve.y
41
+ );
42
+ }
43
+
44
+ // Fractal Brownian Motion for caustic patterns
45
+ fn fbm(p: vec2f) -> f32 {
46
+ var value = 0.0;
47
+ var amplitude = 0.5;
48
+ var frequency = 1.0;
49
+ var pos = p;
50
+
51
+ for (var i = 0; i < 5; i++) {
52
+ value += amplitude * noise(pos * frequency);
53
+ pos += vec2f(1.7, 9.2);
54
+ amplitude *= 0.5;
55
+ frequency *= 2.0;
56
+ }
57
+ return value;
58
+ }
59
+
60
+ // Caustic light pattern — animated voronoi-like cells
61
+ fn caustics(uv: vec2f, time: f32) -> f32 {
62
+ let p = uv * 8.0 + vec2f(time * 0.3, time * 0.2);
63
+ let n1 = fbm(p);
64
+ let n2 = fbm(p + vec2f(1.3, 2.7) + time * 0.1);
65
+ let pattern = fbm(p + vec2f(n1, n2) * 2.0);
66
+ return smoothstep(0.3, 0.7, pattern);
67
+ }
68
+
69
+ // Fresnel approximation (Schlick)
70
+ fn fresnel(cos_theta: f32, ior: f32) -> f32 {
71
+ let r0 = pow((1.0 - ior) / (1.0 + ior), 2.0);
72
+ return r0 + (1.0 - r0) * pow(1.0 - cos_theta, 5.0);
73
+ }
74
+
75
+ // Distance from UV to nearest edge of glass panel
76
+ fn edge_distance(uv: vec2f) -> f32 {
77
+ let glass_min = u.glass_bounds.xy;
78
+ let glass_max = u.glass_bounds.xy + u.glass_bounds.zw;
79
+ let d = min(uv - glass_min, glass_max - uv);
80
+ return min(d.x, d.y);
81
+ }
82
+
83
+ @fragment
84
+ fn fs_main(@builtin(position) frag_coord: vec4f) -> @location(0) vec4f {
85
+ let uv = frag_coord.xy / u.resolution;
86
+ let pixel_size = 1.0 / u.resolution;
87
+
88
+ // Check if fragment is inside the glass panel
89
+ let glass_min = u.glass_bounds.xy;
90
+ let glass_max = u.glass_bounds.xy + u.glass_bounds.zw;
91
+
92
+ if (uv.x < glass_min.x || uv.x > glass_max.x ||
93
+ uv.y < glass_min.y || uv.y > glass_max.y) {
94
+ return textureSample(background_texture, background_sampler, uv);
95
+ }
96
+
97
+ // Progressive blur — variable radius based on edge distance
98
+ let edge_dist = edge_distance(uv);
99
+ let max_edge_dist = min(u.glass_bounds.z, u.glass_bounds.w) * 0.5;
100
+ let blur_factor = smoothstep(0.0, max_edge_dist * 0.3, edge_dist);
101
+ let effective_blur = u.blur_radius * (0.4 + 0.6 * blur_factor);
102
+
103
+ // Refraction displacement
104
+ let center = u.glass_bounds.xy + u.glass_bounds.zw * 0.5;
105
+ let from_center = uv - center;
106
+ let refraction_offset = from_center * u.refraction_strength * 0.02;
107
+
108
+ // Depth-aware blur kernel
109
+ var blur_color = vec3f(0.0);
110
+ var total_weight = 0.0;
111
+ let samples = i32(min(effective_blur * 2.0, 16.0));
112
+ let sigma = max(effective_blur * 0.5, 0.1);
113
+
114
+ for (var x = -8; x <= 8; x++) {
115
+ for (var y = -8; y <= 8; y++) {
116
+ if (abs(x) > samples || abs(y) > samples) { continue; }
117
+
118
+ let offset = vec2f(f32(x), f32(y)) * pixel_size * effective_blur * 0.1;
119
+ let dist_sq = f32(x * x + y * y);
120
+ let weight = exp(-dist_sq / (2.0 * sigma * sigma));
121
+
122
+ let sample_uv = uv + offset + refraction_offset;
123
+ blur_color += textureSample(background_texture, background_sampler, sample_uv).rgb * weight;
124
+ total_weight += weight;
125
+ }
126
+ }
127
+ blur_color /= total_weight;
128
+
129
+ // Chromatic aberration at edges
130
+ if (u.chromatic_aberration > 0.0) {
131
+ let edge_strength = 1.0 - smoothstep(0.0, max_edge_dist * 0.15, edge_dist);
132
+ let aberration_dir = normalize(from_center) * edge_strength * u.chromatic_aberration * 0.003;
133
+
134
+ let r = textureSample(background_texture, background_sampler, uv + refraction_offset + aberration_dir).r;
135
+ let b = textureSample(background_texture, background_sampler, uv + refraction_offset - aberration_dir).b;
136
+ blur_color.x = mix(blur_color.x, r, edge_strength * 0.5);
137
+ blur_color.z = mix(blur_color.z, b, edge_strength * 0.5);
138
+ }
139
+
140
+ // Caustic light pattern
141
+ var caustic_light = 0.0;
142
+ if (u.caustic_intensity > 0.0) {
143
+ let local_uv = (uv - glass_min) / u.glass_bounds.zw;
144
+ caustic_light = caustics(local_uv, u.time) * u.caustic_intensity;
145
+ }
146
+
147
+ // Specular highlight with cursor-tracking light
148
+ let normal_xy = from_center / (u.glass_bounds.zw * 0.5);
149
+ let normal = normalize(vec3f(normal_xy * 0.3, 1.0));
150
+ let view_dir = vec3f(0.0, 0.0, 1.0);
151
+ let cos_theta = max(dot(view_dir, normal), 0.0);
152
+ var spec = fresnel(cos_theta, 1.5);
153
+
154
+ // Light-source-aware specular
155
+ let light_dir = normalize(u.light_pos - uv);
156
+ let light_dot = max(dot(normal_xy, light_dir), 0.0);
157
+ spec *= 0.3 + 0.7 * light_dot;
158
+
159
+ // Combine
160
+ let result = blur_color + vec3f(spec * 0.15 + caustic_light * 0.08);
161
+ let alpha = 0.85 + spec * 0.1;
162
+
163
+ return vec4f(result, alpha);
164
+ }
165
+
166
+ // Vertex shader — full-screen triangle
167
+ @vertex
168
+ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
169
+ // Full-screen triangle trick: 3 vertices cover the entire viewport
170
+ let x = f32(i32(vertex_index) / 2) * 4.0 - 1.0;
171
+ let y = f32(i32(vertex_index) % 2) * 4.0 - 1.0;
172
+ return vec4f(x, y, 0.0, 1.0);
173
+ }
@@ -0,0 +1,32 @@
1
+ export * from "./interaction";
2
+ export { copyToClipboard } from "./useClipboard";
3
+ export { useGlobalDark, type UseGlobalDarkOptions } from "./useGlobalDark";
4
+ export * from "./useKeyboardShortcuts";
5
+ export * from "./useWatercolorBlob";
6
+ export { useCharSplit } from "./useCharSplit";
7
+ export * from "./glass";
8
+ export * from "./pagination";
9
+ export * from "./prng";
10
+ export * from "./virtual";
11
+ export * from "../components/custom/infinite-scroll/composables";
12
+
13
+ // Sidebar composables and types
14
+ export {
15
+ useTreeIndex,
16
+ useScrollTracker,
17
+ useSidebarFollow,
18
+ useSidebarState,
19
+ buildTreeIndex,
20
+ isActive,
21
+ isInActiveChain,
22
+ } from "../components/custom/sidebar";
23
+ export type {
24
+ TreeNode,
25
+ TreeIndexEntry,
26
+ SidebarSection,
27
+ SidebarIndexEntry,
28
+ SidebarState,
29
+ ScrollTrackerOptions,
30
+ SidebarFollowOptions,
31
+ UseSidebarStateOptions,
32
+ } from "../components/custom/sidebar";
@@ -0,0 +1,2 @@
1
+ export { useInfiniteScroll } from "./useInfiniteScroll";
2
+ export type { InfiniteScrollOptions, InfiniteScrollReturn } from "./types";
@@ -0,0 +1,25 @@
1
+ import type { Ref, MaybeRefOrGetter } from "vue";
2
+
3
+ export interface InfiniteScrollOptions {
4
+ /** The scrollable container element. Defaults to window if not provided. */
5
+ scrollContainer?: Ref<HTMLElement | null>;
6
+ /** Distance in pixels from the bottom to trigger loading (default: 200) */
7
+ threshold?: number;
8
+ /** Whether more data is available */
9
+ hasMore: MaybeRefOrGetter<boolean>;
10
+ /** Whether data is currently loading */
11
+ isLoading: MaybeRefOrGetter<boolean>;
12
+ /** Callback invoked when the sentinel enters the viewport */
13
+ onLoadMore: () => void | Promise<void>;
14
+ }
15
+
16
+ export interface InfiniteScrollReturn {
17
+ /** Ref to bind to the sentinel element */
18
+ sentinelRef: Ref<HTMLElement | null>;
19
+ /** Error message from the last failed load, or null */
20
+ error: Ref<string | null>;
21
+ /** Manually trigger a check (e.g., after DOM updates) */
22
+ check: () => void;
23
+ /** Stop observing and reset error state */
24
+ stop: () => void;
25
+ }
@@ -0,0 +1,101 @@
1
+ import { ref, watch, onScopeDispose, toValue, type MaybeRefOrGetter } from "vue";
2
+ import type { InfiniteScrollOptions, InfiniteScrollReturn } from "./types";
3
+
4
+ /**
5
+ * Composable for infinite scroll with IntersectionObserver.
6
+ *
7
+ * Watches a sentinel element at the bottom of the scrollable area.
8
+ * When it enters the viewport and `hasMore` is true / `isLoading` is false,
9
+ * the `onLoadMore` callback fires.
10
+ */
11
+ export function useInfiniteScroll(options: InfiniteScrollOptions): InfiniteScrollReturn {
12
+ const { threshold = 200, hasMore, isLoading, onLoadMore } = options;
13
+ const sentinelRef = ref<HTMLElement | null>(null);
14
+ const error = ref<string | null>(null);
15
+ let observer: IntersectionObserver | null = null;
16
+
17
+ function shouldLoad(): boolean {
18
+ return toValue(hasMore) && !toValue(isLoading);
19
+ }
20
+
21
+ function handleIntersect(entries: IntersectionObserverEntry[]) {
22
+ for (const entry of entries) {
23
+ if (entry.isIntersecting && shouldLoad()) {
24
+ error.value = null;
25
+ try {
26
+ const result = onLoadMore();
27
+ // Handle async onLoadMore callbacks
28
+ if (result && typeof (result as any).catch === "function") {
29
+ (result as Promise<unknown>).catch((e: unknown) => {
30
+ error.value =
31
+ e instanceof Error ? e.message : "Failed to load more";
32
+ });
33
+ }
34
+ } catch (e) {
35
+ error.value =
36
+ e instanceof Error ? e.message : "Failed to load more";
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ function setupObserver(el: HTMLElement) {
43
+ teardown();
44
+ observer = new IntersectionObserver(handleIntersect, {
45
+ root: options.scrollContainer?.value ?? null,
46
+ rootMargin: `0px 0px ${threshold}px 0px`,
47
+ });
48
+ observer.observe(el);
49
+ }
50
+
51
+ function teardown() {
52
+ if (observer) {
53
+ observer.disconnect();
54
+ observer = null;
55
+ }
56
+ error.value = null;
57
+ }
58
+
59
+ function check() {
60
+ if (sentinelRef.value && shouldLoad()) {
61
+ error.value = null;
62
+ try {
63
+ const result = onLoadMore();
64
+ if (result && typeof (result as any).catch === "function") {
65
+ (result as Promise<unknown>).catch((e: unknown) => {
66
+ error.value =
67
+ e instanceof Error ? e.message : "Failed to load more";
68
+ });
69
+ }
70
+ } catch (e) {
71
+ error.value =
72
+ e instanceof Error ? e.message : "Failed to load more";
73
+ }
74
+ }
75
+ }
76
+
77
+ watch(sentinelRef, (el) => {
78
+ if (el) setupObserver(el);
79
+ else teardown();
80
+ });
81
+
82
+ // Re-check when loading finishes (new content may be short enough to need another load)
83
+ watch(
84
+ () => toValue(isLoading),
85
+ (loading) => {
86
+ if (!loading && sentinelRef.value) {
87
+ // Defer to next tick so DOM updates first
88
+ requestAnimationFrame(check);
89
+ }
90
+ },
91
+ );
92
+
93
+ onScopeDispose(teardown);
94
+
95
+ return {
96
+ sentinelRef,
97
+ error,
98
+ check,
99
+ stop: teardown,
100
+ };
101
+ }
@@ -0,0 +1,5 @@
1
+ export { useHeightTransition } from "./useHeightTransition";
2
+ export { useHoverPopover } from "./useHoverPopover";
3
+ export { useHoverToggle } from "./useHoverToggle";
4
+ export { useLeaveTimer } from "./useLeaveTimer";
5
+ export { useTouchGate } from "./useTouchGate";
@@ -0,0 +1,82 @@
1
+ const DEFAULT_EXPAND_DURATION = "var(--duration-normal, 0.3s)";
2
+ const DEFAULT_COLLAPSE_DURATION = "var(--duration-fast, 0.2s)";
3
+ const EXPAND_EASING = "var(--spring-smooth, cubic-bezier(0.16, 1, 0.3, 1))";
4
+ const COLLAPSE_EASING = "var(--ease-out, cubic-bezier(0, 0, 0.2, 1))";
5
+
6
+ export function useHeightTransition(options?: {
7
+ expandDuration?: string;
8
+ collapseDuration?: string;
9
+ onBeforeCollapse?: () => void;
10
+ onAfterExpand?: () => void;
11
+ }) {
12
+ const expandDuration = options?.expandDuration ?? DEFAULT_EXPAND_DURATION;
13
+ const collapseDuration = options?.collapseDuration ?? DEFAULT_COLLAPSE_DURATION;
14
+
15
+ function onBeforeEnter(el: Element) {
16
+ const htmlEl = el as HTMLElement;
17
+ htmlEl.style.height = "0";
18
+ htmlEl.style.opacity = "0";
19
+ }
20
+
21
+ function onEnter(el: Element, done: () => void) {
22
+ const htmlEl = el as HTMLElement;
23
+ const targetHeight = htmlEl.scrollHeight;
24
+ htmlEl.style.transition = `height ${expandDuration} ${EXPAND_EASING}, opacity ${expandDuration} ease`;
25
+ // Force reflow
26
+ void htmlEl.offsetHeight;
27
+ htmlEl.style.height = `${targetHeight}px`;
28
+ htmlEl.style.opacity = "1";
29
+ htmlEl.addEventListener("transitionend", function handler(e) {
30
+ if (e.propertyName !== "height") return;
31
+ htmlEl.removeEventListener("transitionend", handler);
32
+ done();
33
+ });
34
+ }
35
+
36
+ function onAfterEnter(el: Element) {
37
+ const htmlEl = el as HTMLElement;
38
+ htmlEl.style.height = "";
39
+ htmlEl.style.transition = "";
40
+ htmlEl.style.opacity = "";
41
+ options?.onAfterExpand?.();
42
+ htmlEl.scrollIntoView({ behavior: "smooth", block: "nearest" });
43
+ }
44
+
45
+ function onBeforeLeave(el: Element) {
46
+ const htmlEl = el as HTMLElement;
47
+ options?.onBeforeCollapse?.();
48
+ htmlEl.style.height = `${htmlEl.scrollHeight}px`;
49
+ // Force reflow
50
+ void htmlEl.offsetHeight;
51
+ }
52
+
53
+ function onLeave(el: Element, done: () => void) {
54
+ const htmlEl = el as HTMLElement;
55
+ htmlEl.style.transition = `height ${collapseDuration} ${COLLAPSE_EASING}, opacity ${collapseDuration} ease`;
56
+ // Force reflow
57
+ void htmlEl.offsetHeight;
58
+ htmlEl.style.height = "0";
59
+ htmlEl.style.opacity = "0";
60
+ htmlEl.addEventListener("transitionend", function handler(e) {
61
+ if (e.propertyName !== "height") return;
62
+ htmlEl.removeEventListener("transitionend", handler);
63
+ done();
64
+ });
65
+ }
66
+
67
+ function onAfterLeave(el: Element) {
68
+ const htmlEl = el as HTMLElement;
69
+ htmlEl.style.height = "";
70
+ htmlEl.style.transition = "";
71
+ htmlEl.style.opacity = "";
72
+ }
73
+
74
+ return {
75
+ onBeforeEnter,
76
+ onEnter,
77
+ onAfterEnter,
78
+ onBeforeLeave,
79
+ onLeave,
80
+ onAfterLeave,
81
+ };
82
+ }
@@ -0,0 +1,64 @@
1
+ import { ref, reactive, nextTick } from "vue";
2
+ import { useLeaveTimer } from "./useLeaveTimer";
3
+
4
+ const CAN_HOVER = typeof window !== "undefined" && window.matchMedia("(hover: hover)").matches;
5
+
6
+ /**
7
+ * Shared hover-timer + floating-panel positioning pattern.
8
+ * Used by components with hover-activated popover panels (e.g. swatch grids).
9
+ */
10
+ export function useHoverPopover(options?: { canHover?: boolean }) {
11
+ const canHover = options?.canHover ?? CAN_HOVER;
12
+
13
+ const openIndex = ref<number | null>(null);
14
+ const style = reactive({ top: "0px", left: "0px" });
15
+ const leaveTimer = useLeaveTimer(250);
16
+
17
+ function positionPanel(swatchEl: Element, offsetY = -42) {
18
+ const rect = swatchEl.getBoundingClientRect();
19
+ style.top = `${rect.top + offsetY}px`;
20
+ style.left = `${rect.left + rect.width / 2}px`;
21
+ }
22
+
23
+ function onHover(index: number, e: PointerEvent) {
24
+ if (!canHover || e.pointerType === "touch") return;
25
+ cancelLeave();
26
+ openIndex.value = index;
27
+ nextTick(() => positionPanel(e.currentTarget as Element));
28
+ }
29
+
30
+ function onLeave() {
31
+ if (!canHover) return;
32
+ leaveTimer.schedule(() => { openIndex.value = null; });
33
+ }
34
+
35
+ function cancelLeave() {
36
+ leaveTimer.cancel();
37
+ }
38
+
39
+ function close() {
40
+ cancelLeave();
41
+ openIndex.value = null;
42
+ }
43
+
44
+ function onPopoverUpdateTouch(open: boolean, index: number) {
45
+ openIndex.value = open ? index : null;
46
+ }
47
+
48
+ function onSwatchClick(index: number) {
49
+ cancelLeave();
50
+ openIndex.value = openIndex.value === index ? null : index;
51
+ }
52
+
53
+ return {
54
+ canHover,
55
+ openIndex,
56
+ style,
57
+ onHover,
58
+ onLeave,
59
+ cancelLeave,
60
+ close,
61
+ onPopoverUpdateTouch,
62
+ onSwatchClick,
63
+ };
64
+ }
@@ -0,0 +1,103 @@
1
+ import { ref, computed, onBeforeUnmount } from "vue";
2
+ import type { Ref, ComputedRef } from "vue";
3
+
4
+ export interface UseHoverToggleOptions {
5
+ /** Delay before auto-collapse after mouse leaves (ms) */
6
+ collapseDelay?: number;
7
+ /** If true, clicking toggles persistent open state; clicking elsewhere collapses */
8
+ persistOnClick?: boolean;
9
+ /** If true, starts expanded */
10
+ startExpanded?: boolean;
11
+ }
12
+
13
+ export interface UseHoverToggleReturn {
14
+ isExpanded: Ref<boolean>;
15
+ isPinned: Ref<boolean>;
16
+ onMouseEnter: () => void;
17
+ onMouseLeave: () => void;
18
+ onClickToggle: () => void;
19
+ onClickOutside: () => void;
20
+ /** Bind all listeners to a container element */
21
+ containerProps: ComputedRef<Record<string, Function>>;
22
+ }
23
+
24
+ export function useHoverToggle(options: UseHoverToggleOptions = {}): UseHoverToggleReturn {
25
+ const {
26
+ collapseDelay = 2500,
27
+ persistOnClick = true,
28
+ startExpanded = false,
29
+ } = options;
30
+
31
+ const isExpanded = ref(startExpanded);
32
+ const isPinned = ref(false);
33
+ let collapseTimer: ReturnType<typeof setTimeout> | null = null;
34
+
35
+ function clearTimer() {
36
+ if (collapseTimer) {
37
+ clearTimeout(collapseTimer);
38
+ collapseTimer = null;
39
+ }
40
+ }
41
+
42
+ function scheduleCollapse() {
43
+ clearTimer();
44
+ collapseTimer = setTimeout(() => {
45
+ isExpanded.value = false;
46
+ }, collapseDelay);
47
+ }
48
+
49
+ function onMouseEnter() {
50
+ clearTimer();
51
+ isExpanded.value = true;
52
+ }
53
+
54
+ function onMouseLeave() {
55
+ if (!isPinned.value) {
56
+ scheduleCollapse();
57
+ }
58
+ }
59
+
60
+ function onClickToggle() {
61
+ if (persistOnClick) {
62
+ if (isPinned.value) {
63
+ isPinned.value = false;
64
+ scheduleCollapse();
65
+ } else {
66
+ isPinned.value = true;
67
+ isExpanded.value = true;
68
+ clearTimer();
69
+ }
70
+ } else {
71
+ clearTimer();
72
+ isExpanded.value = !isExpanded.value;
73
+ if (isExpanded.value) {
74
+ scheduleCollapse();
75
+ }
76
+ }
77
+ }
78
+
79
+ function onClickOutside() {
80
+ if (isPinned.value) {
81
+ isPinned.value = false;
82
+ }
83
+ isExpanded.value = false;
84
+ clearTimer();
85
+ }
86
+
87
+ const containerProps = computed(() => ({
88
+ onMouseenter: onMouseEnter,
89
+ onMouseleave: onMouseLeave,
90
+ }));
91
+
92
+ onBeforeUnmount(clearTimer);
93
+
94
+ return {
95
+ isExpanded,
96
+ isPinned,
97
+ onMouseEnter,
98
+ onMouseLeave,
99
+ onClickToggle,
100
+ onClickOutside,
101
+ containerProps,
102
+ };
103
+ }
@@ -0,0 +1,17 @@
1
+ export function useLeaveTimer(delay = 250) {
2
+ let timer: ReturnType<typeof setTimeout> | null = null;
3
+
4
+ function schedule(callback: () => void) {
5
+ cancel();
6
+ timer = setTimeout(callback, delay);
7
+ }
8
+
9
+ function cancel() {
10
+ if (timer) {
11
+ clearTimeout(timer);
12
+ timer = null;
13
+ }
14
+ }
15
+
16
+ return { schedule, cancel };
17
+ }