@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,315 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ @title('Dashboard - Commerce Marketing Analytics')
5
+ <PageLayout>
6
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mb-6">
7
+ <div class="flex items-center space-x-2">
8
+ <div class="h-5 w-5 text-gray-500 dark:text-neutral-400 i-hugeicons-calendar-03"></div>
9
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-300">{{ dateRangeDisplay }}</span>
10
+ </div>
11
+
12
+ <div class="flex flex-wrap gap-2 items-center">
13
+ <span class="text-gray-500 text-sm dark:text-neutral-400">compared to</span>
14
+ <div class="relative">
15
+ <select x-model="comparisonType" 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">
16
+ <option value="no-comparison">No comparison</option>
17
+ <option value="previous-period">Previous period</option>
18
+ <option value="previous-year">Previous year</option>
19
+ </select>
20
+ </div>
21
+ <button type="button" class="inline-flex items-center px-3 py-1.5 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">
22
+ <div class="mr-1 h-4 w-4 i-hugeicons-settings-01"></div>
23
+ Auto
24
+ </button>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-6 mb-8 p-4 bg-black dark:bg-neutral-900 rounded-lg">
29
+ <div class="flex flex-col items-center justify-center">
30
+ <div class="font-bold text-4xl text-white">$125k</div>
31
+ <div class="text-gray-400 text-sm">Total Spend</div>
32
+ </div>
33
+ <div class="flex flex-col items-center justify-center">
34
+ <div class="font-bold text-4xl text-white">$375k</div>
35
+ <div class="text-gray-400 text-sm">Total Revenue</div>
36
+ </div>
37
+ <div class="flex flex-col items-center justify-center">
38
+ <div class="font-bold text-4xl text-white">{{ marketingOverview.roi }}%</div>
39
+ <div class="text-gray-400 text-sm">ROI</div>
40
+ </div>
41
+ <div class="flex flex-col items-center justify-center">
42
+ <div class="font-bold text-4xl text-white">7.5k</div>
43
+ <div class="text-gray-400 text-sm">Conversions</div>
44
+ </div>
45
+ <div class="flex flex-col items-center justify-center">
46
+ <div class="font-bold text-4xl text-white">${{ marketingOverview.cpa.toFixed(2) }}</div>
47
+ <div class="text-gray-400 text-sm">Cost Per Acquisition</div>
48
+ </div>
49
+ <div class="flex flex-col items-center justify-center">
50
+ <div class="font-bold text-4xl text-white">{{ marketingOverview.conversionRate }}</div>
51
+ <div class="text-gray-400 text-sm">Conversion Rate</div>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="mb-8 p-4 bg-white dark:bg-neutral-800 rounded-lg shadow">
56
+ <div class="mb-4">
57
+ <h3 class="font-medium leading-6 text-gray-900 text-lg dark:text-white">Marketing Performance</h3>
58
+ <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Revenue vs. marketing spend over time</p>
59
+ </div>
60
+ <div class="h-80 w-full">
61
+ <canvas id="marketing_chart"></canvas>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="grid gap-8 grid-cols-1 lg:grid-cols-2">
66
+ <div>
67
+ <div class="mb-4"><h3 class="font-medium text-gray-900 text-lg dark:text-white">Campaigns</h3></div>
68
+ <div class="overflow-hidden border border-gray-200 rounded-lg dark:border-neutral-700">
69
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
70
+ <thead class="bg-gray-50 dark:bg-neutral-700/50">
71
+ <tr>
72
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Campaign</th>
73
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Spend</th>
74
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Revenue</th>
75
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">ROI</th>
76
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">%</th>
77
+ </tr>
78
+ </thead>
79
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
80
+ <template :for="campaign in campaignsData">
81
+ <tr class="relative hover:bg-gray-50 dark:hover:bg-neutral-700/50">
82
+ <td class="px-4 py-3 text-gray-900 text-sm whitespace-nowrap dark:text-white">
83
+ <div class="absolute inset-0 bg-rose-100/50 dark:bg-rose-900/50" :style="'width: ' + campaign.percentage + '%'"></div>
84
+ <span class="relative z-10">{{ campaign.name }}</span>
85
+ <span class="block relative z-10 text-gray-500 text-xs dark:text-neutral-400">{{ campaign.id }}</span>
86
+ </td>
87
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatCurrency(campaign.spend) }}</span></td>
88
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatCurrency(campaign.revenue) }}</span></td>
89
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ campaign.roi }}%</span></td>
90
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ campaign.percentage }}%</span></td>
91
+ </tr>
92
+ </template>
93
+ </tbody>
94
+ </table>
95
+ </div>
96
+ <div class="flex justify-end mt-2">
97
+ <StxLink to="/dashboard/commerce/analytics/marketing/campaigns" class="text-blue-600 text-sm dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">View all campaigns</StxLink>
98
+ </div>
99
+ </div>
100
+
101
+ <div>
102
+ <div class="mb-4"><h3 class="font-medium text-gray-900 text-lg dark:text-white">Channels</h3></div>
103
+ <div class="overflow-hidden border border-gray-200 rounded-lg dark:border-neutral-700">
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/50">
106
+ <tr>
107
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Channel</th>
108
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Spend</th>
109
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Revenue</th>
110
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">ROI</th>
111
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">%</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="channel in channelsData">
116
+ <tr class="relative hover:bg-gray-50 dark:hover:bg-neutral-700/50">
117
+ <td class="px-4 py-3 text-gray-900 text-sm whitespace-nowrap dark:text-white">
118
+ <div class="absolute inset-0 bg-blue-100/50 dark:bg-blue-900/50" :style="'width: ' + channel.percentage + '%'"></div>
119
+ <span class="relative z-10">{{ channel.name }}</span>
120
+ </td>
121
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatCurrency(channel.spend) }}</span></td>
122
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatCurrency(channel.revenue) }}</span></td>
123
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ channel.roi }}%</span></td>
124
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ channel.percentage }}%</span></td>
125
+ </tr>
126
+ </template>
127
+ </tbody>
128
+ </table>
129
+ </div>
130
+ <div class="flex justify-end mt-2">
131
+ <StxLink to="/dashboard/commerce/analytics/marketing/channels" class="text-blue-600 text-sm dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">View all channels</StxLink>
132
+ </div>
133
+ </div>
134
+ </div>
135
+
136
+ <div class="mt-8">
137
+ <div class="mb-4"><h3 class="font-medium text-gray-900 text-lg dark:text-white">Top Performing Ads</h3></div>
138
+ <div class="overflow-hidden border border-gray-200 rounded-lg dark:border-neutral-700">
139
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
140
+ <thead class="bg-gray-50 dark:bg-neutral-700/50">
141
+ <tr>
142
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Ad</th>
143
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Impressions</th>
144
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Clicks</th>
145
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">CTR</th>
146
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Conversions</th>
147
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">CPA</th>
148
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">%</th>
149
+ </tr>
150
+ </thead>
151
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
152
+ <template :for="ad in adsData">
153
+ <tr class="relative hover:bg-gray-50 dark:hover:bg-neutral-700/50">
154
+ <td class="px-4 py-3 text-gray-900 text-sm whitespace-nowrap dark:text-white">
155
+ <div class="absolute inset-0 bg-purple-100/50 dark:bg-purple-900/50" :style="'width: ' + ad.percentage + '%'"></div>
156
+ <span class="relative z-10">{{ ad.name }}</span>
157
+ <span class="block relative z-10 text-gray-500 text-xs dark:text-neutral-400">{{ ad.id }}</span>
158
+ </td>
159
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatNumber(ad.impressions) }}</span></td>
160
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatNumber(ad.clicks) }}</span></td>
161
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ ad.ctr }}%</span></td>
162
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ formatNumber(ad.conversions) }}</span></td>
163
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">${{ ad.cpa }}</span></td>
164
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300"><span class="relative z-10">{{ ad.percentage }}%</span></td>
165
+ </tr>
166
+ </template>
167
+ </tbody>
168
+ </table>
169
+ </div>
170
+ <div class="flex justify-end mt-2">
171
+ <StxLink to="/dashboard/commerce/analytics/marketing/ads" class="text-blue-600 text-sm dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">View all ads</StxLink>
172
+ </div>
173
+ </div>
174
+ </PageLayout>
175
+ <script client>
176
+
177
+ interface ChartLike { destroy: () => void }
178
+ type ChartCtor = new (canvas: HTMLElement, config: { type: string, data: unknown, options?: unknown }) => ChartLike
179
+
180
+ // Static analytics tables + overview — moved out of the former
181
+ // `<script server>` block (stacksjs/stacks#1838).
182
+ const campaignsRaw = [
183
+ { name: 'Summer Sale 2024', id: 'SUMMER24', spend: 25000, revenue: 75000, roi: 200, conversions: 1500 },
184
+ { name: 'New Product Launch', id: 'NEWPROD', spend: 20000, revenue: 60000, roi: 200, conversions: 1200 },
185
+ { name: 'Holiday Special', id: 'HOLIDAY', spend: 18000, revenue: 54000, roi: 200, conversions: 1080 },
186
+ { name: 'Back to School', id: 'SCHOOL', spend: 15000, revenue: 45000, roi: 200, conversions: 900 },
187
+ { name: 'Flash Sale', id: 'FLASH', spend: 12000, revenue: 36000, roi: 200, conversions: 720 },
188
+ { name: 'Loyalty Program', id: 'LOYALTY', spend: 10000, revenue: 30000, roi: 200, conversions: 600 },
189
+ { name: 'Referral Program', id: 'REFERRAL', spend: 8000, revenue: 24000, roi: 200, conversions: 480 },
190
+ { name: 'Email Newsletter', id: 'EMAIL', spend: 7000, revenue: 21000, roi: 200, conversions: 420 },
191
+ { name: 'Retargeting Campaign', id: 'RETARGET', spend: 6000, revenue: 18000, roi: 200, conversions: 360 },
192
+ { name: 'Social Media Contest', id: 'CONTEST', spend: 4000, revenue: 12000, roi: 200, conversions: 240 },
193
+ ]
194
+
195
+ const channelsRaw = [
196
+ { name: 'Paid Search', spend: 35000, revenue: 105000, roi: 200, conversions: 2100 },
197
+ { name: 'Social Media', spend: 30000, revenue: 90000, roi: 200, conversions: 1800 },
198
+ { name: 'Email Marketing', spend: 20000, revenue: 60000, roi: 200, conversions: 1200 },
199
+ { name: 'Display Ads', spend: 15000, revenue: 45000, roi: 200, conversions: 900 },
200
+ { name: 'Affiliate Marketing', spend: 10000, revenue: 30000, roi: 200, conversions: 600 },
201
+ { name: 'Influencer Marketing', spend: 8000, revenue: 24000, roi: 200, conversions: 480 },
202
+ { name: 'Content Marketing', spend: 5000, revenue: 15000, roi: 200, conversions: 300 },
203
+ { name: 'SMS Marketing', spend: 2000, revenue: 6000, roi: 200, conversions: 120 },
204
+ ]
205
+
206
+ const adsRaw = [
207
+ { name: 'Summer Sale Banner', id: 'AD-001', impressions: 250000, clicks: 12500, ctr: 5, conversions: 625, cpa: 16 },
208
+ { name: 'Product Showcase Video', id: 'AD-002', impressions: 200000, clicks: 10000, ctr: 5, conversions: 500, cpa: 16 },
209
+ { name: 'Limited Time Offer', id: 'AD-003', impressions: 180000, clicks: 9000, ctr: 5, conversions: 450, cpa: 16 },
210
+ { name: 'Customer Testimonial', id: 'AD-004', impressions: 150000, clicks: 7500, ctr: 5, conversions: 375, cpa: 16 },
211
+ { name: 'Free Shipping Promo', id: 'AD-005', impressions: 120000, clicks: 6000, ctr: 5, conversions: 300, cpa: 16 },
212
+ ]
213
+
214
+ const totalCampaignRevenue = campaignsRaw.reduce((s, c) => s + c.revenue, 0)
215
+ const totalChannelRevenue = channelsRaw.reduce((s, c) => s + c.revenue, 0)
216
+ const totalAdConversions = adsRaw.reduce((s, a) => s + a.conversions, 0)
217
+
218
+ const campaignsData = campaignsRaw.map(c => ({ ...c, percentage: Math.round((c.revenue / totalCampaignRevenue) * 100) }))
219
+ const channelsData = channelsRaw.map(c => ({ ...c, percentage: Math.round((c.revenue / totalChannelRevenue) * 100) }))
220
+ const adsData = adsRaw.map(a => ({ ...a, percentage: Math.round((a.conversions / totalAdConversions) * 100) }))
221
+
222
+ const marketingOverview = {
223
+ roi: 200,
224
+ cpa: 16.67,
225
+ conversionRate: '3.2%',
226
+ }
227
+
228
+ function formatNumber(n) {
229
+ return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
230
+ }
231
+
232
+ function formatCurrency(amount) {
233
+ return `$${amount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
234
+ }
235
+
236
+ const dateRangeDisplay = state('All Time: Sep 7, 2023 to Mar 6, 2025')
237
+ const comparisonType = state('no-comparison')
238
+
239
+ const marketingData = state<Array<{ date: string, spend: number, revenue: number }>>([
240
+ { date: '2023-11-01', spend: 5000, revenue: 15000 },
241
+ { date: '2023-12-01', spend: 6000, revenue: 18000 },
242
+ { date: '2024-01-01', spend: 7000, revenue: 21000 },
243
+ { date: '2024-02-01', spend: 8000, revenue: 24000 },
244
+ { date: '2024-03-01', spend: 10000, revenue: 30000 },
245
+ { date: '2024-04-01', spend: 9000, revenue: 27000 },
246
+ { date: '2024-05-01', spend: 8000, revenue: 24000 },
247
+ { date: '2024-06-01', spend: 7000, revenue: 21000 },
248
+ { date: '2024-07-01', spend: 8000, revenue: 24000 },
249
+ { date: '2024-08-01', spend: 7000, revenue: 21000 },
250
+ { date: '2024-09-01', spend: 7000, revenue: 21000 },
251
+ { date: '2024-10-01', spend: 8000, revenue: 24000 },
252
+ { date: '2024-11-01', spend: 6000, revenue: 18000 },
253
+ { date: '2024-12-01', spend: 12000, revenue: 36000 },
254
+ { date: '2025-01-01', spend: 7000, revenue: 21000 },
255
+ { date: '2025-02-01', spend: 5000, revenue: 15000 },
256
+ ])
257
+
258
+ let chartHandle: { destroy: () => void } | null = null
259
+
260
+ onMount(async () => {
261
+ const { Chart, registerables } = await import('@stacksjs/charts')
262
+ Chart.register(...registerables)
263
+ const Ctor = Chart as unknown as ChartCtor
264
+
265
+ chartHandle = useChart({
266
+ Chart: Ctor,
267
+ id: 'marketing_chart',
268
+ type: 'line',
269
+ data: {
270
+ labels: marketingData().map(item => item.date),
271
+ datasets: [
272
+ { label: 'Revenue ($)', data: marketingData().map(item => item.revenue), backgroundColor: 'rgba(16, 185, 129, 0.3)', borderColor: 'rgba(16, 185, 129, 0.8)', borderWidth: 2, tension: 0.4, fill: true, yAxisID: 'y' },
273
+ { label: 'Spend ($)', data: marketingData().map(item => item.spend), backgroundColor: 'rgba(244, 63, 94, 0.1)', borderColor: 'rgba(244, 63, 94, 0.8)', borderWidth: 2, tension: 0.4, fill: false, yAxisID: 'y' },
274
+ ],
275
+ },
276
+ options: {
277
+ responsive: true,
278
+ maintainAspectRatio: false,
279
+ scales: {
280
+ x: { grid: { display: false }, ticks: { maxTicksLimit: 4 } },
281
+ y: { type: 'linear', display: true, position: 'left', beginAtZero: true, grid: { borderDash: [2, 4], color: 'rgba(160, 174, 192, 0.2)' }, ticks: { maxTicksLimit: 6, callback: (value: number | string) => `$${Number(value).toLocaleString()}` } },
282
+ },
283
+ plugins: {
284
+ legend: { display: true, position: 'top' },
285
+ tooltip: {
286
+ mode: 'index',
287
+ intersect: false,
288
+ callbacks: {
289
+ label(context: { dataset: { label?: string }, parsed: { y: number } }) {
290
+ let label = context.dataset.label || ''
291
+ if (label)
292
+ label += ': '
293
+ label += `$${context.parsed.y.toLocaleString()}`
294
+ return label
295
+ },
296
+ },
297
+ },
298
+ },
299
+ },
300
+ })
301
+ })
302
+
303
+ onDestroy(() => {
304
+ chartHandle?.destroy()
305
+ chartHandle = null
306
+ })
307
+ </script>
308
+
309
+ <style scoped>
310
+ .commerce-marketing {
311
+ @apply space-y-6;
312
+ }
313
+ </style>
314
+
315
+ @endsection
@@ -0,0 +1,271 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ @title('Dashboard - Page Analytics')
5
+ <PageLayout>
6
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mb-6">
7
+ <div class="flex items-center space-x-2">
8
+ <div class="h-5 w-5 text-gray-500 dark:text-neutral-400 i-hugeicons-calendar-03"></div>
9
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-300">{{ dateRangeDisplay }}</span>
10
+ </div>
11
+
12
+ <div class="flex flex-wrap gap-2 items-center">
13
+ <span class="text-gray-500 text-sm dark:text-neutral-400">compared to</span>
14
+ <div class="relative">
15
+ <select x-model="comparisonType" 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">
16
+ <option value="no-comparison">No comparison</option>
17
+ <option value="previous-period">Previous period</option>
18
+ <option value="previous-year">Previous year</option>
19
+ </select>
20
+ </div>
21
+ <button type="button" class="inline-flex items-center px-3 py-1.5 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">
22
+ <div class="mr-1 h-4 w-4 i-hugeicons-settings-01"></div>
23
+ Auto
24
+ </button>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="mb-8">
29
+ <h1 class="font-bold text-2xl text-gray-900 dark:text-white">Page Analytics</h1>
30
+ <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Detailed breakdown of page performance and visitor engagement</p>
31
+ </div>
32
+
33
+ <div class="mb-8 p-4 bg-white dark:bg-neutral-800 rounded-lg shadow">
34
+ <div class="mb-4">
35
+ <h3 class="font-medium leading-6 text-gray-900 text-lg dark:text-white">Page Views Trend</h3>
36
+ <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Page views and visitors over time</p>
37
+ </div>
38
+ <div class="h-80 w-full">
39
+ <canvas id="pageViewsTrendChart"></canvas>
40
+ </div>
41
+ </div>
42
+
43
+ <div class="mb-8 p-4 bg-white dark:bg-neutral-800 rounded-lg shadow">
44
+ <div class="mb-4">
45
+ <h3 class="font-medium leading-6 text-gray-900 text-lg dark:text-white">Top Pages</h3>
46
+ <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Most viewed pages on your website</p>
47
+ </div>
48
+ <div class="h-80 w-full">
49
+ <canvas id="topPagesChart"></canvas>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="mb-8">
54
+ <div class="mb-4">
55
+ <h3 class="font-medium text-gray-900 text-lg dark:text-white">All Pages</h3>
56
+ </div>
57
+
58
+ <div class="overflow-hidden border border-gray-200 rounded-lg dark:border-neutral-700">
59
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
60
+ <thead class="bg-gray-50 dark:bg-neutral-700/50">
61
+ <tr>
62
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Page</th>
63
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Entries</th>
64
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Visitors</th>
65
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Views</th>
66
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Avg. Time</th>
67
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Bounce Rate</th>
68
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">%</th>
69
+ </tr>
70
+ </thead>
71
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
72
+ <template :for="page in pagesData">
73
+ <tr class="relative hover:bg-gray-50 dark:hover:bg-neutral-700/50">
74
+ <td class="px-4 py-3 text-gray-900 text-sm whitespace-nowrap dark:text-white">
75
+ <div class="absolute inset-0 bg-blue-100/50 dark:bg-blue-900/50" style="width: {{ page.percentage }}%"></div>
76
+ <span class="relative z-10">{{ page.path }}</span>
77
+ </td>
78
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
79
+ <span class="relative z-10">{{ page.entries }}</span>
80
+ </td>
81
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
82
+ <span class="relative z-10">{{ page.visitors }}</span>
83
+ </td>
84
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
85
+ <span class="relative z-10">{{ page.views }}</span>
86
+ </td>
87
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
88
+ <span class="relative z-10">{{ page.avgTimeOnPage }}</span>
89
+ </td>
90
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
91
+ <span class="relative z-10">{{ page.bounceRate }}</span>
92
+ </td>
93
+ <td class="relative px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">
94
+ <span class="relative z-10">{{ page.percentage }}%</span>
95
+ </td>
96
+ </tr>
97
+ </template>
98
+ </tbody>
99
+ </table>
100
+ </div>
101
+ </div>
102
+
103
+ <div>
104
+ <div class="mb-4">
105
+ <h3 class="font-medium text-gray-900 text-lg dark:text-white">Page Performance</h3>
106
+ <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Core Web Vitals and performance metrics</p>
107
+ </div>
108
+
109
+ <div class="overflow-hidden border border-gray-200 rounded-lg dark:border-neutral-700">
110
+ <table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
111
+ <thead class="bg-gray-50 dark:bg-neutral-700/50">
112
+ <tr>
113
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Page</th>
114
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Load Time (s)</th>
115
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">FCP (s)</th>
116
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">LCP (s)</th>
117
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">CLS</th>
118
+ <th scope="col" class="px-4 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase dark:text-neutral-300">Score</th>
119
+ </tr>
120
+ </thead>
121
+ <tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
122
+ <template :for="page in pagePerformanceData">
123
+ <tr class="hover:bg-gray-50 dark:hover:bg-neutral-700/50">
124
+ <td class="px-4 py-3 text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ page.path }}</td>
125
+ <td class="px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ page.loadTime.toFixed(1) }}</td>
126
+ <td class="px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ page.fcp.toFixed(1) }}</td>
127
+ <td class="px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ page.lcp.toFixed(1) }}</td>
128
+ <td class="px-4 py-3 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-300">{{ page.cls.toFixed(2) }}</td>
129
+ <td class="px-4 py-3 font-medium text-right text-sm whitespace-nowrap {{ getPerformanceColorClass(page.score) }}">{{ page.score }}</td>
130
+ </tr>
131
+ </template>
132
+ </tbody>
133
+ </table>
134
+ </div>
135
+ </div>
136
+ </PageLayout>
137
+ <script client>
138
+
139
+ interface PageRow {
140
+ path: string
141
+ entries: number
142
+ visitors: number
143
+ views: number
144
+ percentage: number
145
+ avgTimeOnPage?: string
146
+ bounceRate?: string
147
+ }
148
+
149
+ interface PerformanceRow {
150
+ path: string
151
+ loadTime: number
152
+ fcp: number
153
+ lcp: number
154
+ cls: number
155
+ score: string
156
+ }
157
+
158
+ interface ChartLike { destroy: () => void }
159
+ type ChartCtor = new (canvas: HTMLElement, config: { type: string, data: unknown, options?: unknown }) => ChartLike
160
+
161
+ const dateRangeDisplay = state('All Time: Sep 7, 2023 to Mar 6, 2025')
162
+ const comparisonType = state('no-comparison')
163
+
164
+ const pagesData = state<PageRow[]>([
165
+ { path: '/', entries: 1800, visitors: 1800, views: 2100, percentage: 25, avgTimeOnPage: '02:15', bounceRate: '65%' },
166
+ { path: '/blog', entries: 613, visitors: 613, views: 739, percentage: 15, avgTimeOnPage: '03:45', bounceRate: '45%' },
167
+ { path: '/about', entries: 451, visitors: 451, views: 577, percentage: 12, avgTimeOnPage: '01:30', bounceRate: '70%' },
168
+ { path: '/contact', entries: 342, visitors: 342, views: 451, percentage: 9, avgTimeOnPage: '01:15', bounceRate: '75%' },
169
+ { path: '/products', entries: 337, visitors: 337, views: 460, percentage: 9, avgTimeOnPage: '04:20', bounceRate: '40%' },
170
+ { path: '/guide/get-started.html', entries: 221, visitors: 229, views: 345, percentage: 7, avgTimeOnPage: '05:45', bounceRate: '30%' },
171
+ { path: '/docs', entries: 216, visitors: 217, views: 302, percentage: 6, avgTimeOnPage: '06:30', bounceRate: '25%' },
172
+ { path: '/guide/intro.html', entries: 212, visitors: 217, views: 322, percentage: 6, avgTimeOnPage: '04:15', bounceRate: '35%' },
173
+ { path: '/guide/get-started', entries: 209, visitors: 212, views: 313, percentage: 6, avgTimeOnPage: '05:30', bounceRate: '32%' },
174
+ { path: '/team', entries: 109, visitors: 110, views: 215, percentage: 5, avgTimeOnPage: '02:45', bounceRate: '60%' },
175
+ ])
176
+
177
+ const pagePerformanceData = state<PerformanceRow[]>([
178
+ { path: '/', loadTime: 0.8, fcp: 0.9, lcp: 1.2, cls: 0.05, score: 'Good' },
179
+ { path: '/blog', loadTime: 1.2, fcp: 1.3, lcp: 2.1, cls: 0.08, score: 'Good' },
180
+ { path: '/about', loadTime: 0.7, fcp: 0.8, lcp: 1.0, cls: 0.03, score: 'Good' },
181
+ { path: '/contact', loadTime: 0.9, fcp: 1.0, lcp: 1.5, cls: 0.04, score: 'Good' },
182
+ { path: '/products', loadTime: 1.5, fcp: 1.7, lcp: 2.5, cls: 0.1, score: 'Needs Improvement' },
183
+ { path: '/guide/get-started.html', loadTime: 1.8, fcp: 2.0, lcp: 2.8, cls: 0.12, score: 'Needs Improvement' },
184
+ { path: '/docs', loadTime: 2.2, fcp: 2.5, lcp: 3.5, cls: 0.15, score: 'Poor' },
185
+ { path: '/guide/intro.html', loadTime: 1.6, fcp: 1.8, lcp: 2.6, cls: 0.11, score: 'Needs Improvement' },
186
+ { path: '/guide/get-started', loadTime: 1.7, fcp: 1.9, lcp: 2.7, cls: 0.11, score: 'Needs Improvement' },
187
+ { path: '/team', loadTime: 0.8, fcp: 0.9, lcp: 1.3, cls: 0.06, score: 'Good' },
188
+ ])
189
+
190
+ const pageViewsTrendData = state<Array<{ date: string, views: number, visitors: number }>>([
191
+ { date: '2023-09-01', views: 800, visitors: 600 },
192
+ { date: '2023-10-01', views: 850, visitors: 650 },
193
+ { date: '2023-11-01', views: 900, visitors: 700 },
194
+ { date: '2023-12-01', views: 1200, visitors: 900 },
195
+ { date: '2024-01-01', views: 1000, visitors: 800 },
196
+ { date: '2024-02-01', views: 1100, visitors: 850 },
197
+ { date: '2024-03-01', views: 1300, visitors: 950 },
198
+ { date: '2024-04-01', views: 1400, visitors: 1050 },
199
+ { date: '2024-05-01', views: 1500, visitors: 1150 },
200
+ { date: '2024-06-01', views: 1600, visitors: 1250 },
201
+ { date: '2024-07-01', views: 1800, visitors: 1400 },
202
+ ])
203
+
204
+ let chartHandles: Array<{ destroy: () => void }> = []
205
+
206
+ function getPerformanceColorClass(score: string): string {
207
+ switch (score) {
208
+ case 'Good': return 'text-green-600 dark:text-green-400'
209
+ case 'Needs Improvement': return 'text-yellow-600 dark:text-yellow-400'
210
+ case 'Poor': return 'text-red-600 dark:text-red-400'
211
+ default: return 'text-gray-600 dark:text-neutral-400'
212
+ }
213
+ }
214
+
215
+ onMount(async () => {
216
+ const { Chart, registerables } = await import('@stacksjs/charts')
217
+ Chart.register(...registerables)
218
+ const Ctor = Chart as unknown as ChartCtor
219
+
220
+ const trend = useChart({
221
+ Chart: Ctor,
222
+ id: 'pageViewsTrendChart',
223
+ type: 'line',
224
+ data: {
225
+ labels: pageViewsTrendData().map(item => item.date),
226
+ datasets: [
227
+ { label: 'Page Views', data: pageViewsTrendData().map(item => item.views), borderColor: 'rgba(59, 130, 246, 0.8)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.4, fill: true },
228
+ { label: 'Visitors', data: pageViewsTrendData().map(item => item.visitors), borderColor: 'rgba(16, 185, 129, 0.8)', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.4, fill: false },
229
+ ],
230
+ },
231
+ options: {
232
+ responsive: true,
233
+ maintainAspectRatio: false,
234
+ scales: { x: { grid: { display: false } }, y: { beginAtZero: true, grid: { borderDash: [2, 4], color: 'rgba(160, 174, 192, 0.2)' }, ticks: { maxTicksLimit: 6 } } },
235
+ plugins: { legend: { position: 'top' }, tooltip: { mode: 'index', intersect: false } },
236
+ },
237
+ })
238
+
239
+ const top = pagesData().slice(0, 5)
240
+ const topPages = useChart({
241
+ Chart: Ctor,
242
+ id: 'topPagesChart',
243
+ type: 'bar',
244
+ data: {
245
+ labels: top.map(item => item.path),
246
+ datasets: [{
247
+ label: 'Page Views',
248
+ data: top.map(item => item.views),
249
+ backgroundColor: 'rgba(59, 130, 246, 0.8)',
250
+ borderColor: 'rgba(59, 130, 246, 1)',
251
+ borderWidth: 1,
252
+ }],
253
+ },
254
+ options: {
255
+ responsive: true,
256
+ maintainAspectRatio: false,
257
+ scales: { x: { grid: { display: false } }, y: { beginAtZero: true, grid: { borderDash: [2, 4], color: 'rgba(160, 174, 192, 0.2)' } } },
258
+ plugins: { legend: { display: false } },
259
+ },
260
+ })
261
+
262
+ chartHandles = [trend.instance, topPages.instance].filter((c): c is ChartLike => c !== null)
263
+ })
264
+
265
+ onDestroy(() => {
266
+ chartHandles.forEach(c => c.destroy())
267
+ chartHandles = []
268
+ })
269
+ </script>
270
+
271
+ @endsection