@polymarbot/nuxt-layer-shadcn-ui 0.1.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 (408) hide show
  1. package/app/assets/styles/animate.css +71 -0
  2. package/app/assets/styles/colors.css +116 -0
  3. package/app/assets/styles/globals.css +43 -0
  4. package/app/assets/styles/index.stories.ts +211 -0
  5. package/app/assets/styles/transition.css +34 -0
  6. package/app/assets/styles/utilities.css +26 -0
  7. package/app/components/shadcn/accordion/Accordion.vue +18 -0
  8. package/app/components/shadcn/accordion/AccordionContent.vue +23 -0
  9. package/app/components/shadcn/accordion/AccordionItem.vue +24 -0
  10. package/app/components/shadcn/accordion/AccordionTrigger.vue +37 -0
  11. package/app/components/shadcn/accordion/index.ts +4 -0
  12. package/app/components/shadcn/alert/Alert.vue +21 -0
  13. package/app/components/shadcn/alert/AlertDescription.vue +17 -0
  14. package/app/components/shadcn/alert/AlertTitle.vue +17 -0
  15. package/app/components/shadcn/alert/index.ts +24 -0
  16. package/app/components/shadcn/avatar/Avatar.vue +18 -0
  17. package/app/components/shadcn/avatar/AvatarFallback.vue +21 -0
  18. package/app/components/shadcn/avatar/AvatarImage.vue +16 -0
  19. package/app/components/shadcn/avatar/index.ts +3 -0
  20. package/app/components/shadcn/badge/Badge.vue +26 -0
  21. package/app/components/shadcn/badge/index.ts +26 -0
  22. package/app/components/shadcn/breadcrumb/Breadcrumb.vue +17 -0
  23. package/app/components/shadcn/breadcrumb/BreadcrumbEllipsis.vue +23 -0
  24. package/app/components/shadcn/breadcrumb/BreadcrumbItem.vue +17 -0
  25. package/app/components/shadcn/breadcrumb/BreadcrumbLink.vue +21 -0
  26. package/app/components/shadcn/breadcrumb/BreadcrumbList.vue +17 -0
  27. package/app/components/shadcn/breadcrumb/BreadcrumbPage.vue +20 -0
  28. package/app/components/shadcn/breadcrumb/BreadcrumbSeparator.vue +22 -0
  29. package/app/components/shadcn/breadcrumb/index.ts +7 -0
  30. package/app/components/shadcn/button/Button.vue +31 -0
  31. package/app/components/shadcn/button/index.ts +38 -0
  32. package/app/components/shadcn/card/Card.vue +22 -0
  33. package/app/components/shadcn/card/CardAction.vue +17 -0
  34. package/app/components/shadcn/card/CardContent.vue +17 -0
  35. package/app/components/shadcn/card/CardDescription.vue +17 -0
  36. package/app/components/shadcn/card/CardFooter.vue +17 -0
  37. package/app/components/shadcn/card/CardHeader.vue +17 -0
  38. package/app/components/shadcn/card/CardTitle.vue +17 -0
  39. package/app/components/shadcn/card/index.ts +7 -0
  40. package/app/components/shadcn/checkbox/Checkbox.vue +35 -0
  41. package/app/components/shadcn/checkbox/index.ts +1 -0
  42. package/app/components/shadcn/collapsible/Collapsible.vue +19 -0
  43. package/app/components/shadcn/collapsible/CollapsibleContent.vue +15 -0
  44. package/app/components/shadcn/collapsible/CollapsibleTrigger.vue +15 -0
  45. package/app/components/shadcn/collapsible/index.ts +3 -0
  46. package/app/components/shadcn/command/Command.vue +87 -0
  47. package/app/components/shadcn/command/CommandDialog.vue +31 -0
  48. package/app/components/shadcn/command/CommandEmpty.vue +27 -0
  49. package/app/components/shadcn/command/CommandGroup.vue +45 -0
  50. package/app/components/shadcn/command/CommandInput.vue +39 -0
  51. package/app/components/shadcn/command/CommandItem.vue +76 -0
  52. package/app/components/shadcn/command/CommandList.vue +25 -0
  53. package/app/components/shadcn/command/CommandSeparator.vue +21 -0
  54. package/app/components/shadcn/command/CommandShortcut.vue +17 -0
  55. package/app/components/shadcn/command/index.ts +25 -0
  56. package/app/components/shadcn/dialog/Dialog.vue +19 -0
  57. package/app/components/shadcn/dialog/DialogClose.vue +15 -0
  58. package/app/components/shadcn/dialog/DialogContent.vue +53 -0
  59. package/app/components/shadcn/dialog/DialogDescription.vue +23 -0
  60. package/app/components/shadcn/dialog/DialogFooter.vue +27 -0
  61. package/app/components/shadcn/dialog/DialogHeader.vue +17 -0
  62. package/app/components/shadcn/dialog/DialogOverlay.vue +21 -0
  63. package/app/components/shadcn/dialog/DialogScrollContent.vue +59 -0
  64. package/app/components/shadcn/dialog/DialogTitle.vue +23 -0
  65. package/app/components/shadcn/dialog/DialogTrigger.vue +15 -0
  66. package/app/components/shadcn/dialog/index.ts +10 -0
  67. package/app/components/shadcn/dropdown-menu/DropdownMenu.vue +19 -0
  68. package/app/components/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +39 -0
  69. package/app/components/shadcn/dropdown-menu/DropdownMenuContent.vue +39 -0
  70. package/app/components/shadcn/dropdown-menu/DropdownMenuGroup.vue +15 -0
  71. package/app/components/shadcn/dropdown-menu/DropdownMenuItem.vue +31 -0
  72. package/app/components/shadcn/dropdown-menu/DropdownMenuLabel.vue +23 -0
  73. package/app/components/shadcn/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  74. package/app/components/shadcn/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  75. package/app/components/shadcn/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  76. package/app/components/shadcn/dropdown-menu/DropdownMenuShortcut.vue +17 -0
  77. package/app/components/shadcn/dropdown-menu/DropdownMenuSub.vue +18 -0
  78. package/app/components/shadcn/dropdown-menu/DropdownMenuSubContent.vue +27 -0
  79. package/app/components/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
  80. package/app/components/shadcn/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  81. package/app/components/shadcn/dropdown-menu/index.ts +16 -0
  82. package/app/components/shadcn/field/Field.vue +25 -0
  83. package/app/components/shadcn/field/FieldContent.vue +20 -0
  84. package/app/components/shadcn/field/FieldDescription.vue +22 -0
  85. package/app/components/shadcn/field/FieldError.vue +53 -0
  86. package/app/components/shadcn/field/FieldGroup.vue +20 -0
  87. package/app/components/shadcn/field/FieldLabel.vue +23 -0
  88. package/app/components/shadcn/field/FieldLegend.vue +24 -0
  89. package/app/components/shadcn/field/FieldSeparator.vue +29 -0
  90. package/app/components/shadcn/field/FieldSet.vue +21 -0
  91. package/app/components/shadcn/field/FieldTitle.vue +20 -0
  92. package/app/components/shadcn/field/index.ts +39 -0
  93. package/app/components/shadcn/input/Input.vue +33 -0
  94. package/app/components/shadcn/input/index.ts +1 -0
  95. package/app/components/shadcn/input-group/InputGroup.vue +35 -0
  96. package/app/components/shadcn/input-group/InputGroupAddon.vue +36 -0
  97. package/app/components/shadcn/input-group/InputGroupButton.vue +29 -0
  98. package/app/components/shadcn/input-group/InputGroupInput.vue +19 -0
  99. package/app/components/shadcn/input-group/InputGroupText.vue +19 -0
  100. package/app/components/shadcn/input-group/InputGroupTextarea.vue +19 -0
  101. package/app/components/shadcn/input-group/index.ts +51 -0
  102. package/app/components/shadcn/label/Label.vue +26 -0
  103. package/app/components/shadcn/label/index.ts +1 -0
  104. package/app/components/shadcn/number-field/NumberField.vue +20 -0
  105. package/app/components/shadcn/number-field/NumberFieldContent.vue +14 -0
  106. package/app/components/shadcn/number-field/NumberFieldDecrement.vue +22 -0
  107. package/app/components/shadcn/number-field/NumberFieldIncrement.vue +22 -0
  108. package/app/components/shadcn/number-field/NumberFieldInput.vue +16 -0
  109. package/app/components/shadcn/number-field/index.ts +5 -0
  110. package/app/components/shadcn/pagination/Pagination.vue +26 -0
  111. package/app/components/shadcn/pagination/PaginationContent.vue +22 -0
  112. package/app/components/shadcn/pagination/PaginationEllipsis.vue +25 -0
  113. package/app/components/shadcn/pagination/PaginationFirst.vue +33 -0
  114. package/app/components/shadcn/pagination/PaginationItem.vue +34 -0
  115. package/app/components/shadcn/pagination/PaginationLast.vue +33 -0
  116. package/app/components/shadcn/pagination/PaginationNext.vue +33 -0
  117. package/app/components/shadcn/pagination/PaginationPrevious.vue +33 -0
  118. package/app/components/shadcn/pagination/index.ts +8 -0
  119. package/app/components/shadcn/pin-input/PinInput.vue +26 -0
  120. package/app/components/shadcn/pin-input/PinInputGroup.vue +21 -0
  121. package/app/components/shadcn/pin-input/PinInputSeparator.vue +19 -0
  122. package/app/components/shadcn/pin-input/PinInputSlot.vue +21 -0
  123. package/app/components/shadcn/pin-input/index.ts +4 -0
  124. package/app/components/shadcn/popover/Popover.vue +19 -0
  125. package/app/components/shadcn/popover/PopoverAnchor.vue +15 -0
  126. package/app/components/shadcn/popover/PopoverContent.vue +45 -0
  127. package/app/components/shadcn/popover/PopoverTrigger.vue +15 -0
  128. package/app/components/shadcn/popover/index.ts +4 -0
  129. package/app/components/shadcn/progress/Progress.vue +38 -0
  130. package/app/components/shadcn/progress/index.ts +1 -0
  131. package/app/components/shadcn/radio-group/RadioGroup.vue +25 -0
  132. package/app/components/shadcn/radio-group/RadioGroupItem.vue +40 -0
  133. package/app/components/shadcn/radio-group/index.ts +2 -0
  134. package/app/components/shadcn/scroll-area/ScrollArea.vue +33 -0
  135. package/app/components/shadcn/scroll-area/ScrollBar.vue +32 -0
  136. package/app/components/shadcn/scroll-area/index.ts +2 -0
  137. package/app/components/shadcn/select/Select.vue +19 -0
  138. package/app/components/shadcn/select/SelectContent.vue +51 -0
  139. package/app/components/shadcn/select/SelectGroup.vue +15 -0
  140. package/app/components/shadcn/select/SelectItem.vue +44 -0
  141. package/app/components/shadcn/select/SelectItemText.vue +15 -0
  142. package/app/components/shadcn/select/SelectLabel.vue +17 -0
  143. package/app/components/shadcn/select/SelectScrollDownButton.vue +26 -0
  144. package/app/components/shadcn/select/SelectScrollUpButton.vue +26 -0
  145. package/app/components/shadcn/select/SelectSeparator.vue +19 -0
  146. package/app/components/shadcn/select/SelectTrigger.vue +33 -0
  147. package/app/components/shadcn/select/SelectValue.vue +15 -0
  148. package/app/components/shadcn/select/index.ts +11 -0
  149. package/app/components/shadcn/separator/Separator.vue +29 -0
  150. package/app/components/shadcn/separator/index.ts +1 -0
  151. package/app/components/shadcn/sheet/Sheet.vue +19 -0
  152. package/app/components/shadcn/sheet/SheetClose.vue +15 -0
  153. package/app/components/shadcn/sheet/SheetContent.vue +62 -0
  154. package/app/components/shadcn/sheet/SheetDescription.vue +21 -0
  155. package/app/components/shadcn/sheet/SheetFooter.vue +16 -0
  156. package/app/components/shadcn/sheet/SheetHeader.vue +15 -0
  157. package/app/components/shadcn/sheet/SheetOverlay.vue +21 -0
  158. package/app/components/shadcn/sheet/SheetTitle.vue +21 -0
  159. package/app/components/shadcn/sheet/SheetTrigger.vue +15 -0
  160. package/app/components/shadcn/sheet/index.ts +8 -0
  161. package/app/components/shadcn/sidebar/Sidebar.vue +96 -0
  162. package/app/components/shadcn/sidebar/SidebarContent.vue +18 -0
  163. package/app/components/shadcn/sidebar/SidebarFooter.vue +18 -0
  164. package/app/components/shadcn/sidebar/SidebarGroup.vue +18 -0
  165. package/app/components/shadcn/sidebar/SidebarGroupAction.vue +27 -0
  166. package/app/components/shadcn/sidebar/SidebarGroupContent.vue +18 -0
  167. package/app/components/shadcn/sidebar/SidebarGroupLabel.vue +25 -0
  168. package/app/components/shadcn/sidebar/SidebarHeader.vue +18 -0
  169. package/app/components/shadcn/sidebar/SidebarInput.vue +22 -0
  170. package/app/components/shadcn/sidebar/SidebarInset.vue +21 -0
  171. package/app/components/shadcn/sidebar/SidebarMenu.vue +18 -0
  172. package/app/components/shadcn/sidebar/SidebarMenuAction.vue +35 -0
  173. package/app/components/shadcn/sidebar/SidebarMenuBadge.vue +26 -0
  174. package/app/components/shadcn/sidebar/SidebarMenuButton.vue +48 -0
  175. package/app/components/shadcn/sidebar/SidebarMenuButtonChild.vue +36 -0
  176. package/app/components/shadcn/sidebar/SidebarMenuItem.vue +18 -0
  177. package/app/components/shadcn/sidebar/SidebarMenuSkeleton.vue +35 -0
  178. package/app/components/shadcn/sidebar/SidebarMenuSub.vue +22 -0
  179. package/app/components/shadcn/sidebar/SidebarMenuSubButton.vue +36 -0
  180. package/app/components/shadcn/sidebar/SidebarMenuSubItem.vue +18 -0
  181. package/app/components/shadcn/sidebar/SidebarProvider.vue +82 -0
  182. package/app/components/shadcn/sidebar/SidebarRail.vue +33 -0
  183. package/app/components/shadcn/sidebar/SidebarSeparator.vue +19 -0
  184. package/app/components/shadcn/sidebar/SidebarTrigger.vue +27 -0
  185. package/app/components/shadcn/sidebar/index.ts +60 -0
  186. package/app/components/shadcn/sidebar/utils.ts +19 -0
  187. package/app/components/shadcn/skeleton/Skeleton.vue +17 -0
  188. package/app/components/shadcn/skeleton/index.ts +1 -0
  189. package/app/components/shadcn/slider/Slider.vue +43 -0
  190. package/app/components/shadcn/slider/index.ts +1 -0
  191. package/app/components/shadcn/sonner/Sonner.vue +42 -0
  192. package/app/components/shadcn/sonner/index.ts +1 -0
  193. package/app/components/shadcn/switch/Switch.vue +38 -0
  194. package/app/components/shadcn/switch/index.ts +1 -0
  195. package/app/components/shadcn/table/Table.vue +16 -0
  196. package/app/components/shadcn/table/TableBody.vue +17 -0
  197. package/app/components/shadcn/table/TableCaption.vue +17 -0
  198. package/app/components/shadcn/table/TableCell.vue +22 -0
  199. package/app/components/shadcn/table/TableEmpty.vue +34 -0
  200. package/app/components/shadcn/table/TableFooter.vue +17 -0
  201. package/app/components/shadcn/table/TableHead.vue +17 -0
  202. package/app/components/shadcn/table/TableHeader.vue +17 -0
  203. package/app/components/shadcn/table/TableRow.vue +17 -0
  204. package/app/components/shadcn/table/index.ts +9 -0
  205. package/app/components/shadcn/table/utils.ts +10 -0
  206. package/app/components/shadcn/tabs/Tabs.vue +24 -0
  207. package/app/components/shadcn/tabs/TabsContent.vue +21 -0
  208. package/app/components/shadcn/tabs/TabsList.vue +24 -0
  209. package/app/components/shadcn/tabs/TabsTrigger.vue +26 -0
  210. package/app/components/shadcn/tabs/index.ts +4 -0
  211. package/app/components/shadcn/textarea/Textarea.vue +28 -0
  212. package/app/components/shadcn/textarea/index.ts +1 -0
  213. package/app/components/shadcn/toggle/Toggle.vue +35 -0
  214. package/app/components/shadcn/toggle/index.ts +28 -0
  215. package/app/components/shadcn/toggle-group/ToggleGroup.vue +49 -0
  216. package/app/components/shadcn/toggle-group/ToggleGroupItem.vue +46 -0
  217. package/app/components/shadcn/toggle-group/index.ts +2 -0
  218. package/app/components/shadcn/tooltip/Tooltip.vue +19 -0
  219. package/app/components/shadcn/tooltip/TooltipContent.vue +34 -0
  220. package/app/components/shadcn/tooltip/TooltipProvider.vue +14 -0
  221. package/app/components/shadcn/tooltip/TooltipTrigger.vue +15 -0
  222. package/app/components/shadcn/tooltip/index.ts +4 -0
  223. package/app/components/ui/Accordion/index.stories.ts +108 -0
  224. package/app/components/ui/Accordion/index.vue +80 -0
  225. package/app/components/ui/Accordion/types.ts +27 -0
  226. package/app/components/ui/Alert/index.stories.ts +53 -0
  227. package/app/components/ui/Alert/index.vue +61 -0
  228. package/app/components/ui/Alert/types.ts +9 -0
  229. package/app/components/ui/AlertDialog/index.stories.ts +108 -0
  230. package/app/components/ui/AlertDialog/index.vue +25 -0
  231. package/app/components/ui/AsyncDataTable/en.json +3 -0
  232. package/app/components/ui/AsyncDataTable/index.stories.ts +141 -0
  233. package/app/components/ui/AsyncDataTable/index.vue +312 -0
  234. package/app/components/ui/AsyncDataTable/types.ts +53 -0
  235. package/app/components/ui/Avatar/index.stories.ts +84 -0
  236. package/app/components/ui/Avatar/index.vue +52 -0
  237. package/app/components/ui/Avatar/types.ts +8 -0
  238. package/app/components/ui/Badge/index.stories.ts +67 -0
  239. package/app/components/ui/Badge/index.vue +12 -0
  240. package/app/components/ui/Badge/types.ts +3 -0
  241. package/app/components/ui/Breadcrumb/index.stories.ts +52 -0
  242. package/app/components/ui/Breadcrumb/index.vue +61 -0
  243. package/app/components/ui/Breadcrumb/types.ts +11 -0
  244. package/app/components/ui/Button/index.stories.ts +145 -0
  245. package/app/components/ui/Button/index.vue +63 -0
  246. package/app/components/ui/Button/types.ts +14 -0
  247. package/app/components/ui/ButtonGroup/index.stories.ts +75 -0
  248. package/app/components/ui/ButtonGroup/index.vue +22 -0
  249. package/app/components/ui/ButtonGroup/types.ts +3 -0
  250. package/app/components/ui/Card/index.stories.ts +65 -0
  251. package/app/components/ui/Card/index.vue +28 -0
  252. package/app/components/ui/Card/types.ts +3 -0
  253. package/app/components/ui/Checkbox/index.stories.ts +68 -0
  254. package/app/components/ui/Checkbox/index.vue +23 -0
  255. package/app/components/ui/Checkbox/types.ts +3 -0
  256. package/app/components/ui/CopyButton/en.json +4 -0
  257. package/app/components/ui/CopyButton/index.stories.ts +55 -0
  258. package/app/components/ui/CopyButton/index.vue +98 -0
  259. package/app/components/ui/CopyButton/types.ts +10 -0
  260. package/app/components/ui/DataTable/en.json +3 -0
  261. package/app/components/ui/DataTable/index.stories.ts +231 -0
  262. package/app/components/ui/DataTable/index.vue +505 -0
  263. package/app/components/ui/DataTable/types.ts +42 -0
  264. package/app/components/ui/DatePicker/en.json +9 -0
  265. package/app/components/ui/DatePicker/index.stories.ts +70 -0
  266. package/app/components/ui/DatePicker/index.vue +127 -0
  267. package/app/components/ui/DatePicker/style.css +88 -0
  268. package/app/components/ui/DatePicker/types.ts +41 -0
  269. package/app/components/ui/DateRangePicker/en.json +5 -0
  270. package/app/components/ui/DateRangePicker/index.stories.ts +67 -0
  271. package/app/components/ui/DateRangePicker/index.vue +138 -0
  272. package/app/components/ui/DateRangePicker/types.ts +31 -0
  273. package/app/components/ui/Divider/index.stories.ts +42 -0
  274. package/app/components/ui/Divider/index.vue +16 -0
  275. package/app/components/ui/Divider/types.ts +3 -0
  276. package/app/components/ui/Drawer/index.stories.ts +124 -0
  277. package/app/components/ui/Drawer/index.vue +197 -0
  278. package/app/components/ui/Drawer/types.ts +22 -0
  279. package/app/components/ui/Dropdown/index.stories.ts +145 -0
  280. package/app/components/ui/Dropdown/index.vue +258 -0
  281. package/app/components/ui/Dropdown/types.ts +87 -0
  282. package/app/components/ui/FormItem/index.stories.ts +70 -0
  283. package/app/components/ui/FormItem/index.vue +56 -0
  284. package/app/components/ui/FormItem/types.ts +14 -0
  285. package/app/components/ui/Help/index.stories.ts +54 -0
  286. package/app/components/ui/Help/index.vue +35 -0
  287. package/app/components/ui/Help/types.ts +8 -0
  288. package/app/components/ui/Icon/index.stories.ts +68 -0
  289. package/app/components/ui/Icon/index.vue +30 -0
  290. package/app/components/ui/Icon/types.ts +5 -0
  291. package/app/components/ui/Input/index.stories.ts +73 -0
  292. package/app/components/ui/Input/index.vue +92 -0
  293. package/app/components/ui/Input/types.ts +9 -0
  294. package/app/components/ui/InputCurrency/index.stories.ts +75 -0
  295. package/app/components/ui/InputCurrency/index.vue +31 -0
  296. package/app/components/ui/InputCurrency/types.ts +4 -0
  297. package/app/components/ui/InputNumber/index.stories.ts +56 -0
  298. package/app/components/ui/InputNumber/index.vue +76 -0
  299. package/app/components/ui/InputNumber/types.ts +10 -0
  300. package/app/components/ui/InputOtp/index.stories.ts +39 -0
  301. package/app/components/ui/InputOtp/index.vue +45 -0
  302. package/app/components/ui/InputOtp/types.ts +5 -0
  303. package/app/components/ui/InputPercent/index.stories.ts +32 -0
  304. package/app/components/ui/InputPercent/index.vue +8 -0
  305. package/app/components/ui/InputRange/index.stories.ts +37 -0
  306. package/app/components/ui/InputRange/index.vue +49 -0
  307. package/app/components/ui/InputRange/types.ts +8 -0
  308. package/app/components/ui/Loading/index.stories.ts +36 -0
  309. package/app/components/ui/Loading/index.vue +15 -0
  310. package/app/components/ui/Loading/types.ts +3 -0
  311. package/app/components/ui/Markdown/index.stories.ts +52 -0
  312. package/app/components/ui/Markdown/index.vue +22 -0
  313. package/app/components/ui/Markdown/themes/github.css +1248 -0
  314. package/app/components/ui/Markdown/types.ts +3 -0
  315. package/app/components/ui/Modal/index.stories.ts +124 -0
  316. package/app/components/ui/Modal/index.vue +202 -0
  317. package/app/components/ui/Modal/types.ts +23 -0
  318. package/app/components/ui/ModalContent/index.stories.ts +47 -0
  319. package/app/components/ui/ModalContent/index.vue +79 -0
  320. package/app/components/ui/ModalContent/types.ts +9 -0
  321. package/app/components/ui/PageCard/index.stories.ts +106 -0
  322. package/app/components/ui/PageCard/index.vue +135 -0
  323. package/app/components/ui/PageCard/types.ts +16 -0
  324. package/app/components/ui/Pagination/en.json +3 -0
  325. package/app/components/ui/Pagination/index.stories.ts +82 -0
  326. package/app/components/ui/Pagination/index.vue +173 -0
  327. package/app/components/ui/Pagination/types.ts +18 -0
  328. package/app/components/ui/Popover/index.stories.ts +67 -0
  329. package/app/components/ui/Popover/index.vue +21 -0
  330. package/app/components/ui/Popover/types.ts +5 -0
  331. package/app/components/ui/Qrcode/index.stories.ts +57 -0
  332. package/app/components/ui/Qrcode/index.vue +40 -0
  333. package/app/components/ui/Qrcode/types.ts +3 -0
  334. package/app/components/ui/Radio/index.stories.ts +71 -0
  335. package/app/components/ui/Radio/index.vue +10 -0
  336. package/app/components/ui/Radio/types.ts +3 -0
  337. package/app/components/ui/RadioCardGroup/index.stories.ts +90 -0
  338. package/app/components/ui/RadioCardGroup/index.vue +64 -0
  339. package/app/components/ui/RadioCardGroup/types.ts +13 -0
  340. package/app/components/ui/ScrollArea/index.stories.ts +66 -0
  341. package/app/components/ui/ScrollArea/index.vue +64 -0
  342. package/app/components/ui/ScrollArea/types.ts +5 -0
  343. package/app/components/ui/SearchSelect/en.json +5 -0
  344. package/app/components/ui/SearchSelect/index.stories.ts +126 -0
  345. package/app/components/ui/SearchSelect/index.vue +259 -0
  346. package/app/components/ui/SearchSelect/types.ts +39 -0
  347. package/app/components/ui/Select/en.json +6 -0
  348. package/app/components/ui/Select/index.stories.ts +128 -0
  349. package/app/components/ui/Select/index.vue +267 -0
  350. package/app/components/ui/Select/types.ts +34 -0
  351. package/app/components/ui/Skeleton/index.stories.ts +56 -0
  352. package/app/components/ui/Skeleton/index.vue +12 -0
  353. package/app/components/ui/Skeleton/types.ts +4 -0
  354. package/app/components/ui/Slider/index.stories.ts +60 -0
  355. package/app/components/ui/Slider/index.vue +27 -0
  356. package/app/components/ui/Slider/types.ts +5 -0
  357. package/app/components/ui/Surface/index.stories.ts +50 -0
  358. package/app/components/ui/Surface/index.vue +108 -0
  359. package/app/components/ui/Surface/types.ts +8 -0
  360. package/app/components/ui/Switch/index.stories.ts +32 -0
  361. package/app/components/ui/Switch/index.vue +10 -0
  362. package/app/components/ui/Switch/types.ts +3 -0
  363. package/app/components/ui/Tabs/index.stories.ts +116 -0
  364. package/app/components/ui/Tabs/index.vue +94 -0
  365. package/app/components/ui/Tabs/types.ts +19 -0
  366. package/app/components/ui/Tag/index.stories.ts +51 -0
  367. package/app/components/ui/Tag/index.vue +108 -0
  368. package/app/components/ui/Tag/types.ts +8 -0
  369. package/app/components/ui/Textarea/index.stories.ts +35 -0
  370. package/app/components/ui/Textarea/index.vue +50 -0
  371. package/app/components/ui/Textarea/types.ts +8 -0
  372. package/app/components/ui/Toast/index.stories.ts +48 -0
  373. package/app/components/ui/Toast/index.vue +21 -0
  374. package/app/components/ui/Toast/types.ts +5 -0
  375. package/app/components/ui/Tooltip/index.stories.ts +62 -0
  376. package/app/components/ui/Tooltip/index.vue +72 -0
  377. package/app/components/ui/Tooltip/types.ts +7 -0
  378. package/app/components/ui/WebLink/index.stories.ts +59 -0
  379. package/app/components/ui/WebLink/index.vue +61 -0
  380. package/app/components/ui/WebLink/types.ts +11 -0
  381. package/app/composables/index.ts +9 -0
  382. package/app/composables/useDialog.ts +76 -0
  383. package/app/composables/useToast.ts +49 -0
  384. package/app/en.json +23 -0
  385. package/app/types/index.ts +7 -0
  386. package/app/utils/index.ts +6 -0
  387. package/i18n/messages/ar.json +65 -0
  388. package/i18n/messages/de.json +65 -0
  389. package/i18n/messages/en.json +65 -0
  390. package/i18n/messages/es.json +65 -0
  391. package/i18n/messages/fr.json +65 -0
  392. package/i18n/messages/hi.json +65 -0
  393. package/i18n/messages/id.json +65 -0
  394. package/i18n/messages/it.json +65 -0
  395. package/i18n/messages/ja.json +65 -0
  396. package/i18n/messages/ko.json +65 -0
  397. package/i18n/messages/nl.json +65 -0
  398. package/i18n/messages/pl.json +65 -0
  399. package/i18n/messages/pt.json +65 -0
  400. package/i18n/messages/ru.json +65 -0
  401. package/i18n/messages/th.json +65 -0
  402. package/i18n/messages/tr.json +65 -0
  403. package/i18n/messages/vi.json +65 -0
  404. package/i18n/messages/zh-CN.json +65 -0
  405. package/i18n/messages/zh-TW.json +65 -0
  406. package/i18n.config.ts +19 -0
  407. package/nuxt.config.ts +62 -0
  408. package/package.json +46 -0
@@ -0,0 +1,51 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import Tag from './index.vue'
3
+
4
+ type TagType = 'default' | 'success' | 'info' | 'help' | 'warn' | 'danger'
5
+ type TagVariant = 'solid' | 'soft' | 'bordered' | 'flat'
6
+
7
+ const types: TagType[] = [ 'default', 'success', 'info', 'help', 'warn', 'danger' ]
8
+ const variants: TagVariant[] = [ 'solid', 'soft', 'bordered', 'flat' ]
9
+
10
+ const meta = {
11
+ title: 'UI/Tag',
12
+ component: Tag,
13
+ argTypes: {
14
+ type: { control: 'select', options: types },
15
+ variant: { control: 'select', options: variants },
16
+ },
17
+ args: {
18
+ type: 'default',
19
+ variant: 'soft',
20
+ },
21
+ } satisfies Meta<typeof Tag>
22
+
23
+ export default meta
24
+ type Story = StoryObj<typeof meta>
25
+
26
+ export const Default: Story = {
27
+ render: args => ({
28
+ components: { Tag },
29
+ setup: () => ({ args, types, variants }),
30
+ template: `
31
+ <div class="space-y-10">
32
+ <!-- Controlled -->
33
+ <section>
34
+ <h3 class="mb-4 text-lg font-medium">Controlled</h3>
35
+ <Tag v-bind="args">Tag</Tag>
36
+ </section>
37
+
38
+ <!-- Variants × Types matrix -->
39
+ <section>
40
+ <h3 class="mb-4 text-lg font-medium">Variants × Types</h3>
41
+ <div class="space-y-3">
42
+ <div v-for="v in variants" :key="v" class="flex flex-wrap items-center gap-3">
43
+ <span class="w-20 text-sm text-muted-foreground">{{ v }}</span>
44
+ <Tag v-for="t in types" :key="t" :type="t" :variant="v">{{ t }}</Tag>
45
+ </div>
46
+ </div>
47
+ </section>
48
+ </div>
49
+ `,
50
+ }),
51
+ }
@@ -0,0 +1,108 @@
1
+ <script setup lang="ts">
2
+ import { cva } from 'class-variance-authority'
3
+ import type { TagProps } from './types'
4
+
5
+ const tagVariants = cva(
6
+ 'inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium',
7
+ {
8
+ variants: {
9
+ variant: {
10
+ solid: 'border',
11
+ soft: 'border',
12
+ bordered: 'border bg-transparent',
13
+ flat: '',
14
+ },
15
+ type: {
16
+ default: '',
17
+ success: '',
18
+ info: '',
19
+ help: '',
20
+ warn: '',
21
+ danger: '',
22
+ },
23
+ },
24
+ compoundVariants: [
25
+ // solid — full color background
26
+ { variant: 'solid', type: 'default', class: `
27
+ border-transparent bg-accent text-accent-foreground
28
+ ` },
29
+ { variant: 'solid', type: 'success', class: `
30
+ border-success bg-success text-success-foreground
31
+ ` },
32
+ { variant: 'solid', type: 'info', class: `
33
+ border-info bg-info text-info-foreground
34
+ ` },
35
+ { variant: 'solid', type: 'help', class: `
36
+ border-help bg-help text-help-foreground
37
+ ` },
38
+ { variant: 'solid', type: 'warn', class: `
39
+ border-warn bg-warn text-warn-foreground
40
+ ` },
41
+ { variant: 'solid', type: 'danger', class: `
42
+ border-danger bg-danger text-danger-foreground
43
+ ` },
44
+ // soft — tinted background + soft border
45
+ { variant: 'soft', type: 'default', class: `
46
+ border-border bg-secondary text-secondary-foreground
47
+ ` },
48
+ { variant: 'soft', type: 'success', class: `
49
+ border-success/50 bg-success/10 text-success
50
+ ` },
51
+ { variant: 'soft', type: 'info', class: `
52
+ border-info/50 bg-info/10 text-info
53
+ ` },
54
+ { variant: 'soft', type: 'help', class: `
55
+ border-help/50 bg-help/10 text-help
56
+ ` },
57
+ { variant: 'soft', type: 'warn', class: `
58
+ border-warn/50 bg-warn/10 text-warn
59
+ ` },
60
+ { variant: 'soft', type: 'danger', class: `
61
+ border-danger/50 bg-danger/10 text-danger
62
+ ` },
63
+ // bordered — border only
64
+ { variant: 'bordered', type: 'default', class: `
65
+ border-border text-foreground
66
+ ` },
67
+ { variant: 'bordered', type: 'success', class: `
68
+ border-success/50 text-success
69
+ ` },
70
+ { variant: 'bordered', type: 'info', class: 'border-info/50 text-info' },
71
+ { variant: 'bordered', type: 'help', class: 'border-help/50 text-help' },
72
+ { variant: 'bordered', type: 'warn', class: 'border-warn/50 text-warn' },
73
+ { variant: 'bordered', type: 'danger', class: `
74
+ border-danger/50 text-danger
75
+ ` },
76
+ // flat — tinted background only
77
+ { variant: 'flat', type: 'default', class: `
78
+ bg-secondary text-secondary-foreground
79
+ ` },
80
+ { variant: 'flat', type: 'success', class: 'bg-success/10 text-success' },
81
+ { variant: 'flat', type: 'info', class: 'bg-info/10 text-info' },
82
+ { variant: 'flat', type: 'help', class: 'bg-help/10 text-help' },
83
+ { variant: 'flat', type: 'warn', class: 'bg-warn/10 text-warn' },
84
+ { variant: 'flat', type: 'danger', class: 'bg-danger/10 text-danger' },
85
+ ],
86
+ defaultVariants: {
87
+ variant: 'soft',
88
+ type: 'default',
89
+ },
90
+ },
91
+ )
92
+
93
+ const props = withDefaults(defineProps<TagProps>(), {
94
+ type: 'default',
95
+ variant: 'soft',
96
+ class: undefined,
97
+ })
98
+
99
+ const mergedClass = computed(() =>
100
+ cn(tagVariants({ type: props.type, variant: props.variant }), props.class),
101
+ )
102
+ </script>
103
+
104
+ <template>
105
+ <span :class="mergedClass">
106
+ <slot />
107
+ </span>
108
+ </template>
@@ -0,0 +1,8 @@
1
+ export type TagType = 'default' | 'success' | 'info' | 'help' | 'warn' | 'danger'
2
+ export type TagVariant = 'solid' | 'soft' | 'bordered' | 'flat'
3
+
4
+ export interface TagProps {
5
+ type?: TagType
6
+ variant?: TagVariant
7
+ class?: ClassValue
8
+ }
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import Textarea from './index.vue'
3
+
4
+ const meta = {
5
+ title: 'UI/Textarea',
6
+ component: Textarea,
7
+ argTypes: {
8
+ disabled: { control: 'boolean' },
9
+ readonly: { control: 'boolean' },
10
+ invalid: { control: 'boolean' },
11
+ },
12
+ args: {
13
+ disabled: false,
14
+ readonly: false,
15
+ invalid: false,
16
+ },
17
+ } satisfies Meta
18
+
19
+ export default meta
20
+ type Story = StoryObj<typeof meta>
21
+
22
+ export const Default: Story = {
23
+ render: args => ({
24
+ components: { Textarea },
25
+ setup: () => ({ args }),
26
+ template: `
27
+ <div class="max-w-sm">
28
+ <section>
29
+ <h3 class="mb-4 text-lg font-medium">Controlled</h3>
30
+ <Textarea v-bind="args" placeholder="Type your message here..." />
31
+ </section>
32
+ </div>
33
+ `,
34
+ }),
35
+ }
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import { Textarea as ShadcnTextarea } from '@polymarbot/nuxt-layer-shadcn-ui/app/components/shadcn/textarea'
3
+ import type { TextareaProps } from './types'
4
+
5
+ defineOptions({ inheritAttrs: false })
6
+
7
+ const props = withDefaults(defineProps<TextareaProps>(), {
8
+ modelValue: undefined,
9
+ autocomplete: undefined,
10
+ rows: undefined,
11
+ invalid: false,
12
+ class: undefined,
13
+ })
14
+
15
+ const emit = defineEmits<{
16
+ 'update:modelValue': [value: string]
17
+ 'change': [value: string]
18
+ }>()
19
+
20
+ function handleInput (event: Event) {
21
+ const target = event.target as HTMLTextAreaElement
22
+ emit('update:modelValue', target.value)
23
+ }
24
+
25
+ function handleChange (event: Event) {
26
+ const target = event.target as HTMLTextAreaElement
27
+ emit('change', target.value)
28
+ }
29
+
30
+ const mergedClass = computed(() =>
31
+ cn(
32
+ props.rows ? 'field-sizing-fixed!' : '',
33
+ props.class,
34
+ ),
35
+ )
36
+ </script>
37
+
38
+ <template>
39
+ <ShadcnTextarea
40
+ :modelValue="modelValue"
41
+ :rows="rows"
42
+ :class="mergedClass"
43
+ :aria-invalid="invalid || undefined"
44
+ :data-1p-ignore="autocomplete === 'off' || !autocomplete ? true : undefined"
45
+ :autocomplete="autocomplete || 'off'"
46
+ v-bind="$attrs"
47
+ @input="handleInput"
48
+ @change="handleChange"
49
+ />
50
+ </template>
@@ -0,0 +1,8 @@
1
+ export interface TextareaProps {
2
+ modelValue?: string
3
+ /** Set to enable browser/password-manager autofill. Defaults to 'off'. */
4
+ autocomplete?: string
5
+ rows?: number
6
+ invalid?: boolean
7
+ class?: ClassValue
8
+ }
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import { toast } from 'vue-sonner'
3
+ import Button from '../Button/index.vue'
4
+ import Toast from './index.vue'
5
+
6
+ const meta = {
7
+ title: 'UI/Toast',
8
+ component: Toast,
9
+ } satisfies Meta<typeof Toast>
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof meta>
13
+
14
+ export const Default: Story = {
15
+ render: () => ({
16
+ components: { Toast, Button },
17
+ setup () {
18
+ const showDefault = () => toast('This is a default toast')
19
+ const showSuccess = () => toast.success('Operation completed successfully')
20
+ const showError = () => toast.error('Something went wrong')
21
+ const showInfo = () => toast.info('Here is some information')
22
+ const showWarning = () => toast.warning('Please be careful')
23
+ const showWithDescription = () => toast('Event created', { description: 'Your event has been scheduled for tomorrow at 3:00 PM.' })
24
+ return { showDefault, showSuccess, showError, showInfo, showWarning, showWithDescription }
25
+ },
26
+ template: `
27
+ <div class="space-y-10">
28
+ <Toast position="bottom-right" />
29
+
30
+ <section>
31
+ <h3 class="mb-4 text-lg font-medium">Toast Types</h3>
32
+ <div class="flex flex-wrap gap-3">
33
+ <Button variant="outline" @click="showDefault">Default</Button>
34
+ <Button variant="outline" @click="showSuccess">Success</Button>
35
+ <Button variant="outline" @click="showError">Error</Button>
36
+ <Button variant="outline" @click="showInfo">Info</Button>
37
+ <Button variant="outline" @click="showWarning">Warning</Button>
38
+ </div>
39
+ </section>
40
+
41
+ <section>
42
+ <h3 class="mb-4 text-lg font-medium">With Description</h3>
43
+ <Button variant="outline" @click="showWithDescription">Show Toast with Description</Button>
44
+ </section>
45
+ </div>
46
+ `,
47
+ }),
48
+ }
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import { Toaster as ShadcnSonner } from '@polymarbot/nuxt-layer-shadcn-ui/app/components/shadcn/sonner'
3
+ import 'vue-sonner/style.css'
4
+ import type { ToastProps } from './types'
5
+
6
+ defineProps<ToastProps>()
7
+ </script>
8
+
9
+ <template>
10
+ <ShadcnSonner
11
+ :position="position ?? 'bottom-right'"
12
+ :duration="5000"
13
+ richColors
14
+ closeButton
15
+ :style="{
16
+ '--normal-bg': 'var(--color-popover)',
17
+ '--normal-text': 'var(--color-popover-foreground)',
18
+ '--normal-border': 'var(--color-border)',
19
+ }"
20
+ />
21
+ </template>
@@ -0,0 +1,5 @@
1
+ export type ToastPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'top-center' | 'bottom-center'
2
+
3
+ export interface ToastProps {
4
+ position?: ToastPosition
5
+ }
@@ -0,0 +1,62 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import Button from '../Button/index.vue'
3
+ import Tooltip from './index.vue'
4
+
5
+ const meta = {
6
+ title: 'UI/Tooltip',
7
+ component: Tooltip,
8
+ argTypes: {
9
+ disabled: { control: 'boolean' },
10
+ },
11
+ args: {
12
+ disabled: false,
13
+ },
14
+ } satisfies Meta<typeof Tooltip>
15
+
16
+ export default meta
17
+ type Story = StoryObj<typeof meta>
18
+
19
+ export const Default: Story = {
20
+ render: args => ({
21
+ components: { Tooltip, Button },
22
+ setup: () => ({ args }),
23
+ template: `
24
+ <div class="space-y-10">
25
+ <!-- Controlled -->
26
+ <section>
27
+ <h3 class="mb-4 text-lg font-medium">Controlled</h3>
28
+ <Tooltip text="This is a tooltip" v-bind="args">
29
+ <Button variant="outline">Hover me</Button>
30
+ </Tooltip>
31
+ </section>
32
+
33
+ <!-- Positions -->
34
+ <section>
35
+ <h3 class="mb-4 text-lg font-medium">Positions</h3>
36
+ <div class="flex flex-wrap items-center gap-4 py-10 justify-center">
37
+ <Tooltip text="Top tooltip" position="top">
38
+ <Button variant="outline">Top</Button>
39
+ </Tooltip>
40
+ <Tooltip text="Bottom tooltip" position="bottom">
41
+ <Button variant="outline">Bottom</Button>
42
+ </Tooltip>
43
+ <Tooltip text="Left tooltip" position="left">
44
+ <Button variant="outline">Left</Button>
45
+ </Tooltip>
46
+ <Tooltip text="Right tooltip" position="right">
47
+ <Button variant="outline">Right</Button>
48
+ </Tooltip>
49
+ </div>
50
+ </section>
51
+
52
+ <!-- Long Text -->
53
+ <section>
54
+ <h3 class="mb-4 text-lg font-medium">Long Text</h3>
55
+ <Tooltip text="This is a longer tooltip message that demonstrates how the tooltip handles multi-line content and wraps properly within its container.">
56
+ <Button variant="outline">Long Tooltip</Button>
57
+ </Tooltip>
58
+ </section>
59
+ </div>
60
+ `,
61
+ }),
62
+ }
@@ -0,0 +1,72 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ Tooltip as ShadcnTooltip,
4
+ TooltipContent,
5
+ TooltipProvider,
6
+ TooltipTrigger,
7
+ } from '@polymarbot/nuxt-layer-shadcn-ui/app/components/shadcn/tooltip'
8
+ import type { TooltipProps } from './types'
9
+
10
+ const props = withDefaults(defineProps<TooltipProps>(), {
11
+ text: undefined,
12
+ position: 'top',
13
+ disabled: false,
14
+ class: undefined,
15
+ })
16
+
17
+ const emit = defineEmits<{ open: [], close: []}>()
18
+
19
+ const { isMobile } = useDevice()
20
+
21
+ const sanitizedText = computed(() => props.text ? safeHtml(props.text) : '')
22
+ const shouldShow = computed(() => !!props.text && !props.disabled)
23
+
24
+ // Mobile: programmatic open via touch; Desktop: undefined = uncontrolled
25
+ const mobileOpen = ref<boolean | undefined>(undefined)
26
+
27
+ function onTouchStart () {
28
+ if (isMobile.value) {
29
+ mobileOpen.value = true
30
+ }
31
+ }
32
+
33
+ function onOpenChange (value: boolean) {
34
+ if (isMobile.value) {
35
+ mobileOpen.value = value
36
+ }
37
+ if (value) {
38
+ emit('open')
39
+ } else {
40
+ emit('close')
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <TooltipProvider
47
+ :delayDuration="isMobile ? 0 : 300"
48
+ :disableClosingTrigger="disableClosingTrigger || isMobile"
49
+ >
50
+ <ShadcnTooltip
51
+ :open="mobileOpen"
52
+ @update:open="onOpenChange"
53
+ >
54
+ <TooltipTrigger
55
+ asChild
56
+ @touchstart.passive="onTouchStart"
57
+ >
58
+ <slot />
59
+ </TooltipTrigger>
60
+ <TooltipContent
61
+ v-if="shouldShow"
62
+ :side="position"
63
+ class="max-w-[24rem]"
64
+ >
65
+ <span
66
+ :class="props.class"
67
+ v-html="sanitizedText"
68
+ />
69
+ </TooltipContent>
70
+ </ShadcnTooltip>
71
+ </TooltipProvider>
72
+ </template>
@@ -0,0 +1,7 @@
1
+ export interface TooltipProps {
2
+ text?: string
3
+ position?: 'top' | 'bottom' | 'left' | 'right'
4
+ disabled?: boolean
5
+ disableClosingTrigger?: boolean
6
+ class?: ClassValue
7
+ }
@@ -0,0 +1,59 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import WebLink from './index.vue'
3
+
4
+ const meta = {
5
+ title: 'UI/WebLink',
6
+ component: WebLink,
7
+ } satisfies Meta<typeof WebLink>
8
+
9
+ export default meta
10
+ type Story = StoryObj<typeof meta>
11
+
12
+ export const Default: Story = {
13
+ render: () => ({
14
+ components: { WebLink },
15
+ template: `
16
+ <div class="space-y-10">
17
+ <section>
18
+ <h3 class="mb-4 text-lg font-medium">Internal Link</h3>
19
+ <WebLink href="/dashboard">Go to Dashboard</WebLink>
20
+ </section>
21
+
22
+ <section>
23
+ <h3 class="mb-4 text-lg font-medium">External Link</h3>
24
+ <WebLink href="https://example.com">Visit Example.com</WebLink>
25
+ <p class="mt-1 text-sm text-muted-foreground">External links automatically open in a new tab and show a trailing icon.</p>
26
+ </section>
27
+
28
+ <section>
29
+ <h3 class="mb-4 text-lg font-medium">External Link without Icon</h3>
30
+ <WebLink href="https://example.com" :externalIcon="false">No trailing icon</WebLink>
31
+ </section>
32
+
33
+ <section>
34
+ <h3 class="mb-4 text-lg font-medium">With Explicit Target</h3>
35
+ <WebLink href="https://example.com" target="_self">Same Tab External Link</WebLink>
36
+ </section>
37
+
38
+ <section>
39
+ <h3 class="mb-4 text-lg font-medium">Unstyled</h3>
40
+ <div class="flex flex-col gap-2">
41
+ <WebLink href="/settings" unstyled>Unstyled internal link (no color or underline)</WebLink>
42
+ <WebLink href="https://example.com" unstyled>Unstyled external link (icon still shows)</WebLink>
43
+ </div>
44
+ </section>
45
+
46
+ <section>
47
+ <h3 class="mb-4 text-lg font-medium">Inline Usage</h3>
48
+ <p class="text-sm">
49
+ Please read our
50
+ <WebLink href="https://example.com/terms">Terms of Service</WebLink>
51
+ and
52
+ <WebLink href="https://example.com/privacy">Privacy Policy</WebLink>
53
+ before continuing.
54
+ </p>
55
+ </section>
56
+ </div>
57
+ `,
58
+ }),
59
+ }
@@ -0,0 +1,61 @@
1
+ <script setup lang="ts">
2
+ import type { RouteLocationRaw } from 'vue-router'
3
+ import type { WebLinkProps } from './types'
4
+
5
+ const props = withDefaults(defineProps<WebLinkProps>(), {
6
+ href: undefined,
7
+ to: undefined,
8
+ target: undefined,
9
+ externalIcon: true,
10
+ class: undefined,
11
+ })
12
+
13
+ const localePath = useLocalePath()
14
+
15
+ const isExternal = computed(() => props.href ? isUrl(props.href) : false)
16
+
17
+ const showExternalIcon = computed(() => props.externalIcon && isExternal.value)
18
+
19
+ // Compute the final destination (supports both href string and to route object)
20
+ const finalTo = computed<RouteLocationRaw | undefined>(() => {
21
+ if (props.to) return props.to
22
+ if (props.href) {
23
+ // Apply locale path for internal links only
24
+ return isExternal.value ? props.href : localePath(props.href)
25
+ }
26
+ return undefined
27
+ })
28
+ const finalTarget = computed(() => {
29
+ if (props.target) return props.target
30
+ // Auto set _blank for external links
31
+ return isExternal.value ? '_blank' : undefined
32
+ })
33
+ const finalRel = computed(() => {
34
+ // Add security attrs for external links opening in new tab
35
+ return finalTarget.value === '_blank' ? 'noopener noreferrer' : undefined
36
+ })
37
+
38
+ // Merge default class with external class
39
+ const mergedClass = computed(() => {
40
+ if (props.unstyled) {
41
+ return props.class
42
+ }
43
+ return cn('text-info underline', props.class)
44
+ })
45
+ </script>
46
+
47
+ <template>
48
+ <NuxtLink
49
+ :to="finalTo"
50
+ :target="finalTarget"
51
+ :rel="finalRel"
52
+ :class="mergedClass"
53
+ >
54
+ <slot />
55
+ <Icon
56
+ v-if="showExternalIcon"
57
+ name="external-link"
58
+ class="ml-0.5 inline size-[1em] align-[-0.125em]"
59
+ />
60
+ </NuxtLink>
61
+ </template>
@@ -0,0 +1,11 @@
1
+ import type { NuxtLinkProps } from '#app'
2
+ import type { RouteLocationRaw } from 'vue-router'
3
+
4
+ export interface WebLinkProps extends /* @vue-ignore */ NuxtLinkProps {
5
+ href?: string
6
+ to?: RouteLocationRaw
7
+ target?: string
8
+ unstyled?: boolean
9
+ externalIcon?: boolean
10
+ class?: ClassValue
11
+ }
@@ -0,0 +1,9 @@
1
+ // Re-export shared composables used by this layer. Nuxt auto-imports everything
2
+ // exported from `app/composables/**`, so listed symbols become global.
3
+ export {
4
+ useScrollState,
5
+ useDevice,
6
+ usePagination,
7
+ useTranslations,
8
+ useDate,
9
+ } from '@polymarbot/uitls-shared/vue/composables'