@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,565 @@
1
+ <script server>
2
+ // Web sidebar for the dashboard. Framework-owned nav chrome: the markup is
3
+ // built server-side in resources/functions/dashboard/sidebar.ts and the look
4
+ // lives in the plain-CSS <style> block below (stx does not expand Crosswind
5
+ // @apply in a layout <style>, so it is hand-written). Sections come
6
+ // from the discovered-models manifest + config/dashboard.ts toggles.
7
+ // Project-root-anchored (`~/`), not relative. The stx client bundler resolves a
8
+ // relative import against the PAGE that extends this layout, not against this
9
+ // file, so `../../..` silently pointed somewhere different for every page depth
10
+ // and the bundle failed for any page more than one level under views/dashboard.
11
+ import { buildSidebarChunks } from '~/storage/framework/defaults/resources/functions/dashboard/sidebar'
12
+
13
+ // Pre-rendered, self-contained sidebar HTML (home link, section nav, settings
14
+ // link), built server-side and interpolated raw below. This intentionally does
15
+ // NOT depend on `@stacksjs/components`' <Sidebar>: 0.2.9x stopped shipping
16
+ // tag-resolvable .stx sources (only hashed dist/ output), so the component
17
+ // fatal-errored the whole dashboard with an ENOENT (stacksjs/stacks#1989). Each
18
+ // rendered <a> already carries data-required-roles, which the applyRoleFilter
19
+ // effect below reads directly for role gating.
20
+ export const sidebarChunks = buildSidebarChunks()
21
+ </script>
22
+
23
+ <!-- Dashboard icon stylesheet. Most dashboard icons are applied via dynamic
24
+ `:class="…"` bindings whose class names live in <script> state, which the stx
25
+ Crosswind extractor can't see — so their CSS is never generated inline and they
26
+ render as empty boxes. The dev server generates the full icon set once and serves
27
+ it here (browser-cached), instead of inlining ~260KB into every page. Route:
28
+ `/__deps/dashboard-icons.css` in storage/framework/core/actions/src/dev/dashboard.ts. -->
29
+ <link rel="stylesheet" href="/__deps/dashboard-icons.css">
30
+
31
+ <style>
32
+ /*
33
+ * Make every chart canvas fill its wrapper. @stacksjs/charts sizes its
34
+ * bitmap from `getBoundingClientRect()`, so without CSS dimensions the
35
+ * canvas stays at the intrinsic 300x150 default and the chart renders
36
+ * cropped (bar charts lose right-side bars; doughnuts overflow because
37
+ * the parent grid cell is sized but the canvas isn't).
38
+ */
39
+ canvas[id$="_chart"] {
40
+ display: block;
41
+ width: 100% !important;
42
+ height: 100% !important;
43
+ }
44
+
45
+ /*
46
+ * Dashboard body + sidebar. Plain CSS on purpose: stx serves a layout's raw
47
+ * style rules verbatim, but it does NOT expand Crosswind @apply here, so these
48
+ * are hand-written. Class names match the markup built in
49
+ * resources/functions/dashboard/sidebar.ts. Fixed 250px pane: Home pinned top,
50
+ * sections scroll in the middle, Settings pinned bottom.
51
+ */
52
+ /*
53
+ * The window background is owned by the main content pane, not the body element.
54
+ * In the native Craft window the WKWebView is transparent and an
55
+ * NSVisualEffectView (real macOS vibrancy) sits behind the sidebar strip; a
56
+ * solid body background would paint over it. So the body stays clear and the
57
+ * content color lives on the scrolling pane, which lets the frosted material
58
+ * read through the translucent sidebar. (Do not write angle-bracket tag names in
59
+ * a layout style-block comment — stx parses them as elements and breaks out.)
60
+ */
61
+ body {
62
+ background: transparent;
63
+ }
64
+ [data-stx-content] {
65
+ min-height: 100vh;
66
+ background: #f4f4f5;
67
+ }
68
+ .dark [data-stx-content] {
69
+ background: #0a0a0a;
70
+ }
71
+ .dashboard-sidebar {
72
+ position: fixed;
73
+ inset: 0 auto 0 0;
74
+ width: 250px;
75
+ display: flex;
76
+ flex-direction: column;
77
+ padding: 0 12px 10px;
78
+ overflow: hidden;
79
+ /* Translucent so the native NSVisualEffectView vibrancy reads through in the
80
+ Craft window; the blur is the frosted-glass fallback in a plain browser,
81
+ where there is no material behind the pane. */
82
+ background: rgba(255, 255, 255, 0.55);
83
+ -webkit-backdrop-filter: saturate(180%) blur(24px);
84
+ backdrop-filter: saturate(180%) blur(24px);
85
+ /* No hard border: a soft cast shadow to the right lifts the translucent pane
86
+ ABOVE the content, so it reads as a glass layer laid on top (Finder-style)
87
+ rather than a flat column butted beside it. The 1px inset is the hairline. */
88
+ box-shadow: 1px 0 0 rgba(0, 0, 0, 0.05), 12px 0 34px -10px rgba(0, 0, 0, 0.18);
89
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', sans-serif;
90
+ -webkit-font-smoothing: antialiased;
91
+ z-index: 40;
92
+ }
93
+ .sidebar-header {
94
+ flex-shrink: 0;
95
+ height: 38px;
96
+ }
97
+ .sidebar-nav {
98
+ flex: 1 1 auto;
99
+ min-height: 0;
100
+ overflow-y: auto;
101
+ scrollbar-width: none;
102
+ }
103
+ .sidebar-nav::-webkit-scrollbar {
104
+ width: 0;
105
+ }
106
+ .sidebar-link {
107
+ display: flex;
108
+ align-items: center;
109
+ gap: 10px;
110
+ flex-shrink: 0;
111
+ height: 30px;
112
+ padding: 0 10px;
113
+ border-radius: 6px;
114
+ color: #3a3a3c;
115
+ font-size: 13px;
116
+ font-weight: 450;
117
+ text-decoration: none;
118
+ white-space: nowrap;
119
+ overflow: hidden;
120
+ text-overflow: ellipsis;
121
+ transition: background-color 0.12s ease, color 0.12s ease;
122
+ }
123
+ .sidebar-link:hover {
124
+ background: rgba(0, 0, 0, 0.05);
125
+ }
126
+ .sidebar-link[data-active="true"] {
127
+ background: #007aff;
128
+ color: #fff;
129
+ }
130
+ .sidebar-link-home {
131
+ font-weight: 550;
132
+ }
133
+ .sidebar-nav .sidebar-link {
134
+ margin-top: 1px;
135
+ }
136
+ .sidebar-icon {
137
+ display: inline-flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ flex-shrink: 0;
141
+ width: 18px;
142
+ height: 18px;
143
+ opacity: 0.82;
144
+ }
145
+ .sidebar-icon svg {
146
+ width: 18px;
147
+ height: 18px;
148
+ }
149
+ .sidebar-link[data-active="true"] .sidebar-icon {
150
+ opacity: 1;
151
+ }
152
+ .sidebar-section {
153
+ margin-top: 12px;
154
+ }
155
+ .sidebar-section-label {
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: space-between;
159
+ width: 100%;
160
+ height: 22px;
161
+ padding: 0 10px;
162
+ background: none;
163
+ border: 0;
164
+ cursor: pointer;
165
+ color: #8a8a8e;
166
+ font-size: 11px;
167
+ font-weight: 600;
168
+ letter-spacing: 0.03em;
169
+ text-transform: uppercase;
170
+ }
171
+ .sidebar-section-label:hover {
172
+ color: #6a6a6e;
173
+ }
174
+ .sidebar-section-list {
175
+ list-style: none;
176
+ margin: 2px 0 0;
177
+ padding: 0;
178
+ }
179
+ .sidebar-section.collapsed .sidebar-section-list {
180
+ display: none;
181
+ }
182
+ .sidebar-chevron {
183
+ width: 7px;
184
+ height: 7px;
185
+ border-right: 1.5px solid currentColor;
186
+ border-bottom: 1.5px solid currentColor;
187
+ transform: rotate(45deg);
188
+ transition: transform 0.15s ease;
189
+ opacity: 0.7;
190
+ }
191
+ .sidebar-section.collapsed .sidebar-chevron {
192
+ transform: rotate(-45deg);
193
+ }
194
+ .dark .dashboard-sidebar {
195
+ background: rgba(28, 28, 30, 0.55);
196
+ box-shadow: 1px 0 0 rgba(255, 255, 255, 0.06), 12px 0 34px -10px rgba(0, 0, 0, 0.55);
197
+ }
198
+ .dark .sidebar-link {
199
+ color: #d1d1d6;
200
+ }
201
+ .dark .sidebar-link:hover {
202
+ background: rgba(255, 255, 255, 0.06);
203
+ }
204
+ .dark .sidebar-link[data-active="true"] {
205
+ background: #0a84ff;
206
+ color: #fff;
207
+ }
208
+ .dark .sidebar-section-label {
209
+ color: #8d8d92;
210
+ }
211
+ .dark .sidebar-section-label:hover {
212
+ color: #aeaeb2;
213
+ }
214
+ </style>
215
+
216
+ <script>
217
+ // Dynamic import map injection. Pages do `await import('@stacksjs/charts')`
218
+ // in their `<script client>` blocks, which the browser refuses to resolve
219
+ // without an import map. Writing a literal `<script type="importmap">` here
220
+ // would be the obvious fix, but STX's layout-script processor strips the
221
+ // `type` attribute and wraps the body in an IIFE — destroying it. Instead
222
+ // we inject the import map programmatically via DOM, synchronously, before
223
+ // any page-level script (and therefore before any dynamic import) runs.
224
+ // The matching `/__deps/charts.js` route lives in dev/dashboard.ts.
225
+ ;(function () {
226
+ if (typeof document === 'undefined') return
227
+ // SPA fragment swaps re-execute scripts — only install once.
228
+ if (document.querySelector('script[data-stx-importmap]')) return
229
+ var s = document.createElement('script')
230
+ s.type = 'importmap'
231
+ s.setAttribute('data-stx-importmap', '')
232
+ s.textContent = '{"imports":{"@stacksjs/charts":"/__deps/charts.js"}}'
233
+ ;(document.head || document.documentElement).prepend(s)
234
+ })();
235
+ </script>
236
+
237
+ <script>
238
+ // Dashboard-wide chart helpers exposed on window so feature pages can call
239
+ // `useChart(...)` / `useCharts(...)` without importing the composables
240
+ // module. The page's `<script client>` blocks run inside a non-module
241
+ // `<script data-stx-scoped>` tag, so an ES `import` at the top of the
242
+ // file is a syntax error. Exposing these globals here lets every page
243
+ // drop the import and call the helper directly.
244
+ ;(function () {
245
+ if (typeof window === 'undefined') return
246
+ if (window.useChart) return
247
+
248
+ function useChart(opts) {
249
+ if (typeof document === 'undefined')
250
+ return { instance: null, destroy: function () {} }
251
+ var el = document.getElementById(opts.id)
252
+ if (!el) {
253
+ console.warn('[useChart] no element with id "' + opts.id + '" — chart not initialised')
254
+ return { instance: null, destroy: function () {} }
255
+ }
256
+ var instance = new opts.Chart(el, { type: opts.type, data: opts.data, options: opts.options })
257
+ return {
258
+ instance: instance,
259
+ destroy: function () { instance.destroy() },
260
+ }
261
+ }
262
+
263
+ function useCharts(specs) {
264
+ var handles = specs.map(useChart)
265
+ return {
266
+ handles: handles,
267
+ destroyAll: function () { handles.forEach(function (h) { h.destroy() }) },
268
+ }
269
+ }
270
+
271
+ window.useChart = useChart
272
+ window.useCharts = useCharts
273
+ })()
274
+ </script>
275
+
276
+ <script client>
277
+ // Craft native sidebar integration
278
+ // Maps sidebar itemIds to STX page routes for SPA navigation
279
+ const sidebarRoutes = {
280
+ 'home': '/',
281
+ 'dependencies': '/dependencies',
282
+ 'services': '/health',
283
+ 'ci': '/ci',
284
+ 'components': '/components',
285
+ 'functions': '/functions',
286
+ 'releases': '/releases',
287
+ 'packages': '/packages',
288
+ 'content-dashboard': '/content/dashboard',
289
+ 'files': '/content/files',
290
+ 'blog': '/content/blog',
291
+ 'pages': '/content/pages',
292
+ 'posts': '/content/posts',
293
+ 'categories': '/content/categories',
294
+ 'tags': '/content/tags',
295
+ 'comments': '/content/comments',
296
+ 'authors': '/content/authors',
297
+ 'seo': '/content/seo',
298
+ 'deployments': '/deployments',
299
+ 'requests': '/requests',
300
+ 'realtime': '/realtime',
301
+ 'actions': '/actions',
302
+ 'commands': '/commands',
303
+ 'queue': '/queue',
304
+ 'jobs': '/jobs',
305
+ 'inbox': '/inbox',
306
+ 'queries': '/queries',
307
+ 'notifications': '/notifications/dashboard',
308
+ 'data-dashboard': '/data/dashboard',
309
+ 'activity': '/data/activity',
310
+ 'users': '/data/users',
311
+ 'teams': '/data/teams',
312
+ 'subscribers': '/data/subscribers',
313
+ 'commerce-dashboard': '/commerce/dashboard',
314
+ 'pos': '/commerce/pos',
315
+ 'customers': '/commerce/customers',
316
+ 'orders': '/commerce/orders',
317
+ 'products': '/commerce/products',
318
+ 'coupons': '/commerce/coupons',
319
+ 'gift-cards': '/commerce/gift-cards',
320
+ 'payments': '/commerce/payments',
321
+ 'delivery': '/commerce/delivery',
322
+ 'taxes': '/commerce/taxes',
323
+ 'lists': '/marketing/lists',
324
+ 'social-posts': '/marketing/social-posts',
325
+ 'campaigns': '/marketing/campaigns',
326
+ 'marketing-reviews': '/marketing/reviews',
327
+ 'analytics-web': '/analytics/web',
328
+ 'analytics-blog': '/analytics/blog',
329
+ 'analytics-goals': '/analytics/goals',
330
+ 'analytics-commerce': '/analytics/commerce/web',
331
+ 'analytics-sales': '/analytics/commerce/sales',
332
+ 'analytics-marketing': '/analytics/marketing',
333
+ 'cloud': '/cloud',
334
+ 'servers': '/servers',
335
+ 'serverless': '/serverless',
336
+ 'dns': '/dns',
337
+ 'permissions': '/management/permissions',
338
+ 'kanban': '/kanban',
339
+ 'mailboxes': '/mailboxes',
340
+ 'logs': '/logs',
341
+ 'buddy': '/buddy',
342
+ 'environment': '/environment',
343
+ 'access-tokens': '/access-tokens',
344
+ 'settings': '/settings',
345
+ }
346
+
347
+ // Handle Craft native sidebar selection events
348
+ window.craft = window.craft || {}
349
+ window.craft._sidebarSelectHandler = (event) => {
350
+ const url = sidebarRoutes[event.itemId]
351
+ || (event.itemId && event.itemId.startsWith('model-') ? '/models/' + event.itemId.slice(6) : null)
352
+ if (url) {
353
+ navigate(url)
354
+ }
355
+ }
356
+
357
+ // Global toast queue. Composables across the dashboard call
358
+ // `pushToast(...)` (defined in defaults/functions/toasts.ts) when
359
+ // network requests fail or succeed; that signal is rendered in the
360
+ // fixed-position container below the <main> slot. Mounted in the
361
+ // layout so every dashboard page picks it up without opting in.
362
+ // `~/`-anchored for the same reason as the sidebar import above.
363
+ import { useToasts, dismissToast } from '~/storage/framework/defaults/functions/toasts'
364
+ const { toasts } = useToasts()
365
+
366
+ // Helpers below return COMPLETE class strings (static + dynamic) and are
367
+ // applied via `:class="fn(...)"` because stx's `{{ ... }}` placeholder is
368
+ // not reactively bound inside a `class` attribute — only inside text content.
369
+ const toastIconClass = (type) => `flex-shrink-0 h-5 w-5 mt-0.5 ${({
370
+ success: 'i-hugeicons-checkmark-circle-02 text-green-500 dark:text-green-400',
371
+ error: 'i-hugeicons-alert-02 text-red-500 dark:text-red-400',
372
+ warning: 'i-hugeicons-alert-circle text-yellow-500 dark:text-yellow-400',
373
+ info: 'i-hugeicons-information-circle text-blue-500 dark:text-blue-400',
374
+ }[type] || 'i-hugeicons-information-circle text-gray-500 dark:text-neutral-400')}`
375
+
376
+ const toastWrapperClass = (type) => `pointer-events-auto overflow-hidden bg-white dark:bg-neutral-800 ring-1 ${({
377
+ success: 'ring-green-500/20',
378
+ error: 'ring-red-500/30',
379
+ warning: 'ring-yellow-500/20',
380
+ info: 'ring-blue-500/20',
381
+ }[type] || 'ring-black/5 dark:ring-white/10')} rounded-lg shadow-lg`
382
+
383
+ // Role-gated sidebar filter (stacksjs/stacks#1843).
384
+ //
385
+ // The server emits sidebar `<a>` items with `data-required-roles="…"` for
386
+ // any model that declares `dashboard.roles: ['admin', 'dev', …]`. We
387
+ // walk those nodes on hydration and on auth-store changes, hiding rows
388
+ // the current viewer can't access.
389
+ //
390
+ // Permissive default: when the viewer is unauthenticated (the localhost
391
+ // dev dashboard) `isDev()` returns true so every gated row stays visible.
392
+ // In production deployments where `/api/dashboard/*` sits behind auth,
393
+ // the endpoint returns real role data and the filter hides what the
394
+ // viewer can't reach.
395
+ // Guarded: `useStore('auth')` THROWS when the store was never registered, and a
396
+ // throw here aborts scope registration for the entire page, leaving every signal
397
+ // on every dashboard page unbound. A missing auth store must degrade to the
398
+ // permissive default described above, not take the dashboard down with it.
399
+ const auth = (() => {
400
+ try {
401
+ const store = useStore('auth')
402
+ store.load()
403
+ return store
404
+ }
405
+ catch {
406
+ return null
407
+ }
408
+ })()
409
+
410
+ function applyRoleFilter() {
411
+ // No auth store means no role data, which is the unauthenticated case: show
412
+ // every gated row rather than hiding the whole sidebar.
413
+ const roleList = auth ? auth.roles() : []
414
+ const unauth = auth ? auth.unauthenticated() : true
415
+ const nodes = document.querySelectorAll('[data-required-roles]')
416
+ for (const el of nodes) {
417
+ const required = (el.getAttribute('data-required-roles') || '')
418
+ .split(',').map(s => s.trim()).filter(Boolean)
419
+ if (required.length === 0) continue
420
+ // Unauthenticated viewers (no auth wired) see everything — keeps the
421
+ // dev dashboard usable. Once authenticated, role membership becomes
422
+ // the authoritative answer.
423
+ const allowed = unauth || required.some(r => roleList.includes(r))
424
+ // Hide the parent <li> when the link is inside one; otherwise the
425
+ // link itself. Either way the row disappears from the rendered
426
+ // sidebar; CSS `display: none` keeps the DOM intact for SPA nav so
427
+ // a later role change can re-show without a re-render.
428
+ const target = el.closest('li') || el
429
+ target.style.display = allowed ? '' : 'none'
430
+ }
431
+ }
432
+
433
+ effect(() => {
434
+ // `effect` re-runs whenever `auth.roles()` / `auth.unauthenticated()`
435
+ // change. Includes the first run, which executes after hydration once
436
+ // the auth fetch resolves.
437
+ applyRoleFilter()
438
+ })
439
+ </script>
440
+
441
+ <aside data-stx-sidebar class="dashboard-sidebar" role="navigation" aria-label="Sidebar">
442
+ <!-- Traffic lights are native (titlebarHidden window) — this strip reserves
443
+ their space at the top of the pane so the first nav row clears them. -->
444
+ <div class="sidebar-header"></div>
445
+ {{{ sidebarChunks.top }}}
446
+ <nav class="sidebar-nav">{{{ sidebarChunks.nav }}}</nav>
447
+ {{{ sidebarChunks.bottom }}}
448
+ </aside>
449
+
450
+ <script>
451
+ // Web sidebar wiring: collapse restore, active highlight, SPA navigation.
452
+ // Runs as a plain <script> IIFE (like the import-map script above), NOT via
453
+ // onMount: stx gives a LAYOUT no reactive scope of its own, so its onMount /
454
+ // effect callbacks never fire ("global mountCallbacks: 0") — the previous
455
+ // onMount version silently never ran, which is why no link was ever highlighted.
456
+ // A DOMContentLoaded IIFE plus the stx:navigate event cover hard loads and every
457
+ // SPA route change without depending on a scope mount.
458
+ ;(function () {
459
+ if (typeof document === 'undefined') return
460
+
461
+ // Highlight the sidebar link for the CURRENT route. Longest-prefix match, so a
462
+ // nested/detail page (e.g. /commerce/products/42) still lights up its section
463
+ // link (/commerce/products); the root link (/) only ever matches the home page.
464
+ function syncActive(url) {
465
+ var pane = document.querySelector('[data-stx-sidebar]')
466
+ if (!pane) return
467
+ var path
468
+ try { path = new URL(url || location.href, location.origin).pathname }
469
+ catch (e) { path = location.pathname }
470
+ var norm = function (p) { return (p || '/').replace(/\/+$/, '') || '/' }
471
+ var cur = norm(path)
472
+ var best = null
473
+ var bestLen = -1
474
+ var links = pane.querySelectorAll('a.sidebar-link[href]')
475
+ for (var i = 0; i < links.length; i++) {
476
+ var href = links[i].getAttribute('href') || ''
477
+ if (href.indexOf('http') === 0) continue
478
+ var h = norm(href)
479
+ // `${cur}/`.startsWith(`${h}/`) catches an exact hit and any child path,
480
+ // while the trailing slash stops /health matching /health-check.
481
+ if ((cur + '/').indexOf(h + '/') === 0 && h.length > bestLen) {
482
+ best = links[i]
483
+ bestLen = h.length
484
+ }
485
+ }
486
+ var actives = pane.querySelectorAll('a.sidebar-link[data-active]')
487
+ for (var j = 0; j < actives.length; j++) actives[j].removeAttribute('data-active')
488
+ if (best) best.setAttribute('data-active', 'true')
489
+ }
490
+
491
+ function init() {
492
+ var pane = document.querySelector('[data-stx-sidebar]')
493
+ if (!pane) return
494
+
495
+ // Restore per-section collapsed state persisted by the section toggle
496
+ // (the inline onclick in renderSection writes localStorage['sidebar-collapsed']).
497
+ try {
498
+ var saved = JSON.parse(localStorage.getItem('sidebar-collapsed') || '{}')
499
+ var sections = pane.querySelectorAll('.sidebar-section')
500
+ for (var i = 0; i < sections.length; i++) {
501
+ if (saved[sections[i].getAttribute('data-section')]) sections[i].classList.add('collapsed')
502
+ }
503
+ } catch (e) {}
504
+
505
+ syncActive()
506
+
507
+ // Bind route + click listeners once. This script can re-run on SPA fragment
508
+ // swaps, so guard against stacking duplicate handlers on the persistent pane.
509
+ if (!pane.__sidebarWired) {
510
+ pane.__sidebarWired = true
511
+
512
+ // Follow EVERY route change, not just sidebar clicks. navigate() dispatches
513
+ // stx:navigate (content links, programmatic navigate, and popstate
514
+ // back/forward all route through it), so the highlight tracks the real
515
+ // route instead of only updating when a sidebar item is clicked.
516
+ window.addEventListener('stx:navigate', function (event) {
517
+ syncActive(event && event.detail && event.detail.url)
518
+ })
519
+
520
+ // SPA-navigate sidebar links; fall back to full loads when the router isn't
521
+ // available or the target is external. The highlight is driven by the
522
+ // stx:navigate listener above, so we don't toggle data-active here.
523
+ pane.addEventListener('click', function (event) {
524
+ var link = event.target.closest('a.sidebar-link')
525
+ if (!link) return
526
+ var href = link.getAttribute('href')
527
+ if (!href || href.indexOf('http') === 0 || typeof navigate !== 'function') return
528
+ event.preventDefault()
529
+ navigate(href)
530
+ })
531
+ }
532
+ }
533
+
534
+ if (document.querySelector('[data-stx-sidebar]')) init()
535
+ else document.addEventListener('DOMContentLoaded', init)
536
+ })();
537
+ </script>
538
+
539
+ <main data-stx-content style="margin-left: 250px">
540
+ @slot('content')
541
+ </main>
542
+
543
+ <!-- Global toast container. Top-right stack, newest at the bottom.
544
+ Pointer-events-none on the wrapper + auto on individual toasts so
545
+ surrounding UI stays clickable while a toast is up. -->
546
+ <div class="flex fixed right-4 top-4 z-[60] flex-col gap-2 max-w-sm w-full pointer-events-none">
547
+ <template :for="toast in toasts">
548
+ <div role="alert" aria-live="assertive" :class="toastWrapperClass(toast.type)">
549
+ <div class="flex gap-3 items-start p-4">
550
+ <div :class="toastIconClass(toast.type)"></div>
551
+ <div class="flex-1 min-w-0">
552
+ <p class="font-medium text-gray-900 text-sm dark:text-neutral-100">{{ toast.title }}</p>
553
+ @if(toast.detail)
554
+ <p class="mt-1 break-words text-gray-500 text-xs dark:text-neutral-400">{{ toast.detail }}</p>
555
+ @endif
556
+ </div>
557
+ <button type="button" @click="dismissToast({{ toast.id }})" class="flex-shrink-0 text-gray-400 hover:text-gray-600 dark:hover:text-neutral-200" aria-label="Dismiss">
558
+ <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
559
+ <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"></path>
560
+ </svg>
561
+ </button>
562
+ </div>
563
+ </div>
564
+ </template>
565
+ </div>
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <meta charset="utf-8" />
4
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5
+ <title>Stacks Dashboard</title>
6
+ </head>
7
+ <body class="min-h-screen bg-neutral-100 dark:bg-neutral-950">
8
+ @yield('content')
9
+ </body>
10
+ </html>
@@ -0,0 +1,48 @@
1
+ @extends('layouts/guest')
2
+
3
+ @section('content')
4
+ <script client>
5
+ // Login form (stacksjs/stacks#1838). Previously a `<script server>` block
6
+ // that tried to reassign `const isLoading = false` at runtime — which
7
+ // throws in strict-mode JS, so the form's loading/error state never
8
+ // actually updated. Now uses `state(...)` signals for proper reactivity
9
+ // and the auto-imported `navigate()` for SPA navigation instead of the
10
+ // nonexistent `useRouter()`.
11
+ import { useAuth } from '../../functions/auth'
12
+
13
+ const { login } = useAuth()
14
+
15
+ const isLoading = state(false)
16
+ const error = state('')
17
+
18
+ async function handleLogin(credentials) {
19
+ isLoading.set(true)
20
+ error.set('')
21
+
22
+ try {
23
+ const result = await login(credentials)
24
+
25
+ if (result && 'errors' in result) {
26
+ error.set(result.message || 'Invalid credentials')
27
+ return
28
+ }
29
+
30
+ navigate('/')
31
+ }
32
+ catch (err) {
33
+ error.set(err.message || 'An error occurred during login')
34
+ }
35
+ finally {
36
+ isLoading.set(false)
37
+ }
38
+ }
39
+ </script>
40
+
41
+ @title('Login - Stacks Dashboard')
42
+ <Login
43
+ @submit="handleLogin"
44
+ :isLoading="isLoading()"
45
+ :error="error()"
46
+ />
47
+
48
+ @endsection