@stacksjs/defaults 0.70.207 → 0.70.208

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/TODO.md +21 -0
  2. package/ai/AGENTS.md +79 -0
  3. package/ai/README.md +45 -0
  4. package/ai/claude/launch.json +12 -0
  5. package/ai/skills/stacks-actions/SKILL.md +128 -0
  6. package/ai/skills/stacks-ai/SKILL.md +276 -0
  7. package/ai/skills/stacks-alias/SKILL.md +94 -0
  8. package/ai/skills/stacks-analytics/SKILL.md +91 -0
  9. package/ai/skills/stacks-api/SKILL.md +738 -0
  10. package/ai/skills/stacks-arrays/SKILL.md +277 -0
  11. package/ai/skills/stacks-auth/SKILL.md +422 -0
  12. package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
  13. package/ai/skills/stacks-brandkit/SKILL.md +811 -0
  14. package/ai/skills/stacks-browse/SKILL.md +127 -0
  15. package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
  16. package/ai/skills/stacks-browser/SKILL.md +145 -0
  17. package/ai/skills/stacks-buddy/SKILL.md +676 -0
  18. package/ai/skills/stacks-build/SKILL.md +163 -0
  19. package/ai/skills/stacks-cache/SKILL.md +125 -0
  20. package/ai/skills/stacks-calendar/SKILL.md +113 -0
  21. package/ai/skills/stacks-chat/SKILL.md +371 -0
  22. package/ai/skills/stacks-cli/SKILL.md +112 -0
  23. package/ai/skills/stacks-cloud/SKILL.md +192 -0
  24. package/ai/skills/stacks-cms/SKILL.md +217 -0
  25. package/ai/skills/stacks-collections/SKILL.md +82 -0
  26. package/ai/skills/stacks-commerce/SKILL.md +114 -0
  27. package/ai/skills/stacks-composables/SKILL.md +161 -0
  28. package/ai/skills/stacks-config/SKILL.md +144 -0
  29. package/ai/skills/stacks-configuration/SKILL.md +154 -0
  30. package/ai/skills/stacks-cron/SKILL.md +123 -0
  31. package/ai/skills/stacks-crosswind/SKILL.md +190 -0
  32. package/ai/skills/stacks-dashboard/SKILL.md +173 -0
  33. package/ai/skills/stacks-database/SKILL.md +286 -0
  34. package/ai/skills/stacks-datetime/SKILL.md +269 -0
  35. package/ai/skills/stacks-dependencies/SKILL.md +111 -0
  36. package/ai/skills/stacks-deploy/SKILL.md +102 -0
  37. package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
  38. package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
  39. package/ai/skills/stacks-design-output/SKILL.md +55 -0
  40. package/ai/skills/stacks-design-soft/SKILL.md +156 -0
  41. package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
  42. package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
  43. package/ai/skills/stacks-desktop/SKILL.md +78 -0
  44. package/ai/skills/stacks-development/SKILL.md +298 -0
  45. package/ai/skills/stacks-dns/SKILL.md +149 -0
  46. package/ai/skills/stacks-docs/SKILL.md +109 -0
  47. package/ai/skills/stacks-email/SKILL.md +236 -0
  48. package/ai/skills/stacks-enums/SKILL.md +100 -0
  49. package/ai/skills/stacks-env/SKILL.md +181 -0
  50. package/ai/skills/stacks-error-handling/SKILL.md +137 -0
  51. package/ai/skills/stacks-events/SKILL.md +228 -0
  52. package/ai/skills/stacks-faker/SKILL.md +158 -0
  53. package/ai/skills/stacks-git/SKILL.md +158 -0
  54. package/ai/skills/stacks-guard/SKILL.md +98 -0
  55. package/ai/skills/stacks-health/SKILL.md +75 -0
  56. package/ai/skills/stacks-http/SKILL.md +316 -0
  57. package/ai/skills/stacks-i18n/SKILL.md +198 -0
  58. package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
  59. package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
  60. package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
  61. package/ai/skills/stacks-investigate/SKILL.md +119 -0
  62. package/ai/skills/stacks-jobs/SKILL.md +136 -0
  63. package/ai/skills/stacks-lint/SKILL.md +184 -0
  64. package/ai/skills/stacks-listeners/SKILL.md +99 -0
  65. package/ai/skills/stacks-logging/SKILL.md +78 -0
  66. package/ai/skills/stacks-mail/SKILL.md +120 -0
  67. package/ai/skills/stacks-middleware/SKILL.md +249 -0
  68. package/ai/skills/stacks-migrations/SKILL.md +105 -0
  69. package/ai/skills/stacks-models/SKILL.md +267 -0
  70. package/ai/skills/stacks-new-feature/SKILL.md +206 -0
  71. package/ai/skills/stacks-notifications/SKILL.md +210 -0
  72. package/ai/skills/stacks-objects/SKILL.md +205 -0
  73. package/ai/skills/stacks-office-hours/SKILL.md +134 -0
  74. package/ai/skills/stacks-orm/SKILL.md +342 -0
  75. package/ai/skills/stacks-path/SKILL.md +118 -0
  76. package/ai/skills/stacks-payments/SKILL.md +373 -0
  77. package/ai/skills/stacks-plan-review/SKILL.md +152 -0
  78. package/ai/skills/stacks-plugins/SKILL.md +149 -0
  79. package/ai/skills/stacks-push/SKILL.md +376 -0
  80. package/ai/skills/stacks-query-builder/SKILL.md +128 -0
  81. package/ai/skills/stacks-queue/SKILL.md +559 -0
  82. package/ai/skills/stacks-realtime/SKILL.md +442 -0
  83. package/ai/skills/stacks-redesign/SKILL.md +182 -0
  84. package/ai/skills/stacks-registry/SKILL.md +58 -0
  85. package/ai/skills/stacks-repl/SKILL.md +80 -0
  86. package/ai/skills/stacks-retro/SKILL.md +122 -0
  87. package/ai/skills/stacks-review/SKILL.md +135 -0
  88. package/ai/skills/stacks-router/SKILL.md +231 -0
  89. package/ai/skills/stacks-routes/SKILL.md +105 -0
  90. package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
  91. package/ai/skills/stacks-scheduler/SKILL.md +363 -0
  92. package/ai/skills/stacks-search-engine/SKILL.md +112 -0
  93. package/ai/skills/stacks-security/SKILL.md +129 -0
  94. package/ai/skills/stacks-security-audit/SKILL.md +128 -0
  95. package/ai/skills/stacks-server/SKILL.md +458 -0
  96. package/ai/skills/stacks-shell/SKILL.md +62 -0
  97. package/ai/skills/stacks-slug/SKILL.md +87 -0
  98. package/ai/skills/stacks-sms/SKILL.md +385 -0
  99. package/ai/skills/stacks-socials/SKILL.md +303 -0
  100. package/ai/skills/stacks-storage/SKILL.md +576 -0
  101. package/ai/skills/stacks-strings/SKILL.md +416 -0
  102. package/ai/skills/stacks-stx/SKILL.md +176 -0
  103. package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
  104. package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
  105. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
  106. package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
  107. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
  108. package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
  109. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
  110. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
  111. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
  112. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
  113. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
  114. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
  115. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
  116. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
  117. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
  118. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
  119. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
  120. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
  121. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
  122. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
  123. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
  124. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
  125. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
  126. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
  127. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
  128. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
  129. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
  130. package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
  131. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
  132. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
  133. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
  134. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
  135. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
  136. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
  137. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
  138. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
  139. package/ai/skills/stacks-testing/SKILL.md +129 -0
  140. package/ai/skills/stacks-tunnel/SKILL.md +125 -0
  141. package/ai/skills/stacks-types/SKILL.md +178 -0
  142. package/ai/skills/stacks-ui/SKILL.md +246 -0
  143. package/ai/skills/stacks-utils/SKILL.md +444 -0
  144. package/ai/skills/stacks-validation/SKILL.md +371 -0
  145. package/ai/skills/stacks-whois/SKILL.md +315 -0
  146. package/assets/world-map-data.ts +121 -0
  147. package/bootstrap.ts +114 -0
  148. package/docs/api-examples.md +46 -0
  149. package/docs/index.md +24 -0
  150. package/docs/markdown-examples.md +87 -0
  151. package/functions/analytics.ts +97 -0
  152. package/functions/api.ts +143 -0
  153. package/functions/auth.ts +208 -0
  154. package/functions/billing/payments.ts +149 -0
  155. package/functions/blog.ts +120 -0
  156. package/functions/cms/categorizables.ts +107 -0
  157. package/functions/cms/pages.ts +108 -0
  158. package/functions/cms/posts.ts +100 -0
  159. package/functions/cms/taggables.ts +102 -0
  160. package/functions/commerce/coupons.ts +128 -0
  161. package/functions/commerce/customers.ts +128 -0
  162. package/functions/commerce/gift-cards.ts +119 -0
  163. package/functions/commerce/orders.ts +112 -0
  164. package/functions/commerce/payments.ts +119 -0
  165. package/functions/commerce/products/categories.ts +123 -0
  166. package/functions/commerce/products/manufacturers.ts +123 -0
  167. package/functions/commerce/products/products.ts +123 -0
  168. package/functions/commerce/products/reviews.ts +123 -0
  169. package/functions/commerce/products/units.ts +123 -0
  170. package/functions/commerce/products/variants.ts +123 -0
  171. package/functions/commerce/shippings/delivery-routes.ts +123 -0
  172. package/functions/commerce/shippings/digital-deliveries.ts +119 -0
  173. package/functions/commerce/shippings/drivers.ts +123 -0
  174. package/functions/commerce/shippings/license-keys.ts +123 -0
  175. package/functions/commerce/shippings/shipping-methods.ts +123 -0
  176. package/functions/commerce/shippings/shipping-rates.ts +119 -0
  177. package/functions/commerce/shippings/shipping-zones.ts +119 -0
  178. package/functions/commerce/taxes.ts +119 -0
  179. package/functions/commerce/waitlist/products.ts +123 -0
  180. package/functions/commerce/waitlist/restaurants.ts +123 -0
  181. package/functions/craft.ts +107 -0
  182. package/functions/dashboard.ts +153 -0
  183. package/functions/inbox.ts +95 -0
  184. package/functions/jobs.ts +86 -0
  185. package/functions/monitoring/errors.ts +295 -0
  186. package/functions/queue.ts +111 -0
  187. package/functions/realtime/websockets.ts +96 -0
  188. package/functions/realtime.ts +52 -0
  189. package/functions/releases.ts +49 -0
  190. package/functions/search.ts +126 -0
  191. package/functions/toasts.ts +95 -0
  192. package/functions/uploads.ts +216 -0
  193. package/ide/.gitignore +4 -0
  194. package/ide/cursor/rules/auto-imports.mdc +574 -0
  195. package/ide/cursor/rules/code-style.mdc +12 -0
  196. package/ide/cursor/rules/documentation.mdc +9 -0
  197. package/ide/cursor/rules/error-handling-validation.mdc +11 -0
  198. package/ide/cursor/rules/key-conventions.mdc +11 -0
  199. package/ide/cursor/rules/project-structure.mdc +169 -0
  200. package/ide/cursor/rules/readme.mdc +318 -0
  201. package/ide/cursor/rules/syntax-formatting.mdc +9 -0
  202. package/ide/cursor/rules/testing.mdc +10 -0
  203. package/ide/cursor/rules/typescript.mdc +9 -0
  204. package/ide/cursor/rules/ui-styling.mdc +0 -0
  205. package/ide/dictionary.txt +397 -0
  206. package/ide/jetbrains/.fleet/settings.json +4 -0
  207. package/ide/jetbrains/.idea/.gitignore +5 -0
  208. package/ide/jetbrains/.idea/.name +1 -0
  209. package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
  210. package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
  211. package/ide/jetbrains/.idea/modules.xml +8 -0
  212. package/ide/jetbrains/.idea/stacks.iml +22 -0
  213. package/ide/jetbrains/.idea/vcs.xml +6 -0
  214. package/ide/jetbrains/.idea/webResources.xml +14 -0
  215. package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
  216. package/ide/jetbrains/installed.txt +4 -0
  217. package/ide/jetbrains/options/github-copilot.xml +5 -0
  218. package/ide/jetbrains/options/nodejs.xml +7 -0
  219. package/ide/jetbrains/options/templates.xml +124 -0
  220. package/ide/jetbrains/templates/JavaScript.xml +6 -0
  221. package/ide/jetbrains/templates/Stacks.xml +8 -0
  222. package/ide/vscode/.vscode/README.md +23 -0
  223. package/ide/vscode/.vscode/extensions.json +5 -0
  224. package/ide/vscode/.vscode/settings.json +176 -0
  225. package/ide/vscode/.vscode/stacks.code-snippets +181 -0
  226. package/ide/vscode/LICENSE.md +21 -0
  227. package/ide/vscode/README.md +36 -0
  228. package/ide/vscode/logo.png +0 -0
  229. package/ide/vscode/package.json +79 -0
  230. package/ide/zed/.zed/settings.json +139 -0
  231. package/lang/README.md +28 -0
  232. package/lang/de.yml +14 -0
  233. package/lang/en.yml +15 -0
  234. package/package.json +19 -3
  235. package/project/bootstrap +161 -0
  236. package/project/buddy +175 -0
  237. package/project/storage/framework/tsconfig.app.json +50 -0
  238. package/project/storage/framework/tsconfig.base.json +58 -0
  239. package/routes/core.ts +78 -0
  240. package/routes/dashboard-api.ts +233 -0
  241. package/routes/dashboard.ts +739 -0
  242. package/routes/email.ts +129 -0
  243. package/stores/[name].stx +16 -0
  244. package/stores/git.ts +71 -0
  245. package/stores/payment.ts +474 -0
  246. package/stores/queue.ts +43 -0
  247. package/stores/user.ts +29 -0
  248. package/stx-components-plugin.ts +25 -0
  249. package/styles/design-tokens.css +597 -0
  250. package/types/dashboard.ts +70 -0
  251. package/types/defaults.ts +438 -0
  252. package/vcs/github/CODE_OF_CONDUCT.md +83 -0
  253. package/vcs/github/CONTRIBUTING.md +187 -0
  254. package/vcs/github/EXPLANATIONS.md +41 -0
  255. package/vcs/github/FUNDING.yml +1 -0
  256. package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  257. package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
  258. package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  259. package/vcs/github/SECURITY.md +70 -0
  260. package/vcs/github/renovate.json +5 -0
  261. package/vcs/github/stale.yml +14 -0
  262. package/vcs/github/workflows/README.md +16 -0
  263. package/vcs/github/workflows/ci.yml +114 -0
  264. package/vcs/github/workflows/export-size.yml +25 -0
  265. package/vcs/github/workflows/labeler.yml +13 -0
  266. package/vcs/github/workflows/release.yml +219 -0
  267. package/views/[...all].stx +8 -0
  268. package/views/about.md +3 -0
  269. package/views/auth/login.stx +1 -0
  270. package/views/auth/signup.stx +85 -0
  271. package/views/dashboard/.discovered-models.json +542 -0
  272. package/views/dashboard/AUDIT.md +904 -0
  273. package/views/dashboard/[...all].stx +89 -0
  274. package/views/dashboard/access-tokens/index.stx +177 -0
  275. package/views/dashboard/actions/index.stx +129 -0
  276. package/views/dashboard/analytics/blog/index.stx +356 -0
  277. package/views/dashboard/analytics/browsers/index.stx +263 -0
  278. package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
  279. package/views/dashboard/analytics/commerce/web/index.stx +379 -0
  280. package/views/dashboard/analytics/countries/index.stx +289 -0
  281. package/views/dashboard/analytics/devices/index.stx +305 -0
  282. package/views/dashboard/analytics/events/index.stx +536 -0
  283. package/views/dashboard/analytics/index.stx +88 -0
  284. package/views/dashboard/analytics/marketing/index.stx +315 -0
  285. package/views/dashboard/analytics/pages/index.stx +271 -0
  286. package/views/dashboard/analytics/referrers/index.stx +319 -0
  287. package/views/dashboard/analytics/web/index.stx +356 -0
  288. package/views/dashboard/buddy/index.stx +198 -0
  289. package/views/dashboard/ci/index.stx +462 -0
  290. package/views/dashboard/cloud/index.stx +452 -0
  291. package/views/dashboard/commands/index.stx +295 -0
  292. package/views/dashboard/commerce/categories/index.stx +406 -0
  293. package/views/dashboard/commerce/coupons/index.stx +485 -0
  294. package/views/dashboard/commerce/customers/index.stx +410 -0
  295. package/views/dashboard/commerce/dashboard/index.stx +287 -0
  296. package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
  297. package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
  298. package/views/dashboard/commerce/delivery/drivers.stx +397 -0
  299. package/views/dashboard/commerce/delivery/index.stx +18 -0
  300. package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
  301. package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
  302. package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
  303. package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
  304. package/views/dashboard/commerce/delivery/tabs.ts +25 -0
  305. package/views/dashboard/commerce/gift-cards/index.stx +561 -0
  306. package/views/dashboard/commerce/manufacturers/index.stx +308 -0
  307. package/views/dashboard/commerce/orders/index.stx +247 -0
  308. package/views/dashboard/commerce/payments/index.stx +535 -0
  309. package/views/dashboard/commerce/pos/index.stx +653 -0
  310. package/views/dashboard/commerce/printers/devices/index.stx +273 -0
  311. package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
  312. package/views/dashboard/commerce/products/detail.stx +563 -0
  313. package/views/dashboard/commerce/products/index.stx +370 -0
  314. package/views/dashboard/commerce/reviews/index.stx +656 -0
  315. package/views/dashboard/commerce/reviews/index.ts +0 -0
  316. package/views/dashboard/commerce/taxes/index.stx +377 -0
  317. package/views/dashboard/commerce/units/index.stx +317 -0
  318. package/views/dashboard/commerce/variants/index.stx +319 -0
  319. package/views/dashboard/commerce/waitlist/products.stx +942 -0
  320. package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
  321. package/views/dashboard/components/index.stx +330 -0
  322. package/views/dashboard/composables/index.ts +19 -0
  323. package/views/dashboard/composables/useChart.ts +77 -0
  324. package/views/dashboard/composables/useNavigation.ts +99 -0
  325. package/views/dashboard/composables/useRole.ts +58 -0
  326. package/views/dashboard/composables/useTheme.ts +74 -0
  327. package/views/dashboard/content/authors/index.stx +171 -0
  328. package/views/dashboard/content/blog/index.stx +493 -0
  329. package/views/dashboard/content/categories/index.stx +169 -0
  330. package/views/dashboard/content/comments/index.stx +189 -0
  331. package/views/dashboard/content/dashboard.stx +383 -0
  332. package/views/dashboard/content/files/index.stx +706 -0
  333. package/views/dashboard/content/pages/index.stx +174 -0
  334. package/views/dashboard/content/posts/index.stx +269 -0
  335. package/views/dashboard/content/seo/index.stx +240 -0
  336. package/views/dashboard/content/tags/index.stx +167 -0
  337. package/views/dashboard/data/activity/index.stx +261 -0
  338. package/views/dashboard/data/dashboard/index.stx +116 -0
  339. package/views/dashboard/data/subscribers.stx +270 -0
  340. package/views/dashboard/data/teams.stx +275 -0
  341. package/views/dashboard/data/users.stx +279 -0
  342. package/views/dashboard/dependencies/index.stx +178 -0
  343. package/views/dashboard/deployments/[id].stx +234 -0
  344. package/views/dashboard/deployments/index.stx +9 -0
  345. package/views/dashboard/dns/index.stx +163 -0
  346. package/views/dashboard/environment/index.stx +283 -0
  347. package/views/dashboard/errors/index.stx +274 -0
  348. package/views/dashboard/forgot-password.stx +57 -0
  349. package/views/dashboard/functions/index.stx +159 -0
  350. package/views/dashboard/health/index.stx +248 -0
  351. package/views/dashboard/inbox/activity.stx +350 -0
  352. package/views/dashboard/inbox/index.stx +452 -0
  353. package/views/dashboard/inbox/settings.stx +290 -0
  354. package/views/dashboard/index.stx +252 -0
  355. package/views/dashboard/insights/index.stx +529 -0
  356. package/views/dashboard/jobs/[id].stx +430 -0
  357. package/views/dashboard/jobs/history.stx +222 -0
  358. package/views/dashboard/jobs/index.stx +214 -0
  359. package/views/dashboard/kanban/[id].stx +899 -0
  360. package/views/dashboard/kanban/index.stx +260 -0
  361. package/views/dashboard/layouts/default.stx +565 -0
  362. package/views/dashboard/layouts/guest.stx +10 -0
  363. package/views/dashboard/login.stx +48 -0
  364. package/views/dashboard/logs/index.stx +540 -0
  365. package/views/dashboard/mailboxes/index.stx +149 -0
  366. package/views/dashboard/management/permissions/index.stx +490 -0
  367. package/views/dashboard/marketing/campaigns/index.stx +604 -0
  368. package/views/dashboard/marketing/lists/index.stx +514 -0
  369. package/views/dashboard/marketing/reviews/index.stx +475 -0
  370. package/views/dashboard/marketing/social-posts/index.stx +560 -0
  371. package/views/dashboard/models/[model].stx +195 -0
  372. package/views/dashboard/models/index.stx +159 -0
  373. package/views/dashboard/monitoring/errors/index.stx +415 -0
  374. package/views/dashboard/notifications/dashboard.stx +383 -0
  375. package/views/dashboard/notifications/email.stx +336 -0
  376. package/views/dashboard/notifications/history.stx +373 -0
  377. package/views/dashboard/notifications/sms.stx +332 -0
  378. package/views/dashboard/packages/index.stx +195 -0
  379. package/views/dashboard/queries/[id].stx +381 -0
  380. package/views/dashboard/queries/history.stx +227 -0
  381. package/views/dashboard/queries/index.stx +335 -0
  382. package/views/dashboard/queries/slow.stx +318 -0
  383. package/views/dashboard/queue/index.stx +427 -0
  384. package/views/dashboard/realtime/index.stx +429 -0
  385. package/views/dashboard/register.stx +46 -0
  386. package/views/dashboard/releases/index.stx +389 -0
  387. package/views/dashboard/requests/index.stx +462 -0
  388. package/views/dashboard/serverless/index.stx +475 -0
  389. package/views/dashboard/servers/[id].stx +299 -0
  390. package/views/dashboard/servers/index.stx +483 -0
  391. package/views/dashboard/settings/billing.stx +50 -0
  392. package/views/dashboard/settings/index.stx +256 -0
  393. package/views/dashboard/settings/mail.stx +252 -0
  394. package/views/dashboard/stores/auth.ts +123 -0
  395. package/views/dashboard/stores/ci.ts +342 -0
  396. package/views/dashboard/stores/index.ts +129 -0
  397. package/views/dashboard/stores/kanban.ts +723 -0
  398. package/views/dashboard/stores/rbac.ts +350 -0
  399. package/views/dashboard/stx.config.ts +34 -0
  400. package/views/dashboard/teams/[id].stx +170 -0
  401. package/views/forum/category.stx +92 -0
  402. package/views/forum/index.stx +209 -0
  403. package/views/forum/new-topic.stx +113 -0
  404. package/views/forum/profile.stx +1 -0
  405. package/views/forum/topic.stx +143 -0
  406. package/views/hello-world/[name].stx +47 -0
  407. package/views/index.stx +21 -0
  408. package/views/system-tray/index.stx +147 -0
@@ -0,0 +1,317 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ <div class="sm:flex sm:items-center sm:justify-between">
5
+ <PageHeader title="Units" description="Manage measurement units for your products" />
6
+ <div class="mt-4 sm:mt-0">
7
+ <button
8
+ type="button"
9
+ @click="openAddModal()"
10
+ class="inline-flex items-center px-3 py-2 font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
11
+ >
12
+ <div class="mr-1 h-5 w-5 i-hugeicons-plus-sign"></div>
13
+ Add unit
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <!-- Filters -->
19
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mt-6">
20
+ <div class="relative max-w-sm">
21
+ <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
22
+ <div class="h-5 w-5 text-gray-400 i-hugeicons-search-01"></div>
23
+ </div>
24
+ <input
25
+ x-model="searchQuery"
26
+ type="text"
27
+ class="block pl-10 pr-3 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:placeholder:text-neutral-500 dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
28
+ placeholder="Search units..."
29
+ />
30
+ </div>
31
+
32
+ <div class="flex flex-col gap-4 sm:flex-row">
33
+ <select
34
+ x-model="typeFilter"
35
+ class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
36
+ >
37
+ <option value="all">All Types</option>
38
+ <template :for="type in unitTypes">
39
+ <option value="{{ type }}">{{ type }}</option>
40
+ </template>
41
+ </select>
42
+
43
+ <select
44
+ x-model="defaultFilter"
45
+ class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
46
+ >
47
+ <option value="all">All Units</option>
48
+ <option value="default">Default Units</option>
49
+ <option value="not-default">Non-Default Units</option>
50
+ </select>
51
+ </div>
52
+ </div>
53
+
54
+ <!-- Units table -->
55
+ <div class="flow-root mt-6">
56
+ <div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
57
+ <div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
58
+ <div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
59
+ <table class="min-w-full divide-gray-300 divide-y dark:divide-neutral-700">
60
+ <thead class="bg-gray-50 dark:bg-neutral-700">
61
+ <tr>
62
+ <th scope="col" class="pl-4 pr-3 py-3.5 sm:pl-6 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
63
+ <button @click="toggleSort('name')" class="inline-flex items-center group">
64
+ Name
65
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
66
+ <div class="h-4 w-4 {{ sortBy() === 'name' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
67
+ </span>
68
+ </button>
69
+ </th>
70
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
71
+ <button @click="toggleSort('abbreviation')" class="inline-flex items-center group">
72
+ Abbreviation
73
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
74
+ <div class="h-4 w-4 {{ sortBy() === 'abbreviation' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
75
+ </span>
76
+ </button>
77
+ </th>
78
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
79
+ <button @click="toggleSort('type')" class="inline-flex items-center group">
80
+ Type
81
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
82
+ <div class="h-4 w-4 {{ sortBy() === 'type' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
83
+ </span>
84
+ </button>
85
+ </th>
86
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Description</th>
87
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Default</th>
88
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-right text-sm dark:text-neutral-200">
89
+ <button @click="toggleSort('createdAt')" class="inline-flex items-center text-right group">
90
+ Created
91
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
92
+ <div class="h-4 w-4 {{ sortBy() === 'createdAt' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
93
+ </span>
94
+ </button>
95
+ </th>
96
+ <th scope="col" class="relative pl-3 pr-4 py-3.5 sm:pr-6">
97
+ <span class="sr-only">Actions</span>
98
+ </th>
99
+ </tr>
100
+ </thead>
101
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
102
+ <template :for="unit in filteredUnits">
103
+ <tr>
104
+ <td class="pl-4 pr-3 py-4 sm:pl-6 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ unit.name }}</td>
105
+ <td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ unit.abbreviation }}</td>
106
+ <td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ unit.type }}</td>
107
+ <td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-300">{{ unit.description }}</td>
108
+ <td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">
109
+ @if(unit.isDefault)
110
+ <div class="h-5 w-5 text-green-500 i-hugeicons-checkmark-circle-02"></div>
111
+ @else
112
+ <div class="h-5 w-5 text-gray-400 i-hugeicons-cancel-circle"></div>
113
+ @endif
114
+ </td>
115
+ <td class="px-3 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ unit.createdAt }}</td>
116
+ <td class="relative pl-3 pr-4 py-4 sm:pr-6 font-medium text-right text-sm whitespace-nowrap">
117
+ <div class="flex items-center justify-end space-x-2">
118
+ <button type="button" class="text-gray-400 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 duration-150 transition-colors">
119
+ <div class="h-5 w-5 i-hugeicons-edit-01"></div>
120
+ </button>
121
+ <button type="button" class="text-gray-400 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 duration-150 transition-colors">
122
+ <div class="h-5 w-5 i-hugeicons-waste"></div>
123
+ </button>
124
+ </div>
125
+ </td>
126
+ </tr>
127
+ </template>
128
+ @if(filteredUnits().length === 0)
129
+ <tr>
130
+ <td colspan="7" class="px-6 py-4 text-center text-gray-500 text-sm dark:text-neutral-400">
131
+ No units found matching your criteria
132
+ </td>
133
+ </tr>
134
+ @endif
135
+ </tbody>
136
+ </table>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- Add Unit Modal -->
145
+ <div :show="showAddModal" class="fixed inset-0 overflow-y-auto z-10">
146
+ <div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
147
+ <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeAddModal()"></div>
148
+
149
+ <div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
150
+ <div>
151
+ <div class="mt-3 sm:mt-5 text-center">
152
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Add New Unit</h3>
153
+ <div class="mt-4">
154
+ <div class="space-y-4">
155
+ <div class="grid gap-4 grid-cols-2">
156
+ <div>
157
+ <label for="unit-name" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Name</label>
158
+ <div class="mt-2">
159
+ <input type="text" id="unit-name" x-model="newName" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
160
+ </div>
161
+ </div>
162
+ <div>
163
+ <label for="unit-abbreviation" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Abbreviation</label>
164
+ <div class="mt-2">
165
+ <input type="text" id="unit-abbreviation" x-model="newAbbreviation" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
166
+ </div>
167
+ </div>
168
+ </div>
169
+ <div>
170
+ <label for="unit-type" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Type</label>
171
+ <div class="mt-2">
172
+ <select id="unit-type" x-model="newType" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm">
173
+ <option value="">Select a type</option>
174
+ <template :for="type in unitTypes">
175
+ <option value="{{ type }}">{{ type }}</option>
176
+ </template>
177
+ <option value="Other">Other</option>
178
+ </select>
179
+ </div>
180
+ </div>
181
+ <div>
182
+ <label for="unit-description" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Description</label>
183
+ <div class="mt-2">
184
+ <textarea id="unit-description" x-model="newDescription" rows="2" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"></textarea>
185
+ </div>
186
+ </div>
187
+ <div class="flex items-center">
188
+ <input id="unit-default" type="checkbox" x-model="newIsDefault" class="h-4 w-4 text-blue-600 dark:bg-neutral-700 border-gray-300 rounded dark:border-neutral-600 focus:ring-blue-600" />
189
+ <label for="unit-default" class="block ml-2 text-gray-900 text-sm dark:text-neutral-200">Set as default for this type</label>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ <div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
196
+ <button type="button" @click="addUnit()" class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">Add</button>
197
+ <button type="button" @click="closeAddModal()" class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">Cancel</button>
198
+ </div>
199
+ </div>
200
+ </PageLayout>
201
+ <script client>
202
+ interface Unit {
203
+ id: number
204
+ name: string
205
+ abbreviation: string
206
+ type: string
207
+ description: string
208
+ isDefault: boolean
209
+ createdAt: string
210
+ }
211
+
212
+ const initialUnits: Unit[] = [
213
+ { id: 1, name: 'Slice', abbreviation: 'slice', type: 'Food', description: 'Individual slice of pizza or cake', isDefault: true, createdAt: '2023-05-15' },
214
+ { id: 2, name: 'Whole', abbreviation: 'whole', type: 'Food', description: 'Complete item (e.g., whole pizza, whole cake)', isDefault: false, createdAt: '2023-05-15' },
215
+ { id: 3, name: 'Milliliter', abbreviation: 'ml', type: 'Beverage', description: 'Volume measurement for beverages', isDefault: true, createdAt: '2023-06-02' },
216
+ { id: 4, name: 'Bottle', abbreviation: 'btl', type: 'Beverage', description: 'Standard bottle size (varies by product)', isDefault: false, createdAt: '2023-06-02' },
217
+ { id: 5, name: 'Piece', abbreviation: 'pc', type: 'General', description: 'Individual item count', isDefault: true, createdAt: '2023-06-10' },
218
+ { id: 6, name: 'Box', abbreviation: 'box', type: 'Package', description: 'Box containing multiple items', isDefault: true, createdAt: '2023-07-05' },
219
+ { id: 7, name: 'Serving', abbreviation: 'srv', type: 'Food', description: 'Individual portion size', isDefault: false, createdAt: '2023-07-12' },
220
+ { id: 8, name: 'Gram', abbreviation: 'g', type: 'Weight', description: 'Weight measurement for food items', isDefault: true, createdAt: '2023-08-03' },
221
+ ]
222
+
223
+ const units = state(initialUnits)
224
+ const searchQuery = state('')
225
+ const sortBy = state<'name' | 'abbreviation' | 'type' | 'createdAt'>('name')
226
+ const sortOrder = state<'asc' | 'desc'>('asc')
227
+ const typeFilter = state<string>('all')
228
+ const defaultFilter = state<'all' | 'default' | 'not-default'>('all')
229
+
230
+ const showAddModal = state(false)
231
+ const newName = state('')
232
+ const newAbbreviation = state('')
233
+ const newType = state<string>('')
234
+ const newDescription = state('')
235
+ const newIsDefault = state(false)
236
+
237
+ function unitTypes(): string[] {
238
+ return Array.from(new Set(units().map(u => u.type))).sort()
239
+ }
240
+
241
+ const filteredUnits = derived(() => {
242
+ const q = searchQuery().toLowerCase()
243
+ const tFilter = typeFilter()
244
+ const dFilter = defaultFilter()
245
+ const by = sortBy()
246
+ const dir = sortOrder()
247
+
248
+ return units()
249
+ .filter((u) => {
250
+ const matchesSearch
251
+ = u.name.toLowerCase().includes(q)
252
+ || u.abbreviation.toLowerCase().includes(q)
253
+ || u.description.toLowerCase().includes(q)
254
+ const matchesType = tFilter === 'all' || u.type === tFilter
255
+ const matchesDefault
256
+ = dFilter === 'all'
257
+ || (dFilter === 'default' && u.isDefault)
258
+ || (dFilter === 'not-default' && !u.isDefault)
259
+ return matchesSearch && matchesType && matchesDefault
260
+ })
261
+ .sort((a, b) => {
262
+ let cmp = 0
263
+ if (by === 'name') cmp = a.name.localeCompare(b.name)
264
+ else if (by === 'type') cmp = a.type.localeCompare(b.type)
265
+ else if (by === 'abbreviation') cmp = a.abbreviation.localeCompare(b.abbreviation)
266
+ else if (by === 'createdAt') cmp = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
267
+ return dir === 'asc' ? cmp : -cmp
268
+ })
269
+ })
270
+
271
+ function toggleSort(column: 'name' | 'abbreviation' | 'type' | 'createdAt'): void {
272
+ if (sortBy() === column) {
273
+ sortOrder.update(d => d === 'asc' ? 'desc' : 'asc')
274
+ }
275
+ else {
276
+ sortBy.set(column)
277
+ sortOrder.set('asc')
278
+ }
279
+ }
280
+
281
+ function openAddModal(): void {
282
+ newName.set('')
283
+ newAbbreviation.set('')
284
+ newType.set('')
285
+ newDescription.set('')
286
+ newIsDefault.set(false)
287
+ showAddModal.set(true)
288
+ }
289
+
290
+ function closeAddModal(): void {
291
+ showAddModal.set(false)
292
+ }
293
+
294
+ function addUnit(): void {
295
+ const list = units()
296
+ const id = list.length > 0 ? Math.max(...list.map(u => u.id)) + 1 : 1
297
+ const isDefault = newIsDefault()
298
+ const type = newType()
299
+ // If marking as default, clear default on other units of the same type.
300
+ const next = isDefault
301
+ ? list.map(u => u.type === type ? { ...u, isDefault: false } : u)
302
+ : list
303
+
304
+ units.set([...next, {
305
+ id,
306
+ name: newName(),
307
+ abbreviation: newAbbreviation(),
308
+ type,
309
+ description: newDescription(),
310
+ isDefault,
311
+ createdAt: new Date().toISOString().split('T')[0] || '',
312
+ }])
313
+ closeAddModal()
314
+ }
315
+ </script>
316
+
317
+ @endsection
@@ -0,0 +1,319 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ <div class="sm:flex sm:items-center sm:justify-between">
5
+ <PageHeader title="Variants" description="Manage product variants and options" />
6
+ <div class="mt-4 sm:mt-0">
7
+ <button
8
+ type="button"
9
+ @click="openAddModal()"
10
+ class="inline-flex items-center px-3 py-2 font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
11
+ >
12
+ <div class="mr-1 h-5 w-5 i-hugeicons-plus-sign"></div>
13
+ Add variant type
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <!-- Filters -->
19
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mt-6">
20
+ <div class="relative max-w-sm">
21
+ <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
22
+ <div class="h-5 w-5 text-gray-400 i-hugeicons-search-01"></div>
23
+ </div>
24
+ <input
25
+ x-model="searchQuery"
26
+ type="text"
27
+ class="block pl-10 pr-3 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:placeholder:text-neutral-500 dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
28
+ placeholder="Search variants..."
29
+ />
30
+ </div>
31
+
32
+ <div class="flex flex-col gap-4 sm:flex-row">
33
+ <select
34
+ x-model="activeFilter"
35
+ class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
36
+ >
37
+ <option value="all">All Variants</option>
38
+ <option value="active">Active Only</option>
39
+ <option value="inactive">Inactive Only</option>
40
+ </select>
41
+ </div>
42
+ </div>
43
+
44
+ <!-- Variants table -->
45
+ <div class="flow-root mt-6">
46
+ <div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
47
+ <div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
48
+ <div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
49
+ <table class="min-w-full divide-gray-300 divide-y dark:divide-neutral-700">
50
+ <thead class="bg-gray-50 dark:bg-neutral-700">
51
+ <tr>
52
+ <th scope="col" class="pl-4 pr-3 py-3.5 sm:pl-6 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
53
+ <button @click="toggleSort('name')" class="inline-flex items-center group">
54
+ Variant Type
55
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
56
+ <div class="h-4 w-4 {{ sortBy() === 'name' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
57
+ </span>
58
+ </button>
59
+ </th>
60
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Description</th>
61
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
62
+ <button @click="toggleSort('optionCount')" class="inline-flex items-center group">
63
+ Options
64
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
65
+ <div class="h-4 w-4 {{ sortBy() === 'optionCount' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
66
+ </span>
67
+ </button>
68
+ </th>
69
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Status</th>
70
+ <th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-right text-sm dark:text-neutral-200">
71
+ <button @click="toggleSort('createdAt')" class="inline-flex items-center text-right group">
72
+ Created
73
+ <span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
74
+ <div class="h-4 w-4 {{ sortBy() === 'createdAt' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
75
+ </span>
76
+ </button>
77
+ </th>
78
+ <th scope="col" class="relative pl-3 pr-4 py-3.5 sm:pr-6">
79
+ <span class="sr-only">Actions</span>
80
+ </th>
81
+ </tr>
82
+ </thead>
83
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
84
+ <template :for="variantType in filteredVariantTypes">
85
+ <tr>
86
+ <td class="pl-4 pr-3 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ variantType.name }}</td>
87
+ <td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-300">{{ variantType.description }}</td>
88
+ <td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-300">
89
+ <div class="flex flex-wrap gap-1">
90
+ <template :for="option in variantType.options.slice(0, 5)">
91
+ <span class="inline-flex items-center px-2 py-1 font-medium text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-900 rounded-full">
92
+ {{ option }}
93
+ </span>
94
+ </template>
95
+ @if(variantType.options.length > 5)
96
+ <span class="inline-flex items-center px-2 py-1 font-medium text-gray-600 text-xs dark:text-neutral-300 bg-gray-50 dark:bg-neutral-700 rounded-full">
97
+ +{{ variantType.options.length - 5 }} more
98
+ </span>
99
+ @endif
100
+ </div>
101
+ </td>
102
+ <td class="px-3 py-4 text-sm whitespace-nowrap">
103
+ <span class="inline-flex items-center px-2.5 py-0.5 font-medium text-xs rounded-full {{ variantType.active ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300' : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300' }}">
104
+ {{ variantType.active ? 'Active' : 'Inactive' }}
105
+ </span>
106
+ </td>
107
+ <td class="px-3 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ variantType.createdAt }}</td>
108
+ <td class="relative pl-3 pr-4 py-4 sm:pr-6 font-medium text-right text-sm whitespace-nowrap">
109
+ <div class="flex items-center justify-end space-x-2">
110
+ <button type="button" class="text-gray-400 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 duration-150 transition-colors">
111
+ <div class="h-5 w-5 i-hugeicons-edit-01"></div>
112
+ </button>
113
+ <button type="button" class="text-gray-400 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 duration-150 transition-colors">
114
+ <div class="h-5 w-5 i-hugeicons-waste"></div>
115
+ </button>
116
+ </div>
117
+ </td>
118
+ </tr>
119
+ </template>
120
+ @if(filteredVariantTypes().length === 0)
121
+ <tr>
122
+ <td colspan="6" class="px-6 py-4 text-center text-gray-500 text-sm dark:text-neutral-400">
123
+ No variant types found matching your criteria
124
+ </td>
125
+ </tr>
126
+ @endif
127
+ </tbody>
128
+ </table>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+
136
+ <!-- Add Variant Type Modal -->
137
+ <div :show="showAddModal" class="fixed inset-0 overflow-y-auto z-10">
138
+ <div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
139
+ <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeAddModal()"></div>
140
+
141
+ <div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
142
+ <div>
143
+ <div class="mt-3 sm:mt-5 text-center">
144
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Add New Variant Type</h3>
145
+ <div class="mt-4">
146
+ <div class="space-y-4">
147
+ <div>
148
+ <label for="variant-name" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Name</label>
149
+ <div class="mt-2">
150
+ <input type="text" id="variant-name" x-model="newName" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
151
+ </div>
152
+ </div>
153
+ <div>
154
+ <label for="variant-description" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Description</label>
155
+ <div class="mt-2">
156
+ <textarea id="variant-description" x-model="newDescription" rows="2" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"></textarea>
157
+ </div>
158
+ </div>
159
+ <div>
160
+ <label class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Options</label>
161
+ <div class="mt-2">
162
+ <div class="flex flex-wrap gap-2 mb-2">
163
+ <template :for="(option, index) in newOptions">
164
+ <div class="inline-flex items-center px-2 py-1 font-medium text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-900 rounded-full">
165
+ {{ option }}
166
+ <button
167
+ type="button"
168
+ class="ml-1 text-blue-400 dark:text-blue-300 hover:text-blue-600 dark:hover:text-blue-100"
169
+ @click="removeOption(index)"
170
+ >
171
+ <div class="h-4 w-4 i-hugeicons-cancel-circle"></div>
172
+ </button>
173
+ </div>
174
+ </template>
175
+ </div>
176
+ <div class="flex">
177
+ <input
178
+ type="text"
179
+ x-model="newOption"
180
+ placeholder="Add option"
181
+ class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-l-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"
182
+ @keyup.enter="addOption()"
183
+ />
184
+ <button
185
+ type="button"
186
+ @click="addOption()"
187
+ class="inline-flex items-center px-3 py-2 font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-r-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
188
+ >
189
+ Add
190
+ </button>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ <div class="flex items-center">
195
+ <input id="variant-active" type="checkbox" x-model="newActive" class="h-4 w-4 text-blue-600 dark:bg-neutral-700 border-gray-300 rounded dark:border-neutral-600 focus:ring-blue-600" />
196
+ <label for="variant-active" class="block ml-2 text-gray-900 text-sm dark:text-neutral-200">Active</label>
197
+ </div>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+ <div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
203
+ <button type="button" @click="addVariantType()" class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">Add</button>
204
+ <button type="button" @click="closeAddModal()" class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">Cancel</button>
205
+ </div>
206
+ </div>
207
+ </PageLayout>
208
+ <script client>
209
+ interface VariantType {
210
+ id: number
211
+ name: string
212
+ description: string
213
+ options: string[]
214
+ active: boolean
215
+ createdAt: string
216
+ }
217
+
218
+ const initialVariantTypes: VariantType[] = [
219
+ { id: 1, name: 'Size', description: 'Food portion size options', options: ['Small', 'Medium', 'Large', 'Family Size'], active: true, createdAt: '2023-05-10' },
220
+ { id: 2, name: 'Crust Type', description: 'Pizza crust options', options: ['Thin', 'Regular', 'Thick', 'Stuffed', 'Gluten-Free'], active: true, createdAt: '2023-05-15' },
221
+ { id: 3, name: 'Spice Level', description: 'Heat intensity options', options: ['Mild', 'Medium', 'Hot', 'Extra Hot'], active: true, createdAt: '2023-06-01' },
222
+ { id: 4, name: 'Protein', description: 'Protein options for dishes', options: ['Chicken', 'Beef', 'Pork', 'Tofu', 'Shrimp', 'None'], active: true, createdAt: '2023-06-10' },
223
+ { id: 5, name: 'Toppings', description: 'Additional toppings for dishes', options: ['Cheese', 'Mushrooms', 'Peppers', 'Onions', 'Olives', 'Bacon'], active: true, createdAt: '2023-06-20' },
224
+ { id: 6, name: 'Dietary', description: 'Dietary preference options', options: ['Vegetarian', 'Vegan', 'Gluten-Free', 'Dairy-Free', 'Keto', 'Low-Carb'], active: true, createdAt: '2023-07-05' },
225
+ { id: 7, name: 'Sauce', description: 'Sauce options for dishes', options: ['Marinara', 'Alfredo', 'BBQ', 'Buffalo', 'Sweet & Sour', 'None'], active: true, createdAt: '2023-07-15' },
226
+ { id: 8, name: 'Sweetness', description: 'Sweetness level options', options: ['Not Sweet', 'Slightly Sweet', 'Medium Sweet', 'Very Sweet'], active: true, createdAt: '2023-08-01' },
227
+ ]
228
+
229
+ const variantTypes = state(initialVariantTypes)
230
+ const searchQuery = state('')
231
+ const sortBy = state<'name' | 'optionCount' | 'createdAt'>('name')
232
+ const sortOrder = state<'asc' | 'desc'>('asc')
233
+ const activeFilter = state<'all' | 'active' | 'inactive'>('all')
234
+
235
+ const showAddModal = state(false)
236
+ const newName = state('')
237
+ const newDescription = state('')
238
+ const newOptions = state<string[]>([])
239
+ const newActive = state(true)
240
+ const newOption = state('')
241
+
242
+ const filteredVariantTypes = derived(() => {
243
+ const q = searchQuery().toLowerCase()
244
+ const aFilter = activeFilter()
245
+ const by = sortBy()
246
+ const dir = sortOrder()
247
+
248
+ return variantTypes()
249
+ .filter((v) => {
250
+ const matchesSearch
251
+ = v.name.toLowerCase().includes(q)
252
+ || v.description.toLowerCase().includes(q)
253
+ || v.options.some(o => o.toLowerCase().includes(q))
254
+ const matchesActive
255
+ = aFilter === 'all'
256
+ || (aFilter === 'active' && v.active)
257
+ || (aFilter === 'inactive' && !v.active)
258
+ return matchesSearch && matchesActive
259
+ })
260
+ .sort((a, b) => {
261
+ let cmp = 0
262
+ if (by === 'name') cmp = a.name.localeCompare(b.name)
263
+ else if (by === 'optionCount') cmp = a.options.length - b.options.length
264
+ else if (by === 'createdAt') cmp = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
265
+ return dir === 'asc' ? cmp : -cmp
266
+ })
267
+ })
268
+
269
+ function toggleSort(column: 'name' | 'optionCount' | 'createdAt'): void {
270
+ if (sortBy() === column) {
271
+ sortOrder.update(d => d === 'asc' ? 'desc' : 'asc')
272
+ }
273
+ else {
274
+ sortBy.set(column)
275
+ sortOrder.set('asc')
276
+ }
277
+ }
278
+
279
+ function addOption(): void {
280
+ const o = newOption().trim()
281
+ if (!o)
282
+ return
283
+ newOptions.update(list => [...list, o])
284
+ newOption.set('')
285
+ }
286
+
287
+ function removeOption(index: number): void {
288
+ newOptions.update(list => list.filter((_, i) => i !== index))
289
+ }
290
+
291
+ function openAddModal(): void {
292
+ newName.set('')
293
+ newDescription.set('')
294
+ newOptions.set([])
295
+ newActive.set(true)
296
+ newOption.set('')
297
+ showAddModal.set(true)
298
+ }
299
+
300
+ function closeAddModal(): void {
301
+ showAddModal.set(false)
302
+ }
303
+
304
+ function addVariantType(): void {
305
+ const list = variantTypes()
306
+ const id = list.length > 0 ? Math.max(...list.map(v => v.id)) + 1 : 1
307
+ variantTypes.set([...list, {
308
+ id,
309
+ name: newName(),
310
+ description: newDescription(),
311
+ options: [...newOptions()],
312
+ active: newActive(),
313
+ createdAt: new Date().toISOString().split('T')[0] || '',
314
+ }])
315
+ closeAddModal()
316
+ }
317
+ </script>
318
+
319
+ @endsection