@stacksjs/defaults 0.70.54

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 (286) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +2 -0
  3. package/package.json +20 -0
  4. package/resources/assets/fonts/013717e9.woff +0 -0
  5. package/resources/assets/fonts/03355817.woff2 +0 -0
  6. package/resources/assets/fonts/0380de7e.woff2 +0 -0
  7. package/resources/assets/fonts/0ba5d32a.woff +0 -0
  8. package/resources/assets/fonts/0bd57ddf.woff2 +0 -0
  9. package/resources/assets/fonts/19de0a60.woff2 +0 -0
  10. package/resources/assets/fonts/20b87e84.woff +0 -0
  11. package/resources/assets/fonts/4bbc67e1.woff +0 -0
  12. package/resources/assets/fonts/576fb0d7.woff +0 -0
  13. package/resources/assets/fonts/5ea10ee5.woff2 +0 -0
  14. package/resources/assets/fonts/6413fc0a.woff +0 -0
  15. package/resources/assets/fonts/72c114cf.woff +0 -0
  16. package/resources/assets/fonts/73c57e73.woff2 +0 -0
  17. package/resources/assets/fonts/813dca6c.woff +0 -0
  18. package/resources/assets/fonts/8a9b0995.woff2 +0 -0
  19. package/resources/assets/fonts/90b4832f.woff +0 -0
  20. package/resources/assets/fonts/9394ab85.woff2 +0 -0
  21. package/resources/assets/fonts/9b3c7d7f.woff2 +0 -0
  22. package/resources/assets/fonts/Monaco.ttf +0 -0
  23. package/resources/assets/fonts/b1b36d74.woff +0 -0
  24. package/resources/assets/fonts/b5d74798.woff2 +0 -0
  25. package/resources/assets/fonts/b9f81a4d.woff +0 -0
  26. package/resources/assets/fonts/c9784008.woff2 +0 -0
  27. package/resources/assets/fonts/cf692227.woff +0 -0
  28. package/resources/assets/fonts/d1c6ab51.woff2 +0 -0
  29. package/resources/assets/fonts/e2eb62fc.woff +0 -0
  30. package/resources/assets/fonts/fe21f8d8.woff2 +0 -0
  31. package/resources/assets/fonts/nps/CampmateScript-Regular.woff2 +0 -0
  32. package/resources/assets/fonts/nps/NPS_2026-variable.woff2 +0 -0
  33. package/resources/assets/fonts/nps/RedwoodSerif-Regular.woff2 +0 -0
  34. package/resources/assets/fonts/nps/SequoiaSans-Regular.woff2 +0 -0
  35. package/resources/assets/fonts/nps/Switchback-Regular.woff2 +0 -0
  36. package/resources/assets/images/app-icon.png +0 -0
  37. package/resources/assets/images/bg-img.png +0 -0
  38. package/resources/assets/images/park-ridge.svg +15 -0
  39. package/resources/assets/images/topography.svg +1 -0
  40. package/resources/assets/scripts/main.ts +2153 -0
  41. package/resources/assets/styles/README.md +19 -0
  42. package/resources/assets/styles/docs/main.css +1 -0
  43. package/resources/assets/styles/docs/overrides.css +1 -0
  44. package/resources/assets/styles/docs/vars.css +8 -0
  45. package/resources/assets/styles/main.css +1419 -0
  46. package/resources/components/Button.stx +70 -0
  47. package/resources/components/Buttons/BaseButton.stx +39 -0
  48. package/resources/components/Buttons/Counter.stx +28 -0
  49. package/resources/components/Buttons/ToggleDark.stx +11 -0
  50. package/resources/components/Container.stx +10 -0
  51. package/resources/components/Dashboard/.gitkeep +0 -0
  52. package/resources/components/Dashboard/Auth/ForgotPassword.stx +127 -0
  53. package/resources/components/Dashboard/Auth/Login.stx +212 -0
  54. package/resources/components/Dashboard/Auth/Register.stx +306 -0
  55. package/resources/components/Dashboard/Avatar.stx +123 -0
  56. package/resources/components/Dashboard/Billing/ActivePlan.stx +57 -0
  57. package/resources/components/Dashboard/Billing/CardBrands.stx +32 -0
  58. package/resources/components/Dashboard/Billing/CardForm.stx +34 -0
  59. package/resources/components/Dashboard/Billing/OneTimePayment.stx +28 -0
  60. package/resources/components/Dashboard/Billing/PaymentForm.stx +33 -0
  61. package/resources/components/Dashboard/Billing/PaymentMethod.stx +66 -0
  62. package/resources/components/Dashboard/Billing/PaymentMethodList.stx +52 -0
  63. package/resources/components/Dashboard/Billing/Plans.stx +136 -0
  64. package/resources/components/Dashboard/Buttons/AppButton.stx +48 -0
  65. package/resources/components/Dashboard/Buttons/IconButton.stx +20 -0
  66. package/resources/components/Dashboard/Card.stx +78 -0
  67. package/resources/components/Dashboard/Chart.stx +75 -0
  68. package/resources/components/Dashboard/CodeEditor.stx +41 -0
  69. package/resources/components/Dashboard/Commerce/BulkActionBar.stx +70 -0
  70. package/resources/components/Dashboard/Commerce/CategoriesTable.stx +133 -0
  71. package/resources/components/Dashboard/Commerce/CouponsTable.stx +161 -0
  72. package/resources/components/Dashboard/Commerce/CustomersTable.stx +142 -0
  73. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +80 -0
  74. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryTable.stx +85 -0
  75. package/resources/components/Dashboard/Commerce/Delivery/DriversTable.stx +99 -0
  76. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysTable.stx +92 -0
  77. package/resources/components/Dashboard/Commerce/Delivery/LicenseTemplatesTable.stx +88 -0
  78. package/resources/components/Dashboard/Commerce/Delivery/Pagination.stx +122 -0
  79. package/resources/components/Dashboard/Commerce/Delivery/SearchFilter.stx +23 -0
  80. package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsTable.stx +80 -0
  81. package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesTable.stx +59 -0
  82. package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesTable.stx +71 -0
  83. package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +36 -0
  84. package/resources/components/Dashboard/Commerce/Forms/CouponsForm.stx +191 -0
  85. package/resources/components/Dashboard/Commerce/OrdersTable.stx +131 -0
  86. package/resources/components/Dashboard/Commerce/ProductsTable.stx +170 -0
  87. package/resources/components/Dashboard/CreateRecordModal.stx +363 -0
  88. package/resources/components/Dashboard/DashboardLayout.stx +155 -0
  89. package/resources/components/Dashboard/Deployments/ActivityFeed.stx +54 -0
  90. package/resources/components/Dashboard/Deployments/DeployScript.stx +23 -0
  91. package/resources/components/Dashboard/Deployments/DeploymentHistory.stx +97 -0
  92. package/resources/components/Dashboard/Deployments/DeploymentList.stx +94 -0
  93. package/resources/components/Dashboard/Deployments/LiveTerminalOutput.stx +18 -0
  94. package/resources/components/Dashboard/Elements/Dropdown.stx +57 -0
  95. package/resources/components/Dashboard/Email/EmailActivityChart.stx +111 -0
  96. package/resources/components/Dashboard/Email/EmailCompose.stx +72 -0
  97. package/resources/components/Dashboard/Email/EmailDetail.stx +105 -0
  98. package/resources/components/Dashboard/Email/EmailList.stx +117 -0
  99. package/resources/components/Dashboard/Email/EmailSearch.stx +40 -0
  100. package/resources/components/Dashboard/Email/EmailSidebar.stx +133 -0
  101. package/resources/components/Dashboard/GlobalSearch.stx +124 -0
  102. package/resources/components/Dashboard/MobileSidebar.stx +47 -0
  103. package/resources/components/Dashboard/Modals/BaseModal.stx +50 -0
  104. package/resources/components/Dashboard/Modals/Popups/Alert.stx +112 -0
  105. package/resources/components/Dashboard/Modals/Popups/Toast.stx +70 -0
  106. package/resources/components/Dashboard/Modals/ToastWrapper.stx +35 -0
  107. package/resources/components/Dashboard/Monitoring/ErrorDetailModal.stx +228 -0
  108. package/resources/components/Dashboard/Monitoring/ErrorsTable.stx +184 -0
  109. package/resources/components/Dashboard/Navbar.stx +194 -0
  110. package/resources/components/Dashboard/NavbarModern.stx +188 -0
  111. package/resources/components/Dashboard/NotificationErrorModal.stx +105 -0
  112. package/resources/components/Dashboard/NotificationStatusBadge.stx +20 -0
  113. package/resources/components/Dashboard/Pagination.stx +90 -0
  114. package/resources/components/Dashboard/Queue/QueueTable.stx +127 -0
  115. package/resources/components/Dashboard/Settings/Forms/AIForm.stx +126 -0
  116. package/resources/components/Dashboard/Settings/Forms/AnalyticsForm.stx +52 -0
  117. package/resources/components/Dashboard/Settings/Forms/AppForm.stx +157 -0
  118. package/resources/components/Dashboard/Settings/Forms/CLIForm.stx +66 -0
  119. package/resources/components/Dashboard/Settings/Forms/CacheForm.stx +253 -0
  120. package/resources/components/Dashboard/Settings/Forms/CloudForm.stx +441 -0
  121. package/resources/components/Dashboard/Settings/Forms/DNSForm.stx +307 -0
  122. package/resources/components/Dashboard/Settings/Forms/DatabaseForm.stx +168 -0
  123. package/resources/components/Dashboard/Settings/Forms/EmailForm.stx +100 -0
  124. package/resources/components/Dashboard/Settings/Forms/FileSystemForm.stx +259 -0
  125. package/resources/components/Dashboard/Settings/Forms/HashingForm.stx +119 -0
  126. package/resources/components/Dashboard/Settings/Forms/LibraryForm.stx +389 -0
  127. package/resources/components/Dashboard/Settings/Forms/QueueForm.stx +219 -0
  128. package/resources/components/Dashboard/Settings/Forms/SearchEngineForm.stx +48 -0
  129. package/resources/components/Dashboard/Settings/Forms/SecurityForm.stx +143 -0
  130. package/resources/components/Dashboard/Settings/Forms/ServicesForm.stx +194 -0
  131. package/resources/components/Dashboard/Settings/Forms/StorageForm.stx +191 -0
  132. package/resources/components/Dashboard/Settings/Forms/TeamsForm.stx +33 -0
  133. package/resources/components/Dashboard/Settings/SettingsFormManager.stx +181 -0
  134. package/resources/components/Dashboard/SettingsHeader.stx +88 -0
  135. package/resources/components/Dashboard/SettingsSidebar.stx +234 -0
  136. package/resources/components/Dashboard/Sidebar.stx +23 -0
  137. package/resources/components/Dashboard/SidebarModern.stx +249 -0
  138. package/resources/components/Dashboard/Skeleton/LoadingCard.stx +15 -0
  139. package/resources/components/Dashboard/Skeleton/LoadingDetails.stx +26 -0
  140. package/resources/components/Dashboard/Table.stx +82 -0
  141. package/resources/components/Dashboard/TerminalContainer.stx +97 -0
  142. package/resources/components/Dashboard/Tooltip.stx +166 -0
  143. package/resources/components/Dashboard/Transaction/index.stx +88 -0
  144. package/resources/components/Dashboard/UI/ActivityTable.stx +54 -0
  145. package/resources/components/Dashboard/UI/Avatar.stx +102 -0
  146. package/resources/components/Dashboard/UI/Badge.stx +66 -0
  147. package/resources/components/Dashboard/UI/Button.stx +73 -0
  148. package/resources/components/Dashboard/UI/Card.stx +51 -0
  149. package/resources/components/Dashboard/UI/ChartCard.stx +36 -0
  150. package/resources/components/Dashboard/UI/Checkbox.stx +74 -0
  151. package/resources/components/Dashboard/UI/ConfirmDialog.stx +74 -0
  152. package/resources/components/Dashboard/UI/DataTable.stx +45 -0
  153. package/resources/components/Dashboard/UI/Dropdown.stx +72 -0
  154. package/resources/components/Dashboard/UI/DropdownItem.stx +80 -0
  155. package/resources/components/Dashboard/UI/EmptyState.stx +50 -0
  156. package/resources/components/Dashboard/UI/FilterBar.stx +48 -0
  157. package/resources/components/Dashboard/UI/Input.stx +77 -0
  158. package/resources/components/Dashboard/UI/Modal.stx +75 -0
  159. package/resources/components/Dashboard/UI/PageHeader.stx +69 -0
  160. package/resources/components/Dashboard/UI/PageLayout.stx +84 -0
  161. package/resources/components/Dashboard/UI/Pagination.stx +126 -0
  162. package/resources/components/Dashboard/UI/QuickLinks.stx +31 -0
  163. package/resources/components/Dashboard/UI/RouterLink.stx +31 -0
  164. package/resources/components/Dashboard/UI/Select.stx +84 -0
  165. package/resources/components/Dashboard/UI/ServiceHealth.stx +38 -0
  166. package/resources/components/Dashboard/UI/StatsCard.stx +79 -0
  167. package/resources/components/Dashboard/UI/Table.stx +143 -0
  168. package/resources/components/Dashboard/UI/Tabs.stx +45 -0
  169. package/resources/components/Dashboard/UI/Textarea.stx +93 -0
  170. package/resources/components/Dashboard/UI/Toggle.stx +84 -0
  171. package/resources/components/Dashboard/UI/WindowControls.stx +135 -0
  172. package/resources/components/Dashboard/Widget.stx +89 -0
  173. package/resources/components/Dashboard/WindowControls.stx +119 -0
  174. package/resources/components/Dashboard/index.ts +106 -0
  175. package/resources/components/Docs/Demo/ComboboxCode.md +114 -0
  176. package/resources/components/Docs/Demo/ComboboxDemo.stx +91 -0
  177. package/resources/components/Docs/Demo/DialogCode.md +42 -0
  178. package/resources/components/Docs/Demo/DialogDemo.stx +76 -0
  179. package/resources/components/Docs/Demo/DocsPlayground.stx +39 -0
  180. package/resources/components/Docs/Demo/DropdownCode.md +109 -0
  181. package/resources/components/Docs/Demo/DropdownDemo.stx +82 -0
  182. package/resources/components/Docs/Demo/Hero.stx +100 -0
  183. package/resources/components/Docs/Demo/ListboxCode.md +87 -0
  184. package/resources/components/Docs/Demo/ListboxDemo.stx +59 -0
  185. package/resources/components/Docs/Demo/NotificationCode.md +173 -0
  186. package/resources/components/Docs/Demo/NotificationDemo.stx +99 -0
  187. package/resources/components/Docs/Demo/PopoverCode.md +161 -0
  188. package/resources/components/Docs/Demo/PopoverDemo.stx +96 -0
  189. package/resources/components/Docs/Demo/RadioGroupCode.md +98 -0
  190. package/resources/components/Docs/Demo/RadioGroupDemo.stx +53 -0
  191. package/resources/components/Docs/Demo/StepperCode.md +216 -0
  192. package/resources/components/Docs/Demo/StepperDemo.stx +137 -0
  193. package/resources/components/Docs/Demo/SwitchCode.md +24 -0
  194. package/resources/components/Docs/Demo/SwitchDemo.stx +28 -0
  195. package/resources/components/Docs/Home.stx +7 -0
  196. package/resources/components/Docs/HomeContributors.stx +23 -0
  197. package/resources/components/Docs/HomeSponsors.stx +17 -0
  198. package/resources/components/Docs/HomeTeam.stx +18 -0
  199. package/resources/components/Docs/TeamMember.stx +79 -0
  200. package/resources/components/Email/EmailButton.stx +32 -0
  201. package/resources/components/Email/EmailDivider.stx +20 -0
  202. package/resources/components/Email/EmailImage.stx +24 -0
  203. package/resources/components/Email/EmailLayout.stx +55 -0
  204. package/resources/components/Email/EmailLink.stx +22 -0
  205. package/resources/components/Email/EmailSection.stx +20 -0
  206. package/resources/components/Email/EmailText.stx +30 -0
  207. package/resources/components/Forum/ForumBreadcrumb.stx +38 -0
  208. package/resources/components/Forum/ForumCategory.stx +16 -0
  209. package/resources/components/Forum/ForumCategoryItem.stx +46 -0
  210. package/resources/components/Forum/ForumLayout.stx +36 -0
  211. package/resources/components/Forum/ForumPagination.stx +39 -0
  212. package/resources/components/Forum/ForumPost.stx +71 -0
  213. package/resources/components/Forum/ForumReplyForm.stx +76 -0
  214. package/resources/components/Forum/ForumSidebar.stx +86 -0
  215. package/resources/components/Forum/ForumTopicItem.stx +77 -0
  216. package/resources/components/Forum/ForumTopicList.stx +23 -0
  217. package/resources/components/HelloWorld.stx +253 -0
  218. package/resources/components/Logo.stx +10 -0
  219. package/resources/components/Marketing/CallToAction.stx +30 -0
  220. package/resources/components/Marketing/ComingSoon.stx +155 -0
  221. package/resources/components/Marketing/Faqs.stx +99 -0
  222. package/resources/components/Marketing/Feature.stx +32 -0
  223. package/resources/components/Marketing/Fields.stx +28 -0
  224. package/resources/components/Marketing/Footer.stx +33 -0
  225. package/resources/components/Marketing/Header.stx +51 -0
  226. package/resources/components/Marketing/Hero.stx +46 -0
  227. package/resources/components/Marketing/Layout.stx +26 -0
  228. package/resources/components/Marketing/NavLink.stx +13 -0
  229. package/resources/components/Marketing/Plan.stx +43 -0
  230. package/resources/components/Marketing/Pricing.stx +120 -0
  231. package/resources/components/Marketing/PrimaryFeatures.stx +80 -0
  232. package/resources/components/Marketing/PrimaryFeatures2.stx +98 -0
  233. package/resources/components/Marketing/SecondaryFeatures.stx +80 -0
  234. package/resources/components/Marketing/Testimonials.stx +120 -0
  235. package/resources/components/Pagination.stx +149 -0
  236. package/resources/components/Playground.stx +9 -0
  237. package/resources/components/README.md +87 -0
  238. package/resources/components/Storefront/AnnouncementBar.stx +17 -0
  239. package/resources/components/Storefront/CartDrawer.stx +227 -0
  240. package/resources/components/Storefront/CheckoutSteps.stx +50 -0
  241. package/resources/components/Storefront/Footer.stx +81 -0
  242. package/resources/components/Storefront/Header.stx +66 -0
  243. package/resources/components/Storefront/OrderSummary.stx +79 -0
  244. package/resources/components/Storefront/ProductCard.stx +63 -0
  245. package/resources/components/Storefront/ProductGallery.stx +88 -0
  246. package/resources/components/Storefront/QuantitySelector.stx +97 -0
  247. package/resources/components/index.ts +13 -0
  248. package/resources/emails/email-verification.stx +46 -0
  249. package/resources/emails/layouts/base.html +113 -0
  250. package/resources/emails/password-changed.stx +55 -0
  251. package/resources/emails/password-reset.stx +43 -0
  252. package/resources/emails/subscription-confirmation.stx +99 -0
  253. package/resources/emails/welcome.stx +48 -0
  254. package/resources/functions/README.md +28 -0
  255. package/resources/functions/counter.ts +13 -0
  256. package/resources/functions/dark.ts +4 -0
  257. package/resources/functions/dashboard/analytics.ts +238 -0
  258. package/resources/functions/dashboard/config-io.ts +316 -0
  259. package/resources/functions/dashboard/data.ts +375 -0
  260. package/resources/functions/dashboard/library.ts +250 -0
  261. package/resources/functions/dashboard/sidebar.ts +537 -0
  262. package/resources/functions/dashboard/system.ts +150 -0
  263. package/resources/layouts/403.stx +188 -0
  264. package/resources/layouts/404.stx +34 -0
  265. package/resources/layouts/README.md +14 -0
  266. package/resources/layouts/dashboard/default.stx +20 -0
  267. package/resources/layouts/dashboard/guest.stx +10 -0
  268. package/resources/layouts/default.stx +3 -0
  269. package/resources/layouts/maintenance.stx +11 -0
  270. package/resources/layouts/storefront.stx +73 -0
  271. package/resources/layouts/system-tray/default.stx +3 -0
  272. package/resources/modules/.gitkeep +0 -0
  273. package/resources/plugins/.gitkeep +0 -0
  274. package/resources/plugins/preloader.ts +308 -0
  275. package/resources/types/README.md +3 -0
  276. package/resources/views/cart.stx +149 -0
  277. package/resources/views/checkout/contact.stx +101 -0
  278. package/resources/views/checkout/payment.stx +114 -0
  279. package/resources/views/checkout/shipping.stx +120 -0
  280. package/resources/views/coming-soon.stx +9 -0
  281. package/resources/views/dashboard/custom-page.stx +45 -0
  282. package/resources/views/dashboard/index.stx +24 -0
  283. package/resources/views/emails/welcome.stx +0 -0
  284. package/resources/views/errors/tester.stx +26 -0
  285. package/resources/views/index.stx +2865 -0
  286. package/resources/views/orders/[id].stx +130 -0
@@ -0,0 +1,31 @@
1
+ <script server>
2
+ interface QuickLinksProps {
3
+ title?: string
4
+ links?: any[]
5
+ }
6
+
7
+ const { title = 'Quick Links', links = [] } = defineProps<QuickLinksProps>()
8
+ </script>
9
+ <div class="bg-white dark:bg-neutral-800/90 border border-black/5 rounded-xl dark:border-white/5">
10
+ <div class="p-5 border-b border-neutral-200/60 dark:border-white/5">
11
+ <h3 class="font-semibold text-[14px] text-neutral-900 tracking-tight dark:text-white">{{ title }}</h3>
12
+ </div>
13
+ <div class="divide-neutral-100 divide-y dark:divide-white/5">
14
+ @foreach(links as link)
15
+ <a href="{{ link.href || '#' }}" class="flex gap-3.5 items-center px-5 py-3.5 hover:bg-neutral-50 dark:hover:bg-white/5 transition-colors group">
16
+ <div class="flex flex-shrink-0 items-center justify-center h-9 w-9 bg-neutral-100 dark:bg-white/10 rounded-lg">
17
+ @if(link.icon)
18
+ <div class="{{ link.icon }} w-4.5 h-4.5 text-neutral-500 dark:text-neutral-400"></div>
19
+ @else
20
+ <span class="font-semibold text-[13px] text-neutral-500 dark:text-neutral-400">{{ link.title.charAt(0) }}</span>
21
+ @endif
22
+ </div>
23
+ <div class="flex-1 min-w-0">
24
+ <div class="font-medium text-[13px] text-neutral-900 dark:text-white group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">{{ link.title }}</div>
25
+ <div class="text-[12px] text-neutral-500 truncate dark:text-neutral-400">{{ link.description }}</div>
26
+ </div>
27
+ <div class="flex-shrink-0 h-4 w-4 text-neutral-300 dark:text-neutral-600 group-hover:text-neutral-400 dark:group-hover:text-neutral-500 transition-colors i-hugeicons-arrow-right-01"></div>
28
+ </a>
29
+ @endforeach
30
+ </div>
31
+ </div>
@@ -0,0 +1,31 @@
1
+ <script server>
2
+ /**
3
+ * RouterLink — bridge component for templates that use Vue Router-style
4
+ * `<RouterLink to="…">` syntax. The dashboard is server-rendered MPA, so
5
+ * there's no actual client router; this just maps the `to` prop to a
6
+ * standard `href` and forwards the rest. Keeps existing pages from
7
+ * breaking with `[Error loading component: 'router-link']` while we
8
+ * migrate them off the syntax.
9
+ *
10
+ * `replace` is accepted for parity with Vue's RouterLink; it has no
11
+ * effect under MPA navigation but makes drop-in usage error-free.
12
+ */
13
+ interface RouterLinkProps {
14
+ to?: string
15
+ href?: string
16
+ replace?: boolean
17
+ target?: string
18
+ rel?: string
19
+ }
20
+
21
+ const { to = '', href = '', target = '', rel = '' } = defineProps<RouterLinkProps>()
22
+ const finalHref = href || to
23
+ const finalRel = rel || (target === '_blank' ? 'noopener' : '')
24
+ </script>
25
+ <a
26
+ href="{{ finalHref }}"
27
+ @if(target) target="{{ target }}" @endif
28
+ @if(finalRel) rel="{{ finalRel }}" @endif
29
+ >
30
+ <slot />
31
+ </a>
@@ -0,0 +1,84 @@
1
+ <script server>
2
+ interface SelectProps {
3
+ value?: string
4
+ options?: any[]
5
+ placeholder?: string
6
+ label?: string
7
+ error?: string
8
+ hint?: string
9
+ disabled?: boolean
10
+ required?: boolean
11
+ size?: 'xs' | 'sm' | 'md' | 'lg'
12
+ name?: string
13
+ id?: string
14
+ }
15
+
16
+ const { value = '', options = [], placeholder = 'Select an option', label = '', error = '', hint = '', disabled = false, required = false, size = 'md', name = '', id = '' } = defineProps<SelectProps>()
17
+
18
+ const sizeClasses = {
19
+ xs: 'h-6 text-[11px] px-2',
20
+ sm: 'h-7 text-[12px] px-2.5',
21
+ md: 'h-8 text-[13px] px-3',
22
+ lg: 'h-9 text-[14px] px-3.5'
23
+ }
24
+
25
+ const borderClass = error
26
+ ? 'border-red-400/60 dark:border-red-500/60 focus:ring-red-500/30 focus:border-red-500'
27
+ : 'border-black/10 dark:border-white/15 focus:ring-blue-500/40 focus:border-blue-500/50 hover:border-black/20 dark:hover:border-white/25'
28
+
29
+ const disabledClass = disabled
30
+ ? 'bg-black/5 dark:bg-white/5 text-neutral-400 cursor-not-allowed border-black/5 dark:border-white/10 opacity-40'
31
+ : 'bg-white dark:bg-white/10'
32
+
33
+ const selectClass = [
34
+ 'w-full flex items-center justify-between gap-2 rounded-md border transition-all duration-150',
35
+ 'focus:outline-none focus:ring-2',
36
+ sizeClasses[size],
37
+ borderClass,
38
+ disabledClass
39
+ ].join(' ')
40
+
41
+ const selectId = id || 'select-' + Math.random().toString(36).slice(2, 11)
42
+ </script>
43
+ <div class="relative">
44
+ @if(label)
45
+ <label for="{{ selectId }}" class="block mb-1.5 font-medium text-[13px] text-neutral-600 tracking-tight dark:text-neutral-400">
46
+ {{ label }}
47
+ @if(required)
48
+ <span class="text-red-500">*</span>
49
+ @endif
50
+ </label>
51
+ @endif
52
+
53
+ <div class="relative">
54
+ <select
55
+ id="{{ selectId }}"
56
+ name="{{ name }}"
57
+ class="{{ selectClass }} appearance-none pr-8"
58
+ @if(disabled) disabled @endif
59
+ @if(required) required @endif
60
+ >
61
+ @if(placeholder)
62
+ <option value="" disabled @if(!value) selected @endif>{{ placeholder }}</option>
63
+ @endif
64
+ @foreach(options as option)
65
+ <option
66
+ value="{{ typeof option === 'object' && option !== null ? (option.value ?? option.id ?? option.label ?? '') : option }}"
67
+ @if(option && option.disabled) disabled @endif
68
+ @if((typeof option === 'object' && option !== null ? option.value : option) == value) selected @endif
69
+ >
70
+ {{ typeof option === 'object' && option !== null ? (option.label ?? option.text ?? option.value ?? '') : option }}
71
+ </option>
72
+ @endforeach
73
+ </select>
74
+ <div class="flex absolute inset-y-0 right-0 items-center pr-2 pointer-events-none">
75
+ <div class="h-3.5 w-3.5 text-neutral-400 i-hugeicons-arrow-down-01"></div>
76
+ </div>
77
+ </div>
78
+
79
+ @if(error)
80
+ <p class="mt-1.5 text-[12px] text-red-600 dark:text-red-400">{{ error }}</p>
81
+ @elseif(hint)
82
+ <p class="mt-1.5 text-[12px] text-neutral-500 dark:text-neutral-400">{{ hint }}</p>
83
+ @endif
84
+ </div>
@@ -0,0 +1,38 @@
1
+ <script server>
2
+ interface ServiceHealthProps {
3
+ services?: any[]
4
+ }
5
+
6
+ const { services = [] } = defineProps<ServiceHealthProps>()
7
+
8
+ const allHealthy = services.every(s => s.status === 'healthy')
9
+ </script>
10
+ <div class="bg-white dark:bg-neutral-800/90 border border-black/5 rounded-xl dark:border-white/5">
11
+ <div class="flex items-center justify-between p-5 border-b border-neutral-200/60 dark:border-white/5">
12
+ <h3 class="font-semibold text-[14px] text-neutral-900 tracking-tight dark:text-white">System Health</h3>
13
+ @if(allHealthy)
14
+ <Badge variant="success" size="xs" dot>All Systems Operational</Badge>
15
+ @else
16
+ <Badge variant="warning" size="xs" dot>Degraded</Badge>
17
+ @endif
18
+ </div>
19
+ <div class="divide-neutral-100 divide-y dark:divide-white/5">
20
+ @foreach(services as service)
21
+ <div class="flex items-center justify-between px-5 py-3">
22
+ <div>
23
+ <div class="font-medium text-[13px] text-neutral-900 dark:text-white">{{ service.name }}</div>
24
+ @if(service.latency)
25
+ <div class="text-[12px] text-neutral-500 dark:text-neutral-400">{{ service.latency }}</div>
26
+ @endif
27
+ </div>
28
+ <Badge
29
+ variant="{{ service.status === 'healthy' ? 'success' : service.status === 'offline' ? 'danger' : 'warning' }}"
30
+ size="xs"
31
+ dot
32
+ >
33
+ {{ service.status }}
34
+ </Badge>
35
+ </div>
36
+ @endforeach
37
+ </div>
38
+ </div>
@@ -0,0 +1,79 @@
1
+ <script server>
2
+ interface StatsCardProps {
3
+ title?: string
4
+ value?: string
5
+ subtitle?: string
6
+ trendLabel?: string
7
+ icon?: string
8
+ iconBg?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'neutral'
9
+ loading?: boolean
10
+ trend?: any
11
+ }
12
+
13
+ const { title = '', value = '', subtitle = '', trendLabel = '', icon = '', iconBg = 'primary', loading = false, trend = null } = defineProps<StatsCardProps>()
14
+
15
+ const iconBgClasses = {
16
+ primary: 'bg-blue-500/15 text-blue-600 dark:bg-blue-400/20 dark:text-blue-400',
17
+ success: 'bg-green-500/15 text-green-600 dark:bg-green-400/20 dark:text-green-400',
18
+ warning: 'bg-orange-500/15 text-orange-600 dark:bg-orange-400/20 dark:text-orange-400',
19
+ danger: 'bg-red-500/15 text-red-600 dark:bg-red-400/20 dark:text-red-400',
20
+ info: 'bg-cyan-500/15 text-cyan-600 dark:bg-cyan-400/20 dark:text-cyan-400',
21
+ neutral: 'bg-black/[0.06] text-neutral-600 dark:bg-white/10 dark:text-neutral-400'
22
+ }
23
+
24
+ const trendDirection = trend === null || trend === 0 ? 'neutral' : (trend > 0 ? 'up' : 'down')
25
+
26
+ const trendClasses = {
27
+ up: 'text-green-500 dark:text-green-400',
28
+ down: 'text-red-500 dark:text-red-400',
29
+ neutral: 'text-neutral-500 dark:text-neutral-400'
30
+ }
31
+ </script>
32
+ <div class="p-5 bg-white dark:bg-neutral-800/90 border border-black/5 rounded-xl dark:border-white/5 hover:shadow-black/5 hover:shadow-md dark:hover:shadow-black/20 duration-150 transition-all">
33
+ <div class="flex items-start justify-between">
34
+ <div class="flex-1 min-w-0">
35
+ <p class="font-medium text-[13px] text-neutral-500 tracking-tight truncate dark:text-neutral-400">
36
+ {{ title }}
37
+ </p>
38
+
39
+ <div class="flex gap-2 items-baseline mt-1.5">
40
+ @if(loading)
41
+ <div class="h-7 w-20 bg-black/5 dark:bg-white/10 rounded-md animate-pulse"></div>
42
+ @else
43
+ <p class="font-semibold text-[22px] text-neutral-900 tracking-tight dark:text-white">
44
+ {{ value }}
45
+ </p>
46
+
47
+ @if(trend !== null)
48
+ <span class="inline-flex items-center text-[12px] font-medium {{ trendClasses[trendDirection] }}">
49
+ @if(trendDirection == 'up')
50
+ <svg class="mr-0.5 h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
51
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 15l7-7 7 7"></path>
52
+ </svg>
53
+ @elseif(trendDirection == 'down')
54
+ <svg class="mr-0.5 h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
55
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path>
56
+ </svg>
57
+ @endif
58
+ {{ Math.abs(trend) }}%
59
+ </span>
60
+ @endif
61
+ @endif
62
+ </div>
63
+
64
+ @if(subtitle || trendLabel)
65
+ <p class="mt-1 text-[12px] text-neutral-500 dark:text-neutral-400">
66
+ {{ trendLabel || subtitle }}
67
+ </p>
68
+ @endif
69
+ </div>
70
+
71
+ @if(icon)
72
+ <div class="p-2.5 rounded-lg flex-shrink-0 {{ iconBgClasses[iconBg] }}">
73
+ <div class="{{ icon }} h-5 w-5"></div>
74
+ </div>
75
+ @endif
76
+ </div>
77
+
78
+ <slot />
79
+ </div>
@@ -0,0 +1,143 @@
1
+ <script server>
2
+ interface TableProps {
3
+ columns?: any[]
4
+ data?: any[]
5
+ loading?: boolean
6
+ selectable?: boolean
7
+ striped?: boolean
8
+ bordered?: boolean
9
+ compact?: boolean
10
+ stickyHeader?: boolean
11
+ emptyTitle?: string
12
+ emptyDescription?: string
13
+ rowKey?: string
14
+ hoverable?: boolean
15
+ }
16
+
17
+ const { columns = [], data = [], loading = false, selectable = false, striped = false, bordered = false, compact = false, stickyHeader = false, emptyTitle = 'No data', emptyDescription = 'There are no items to display.', rowKey = 'id', hoverable = true } = defineProps<TableProps>()
18
+
19
+ function getAlignClass(align) {
20
+ switch (align) {
21
+ case 'center': return 'text-center'
22
+ case 'right': return 'text-right'
23
+ default: return 'text-left'
24
+ }
25
+ }
26
+ </script>
27
+ <div class="overflow-hidden relative bg-white dark:bg-neutral-900 border border-stone-200/80 rounded-xl dark:border-neutral-700 shadow-sm">
28
+ <!-- Loading overlay -->
29
+ @if(loading)
30
+ <div class="flex absolute inset-0 z-10 items-center justify-center bg-white/80 dark:bg-neutral-900/80 backdrop-blur-sm">
31
+ <div class="flex gap-2 items-center text-neutral-500 dark:text-neutral-400">
32
+ <div class="h-5 w-5 animate-spin i-hugeicons-loading-03"></div>
33
+ <span class="text-sm">Loading...</span>
34
+ </div>
35
+ </div>
36
+ @endif
37
+
38
+ <div class="overflow-x-auto">
39
+ <table class="w-full">
40
+ <!-- Header -->
41
+ <thead class="bg-stone-50/80 dark:bg-neutral-800/50 {{ stickyHeader ? 'sticky top-0 z-10' : '' }}">
42
+ <tr>
43
+ <!-- Selection checkbox column -->
44
+ @if(selectable)
45
+ <th class="pl-6 pr-2 py-3 w-12">
46
+ <div class="flex items-center justify-center">
47
+ <input
48
+ type="checkbox"
49
+ class="h-4 w-4 text-blue-600 dark:bg-neutral-700 border-stone-300 rounded dark:border-neutral-600 focus:ring-blue-500"
50
+ data-select-all
51
+ >
52
+ </div>
53
+ </th>
54
+ @endif
55
+
56
+ <!-- Data columns -->
57
+ @foreach(columns as column, index)
58
+ <th
59
+ class="{{ index === 0 && !selectable ? 'pl-6' : 'pl-4' }} pr-4 text-xs font-semibold uppercase tracking-wider text-stone-500 dark:text-neutral-400 {{ compact ? 'py-2' : 'py-3.5' }} {{ getAlignClass(column.align) }} {{ column.sortable ? 'cursor-pointer select-none hover:text-stone-700 dark:hover:text-neutral-200' : '' }} {{ column.class || '' }}"
60
+ @if(column.width) style="width: {{ column.width }}" @endif
61
+ data-column="{{ column.key }}"
62
+ >
63
+ <div class="inline-flex gap-1.5 items-center">
64
+ <span>{{ column.label }}</span>
65
+ @if(column.sortable)
66
+ <div class="h-3.5 w-3.5 opacity-30 i-hugeicons-arrow-up-down-01"></div>
67
+ @endif
68
+ </div>
69
+ </th>
70
+ @endforeach
71
+
72
+ <!-- Actions column slot -->
73
+ @if($slots.actions)
74
+ <th class="px-4 py-3 w-12"></th>
75
+ @endif
76
+ </tr>
77
+ </thead>
78
+
79
+ <!-- Body -->
80
+ <tbody class="{{ striped ? 'divide-y-0' : 'divide-y divide-stone-100 dark:divide-neutral-700' }}">
81
+ @foreach(data as row, rowIndex)
82
+ <tr
83
+ class="{{ hoverable ? 'hover:bg-stone-50/50 dark:hover:bg-neutral-800/50' : '' }} {{ striped && rowIndex % 2 == 1 ? 'bg-stone-50/30 dark:bg-neutral-800/25' : '' }} transition-colors"
84
+ data-row-id="{{ row[rowKey] }}"
85
+ >
86
+ <!-- Selection checkbox -->
87
+ @if(selectable)
88
+ <td class="w-12 pl-6 pr-2 {{ compact ? 'py-2' : 'py-3.5' }}">
89
+ <div class="flex items-center justify-center">
90
+ <input
91
+ type="checkbox"
92
+ class="h-4 w-4 text-blue-600 dark:bg-neutral-700 border-stone-300 rounded dark:border-neutral-600 focus:ring-blue-500"
93
+ data-row-select
94
+ >
95
+ </div>
96
+ </td>
97
+ @endif
98
+
99
+ <!-- Data cells -->
100
+ @foreach(columns as column, colIndex)
101
+ <td class="{{ colIndex === 0 && !selectable ? 'pl-6' : 'pl-4' }} pr-4 text-sm text-stone-700 dark:text-neutral-200 {{ compact ? 'py-2' : 'py-3.5' }} {{ getAlignClass(column.align) }} {{ column.class || '' }}">
102
+ {{ row[column.key] }}
103
+ </td>
104
+ @endforeach
105
+
106
+ <!-- Actions cell -->
107
+ @if($slots.actions)
108
+ <td class="w-12 px-4 {{ compact ? 'py-2' : 'py-3' }}">
109
+ <slot name="actions" />
110
+ </td>
111
+ @endif
112
+ </tr>
113
+ @endforeach
114
+ </tbody>
115
+ </table>
116
+ </div>
117
+
118
+ <!-- Empty state -->
119
+ @if(data.length == 0 && !loading)
120
+ <div class="flex flex-col items-center justify-center px-4 py-12">
121
+ @if($slots.empty)
122
+ <slot name="empty" />
123
+ @else
124
+ <div class="mb-3 p-3 bg-neutral-100 dark:bg-neutral-800 rounded-full">
125
+ <div class="h-6 w-6 text-neutral-400 i-hugeicons-inbox-01"></div>
126
+ </div>
127
+ <p class="font-medium text-neutral-700 text-sm dark:text-neutral-200">
128
+ {{ emptyTitle }}
129
+ </p>
130
+ <p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">
131
+ {{ emptyDescription }}
132
+ </p>
133
+ @endif
134
+ </div>
135
+ @endif
136
+
137
+ <!-- Footer slot -->
138
+ @if($slots.footer)
139
+ <div class="px-4 py-3 bg-neutral-50/50 dark:bg-neutral-800/25 border-neutral-200 border-t dark:border-neutral-700">
140
+ <slot name="footer" />
141
+ </div>
142
+ @endif
143
+ </div>
@@ -0,0 +1,45 @@
1
+ <script server>
2
+ interface TabsProps {
3
+ tabs?: any[]
4
+ activeTab?: string
5
+ variant?: 'underline' | 'pills' | 'boxed'
6
+ size?: 'sm' | 'md' | 'lg'
7
+ fullWidth?: boolean
8
+ }
9
+
10
+ const { tabs = [], activeTab = '', variant = 'underline', size = 'md', fullWidth = false } = defineProps<TabsProps>()
11
+
12
+ const sizeClasses = {
13
+ sm: 'text-sm py-2 px-3',
14
+ md: 'text-sm py-2.5 px-4',
15
+ lg: 'text-base py-3 px-5'
16
+ }
17
+
18
+ const containerClasses = {
19
+ underline: 'border-b border-neutral-200 dark:border-neutral-700',
20
+ pills: 'gap-2 bg-neutral-100 dark:bg-neutral-800 p-1 rounded-lg',
21
+ boxed: 'border border-neutral-200 dark:border-neutral-700 rounded-lg p-1'
22
+ }
23
+ </script>
24
+ <div class="flex {{ fullWidth ? 'w-full' : '' }} {{ containerClasses[variant] }}" role="tablist">
25
+ @foreach(tabs as tab)
26
+ <button
27
+ type="button"
28
+ role="tab"
29
+ aria-selected="{{ activeTab == tab.id ? 'true' : 'false' }}"
30
+ class="inline-flex items-center justify-center gap-2 font-medium transition-all duration-150 {{ sizeClasses[size] }} {{ fullWidth ? 'flex-1' : '' }} {{ tab.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer' }} @if(variant == 'underline') -mb-px {{ activeTab == tab.id ? 'border-b-2 border-blue-500 text-blue-600 dark:text-blue-400' : 'border-b-2 border-transparent text-neutral-500 hover:text-neutral-700 hover:border-neutral-300 dark:text-neutral-400 dark:hover:text-neutral-200' }} @elseif(variant == 'pills') rounded-md {{ activeTab == tab.id ? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm' : 'text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200' }} @elseif(variant == 'boxed') rounded-md {{ activeTab == tab.id ? 'bg-neutral-100 dark:bg-neutral-800 text-neutral-900 dark:text-white' : 'text-neutral-500 hover:text-neutral-700 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-800/50' }} @endif"
31
+ data-tab-id="{{ tab.id }}"
32
+ @if(tab.disabled) disabled @endif
33
+ >
34
+ @if(tab.icon)
35
+ <div class="{{ tab.icon }} w-4 h-4"></div>
36
+ @endif
37
+ <span>{{ tab.label }}</span>
38
+ @if(tab.badge !== undefined)
39
+ <span class="inline-flex items-center justify-center min-w-[1.25rem] h-5 px-1.5 text-xs font-medium rounded-full {{ activeTab == tab.id ? 'bg-blue-100 text-blue-600 dark:bg-blue-900/50 dark:text-blue-400' : 'bg-neutral-200 text-neutral-600 dark:bg-neutral-700 dark:text-neutral-300' }}">
40
+ {{ tab.badge }}
41
+ </span>
42
+ @endif
43
+ </button>
44
+ @endforeach
45
+ </div>
@@ -0,0 +1,93 @@
1
+ <script server>
2
+ interface TextareaProps {
3
+ value?: string
4
+ label?: string
5
+ placeholder?: string
6
+ error?: string
7
+ hint?: string
8
+ disabled?: boolean
9
+ readonly?: boolean
10
+ required?: boolean
11
+ rows?: number
12
+ maxLength?: number
13
+ showCount?: boolean
14
+ resize?: 'none' | 'vertical' | 'horizontal' | 'both'
15
+ name?: string
16
+ id?: string
17
+ }
18
+
19
+ const { value = '', label = '', placeholder = '', error = '', hint = '', disabled = false, readonly = false, required = false, rows = 3, maxLength = 0, showCount = false, resize = 'vertical', name = '', id = '' } = defineProps<TextareaProps>()
20
+
21
+ const resizeClasses = {
22
+ none: 'resize-none',
23
+ vertical: 'resize-y',
24
+ horizontal: 'resize-x',
25
+ both: 'resize'
26
+ }
27
+
28
+ const borderClass = error
29
+ ? 'border-red-300 dark:border-red-700 focus:ring-red-500/20 focus:border-red-500'
30
+ : 'border-neutral-300 dark:border-neutral-600 hover:border-neutral-400 dark:hover:border-neutral-500 focus:ring-blue-500/20 focus:border-blue-500'
31
+
32
+ const disabledClass = disabled
33
+ ? 'bg-neutral-100 dark:bg-neutral-800 text-neutral-400 cursor-not-allowed border-neutral-200 dark:border-neutral-700'
34
+ : 'bg-white dark:bg-neutral-900'
35
+
36
+ const textareaClass = [
37
+ 'block w-full rounded-lg border transition-all duration-150',
38
+ 'text-sm text-neutral-900 dark:text-white',
39
+ 'placeholder:text-neutral-400 dark:placeholder:text-neutral-500',
40
+ 'focus:outline-none focus:ring-2',
41
+ 'px-3 py-2.5',
42
+ resizeClasses[resize],
43
+ borderClass,
44
+ disabledClass
45
+ ].join(' ')
46
+
47
+ const textareaId = id || 'textarea-' + Math.random().toString(36).slice(2, 11)
48
+ </script>
49
+ <div>
50
+ @if(label || (showCount && maxLength))
51
+ <div class="flex items-center justify-between mb-1.5">
52
+ @if(label)
53
+ <label for="{{ textareaId }}" class="block font-medium text-neutral-700 text-sm dark:text-neutral-200">
54
+ {{ label }}
55
+ @if(required)
56
+ <span class="text-red-500">*</span>
57
+ @endif
58
+ </label>
59
+ @endif
60
+ @if(showCount && maxLength)
61
+ <span class="text-neutral-400 text-xs dark:text-neutral-500">
62
+ <span data-char-count>{{ value.length || 0 }}</span>/{{ maxLength }}
63
+ </span>
64
+ @endif
65
+ </div>
66
+ @endif
67
+
68
+ <div class="relative">
69
+ <textarea
70
+ id="{{ textareaId }}"
71
+ name="{{ name }}"
72
+ rows="{{ rows }}"
73
+ placeholder="{{ placeholder }}"
74
+ class="{{ textareaClass }}"
75
+ @if(disabled) disabled @endif
76
+ @if(readonly) readonly @endif
77
+ @if(required) required @endif
78
+ @if(maxLength) maxlength="{{ maxLength }}" @endif
79
+ >{{ value }}</textarea>
80
+
81
+ @if(showCount && !maxLength)
82
+ <span class="absolute bottom-2 right-2 px-1 text-neutral-400 text-xs dark:text-neutral-500 bg-white dark:bg-neutral-900">
83
+ <span data-char-count>{{ value.length || 0 }}</span> characters
84
+ </span>
85
+ @endif
86
+ </div>
87
+
88
+ @if(error)
89
+ <p class="mt-1.5 text-red-600 text-sm dark:text-red-400">{{ error }}</p>
90
+ @elseif(hint)
91
+ <p class="mt-1.5 text-neutral-500 text-sm dark:text-neutral-400">{{ hint }}</p>
92
+ @endif
93
+ </div>
@@ -0,0 +1,84 @@
1
+ <script server>
2
+ interface ToggleProps {
3
+ checked?: boolean
4
+ label?: string
5
+ description?: string
6
+ disabled?: boolean
7
+ size?: 'sm' | 'md' | 'lg'
8
+ labelPosition?: 'left' | 'right'
9
+ name?: string
10
+ id?: string
11
+ }
12
+
13
+ const { checked = false, label = '', description = '', disabled = false, size = 'md', labelPosition = 'right', name = '', id = '' } = defineProps<ToggleProps>()
14
+
15
+ const trackSizes = {
16
+ sm: 'h-4 w-7',
17
+ md: 'h-5 w-9',
18
+ lg: 'h-6 w-11'
19
+ }
20
+
21
+ const thumbSizes = {
22
+ sm: 'h-3 w-3',
23
+ md: 'h-4 w-4',
24
+ lg: 'h-5 w-5'
25
+ }
26
+
27
+ const translateSizes = {
28
+ sm: 'translate-x-3',
29
+ md: 'translate-x-4',
30
+ lg: 'translate-x-5'
31
+ }
32
+
33
+ const toggleId = id || 'toggle-' + Math.random().toString(36).slice(2, 11)
34
+ </script>
35
+ <div class="flex items-center gap-3 {{ labelPosition === 'left' ? 'flex-row-reverse justify-end' : '' }} {{ disabled ? 'opacity-60 cursor-not-allowed' : '' }}">
36
+ <input
37
+ type="checkbox"
38
+ id="{{ toggleId }}"
39
+ name="{{ name }}"
40
+ class="sr-only peer"
41
+ @if(checked) checked @endif
42
+ @if(disabled) disabled @endif
43
+ >
44
+ <label
45
+ for="{{ toggleId }}"
46
+ class="relative inline-flex shrink-0 rounded-full transition-all duration-150 focus-within:ring-2 focus-within:ring-blue-500/40 {{ trackSizes[size] }} {{ disabled ? 'cursor-not-allowed opacity-40' : 'cursor-pointer' }} peer-checked:bg-green-500 bg-black/15 dark:bg-white/20"
47
+ >
48
+ <span
49
+ class="pointer-events-none inline-block rounded-full bg-white shadow-sm ring-0 transition-transform duration-150 ease-in-out {{ thumbSizes[size] }} peer-checked:{{ translateSizes[size] }} translate-x-0.5"
50
+ ></span>
51
+ </label>
52
+
53
+ @if(label || description)
54
+ <div class="flex-1 min-w-0">
55
+ @if(label)
56
+ <label
57
+ for="{{ toggleId }}"
58
+ class="text-[13px] font-medium tracking-tight {{ disabled ? 'text-neutral-400 dark:text-neutral-600' : 'text-neutral-700 dark:text-neutral-200' }} {{ disabled ? '' : 'cursor-pointer' }}"
59
+ >
60
+ {{ label }}
61
+ </label>
62
+ @endif
63
+ @if(description)
64
+ <p class="text-[12px] mt-0.5 {{ disabled ? 'text-neutral-300 dark:text-neutral-600' : 'text-neutral-500 dark:text-neutral-400' }}">
65
+ {{ description }}
66
+ </p>
67
+ @endif
68
+ </div>
69
+ @endif
70
+ </div>
71
+ <style>
72
+ input:checked + label {
73
+ background-color: rgb(34 197 94);
74
+ }
75
+ input:checked + label span {
76
+ transform: translateX(1rem);
77
+ }
78
+ input:checked + label span[class*="sm"] {
79
+ transform: translateX(0.75rem);
80
+ }
81
+ input:checked + label span[class*="lg"] {
82
+ transform: translateX(1.25rem);
83
+ }
84
+ </style>