@stacksjs/defaults 0.70.206 → 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,273 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ @title('Receipt Printers - Analytics')
5
+ <div class="p-6 space-y-6">
6
+
7
+ <PageHeader title="Receipt Printers Dashboard" description="Monitor and manage your receipt printers across all locations" />
8
+
9
+ <!-- Stats -->
10
+ <dl class="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mt-5">
11
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
12
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Printers</dt>
13
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ totalPrinters() }}</dd>
14
+ <dd class="flex items-center mt-2 text-sm">
15
+ <span class="text-green-600 dark:text-green-400">{{ onlinePrinters() }} Online</span>
16
+ <span class="mx-2 text-gray-500 dark:text-neutral-400">•</span>
17
+ <span class="text-red-600 dark:text-red-400">{{ offlinePrinters() }} Offline</span>
18
+ <span class="mx-2 text-gray-500 dark:text-neutral-400">•</span>
19
+ <span class="text-yellow-600 dark:text-yellow-400">{{ warningPrinters() }} Warning</span>
20
+ </dd>
21
+ </div>
22
+
23
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
24
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Prints</dt>
25
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ totalPrints().toLocaleString() }}</dd>
26
+ <dd class="flex items-center mt-2 text-gray-600 text-sm dark:text-neutral-400">
27
+ <span>Across all printers</span>
28
+ </dd>
29
+ </div>
30
+
31
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
32
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Error Rate</dt>
33
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ errorRate() }}%</dd>
34
+ <dd class="flex items-center mt-2 text-gray-600 text-sm dark:text-neutral-400">
35
+ <span>{{ totalErrors() }} total errors</span>
36
+ </dd>
37
+ </div>
38
+
39
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
40
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Printer Health</dt>
41
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">
42
+ {{ healthPercent() }}%
43
+ </dd>
44
+ <dd class="flex items-center mt-2 text-sm {{ allHealthy() ? 'text-green-600 dark:text-green-400' : 'text-yellow-600 dark:text-yellow-400' }}">
45
+ <div class="h-4 w-4 mr-1 {{ allHealthy() ? 'i-hugeicons-check-circle' : 'i-hugeicons-alert-01' }}"></div>
46
+ <span>{{ allHealthy() ? 'All systems operational' : 'Attention needed' }}</span>
47
+ </dd>
48
+ </div>
49
+ </dl>
50
+
51
+ <!-- Charts -->
52
+ <div class="grid gap-5 grid-cols-1 lg:grid-cols-3 mt-8">
53
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
54
+ <div class="p-6">
55
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Printer Status</h3>
56
+ <div class="mt-2 h-64">
57
+ <canvas id="chart_1"></canvas>
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <div class="overflow-hidden lg:col-span-2 bg-white dark:bg-neutral-800 rounded-lg shadow">
63
+ <div class="p-6">
64
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Print Volume by Printer</h3>
65
+ <div class="mt-2 h-64">
66
+ <canvas id="chart_2"></canvas>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ <!-- Filters -->
73
+ <div class="flex flex-wrap gap-4 mt-8">
74
+ <div class="w-full sm:w-auto">
75
+ <label for="location-filter" class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Location</label>
76
+ <select id="location-filter" x-model="locationFilter" class="block mt-1 pl-3 pr-10 py-2 w-full text-base sm:text-sm dark:text-white dark:bg-neutral-700 border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-blue-500">
77
+ <template :for="location in locations">
78
+ <option :value="location">{{ location }}</option>
79
+ </template>
80
+ </select>
81
+ </div>
82
+ <div class="w-full sm:w-auto">
83
+ <label for="status-filter" class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Status</label>
84
+ <select id="status-filter" x-model="statusFilter" class="block mt-1 pl-3 pr-10 py-2 w-full text-base sm:text-sm dark:text-white dark:bg-neutral-700 border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-blue-500">
85
+ <template :for="status in statuses">
86
+ <option :value="status">{{ status }}</option>
87
+ </template>
88
+ </select>
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Printers Table -->
93
+ <div class="mt-4">
94
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
95
+ <div class="flex items-center justify-between px-4 py-5 sm:px-6">
96
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Receipt Printers</h3>
97
+ <span class="text-gray-500 text-sm dark:text-neutral-400">Showing {{ filteredPrinters().length }} of {{ totalPrinters() }} printers</span>
98
+ </div>
99
+ <div class="border-gray-200 border-t dark:border-neutral-700">
100
+ <div class="overflow-x-auto">
101
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
102
+ <thead class="bg-gray-50 dark:bg-neutral-700">
103
+ <tr>
104
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Name</th>
105
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Mac Address</th>
106
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Location</th>
107
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Terminal</th>
108
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Status</th>
109
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Last Ping</th>
110
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Print Count</th>
111
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Actions</th>
112
+ </tr>
113
+ </thead>
114
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
115
+ <template :for="printer in filteredPrinters">
116
+ <tr>
117
+ <td class="px-6 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ printer.username }}</td>
118
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ printer.macAddress }}</td>
119
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ printer.location }}</td>
120
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ printer.terminal }}</td>
121
+ <td class="px-6 py-4 whitespace-nowrap">
122
+ <span class="inline-flex px-2 font-semibold leading-5 text-xs rounded-full {{ statusBadgeClass(printer.status) }}">
123
+ {{ printer.status }}
124
+ </span>
125
+ </td>
126
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ printer.lastPing }}</td>
127
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">
128
+ {{ printer.printCount.toLocaleString() }}
129
+ @if(printer.errorCount > 0)
130
+ <span class="ml-1 text-red-500 text-xs">({{ printer.errorCount }} errors)</span>
131
+ @endif
132
+ </td>
133
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">
134
+ <div class="flex space-x-2">
135
+ <button class="text-gray-400 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 duration-150 transition-colors">
136
+ <div class="h-5 w-5 i-hugeicons-refresh"></div>
137
+ </button>
138
+ <button class="text-gray-400 dark:text-neutral-400 hover:text-gray-900 dark:hover:text-gray-300 duration-150 transition-colors">
139
+ <div class="h-5 w-5 i-hugeicons-settings-02"></div>
140
+ </button>
141
+ <button class="text-gray-400 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 duration-150 transition-colors">
142
+ <div class="h-5 w-5 i-hugeicons-electric-plugs"></div>
143
+ </button>
144
+ </div>
145
+ </td>
146
+ </tr>
147
+ </template>
148
+ </tbody>
149
+ </table>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </div>
154
+
155
+ <!-- Error Rate Chart -->
156
+ <div class="mt-8">
157
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
158
+ <div class="p-6">
159
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Error Count by Printer</h3>
160
+ <div class="mt-2 h-64">
161
+ <canvas id="chart_3"></canvas>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <script client>
169
+ // Filter options — moved out of the former `<script server>` block
170
+ // (stacksjs/stacks#1838).
171
+ const locations = ['All Locations', 'Main Floor', 'Second Floor', 'Kitchen', 'Pickup Area'] as const
172
+ const statuses = ['All Statuses', 'Online', 'Offline', 'Warning'] as const
173
+
174
+ interface Printer {
175
+ id: number
176
+ username: string
177
+ macAddress: string
178
+ location: string
179
+ terminal: string
180
+ status: 'Online' | 'Offline' | 'Warning'
181
+ lastPing: string
182
+ printCount: number
183
+ errorCount: number
184
+ }
185
+
186
+ const initialPrinters: Printer[] = [
187
+ { id: 1, username: 'Checkout-1', macAddress: '00:1B:44:11:3A:B7', location: 'Main Floor', terminal: 'POS-1', status: 'Online', lastPing: '2 mins ago', printCount: 1245, errorCount: 3 },
188
+ { id: 2, username: 'Checkout-2', macAddress: '00:1B:44:11:3A:C8', location: 'Main Floor', terminal: 'POS-2', status: 'Online', lastPing: '1 min ago', printCount: 987, errorCount: 0 },
189
+ { id: 3, username: 'Kitchen-1', macAddress: '00:1B:44:11:3B:D9', location: 'Kitchen', terminal: 'KDS-1', status: 'Offline', lastPing: '3 hours ago', printCount: 876, errorCount: 12 },
190
+ { id: 4, username: 'Checkout-3', macAddress: '00:1B:44:11:3C:E0', location: 'Second Floor', terminal: 'POS-3', status: 'Online', lastPing: '5 mins ago', printCount: 765, errorCount: 1 },
191
+ { id: 5, username: 'Pickup-1', macAddress: '00:1B:44:11:3D:F1', location: 'Pickup Area', terminal: 'POS-4', status: 'Warning', lastPing: '10 mins ago', printCount: 654, errorCount: 5 },
192
+ { id: 6, username: 'Checkout-4', macAddress: '00:1B:44:11:3E:02', location: 'Main Floor', terminal: 'POS-5', status: 'Online', lastPing: '3 mins ago', printCount: 543, errorCount: 0 },
193
+ { id: 7, username: 'Kitchen-2', macAddress: '00:1B:44:11:3F:13', location: 'Kitchen', terminal: 'KDS-2', status: 'Online', lastPing: '4 mins ago', printCount: 432, errorCount: 2 },
194
+ ]
195
+
196
+ const printers = state(initialPrinters)
197
+ const locationFilter = state<string>('All Locations')
198
+ const statusFilter = state<string>('All Statuses')
199
+
200
+ const filteredPrinters = derived(() => {
201
+ const lFilter = locationFilter()
202
+ const sFilter = statusFilter()
203
+ return printers().filter(p =>
204
+ (lFilter === 'All Locations' || p.location === lFilter)
205
+ && (sFilter === 'All Statuses' || p.status === sFilter),
206
+ )
207
+ })
208
+
209
+ const totalPrinters = derived(() => printers().length)
210
+ const onlinePrinters = derived(() => printers().filter(p => p.status === 'Online').length)
211
+ const offlinePrinters = derived(() => printers().filter(p => p.status === 'Offline').length)
212
+ const warningPrinters = derived(() => printers().filter(p => p.status === 'Warning').length)
213
+ const totalPrints = derived(() => printers().reduce((sum, p) => sum + p.printCount, 0))
214
+ const totalErrors = derived(() => printers().reduce((sum, p) => sum + p.errorCount, 0))
215
+ const errorRate = derived(() => totalPrints() > 0 ? ((totalErrors() / totalPrints()) * 100).toFixed(2) : '0.00')
216
+ const healthPercent = derived(() => totalPrinters() > 0 ? Math.round((onlinePrinters() / totalPrinters()) * 100) : 0)
217
+ const allHealthy = derived(() => onlinePrinters() === totalPrinters() && totalPrinters() > 0)
218
+
219
+ function statusBadgeClass(status: string): string {
220
+ switch (status) {
221
+ case 'Online': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
222
+ case 'Offline': return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300'
223
+ case 'Warning': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300'
224
+ default: return 'bg-gray-100 text-gray-800 dark:bg-neutral-700 dark:text-neutral-300'
225
+ }
226
+ }
227
+
228
+ const statusData = {
229
+ labels: ['Online', 'Offline', 'Warning'],
230
+ datasets: [{ backgroundColor: ['#10B981', '#EF4444', '#F59E0B'], data: [5, 1, 1] }],
231
+ }
232
+
233
+ const printVolumeData = {
234
+ labels: ['Checkout-1', 'Checkout-2', 'Kitchen-1', 'Checkout-3', 'Pickup-1', 'Checkout-4', 'Kitchen-2'],
235
+ datasets: [{ label: 'Print Count', backgroundColor: 'rgba(59, 130, 246, 0.8)', data: [1245, 987, 876, 765, 654, 543, 432] }],
236
+ }
237
+
238
+ const errorRateData = {
239
+ labels: ['Checkout-1', 'Checkout-2', 'Kitchen-1', 'Checkout-3', 'Pickup-1', 'Checkout-4', 'Kitchen-2'],
240
+ datasets: [{ label: 'Error Count', backgroundColor: 'rgba(239, 68, 68, 0.8)', data: [3, 0, 12, 1, 5, 0, 2] }],
241
+ }
242
+
243
+ const chartOptions = {
244
+ responsive: true,
245
+ maintainAspectRatio: false,
246
+ plugins: { legend: { display: true, position: 'bottom' } },
247
+ }
248
+
249
+ const barChartOptions = {
250
+ responsive: true,
251
+ maintainAspectRatio: false,
252
+ plugins: { legend: { display: false } },
253
+ scales: {
254
+ y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
255
+ x: { grid: { display: false } },
256
+ },
257
+ }
258
+
259
+ const { Chart, registerables } = await import('@stacksjs/charts')
260
+ Chart.register(...registerables)
261
+
262
+ const { destroyAll } = useCharts([
263
+ { Chart, id: 'chart_1', type: 'pie', data: statusData, options: chartOptions },
264
+ { Chart, id: 'chart_2', type: 'bar', data: printVolumeData, options: barChartOptions },
265
+ { Chart, id: 'chart_3', type: 'bar', data: errorRateData, options: barChartOptions },
266
+ ])
267
+
268
+ onDestroy(() => {
269
+ destroyAll()
270
+ })
271
+ </script>
272
+
273
+ @endsection
@@ -0,0 +1,308 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ @title('Printer Logs - Analytics')
5
+ <div class="p-6 space-y-6">
6
+
7
+ <PageHeader title="Print Logs" description="View and analyze all print jobs across your receipt printers" />
8
+
9
+ <!-- Stats — sample summary numbers used by all four cards. -->
10
+ <dl class="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mt-5">
11
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
12
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Print Jobs</dt>
13
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ totalPrintsSummary }}</dd>
14
+ <dd class="flex items-center mt-2 text-sm">
15
+ <span class="text-green-600 dark:text-green-400">{{ successfulPrints }} Successful</span>
16
+ <span class="mx-2 text-gray-500 dark:text-neutral-400">•</span>
17
+ <span class="text-red-600 dark:text-red-400">{{ failedPrints }} Failed</span>
18
+ </dd>
19
+ </div>
20
+
21
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
22
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Success Rate</dt>
23
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ successRate }}%</dd>
24
+ <dd class="flex items-center mt-2 text-gray-600 text-sm dark:text-neutral-400">
25
+ <span>{{ warningPrints }} prints with warnings</span>
26
+ </dd>
27
+ </div>
28
+
29
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
30
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Pages</dt>
31
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ totalPages }}</dd>
32
+ <dd class="flex items-center mt-2 text-gray-600 text-sm dark:text-neutral-400">
33
+ <span>Avg. {{ pagesPerPrint }} pages per print</span>
34
+ </dd>
35
+ </div>
36
+
37
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
38
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Average Print Time</dt>
39
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ averagePrintTime }}</dd>
40
+ <dd class="flex items-center mt-2 text-gray-600 text-sm dark:text-neutral-400">
41
+ <span>For successful prints</span>
42
+ </dd>
43
+ </div>
44
+ </dl>
45
+
46
+ <!-- Charts -->
47
+ <div class="grid gap-5 grid-cols-1 lg:grid-cols-2 mt-8">
48
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
49
+ <div class="p-6">
50
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Hourly Print Volume</h3>
51
+ <div class="mt-2 h-64">
52
+ <canvas id="chart_1"></canvas>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
58
+ <div class="p-6">
59
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Print Volume by Printer</h3>
60
+ <div class="mt-2 h-64">
61
+ <canvas id="chart_2"></canvas>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <!-- Filters -->
68
+ <div class="flex flex-wrap gap-4 mt-8">
69
+ <div class="w-full sm:w-auto">
70
+ <label for="printer-filter" class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Printer</label>
71
+ <select id="printer-filter" x-model="printerFilter" class="block mt-1 pl-3 pr-10 py-2 w-full text-base sm:text-sm dark:text-white dark:bg-neutral-700 border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-blue-500">
72
+ <template :for="printer in printerOptions">
73
+ <option :value="printer">{{ printer }}</option>
74
+ </template>
75
+ </select>
76
+ </div>
77
+ <div class="w-full sm:w-auto">
78
+ <label for="status-filter" class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Status</label>
79
+ <select id="status-filter" x-model="statusFilter" class="block mt-1 pl-3 pr-10 py-2 w-full text-base sm:text-sm dark:text-white dark:bg-neutral-700 border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-blue-500">
80
+ <template :for="status in statuses">
81
+ <option :value="status">{{ status }}</option>
82
+ </template>
83
+ </select>
84
+ </div>
85
+ <div class="w-full sm:w-auto">
86
+ <label for="date-filter" class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Date Range</label>
87
+ <select id="date-filter" x-model="dateFilter" class="block mt-1 pl-3 pr-10 py-2 w-full text-base sm:text-sm dark:text-white dark:bg-neutral-700 border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-blue-500">
88
+ <template :for="range in dateRanges">
89
+ <option :value="range">{{ range }}</option>
90
+ </template>
91
+ </select>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- Print Logs Table -->
96
+ <div class="mt-4">
97
+ <div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
98
+ <div class="flex items-center justify-between px-4 py-5 sm:px-6">
99
+ <h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Print Logs</h3>
100
+ <span class="text-gray-500 text-sm dark:text-neutral-400">Showing {{ filteredPrints().length }} of {{ totalPrints() }} prints</span>
101
+ </div>
102
+ <div class="border-gray-200 border-t dark:border-neutral-700">
103
+ <div class="overflow-x-auto">
104
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
105
+ <thead class="bg-gray-50 dark:bg-neutral-700">
106
+ <tr>
107
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">ID</th>
108
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Printer</th>
109
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Document</th>
110
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Timestamp</th>
111
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Status</th>
112
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Duration</th>
113
+ <th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Actions</th>
114
+ </tr>
115
+ </thead>
116
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
117
+ <template :for="print in filteredPrints">
118
+ <tr>
119
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">#{{ print.id.toString().padStart(6, '0') }}</td>
120
+ <td class="px-6 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ print.printer }}</td>
121
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ print.document }}</td>
122
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ print.timestamp }}</td>
123
+ <td class="px-6 py-4 whitespace-nowrap">
124
+ <span class="inline-flex px-2 font-semibold leading-5 text-xs rounded-full {{ statusBadgeClass(print.status) }}">
125
+ {{ print.status }}
126
+ </span>
127
+ </td>
128
+ <td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ print.duration }}</td>
129
+ <td class="px-6 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
130
+ <div class="flex space-x-2">
131
+ <button class="text-gray-400 dark:text-neutral-400 hover:text-gray-900 dark:hover:text-gray-300 duration-150 transition-colors" title="View Details">
132
+ <div class="h-5 w-5 i-hugeicons-view"></div>
133
+ </button>
134
+ <button class="text-gray-400 dark:text-neutral-400 hover:text-gray-900 dark:hover:text-gray-300 duration-150 transition-colors" title="Reprint">
135
+ <div class="h-5 w-5 i-hugeicons-refresh"></div>
136
+ </button>
137
+ <button class="text-gray-400 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 duration-150 transition-colors" title="Delete">
138
+ <div class="h-5 w-5 i-hugeicons-waste"></div>
139
+ </button>
140
+ </div>
141
+ </td>
142
+ </tr>
143
+ </template>
144
+ </tbody>
145
+ </table>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+ <!-- Pagination — static skeleton; no live wiring yet. -->
152
+ <div class="flex items-center justify-between mt-4 px-4 py-3 sm:px-6 border-gray-200 border-t dark:border-neutral-700">
153
+ <div class="flex sm:hidden flex-1 justify-between">
154
+ <a href="#" class="inline-flex relative items-center px-4 py-2 font-medium text-gray-700 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 hover:bg-gray-50 dark:hover:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">Previous</a>
155
+ <a href="#" class="inline-flex relative items-center ml-3 px-4 py-2 font-medium text-gray-700 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 hover:bg-gray-50 dark:hover:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">Next</a>
156
+ </div>
157
+ <div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
158
+ <div>
159
+ <p class="text-gray-700 text-sm dark:text-neutral-300">
160
+ Showing <span class="font-medium">1</span> to <span class="font-medium">15</span> of <span class="font-medium">755</span> results
161
+ </p>
162
+ </div>
163
+ <div>
164
+ <nav class="inline-flex -space-x-px rounded-md shadow-sm isolate" aria-label="Pagination">
165
+ <a href="#" class="inline-flex relative focus:z-20 items-center px-2 py-2 text-gray-400 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset rounded-l-md dark:ring-neutral-600 focus:outline-offset-0">
166
+ <span class="sr-only">Previous</span>
167
+ <div class="h-5 w-5 i-hugeicons-arrow-left-01" aria-hidden="true"></div>
168
+ </a>
169
+ <a href="#" aria-current="page" class="inline-flex relative z-10 focus:z-20 items-center px-4 py-2 font-semibold text-sm text-white bg-blue-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2">1</a>
170
+ <a href="#" class="inline-flex relative focus:z-20 items-center px-4 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset dark:ring-neutral-600 focus:outline-offset-0">2</a>
171
+ <a href="#" class="hidden md:inline-flex relative focus:z-20 items-center px-4 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset dark:ring-neutral-600 focus:outline-offset-0">3</a>
172
+ <span class="inline-flex relative items-center px-4 py-2 font-semibold text-gray-700 text-sm dark:text-neutral-400 ring-1 ring-gray-300 ring-inset dark:ring-neutral-600 focus:outline-offset-0">...</span>
173
+ <a href="#" class="hidden md:inline-flex relative focus:z-20 items-center px-4 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset dark:ring-neutral-600 focus:outline-offset-0">50</a>
174
+ <a href="#" class="inline-flex relative focus:z-20 items-center px-2 py-2 text-gray-400 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset rounded-r-md dark:ring-neutral-600 focus:outline-offset-0">
175
+ <span class="sr-only">Next</span>
176
+ <div class="h-5 w-5 i-hugeicons-arrow-right-01" aria-hidden="true"></div>
177
+ </a>
178
+ </nav>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+
184
+ <script client>
185
+ // Filter options — moved out of the former `<script server>` block
186
+ // (stacksjs/stacks#1838).
187
+ const printerOptions = ['All Printers', 'Checkout-1', 'Checkout-2', 'Checkout-3', 'Checkout-4', 'Kitchen-1', 'Kitchen-2', 'Pickup-1'] as const
188
+ const statuses = ['All Statuses', 'Success', 'Warning', 'Failed'] as const
189
+ const dateRanges = ['Today', 'Yesterday', 'Last 7 days', 'Last 30 days', 'This month', 'Last month'] as const
190
+
191
+ interface PrintLog {
192
+ id: number
193
+ printer: string
194
+ document: string
195
+ timestamp: string
196
+ status: 'Success' | 'Warning' | 'Failed'
197
+ size: string
198
+ pages: number
199
+ duration: string
200
+ }
201
+
202
+ const initialPrints: PrintLog[] = [
203
+ { id: 1, printer: 'Checkout-1', document: 'Receipt #5432', timestamp: '2023-12-01 14:32:45', status: 'Success', size: '8.5KB', pages: 1, duration: '1.2s' },
204
+ { id: 2, printer: 'Checkout-2', document: 'Receipt #5431', timestamp: '2023-12-01 14:30:12', status: 'Success', size: '9.1KB', pages: 1, duration: '1.3s' },
205
+ { id: 3, printer: 'Kitchen-1', document: 'Order #5430', timestamp: '2023-12-01 14:28:55', status: 'Failed', size: '12.3KB', pages: 2, duration: '0.0s' },
206
+ { id: 4, printer: 'Checkout-3', document: 'Receipt #5429', timestamp: '2023-12-01 14:25:33', status: 'Success', size: '8.7KB', pages: 1, duration: '1.1s' },
207
+ { id: 5, printer: 'Pickup-1', document: 'Pickup #5428', timestamp: '2023-12-01 14:22:18', status: 'Success', size: '10.2KB', pages: 1, duration: '1.4s' },
208
+ { id: 6, printer: 'Kitchen-1', document: 'Order #5427', timestamp: '2023-12-01 14:20:05', status: 'Success', size: '11.8KB', pages: 2, duration: '2.1s' },
209
+ { id: 7, printer: 'Checkout-1', document: 'Receipt #5426', timestamp: '2023-12-01 14:18:42', status: 'Success', size: '8.3KB', pages: 1, duration: '1.2s' },
210
+ { id: 8, printer: 'Kitchen-2', document: 'Order #5425', timestamp: '2023-12-01 14:15:30', status: 'Warning', size: '12.5KB', pages: 2, duration: '3.5s' },
211
+ { id: 9, printer: 'Checkout-4', document: 'Receipt #5424', timestamp: '2023-12-01 14:12:22', status: 'Success', size: '8.9KB', pages: 1, duration: '1.3s' },
212
+ { id: 10, printer: 'Checkout-2', document: 'Receipt #5423', timestamp: '2023-12-01 14:10:15', status: 'Success', size: '9.0KB', pages: 1, duration: '1.2s' },
213
+ { id: 11, printer: 'Kitchen-1', document: 'Order #5422', timestamp: '2023-12-01 14:08:03', status: 'Success', size: '11.7KB', pages: 2, duration: '2.0s' },
214
+ { id: 12, printer: 'Checkout-3', document: 'Receipt #5421', timestamp: '2023-12-01 14:05:48', status: 'Success', size: '8.6KB', pages: 1, duration: '1.1s' },
215
+ { id: 13, printer: 'Pickup-1', document: 'Pickup #5420', timestamp: '2023-12-01 14:02:35', status: 'Failed', size: '10.1KB', pages: 1, duration: '0.0s' },
216
+ { id: 14, printer: 'Kitchen-2', document: 'Order #5419', timestamp: '2023-12-01 14:00:20', status: 'Success', size: '12.0KB', pages: 2, duration: '2.2s' },
217
+ { id: 15, printer: 'Checkout-1', document: 'Receipt #5418', timestamp: '2023-12-01 13:58:05', status: 'Success', size: '8.4KB', pages: 1, duration: '1.2s' },
218
+ ]
219
+
220
+ const prints = state(initialPrints)
221
+ const printerFilter = state<string>('All Printers')
222
+ const statusFilter = state<string>('All Statuses')
223
+ const dateFilter = state<string>('Today')
224
+
225
+ const filteredPrints = derived(() => {
226
+ const pFilter = printerFilter()
227
+ const sFilter = statusFilter()
228
+ return prints().filter(p =>
229
+ (pFilter === 'All Printers' || p.printer === pFilter)
230
+ && (sFilter === 'All Statuses' || p.status === sFilter),
231
+ )
232
+ })
233
+
234
+ const totalPrints = derived(() => prints().length)
235
+
236
+ // Summary cards use canned numbers — these are the page-wide rollup
237
+ // values, not derived from `prints[]` (which is just the log slice).
238
+ const totalPrintsSummary = 755
239
+ const successfulPrints = 732
240
+ const failedPrints = 15
241
+ const warningPrints = 8
242
+ const successRate = ((successfulPrints / totalPrintsSummary) * 100).toFixed(1)
243
+ const averagePrintTime = '1.4s'
244
+ const totalPages = 1105
245
+ const pagesPerPrint = (totalPages / totalPrintsSummary).toFixed(1)
246
+
247
+ function statusBadgeClass(status: string): string {
248
+ switch (status) {
249
+ case 'Success': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
250
+ case 'Failed': return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300'
251
+ case 'Warning': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300'
252
+ default: return 'bg-gray-100 text-gray-800 dark:bg-neutral-700 dark:text-neutral-300'
253
+ }
254
+ }
255
+
256
+ const hourlyPrintData = {
257
+ labels: ['9AM', '10AM', '11AM', '12PM', '1PM', '2PM', '3PM', '4PM', '5PM', '6PM', '7PM', '8PM'],
258
+ datasets: [{
259
+ label: 'Print Volume',
260
+ backgroundColor: 'rgba(59, 130, 246, 0.2)',
261
+ borderColor: 'rgba(59, 130, 246, 1)',
262
+ borderWidth: 2,
263
+ pointBackgroundColor: 'rgba(59, 130, 246, 1)',
264
+ pointBorderColor: '#fff',
265
+ pointHoverBackgroundColor: '#fff',
266
+ pointHoverBorderColor: 'rgba(59, 130, 246, 1)',
267
+ fill: true,
268
+ tension: 0.4,
269
+ data: [25, 38, 45, 56, 48, 52, 45, 42, 38, 30, 22, 15],
270
+ }],
271
+ }
272
+
273
+ const printerVolumeData = {
274
+ labels: ['Checkout-1', 'Checkout-2', 'Checkout-3', 'Checkout-4', 'Kitchen-1', 'Kitchen-2', 'Pickup-1'],
275
+ datasets: [{
276
+ label: 'Print Count',
277
+ backgroundColor: 'rgba(16, 185, 129, 0.8)',
278
+ borderColor: 'rgba(16, 185, 129, 1)',
279
+ borderWidth: 1,
280
+ borderRadius: 4,
281
+ data: [120, 105, 95, 85, 150, 130, 70],
282
+ }],
283
+ }
284
+
285
+ const chartOptions = {
286
+ responsive: true,
287
+ maintainAspectRatio: false,
288
+ plugins: { legend: { display: false } },
289
+ scales: {
290
+ y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
291
+ x: { grid: { display: false } },
292
+ },
293
+ }
294
+
295
+ const { Chart, registerables } = await import('@stacksjs/charts')
296
+ Chart.register(...registerables)
297
+
298
+ const { destroyAll } = useCharts([
299
+ { Chart, id: 'chart_1', type: 'line', data: hourlyPrintData, options: chartOptions },
300
+ { Chart, id: 'chart_2', type: 'bar', data: printerVolumeData, options: chartOptions },
301
+ ])
302
+
303
+ onDestroy(() => {
304
+ destroyAll()
305
+ })
306
+ </script>
307
+
308
+ @endsection