@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,72 @@
1
+ <script server>
2
+ interface DropdownProps {
3
+ align?: 'left' | 'right'
4
+ width?: 'auto' | 'sm' | 'md' | 'lg' | 'full'
5
+ disabled?: boolean
6
+ id?: string
7
+ }
8
+
9
+ const { align = 'left', width = 'auto', disabled = false, id = 'dropdown-' + Math.random().toString(36).slice(2, 11) } = defineProps<DropdownProps>()
10
+
11
+ const widthClasses = {
12
+ auto: 'min-w-[12rem]',
13
+ sm: 'w-48',
14
+ md: 'w-56',
15
+ lg: 'w-64',
16
+ full: 'w-full',
17
+ }
18
+
19
+ const alignClass = align === 'right' ? 'right-0' : 'left-0'
20
+ </script>
21
+ <div ref="pageRoot" class="inline-block relative text-left" data-dropdown="{{ id }}">
22
+ <!-- Trigger -->
23
+ <div data-dropdown-trigger>
24
+ {{ triggerSlot }}
25
+ </div>
26
+
27
+ <!-- Menu - macOS popover style -->
28
+ <div
29
+ data-dropdown-menu
30
+ class="absolute z-50 mt-1.5 {{ widthClasses[width] }} {{ alignClass }} origin-top-right bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl backdrop-saturate-150 rounded-lg shadow-lg shadow-black/10 dark:shadow-black/30 border border-black/10 dark:border-white/10 py-1 focus:outline-none hidden"
31
+ >
32
+ <slot />
33
+ </div>
34
+ </div>
35
+ <script client>
36
+ var _root = useRef('pageRoot')
37
+ onMount(function() {
38
+ var el = _root.current;
39
+ if (!el) return;
40
+ const dropdown = el
41
+ if (!dropdown) return
42
+
43
+ const trigger = dropdown.querySelector('[data-dropdown-trigger]')
44
+ const menu = dropdown.querySelector('[data-dropdown-menu]')
45
+ let isOpen = false
46
+
47
+ function toggle() {
48
+ if ({{ disabled ? 'true' : 'false' }}) return
49
+ isOpen = !isOpen
50
+ menu.classList.toggle('hidden', !isOpen)
51
+ }
52
+
53
+ function close() {
54
+ isOpen = false
55
+ menu.classList.add('hidden')
56
+ }
57
+
58
+ trigger?.addEventListener('click', toggle)
59
+
60
+ document.body.addEventListener('click', function(e) {
61
+ if (isOpen && !dropdown.contains(e.target)) {
62
+ close()
63
+ }
64
+ })
65
+
66
+ document.body.addEventListener('keydown', function(e) {
67
+ if (e.key === 'Escape' && isOpen) {
68
+ close()
69
+ }
70
+ })
71
+ })
72
+ </script>
@@ -0,0 +1,80 @@
1
+ <script server>
2
+ interface DropdownItemProps {
3
+ href?: string
4
+ disabled?: boolean
5
+ danger?: boolean
6
+ active?: boolean
7
+ }
8
+
9
+ const { href = '', disabled = false, danger = false, active = false } = defineProps<DropdownItemProps>()
10
+
11
+ function getClasses() {
12
+ const base = [
13
+ 'w-[calc(100%-8px)] mx-1 text-left px-2.5 py-1.5 text-[13px]',
14
+ 'flex items-center gap-2.5',
15
+ 'transition-colors duration-100',
16
+ 'focus:outline-none',
17
+ 'rounded-md',
18
+ ]
19
+
20
+ if (disabled) {
21
+ base.push('opacity-40 cursor-not-allowed')
22
+ } else if (danger) {
23
+ base.push(
24
+ 'text-red-600 dark:text-red-400',
25
+ 'hover:bg-red-500 hover:text-white',
26
+ 'focus:bg-red-500 focus:text-white',
27
+ )
28
+ } else if (active) {
29
+ base.push('bg-blue-500 text-white')
30
+ } else {
31
+ base.push(
32
+ 'text-neutral-700 dark:text-neutral-200',
33
+ 'hover:bg-black/5 dark:hover:bg-white/10',
34
+ 'focus:bg-black/5 dark:focus:bg-white/10',
35
+ )
36
+ }
37
+
38
+ return base.join(' ')
39
+ }
40
+
41
+ const classes = getClasses()
42
+ </script>
43
+ @if(href)
44
+ <a
45
+ href="{{ href }}"
46
+ class="{{ classes }}"
47
+ >
48
+ <!-- Leading icon slot -->
49
+ <span class="flex items-center justify-center h-4 w-4 text-current opacity-70">
50
+ {{ iconSlot }}
51
+ </span>
52
+
53
+ <!-- Content -->
54
+ <span class="flex-1 truncate">
55
+ <slot />
56
+ </span>
57
+
58
+ <!-- Trailing content slot (for shortcuts, badges, etc.) -->
59
+ {{ trailingSlot }}
60
+ </a>
61
+ @else
62
+ <button
63
+ type="button"
64
+ class="{{ classes }}"
65
+ @if(disabled) disabled @endif
66
+ >
67
+ <!-- Leading icon slot -->
68
+ <span class="flex items-center justify-center h-4 w-4 text-current opacity-70">
69
+ {{ iconSlot }}
70
+ </span>
71
+
72
+ <!-- Content -->
73
+ <span class="flex-1 truncate">
74
+ <slot />
75
+ </span>
76
+
77
+ <!-- Trailing content slot (for shortcuts, badges, etc.) -->
78
+ {{ trailingSlot }}
79
+ </button>
80
+ @endif
@@ -0,0 +1,50 @@
1
+ <script server>
2
+ interface EmptyStateProps {
3
+ icon?: string
4
+ title?: string
5
+ description?: string
6
+ actionLabel?: string
7
+ actionIcon?: string
8
+ actionHref?: string
9
+ }
10
+
11
+ const { icon = 'i-hugeicons-folder-02', title = '', description = '', actionLabel = '', actionIcon = '', actionHref = '' } = defineProps<EmptyStateProps>()
12
+ </script>
13
+ <div class="flex flex-col items-center justify-center px-4 py-12 text-center">
14
+ <!-- Icon -->
15
+ <div class="mb-4 p-4 bg-neutral-100 dark:bg-neutral-800 rounded-full">
16
+ @if(iconSlot)
17
+ {{ iconSlot }}
18
+ @else
19
+ <div class="{{ icon }} w-8 h-8 text-neutral-400 dark:text-neutral-500"></div>
20
+ @endif
21
+ </div>
22
+
23
+ <!-- Title -->
24
+ <h3 class="mb-1 font-medium text-lg text-neutral-900 dark:text-white">
25
+ {{ title }}
26
+ </h3>
27
+
28
+ <!-- Description -->
29
+ @if(description)
30
+ <p class="mb-6 max-w-sm text-neutral-500 text-sm dark:text-neutral-400">
31
+ {{ description }}
32
+ </p>
33
+ @endif
34
+
35
+ <!-- Action button -->
36
+ @if(actionLabel)
37
+ <a
38
+ href="{{ actionHref || '#' }}"
39
+ class="inline-flex gap-2 items-center px-4 py-2 font-medium text-sm text-white bg-blue-600 hover:bg-blue-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-neutral-900 transition-colors"
40
+ >
41
+ @if(actionIcon)
42
+ <div class="{{ actionIcon }} w-4 h-4"></div>
43
+ @endif
44
+ {{ actionLabel }}
45
+ </a>
46
+ @endif
47
+
48
+ <!-- Custom action slot -->
49
+ {{ actionSlot }}
50
+ </div>
@@ -0,0 +1,48 @@
1
+ <script server>
2
+ interface FilterBarProps {
3
+ searchPlaceholder?: string
4
+ searchValue?: string
5
+ itemsPerPage?: number
6
+ itemsPerPageOptions?: string
7
+ showItemsPerPage?: boolean
8
+ }
9
+
10
+ const { searchPlaceholder = 'Search...', searchValue = '', itemsPerPage = 10, itemsPerPageOptions = [10, 25, 50, 100], showItemsPerPage = true } = defineProps<FilterBarProps>()
11
+ </script>
12
+ <div class="flex flex-col gap-3 sm:flex-row sm:items-center">
13
+ <!-- Search -->
14
+ <div class="relative flex-1 max-w-sm">
15
+ <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
16
+ <div class="h-4 w-4 text-neutral-400 dark:text-neutral-500 i-hugeicons-search-01"></div>
17
+ </div>
18
+ <input
19
+ type="search"
20
+ value="{{ searchValue }}"
21
+ placeholder="{{ searchPlaceholder }}"
22
+ class="block pl-9 pr-3 py-1.5 w-full text-[13px] text-neutral-900 dark:text-neutral-100 placeholder:text-neutral-400 dark:placeholder:text-neutral-500 bg-white dark:bg-white/10 border border-black/10 rounded-lg dark:border-white/15 focus:border-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500/20 hover:border-black/20 dark:hover:border-white/25 duration-150 transition-all"
23
+ data-filter-search
24
+ >
25
+ </div>
26
+
27
+ <!-- Filter slots -->
28
+ <div class="flex flex-wrap gap-2 items-center">
29
+ <slot />
30
+ </div>
31
+
32
+ <!-- Items per page -->
33
+ @if(showItemsPerPage)
34
+ <div class="flex gap-2 items-center ml-auto text-[12px] text-neutral-500 dark:text-neutral-400">
35
+ <span>Show</span>
36
+ <select
37
+ class="px-2 h-7 text-[12px] text-neutral-700 dark:text-neutral-200 bg-white dark:bg-white/10 border border-black/10 rounded-md dark:border-white/15 focus:border-blue-500/50 focus:ring-blue-500/40"
38
+ data-items-per-page
39
+ >
40
+ @foreach(itemsPerPageOptions as option)
41
+ <option value="{{ option }}" @if(option == itemsPerPage) selected @endif>
42
+ {{ option }}
43
+ </option>
44
+ @endforeach
45
+ </select>
46
+ </div>
47
+ @endif
48
+ </div>
@@ -0,0 +1,77 @@
1
+ <script server>
2
+ interface InputProps {
3
+ value?: string
4
+ type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'
5
+ placeholder?: string
6
+ disabled?: boolean
7
+ readonly?: boolean
8
+ required?: boolean
9
+ error?: string
10
+ hint?: string
11
+ label?: string
12
+ id?: string
13
+ size?: 'xs' | 'sm' | 'md' | 'lg'
14
+ name?: string
15
+ fullWidth?: boolean
16
+ }
17
+
18
+ const { value = '', type = 'text', placeholder = '', disabled = false, readonly = false, required = false, error = '', hint = '', label = '', id = '', size = 'md', name = '', fullWidth = true } = defineProps<InputProps>()
19
+
20
+ const sizeClasses = {
21
+ xs: 'px-2 py-1 text-[11px] h-6',
22
+ sm: 'px-2.5 py-1 text-[12px] h-7',
23
+ md: 'px-3 py-1.5 text-[13px] h-8',
24
+ lg: 'px-3.5 py-2 text-[14px] h-9'
25
+ }
26
+
27
+ const borderClass = error
28
+ ? 'border-red-400/60 dark:border-red-500/60 focus:border-red-500 focus:ring-red-500/30'
29
+ : 'border-stone-200/80 dark:border-white/15 focus:border-blue-400 hover:border-stone-300 dark:hover:border-white/25'
30
+
31
+ const disabledClass = disabled ? 'opacity-40 cursor-not-allowed bg-stone-50 dark:bg-white/5' : ''
32
+
33
+ const inputClass = [
34
+ 'block w-full',
35
+ 'bg-white dark:bg-white/10',
36
+ 'border rounded-lg',
37
+ 'text-stone-900 dark:text-neutral-100',
38
+ 'placeholder:text-stone-400 dark:placeholder:text-neutral-500',
39
+ 'transition-all duration-150',
40
+ 'focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:ring-offset-0',
41
+ sizeClasses[size],
42
+ borderClass,
43
+ disabledClass
44
+ ].join(' ')
45
+
46
+ const inputId = id || 'input-' + Math.random().toString(36).slice(2, 11)
47
+ </script>
48
+ <div class="{{ fullWidth ? 'w-full' : '' }}">
49
+ @if(label)
50
+ <label for="{{ inputId }}" class="block text-[13px] font-medium mb-1.5 tracking-tight {{ error ? 'text-red-600 dark:text-red-400' : 'text-stone-600 dark:text-neutral-400' }}">
51
+ {{ label }}
52
+ @if(required)
53
+ <span class="ml-0.5 text-red-500">*</span>
54
+ @endif
55
+ </label>
56
+ @endif
57
+
58
+ <div class="relative">
59
+ <input
60
+ id="{{ inputId }}"
61
+ type="{{ type }}"
62
+ value="{{ value }}"
63
+ placeholder="{{ placeholder }}"
64
+ name="{{ name }}"
65
+ class="{{ inputClass }}"
66
+ @if(disabled) disabled @endif
67
+ @if(readonly) readonly @endif
68
+ @if(required) required @endif
69
+ >
70
+ </div>
71
+
72
+ @if(error)
73
+ <p class="mt-1.5 text-red-600 text-sm dark:text-red-400">{{ error }}</p>
74
+ @elseif(hint)
75
+ <p class="mt-1.5 text-sm text-stone-500 dark:text-neutral-400">{{ hint }}</p>
76
+ @endif
77
+ </div>
@@ -0,0 +1,75 @@
1
+ <script server>
2
+ interface ModalProps {
3
+ isOpen?: boolean
4
+ title?: string
5
+ description?: string
6
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
7
+ closable?: boolean
8
+ }
9
+
10
+ const { isOpen = false, title = '', description = '', size = 'md', closable = true } = defineProps<ModalProps>()
11
+
12
+ const sizeClasses = {
13
+ sm: 'max-w-sm',
14
+ md: 'max-w-lg',
15
+ lg: 'max-w-2xl',
16
+ xl: 'max-w-4xl',
17
+ full: 'max-w-[calc(100vw-2rem)] max-h-[calc(100vh-2rem)]'
18
+ }
19
+ </script>
20
+ @if(isOpen)
21
+ <div ref="pageRoot" class="fixed inset-0 overflow-y-auto z-50">
22
+ <!-- Overlay -->
23
+ <div class="fixed inset-0 bg-black/50 backdrop-blur-sm" data-modal-overlay></div>
24
+
25
+ <!-- Modal container -->
26
+ <div class="flex items-center justify-center p-4 min-h-full">
27
+ <div class="relative w-full rounded-xl bg-white dark:bg-neutral-900 shadow-2xl {{ sizeClasses[size] }}">
28
+ <!-- Header -->
29
+ @if(title || closable)
30
+ <div class="flex gap-4 items-start justify-between p-6 border-b border-neutral-200 dark:border-neutral-700">
31
+ <div class="min-w-0">
32
+ @if(title)
33
+ <h3 class="font-semibold text-lg text-neutral-900 dark:text-white">
34
+ {{ title }}
35
+ </h3>
36
+ @endif
37
+ @if(description)
38
+ <p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">
39
+ {{ description }}
40
+ </p>
41
+ @endif
42
+ </div>
43
+
44
+ @if(closable)
45
+ <button
46
+ type="button"
47
+ class="-m-2 p-2 text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-lg transition-colors"
48
+ data-modal-close
49
+ >
50
+ <div class="h-5 w-5 i-hugeicons-cancel-01"></div>
51
+ </button>
52
+ @endif
53
+ </div>
54
+ @endif
55
+
56
+ <!-- Body -->
57
+ <div class="p-6">
58
+ <slot />
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ @endif
64
+ <script client>
65
+ var _root = useRef('pageRoot')
66
+ onMount(function() {
67
+ var el = _root.current;
68
+ if (!el) return;
69
+ el.querySelectorAll('[data-modal-overlay], [data-modal-close]').forEach(item => {
70
+ item.addEventListener('click', () => {
71
+ item.closest('.fixed.inset-0')?.remove();
72
+ });
73
+ });
74
+ });
75
+ </script>
@@ -0,0 +1,69 @@
1
+ <script server>
2
+ interface PageHeaderProps {
3
+ title?: string
4
+ description?: string
5
+ backLink?: string
6
+ backLabel?: string
7
+ }
8
+
9
+ const { title = '', description = '', backLink = '', backLabel = 'Back' } = defineProps<PageHeaderProps>()
10
+ </script>
11
+ <div class="mb-6">
12
+ <!-- Back link -->
13
+ @if(backLink)
14
+ <a
15
+ href="{{ backLink }}"
16
+ class="inline-flex gap-1.5 items-center mb-3 text-sm text-stone-500 dark:text-neutral-400 hover:text-stone-700 dark:hover:text-neutral-200 transition-colors"
17
+ >
18
+ <div class="h-4 w-4 i-hugeicons-arrow-left-01"></div>
19
+ <span>{{ backLabel }}</span>
20
+ </a>
21
+ @endif
22
+
23
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
24
+ <div class="flex-1 min-w-0">
25
+ <!-- Title row -->
26
+ <div class="flex gap-3 items-center">
27
+ <slot name="icon" />
28
+ <div>
29
+ <h1 class="font-semibold text-2xl text-stone-900 truncate dark:text-white">
30
+ {{ title }}
31
+ </h1>
32
+ @if(description)
33
+ <p class="mt-1 text-sm text-stone-500 dark:text-neutral-400">
34
+ {{ description }}
35
+ </p>
36
+ @endif
37
+ </div>
38
+ </div>
39
+
40
+ <!-- Tags/badges slot -->
41
+ @if($slots.tags)
42
+ <div class="flex flex-wrap gap-2 mt-2">
43
+ <slot name="tags" />
44
+ </div>
45
+ @endif
46
+ </div>
47
+
48
+ <!-- Actions -->
49
+ @if($slots.actions)
50
+ <div class="flex flex-shrink-0 gap-2 items-center">
51
+ <slot name="actions" />
52
+ </div>
53
+ @endif
54
+ </div>
55
+
56
+ <!-- Tabs slot -->
57
+ @if($slots.tabs)
58
+ <div class="mt-4 border-b border-stone-200 dark:border-neutral-700">
59
+ <slot name="tabs" />
60
+ </div>
61
+ @endif
62
+
63
+ <!-- Filters slot -->
64
+ @if($slots.filters)
65
+ <div class="mt-4">
66
+ <slot name="filters" />
67
+ </div>
68
+ @endif
69
+ </div>
@@ -0,0 +1,84 @@
1
+ <script server>
2
+ interface PageLayoutProps {
3
+ /**
4
+ * Visual variant.
5
+ *
6
+ * - `default` — standard centered column with `mx-auto` + max-width
7
+ * gutter. Use for almost every page.
8
+ * - `centered` — vertically centered hero block on a min-height
9
+ * container. Use for splash / 404 / empty-route pages.
10
+ * - `bare` — no container at all. Use when the page wants to own
11
+ * its own gutter (e.g. a settings page with side-by-side panels
12
+ * that already pad themselves).
13
+ */
14
+ variant?: 'default' | 'centered' | 'bare'
15
+ maxWidth?: 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | 'full'
16
+ padding?: 'none' | 'sm' | 'md' | 'lg'
17
+ spacing?: 'none' | 'sm' | 'md' | 'lg'
18
+ /** Optional min-height utility for the `centered` variant. */
19
+ minHeight?: 'screen' | '70vh' | '80vh' | '90vh'
20
+ }
21
+
22
+ const {
23
+ variant = 'default',
24
+ maxWidth = '7xl',
25
+ padding = 'md',
26
+ spacing = 'md',
27
+ minHeight = '80vh',
28
+ } = defineProps<PageLayoutProps>()
29
+
30
+ const widthClasses = {
31
+ md: 'max-w-md',
32
+ lg: 'max-w-lg',
33
+ xl: 'max-w-xl',
34
+ '2xl': 'max-w-2xl',
35
+ '3xl': 'max-w-3xl',
36
+ '4xl': 'max-w-4xl',
37
+ '5xl': 'max-w-5xl',
38
+ '6xl': 'max-w-6xl',
39
+ '7xl': 'max-w-7xl',
40
+ full: 'max-w-full',
41
+ }
42
+
43
+ const paddingClasses = {
44
+ none: '',
45
+ sm: 'px-4 pt-4 pb-8',
46
+ md: 'px-6 pt-6 pb-12',
47
+ lg: 'px-8 pt-8 pb-16',
48
+ }
49
+
50
+ const spacingClasses = {
51
+ none: '',
52
+ sm: 'space-y-3',
53
+ md: 'space-y-6',
54
+ lg: 'space-y-8',
55
+ }
56
+
57
+ const minHeightClasses = {
58
+ 'screen': 'min-h-screen',
59
+ '70vh': 'min-h-[70vh]',
60
+ '80vh': 'min-h-[80vh]',
61
+ '90vh': 'min-h-[90vh]',
62
+ }
63
+
64
+ const widthClass = widthClasses[maxWidth] || widthClasses['7xl']
65
+ const paddingClass = paddingClasses[padding] || paddingClasses.md
66
+ const spacingClass = spacingClasses[spacing] || spacingClasses.md
67
+ const minHeightClass = minHeightClasses[minHeight] || minHeightClasses['80vh']
68
+
69
+ const defaultClass = ['mx-auto', widthClass, paddingClass, spacingClass].filter(Boolean).join(' ')
70
+ const centeredClass = ['flex items-center justify-center', minHeightClass, paddingClass].filter(Boolean).join(' ')
71
+ </script>
72
+ @if(variant === 'bare')
73
+ <slot />
74
+ @elseif(variant === 'centered')
75
+ <div class="{{ centeredClass }}">
76
+ <div class="mx-auto w-full {{ widthClass }} {{ spacingClass }}">
77
+ <slot />
78
+ </div>
79
+ </div>
80
+ @else
81
+ <div class="{{ defaultClass }}">
82
+ <slot />
83
+ </div>
84
+ @endif
@@ -0,0 +1,126 @@
1
+ <script server>
2
+ interface PaginationProps {
3
+ currentPage?: number
4
+ totalPages?: number
5
+ totalItems?: number
6
+ itemsPerPage?: number
7
+ showItemsPerPage?: boolean
8
+ maxVisiblePages?: number
9
+ itemsPerPageOptions?: string
10
+ baseUrl?: string
11
+ showTotalItems?: boolean
12
+ }
13
+
14
+ const { currentPage = 1, totalPages = 1, totalItems = 0, itemsPerPage = 10, showItemsPerPage = false, maxVisiblePages = 5, itemsPerPageOptions = [10, 25, 50, 100], baseUrl = '', showTotalItems = true } = defineProps<PaginationProps>()
15
+
16
+ // Calculate visible page numbers
17
+ function getVisiblePages() {
18
+ const pages = []
19
+ const total = totalPages
20
+ const current = currentPage
21
+ const max = maxVisiblePages
22
+
23
+ if (total <= max) {
24
+ for (let i = 1; i <= total; i++) {
25
+ pages.push(i)
26
+ }
27
+ } else {
28
+ pages.push(1)
29
+ let start = Math.max(2, current - Math.floor((max - 3) / 2))
30
+ let end = Math.min(total - 1, start + max - 4)
31
+ if (end === total - 1) {
32
+ start = Math.max(2, end - (max - 4))
33
+ }
34
+ if (start > 2) {
35
+ pages.push('...')
36
+ }
37
+ for (let i = start; i <= end; i++) {
38
+ pages.push(i)
39
+ }
40
+ if (end < total - 1) {
41
+ pages.push('...')
42
+ }
43
+ pages.push(total)
44
+ }
45
+ return pages
46
+ }
47
+
48
+ const visiblePages = getVisiblePages()
49
+
50
+ // Calculate item range
51
+ const itemRangeStart = (currentPage - 1) * itemsPerPage + 1
52
+ const itemRangeEnd = Math.min(currentPage * itemsPerPage, totalItems)
53
+
54
+ function getPageUrl(page) {
55
+ return baseUrl ? `${baseUrl}?page=${page}` : `?page=${page}`
56
+ }
57
+ </script>
58
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
59
+ <!-- Left: Items info & per page selector -->
60
+ <div class="flex gap-4 items-center text-neutral-500 text-sm dark:text-neutral-400">
61
+ <!-- Items per page -->
62
+ @if(showItemsPerPage && itemsPerPage)
63
+ <div class="flex gap-2 items-center">
64
+ <span>Show</span>
65
+ <select
66
+ class="text-neutral-700 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 border-neutral-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:ring-blue-500"
67
+ data-items-per-page
68
+ >
69
+ @foreach(itemsPerPageOptions as option)
70
+ <option value="{{ option }}" @if(option == itemsPerPage) selected @endif>
71
+ {{ option }}
72
+ </option>
73
+ @endforeach
74
+ </select>
75
+ <span>per page</span>
76
+ </div>
77
+ @endif
78
+
79
+ <!-- Total items info -->
80
+ @if(showTotalItems && totalItems > 0)
81
+ <div>
82
+ <span class="font-medium text-neutral-700 dark:text-neutral-200">
83
+ {{ itemRangeStart }}-{{ itemRangeEnd }}
84
+ </span>
85
+ of
86
+ <span class="font-medium text-neutral-700 dark:text-neutral-200">
87
+ {{ totalItems }}
88
+ </span>
89
+ items
90
+ </div>
91
+ @endif
92
+ </div>
93
+
94
+ <!-- Right: Page navigation -->
95
+ <nav class="flex gap-1 items-center" aria-label="Pagination">
96
+ <!-- Previous button -->
97
+ <a
98
+ href="{{ currentPage > 1 ? getPageUrl(currentPage - 1) : '#' }}"
99
+ class="p-2 rounded-lg text-sm font-medium transition-colors {{ currentPage == 1 ? 'text-neutral-300 dark:text-neutral-600 cursor-not-allowed pointer-events-none' : 'text-neutral-500 hover:text-neutral-700 hover:bg-neutral-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-800' }}"
100
+ >
101
+ <div class="h-5 w-5 i-hugeicons-arrow-left-01"></div>
102
+ </a>
103
+
104
+ <!-- Page numbers -->
105
+ @foreach(visiblePages as page)
106
+ @if(page == '...')
107
+ <span class="px-2 text-neutral-400 dark:text-neutral-500">...</span>
108
+ @else
109
+ <a
110
+ href="{{ getPageUrl(page) }}"
111
+ class="min-w-[2.25rem] h-9 px-3 rounded-lg text-sm font-medium transition-colors flex items-center justify-center {{ page == currentPage ? 'bg-blue-600 text-white' : 'text-neutral-600 hover:text-neutral-800 hover:bg-neutral-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-800' }}"
112
+ >
113
+ {{ page }}
114
+ </a>
115
+ @endif
116
+ @endforeach
117
+
118
+ <!-- Next button -->
119
+ <a
120
+ href="{{ currentPage < totalPages ? getPageUrl(currentPage + 1) : '#' }}"
121
+ class="p-2 rounded-lg text-sm font-medium transition-colors {{ currentPage == totalPages ? 'text-neutral-300 dark:text-neutral-600 cursor-not-allowed pointer-events-none' : 'text-neutral-500 hover:text-neutral-700 hover:bg-neutral-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-800' }}"
122
+ >
123
+ <div class="h-5 w-5 i-hugeicons-arrow-right-01"></div>
124
+ </a>
125
+ </nav>
126
+ </div>