@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.
- package/TODO.md +21 -0
- package/ai/AGENTS.md +79 -0
- package/ai/README.md +45 -0
- package/ai/claude/launch.json +12 -0
- package/ai/skills/stacks-actions/SKILL.md +128 -0
- package/ai/skills/stacks-ai/SKILL.md +276 -0
- package/ai/skills/stacks-alias/SKILL.md +94 -0
- package/ai/skills/stacks-analytics/SKILL.md +91 -0
- package/ai/skills/stacks-api/SKILL.md +738 -0
- package/ai/skills/stacks-arrays/SKILL.md +277 -0
- package/ai/skills/stacks-auth/SKILL.md +422 -0
- package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
- package/ai/skills/stacks-brandkit/SKILL.md +811 -0
- package/ai/skills/stacks-browse/SKILL.md +127 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
- package/ai/skills/stacks-browser/SKILL.md +145 -0
- package/ai/skills/stacks-buddy/SKILL.md +676 -0
- package/ai/skills/stacks-build/SKILL.md +163 -0
- package/ai/skills/stacks-cache/SKILL.md +125 -0
- package/ai/skills/stacks-calendar/SKILL.md +113 -0
- package/ai/skills/stacks-chat/SKILL.md +371 -0
- package/ai/skills/stacks-cli/SKILL.md +112 -0
- package/ai/skills/stacks-cloud/SKILL.md +192 -0
- package/ai/skills/stacks-cms/SKILL.md +217 -0
- package/ai/skills/stacks-collections/SKILL.md +82 -0
- package/ai/skills/stacks-commerce/SKILL.md +114 -0
- package/ai/skills/stacks-composables/SKILL.md +161 -0
- package/ai/skills/stacks-config/SKILL.md +144 -0
- package/ai/skills/stacks-configuration/SKILL.md +154 -0
- package/ai/skills/stacks-cron/SKILL.md +123 -0
- package/ai/skills/stacks-crosswind/SKILL.md +190 -0
- package/ai/skills/stacks-dashboard/SKILL.md +173 -0
- package/ai/skills/stacks-database/SKILL.md +286 -0
- package/ai/skills/stacks-datetime/SKILL.md +269 -0
- package/ai/skills/stacks-dependencies/SKILL.md +111 -0
- package/ai/skills/stacks-deploy/SKILL.md +102 -0
- package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
- package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
- package/ai/skills/stacks-design-output/SKILL.md +55 -0
- package/ai/skills/stacks-design-soft/SKILL.md +156 -0
- package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
- package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
- package/ai/skills/stacks-desktop/SKILL.md +78 -0
- package/ai/skills/stacks-development/SKILL.md +298 -0
- package/ai/skills/stacks-dns/SKILL.md +149 -0
- package/ai/skills/stacks-docs/SKILL.md +109 -0
- package/ai/skills/stacks-email/SKILL.md +236 -0
- package/ai/skills/stacks-enums/SKILL.md +100 -0
- package/ai/skills/stacks-env/SKILL.md +181 -0
- package/ai/skills/stacks-error-handling/SKILL.md +137 -0
- package/ai/skills/stacks-events/SKILL.md +228 -0
- package/ai/skills/stacks-faker/SKILL.md +158 -0
- package/ai/skills/stacks-git/SKILL.md +158 -0
- package/ai/skills/stacks-guard/SKILL.md +98 -0
- package/ai/skills/stacks-health/SKILL.md +75 -0
- package/ai/skills/stacks-http/SKILL.md +316 -0
- package/ai/skills/stacks-i18n/SKILL.md +198 -0
- package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
- package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
- package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
- package/ai/skills/stacks-investigate/SKILL.md +119 -0
- package/ai/skills/stacks-jobs/SKILL.md +136 -0
- package/ai/skills/stacks-lint/SKILL.md +184 -0
- package/ai/skills/stacks-listeners/SKILL.md +99 -0
- package/ai/skills/stacks-logging/SKILL.md +78 -0
- package/ai/skills/stacks-mail/SKILL.md +120 -0
- package/ai/skills/stacks-middleware/SKILL.md +249 -0
- package/ai/skills/stacks-migrations/SKILL.md +105 -0
- package/ai/skills/stacks-models/SKILL.md +267 -0
- package/ai/skills/stacks-new-feature/SKILL.md +206 -0
- package/ai/skills/stacks-notifications/SKILL.md +210 -0
- package/ai/skills/stacks-objects/SKILL.md +205 -0
- package/ai/skills/stacks-office-hours/SKILL.md +134 -0
- package/ai/skills/stacks-orm/SKILL.md +342 -0
- package/ai/skills/stacks-path/SKILL.md +118 -0
- package/ai/skills/stacks-payments/SKILL.md +373 -0
- package/ai/skills/stacks-plan-review/SKILL.md +152 -0
- package/ai/skills/stacks-plugins/SKILL.md +149 -0
- package/ai/skills/stacks-push/SKILL.md +376 -0
- package/ai/skills/stacks-query-builder/SKILL.md +128 -0
- package/ai/skills/stacks-queue/SKILL.md +559 -0
- package/ai/skills/stacks-realtime/SKILL.md +442 -0
- package/ai/skills/stacks-redesign/SKILL.md +182 -0
- package/ai/skills/stacks-registry/SKILL.md +58 -0
- package/ai/skills/stacks-repl/SKILL.md +80 -0
- package/ai/skills/stacks-retro/SKILL.md +122 -0
- package/ai/skills/stacks-review/SKILL.md +135 -0
- package/ai/skills/stacks-router/SKILL.md +231 -0
- package/ai/skills/stacks-routes/SKILL.md +105 -0
- package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
- package/ai/skills/stacks-scheduler/SKILL.md +363 -0
- package/ai/skills/stacks-search-engine/SKILL.md +112 -0
- package/ai/skills/stacks-security/SKILL.md +129 -0
- package/ai/skills/stacks-security-audit/SKILL.md +128 -0
- package/ai/skills/stacks-server/SKILL.md +458 -0
- package/ai/skills/stacks-shell/SKILL.md +62 -0
- package/ai/skills/stacks-slug/SKILL.md +87 -0
- package/ai/skills/stacks-sms/SKILL.md +385 -0
- package/ai/skills/stacks-socials/SKILL.md +303 -0
- package/ai/skills/stacks-storage/SKILL.md +576 -0
- package/ai/skills/stacks-strings/SKILL.md +416 -0
- package/ai/skills/stacks-stx/SKILL.md +176 -0
- package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
- package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
- package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
- package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
- package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
- package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
- package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
- package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
- package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
- package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
- package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
- package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
- package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
- package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
- package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
- package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
- package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
- package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
- package/ai/skills/stacks-testing/SKILL.md +129 -0
- package/ai/skills/stacks-tunnel/SKILL.md +125 -0
- package/ai/skills/stacks-types/SKILL.md +178 -0
- package/ai/skills/stacks-ui/SKILL.md +246 -0
- package/ai/skills/stacks-utils/SKILL.md +444 -0
- package/ai/skills/stacks-validation/SKILL.md +371 -0
- package/ai/skills/stacks-whois/SKILL.md +315 -0
- package/assets/world-map-data.ts +121 -0
- package/bootstrap.ts +114 -0
- package/docs/api-examples.md +46 -0
- package/docs/index.md +24 -0
- package/docs/markdown-examples.md +87 -0
- package/functions/analytics.ts +97 -0
- package/functions/api.ts +143 -0
- package/functions/auth.ts +208 -0
- package/functions/billing/payments.ts +149 -0
- package/functions/blog.ts +120 -0
- package/functions/cms/categorizables.ts +107 -0
- package/functions/cms/pages.ts +108 -0
- package/functions/cms/posts.ts +100 -0
- package/functions/cms/taggables.ts +102 -0
- package/functions/commerce/coupons.ts +128 -0
- package/functions/commerce/customers.ts +128 -0
- package/functions/commerce/gift-cards.ts +119 -0
- package/functions/commerce/orders.ts +112 -0
- package/functions/commerce/payments.ts +119 -0
- package/functions/commerce/products/categories.ts +123 -0
- package/functions/commerce/products/manufacturers.ts +123 -0
- package/functions/commerce/products/products.ts +123 -0
- package/functions/commerce/products/reviews.ts +123 -0
- package/functions/commerce/products/units.ts +123 -0
- package/functions/commerce/products/variants.ts +123 -0
- package/functions/commerce/shippings/delivery-routes.ts +123 -0
- package/functions/commerce/shippings/digital-deliveries.ts +119 -0
- package/functions/commerce/shippings/drivers.ts +123 -0
- package/functions/commerce/shippings/license-keys.ts +123 -0
- package/functions/commerce/shippings/shipping-methods.ts +123 -0
- package/functions/commerce/shippings/shipping-rates.ts +119 -0
- package/functions/commerce/shippings/shipping-zones.ts +119 -0
- package/functions/commerce/taxes.ts +119 -0
- package/functions/commerce/waitlist/products.ts +123 -0
- package/functions/commerce/waitlist/restaurants.ts +123 -0
- package/functions/craft.ts +107 -0
- package/functions/dashboard.ts +153 -0
- package/functions/inbox.ts +95 -0
- package/functions/jobs.ts +86 -0
- package/functions/monitoring/errors.ts +295 -0
- package/functions/queue.ts +111 -0
- package/functions/realtime/websockets.ts +96 -0
- package/functions/realtime.ts +52 -0
- package/functions/releases.ts +49 -0
- package/functions/search.ts +126 -0
- package/functions/toasts.ts +95 -0
- package/functions/uploads.ts +216 -0
- package/ide/.gitignore +4 -0
- package/ide/cursor/rules/auto-imports.mdc +574 -0
- package/ide/cursor/rules/code-style.mdc +12 -0
- package/ide/cursor/rules/documentation.mdc +9 -0
- package/ide/cursor/rules/error-handling-validation.mdc +11 -0
- package/ide/cursor/rules/key-conventions.mdc +11 -0
- package/ide/cursor/rules/project-structure.mdc +169 -0
- package/ide/cursor/rules/readme.mdc +318 -0
- package/ide/cursor/rules/syntax-formatting.mdc +9 -0
- package/ide/cursor/rules/testing.mdc +10 -0
- package/ide/cursor/rules/typescript.mdc +9 -0
- package/ide/cursor/rules/ui-styling.mdc +0 -0
- package/ide/dictionary.txt +397 -0
- package/ide/jetbrains/.fleet/settings.json +4 -0
- package/ide/jetbrains/.idea/.gitignore +5 -0
- package/ide/jetbrains/.idea/.name +1 -0
- package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
- package/ide/jetbrains/.idea/modules.xml +8 -0
- package/ide/jetbrains/.idea/stacks.iml +22 -0
- package/ide/jetbrains/.idea/vcs.xml +6 -0
- package/ide/jetbrains/.idea/webResources.xml +14 -0
- package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
- package/ide/jetbrains/installed.txt +4 -0
- package/ide/jetbrains/options/github-copilot.xml +5 -0
- package/ide/jetbrains/options/nodejs.xml +7 -0
- package/ide/jetbrains/options/templates.xml +124 -0
- package/ide/jetbrains/templates/JavaScript.xml +6 -0
- package/ide/jetbrains/templates/Stacks.xml +8 -0
- package/ide/vscode/.vscode/README.md +23 -0
- package/ide/vscode/.vscode/extensions.json +5 -0
- package/ide/vscode/.vscode/settings.json +176 -0
- package/ide/vscode/.vscode/stacks.code-snippets +181 -0
- package/ide/vscode/LICENSE.md +21 -0
- package/ide/vscode/README.md +36 -0
- package/ide/vscode/logo.png +0 -0
- package/ide/vscode/package.json +79 -0
- package/ide/zed/.zed/settings.json +139 -0
- package/lang/README.md +28 -0
- package/lang/de.yml +14 -0
- package/lang/en.yml +15 -0
- package/package.json +19 -3
- package/project/bootstrap +161 -0
- package/project/buddy +175 -0
- package/project/storage/framework/tsconfig.app.json +50 -0
- package/project/storage/framework/tsconfig.base.json +58 -0
- package/routes/core.ts +78 -0
- package/routes/dashboard-api.ts +233 -0
- package/routes/dashboard.ts +739 -0
- package/routes/email.ts +129 -0
- package/stores/[name].stx +16 -0
- package/stores/git.ts +71 -0
- package/stores/payment.ts +474 -0
- package/stores/queue.ts +43 -0
- package/stores/user.ts +29 -0
- package/stx-components-plugin.ts +25 -0
- package/styles/design-tokens.css +597 -0
- package/types/dashboard.ts +70 -0
- package/types/defaults.ts +438 -0
- package/vcs/github/CODE_OF_CONDUCT.md +83 -0
- package/vcs/github/CONTRIBUTING.md +187 -0
- package/vcs/github/EXPLANATIONS.md +41 -0
- package/vcs/github/FUNDING.yml +1 -0
- package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
- package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
- package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- package/vcs/github/SECURITY.md +70 -0
- package/vcs/github/renovate.json +5 -0
- package/vcs/github/stale.yml +14 -0
- package/vcs/github/workflows/README.md +16 -0
- package/vcs/github/workflows/ci.yml +114 -0
- package/vcs/github/workflows/export-size.yml +25 -0
- package/vcs/github/workflows/labeler.yml +13 -0
- package/vcs/github/workflows/release.yml +219 -0
- package/views/[...all].stx +8 -0
- package/views/about.md +3 -0
- package/views/auth/login.stx +1 -0
- package/views/auth/signup.stx +85 -0
- package/views/dashboard/.discovered-models.json +542 -0
- package/views/dashboard/AUDIT.md +904 -0
- package/views/dashboard/[...all].stx +89 -0
- package/views/dashboard/access-tokens/index.stx +177 -0
- package/views/dashboard/actions/index.stx +129 -0
- package/views/dashboard/analytics/blog/index.stx +356 -0
- package/views/dashboard/analytics/browsers/index.stx +263 -0
- package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
- package/views/dashboard/analytics/commerce/web/index.stx +379 -0
- package/views/dashboard/analytics/countries/index.stx +289 -0
- package/views/dashboard/analytics/devices/index.stx +305 -0
- package/views/dashboard/analytics/events/index.stx +536 -0
- package/views/dashboard/analytics/index.stx +88 -0
- package/views/dashboard/analytics/marketing/index.stx +315 -0
- package/views/dashboard/analytics/pages/index.stx +271 -0
- package/views/dashboard/analytics/referrers/index.stx +319 -0
- package/views/dashboard/analytics/web/index.stx +356 -0
- package/views/dashboard/buddy/index.stx +198 -0
- package/views/dashboard/ci/index.stx +462 -0
- package/views/dashboard/cloud/index.stx +452 -0
- package/views/dashboard/commands/index.stx +295 -0
- package/views/dashboard/commerce/categories/index.stx +406 -0
- package/views/dashboard/commerce/coupons/index.stx +485 -0
- package/views/dashboard/commerce/customers/index.stx +410 -0
- package/views/dashboard/commerce/dashboard/index.stx +287 -0
- package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
- package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
- package/views/dashboard/commerce/delivery/drivers.stx +397 -0
- package/views/dashboard/commerce/delivery/index.stx +18 -0
- package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
- package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
- package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
- package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
- package/views/dashboard/commerce/delivery/tabs.ts +25 -0
- package/views/dashboard/commerce/gift-cards/index.stx +561 -0
- package/views/dashboard/commerce/manufacturers/index.stx +308 -0
- package/views/dashboard/commerce/orders/index.stx +247 -0
- package/views/dashboard/commerce/payments/index.stx +535 -0
- package/views/dashboard/commerce/pos/index.stx +653 -0
- package/views/dashboard/commerce/printers/devices/index.stx +273 -0
- package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
- package/views/dashboard/commerce/products/detail.stx +563 -0
- package/views/dashboard/commerce/products/index.stx +370 -0
- package/views/dashboard/commerce/reviews/index.stx +656 -0
- package/views/dashboard/commerce/reviews/index.ts +0 -0
- package/views/dashboard/commerce/taxes/index.stx +377 -0
- package/views/dashboard/commerce/units/index.stx +317 -0
- package/views/dashboard/commerce/variants/index.stx +319 -0
- package/views/dashboard/commerce/waitlist/products.stx +942 -0
- package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
- package/views/dashboard/components/index.stx +330 -0
- package/views/dashboard/composables/index.ts +19 -0
- package/views/dashboard/composables/useChart.ts +77 -0
- package/views/dashboard/composables/useNavigation.ts +99 -0
- package/views/dashboard/composables/useRole.ts +58 -0
- package/views/dashboard/composables/useTheme.ts +74 -0
- package/views/dashboard/content/authors/index.stx +171 -0
- package/views/dashboard/content/blog/index.stx +493 -0
- package/views/dashboard/content/categories/index.stx +169 -0
- package/views/dashboard/content/comments/index.stx +189 -0
- package/views/dashboard/content/dashboard.stx +383 -0
- package/views/dashboard/content/files/index.stx +706 -0
- package/views/dashboard/content/pages/index.stx +174 -0
- package/views/dashboard/content/posts/index.stx +269 -0
- package/views/dashboard/content/seo/index.stx +240 -0
- package/views/dashboard/content/tags/index.stx +167 -0
- package/views/dashboard/data/activity/index.stx +261 -0
- package/views/dashboard/data/dashboard/index.stx +116 -0
- package/views/dashboard/data/subscribers.stx +270 -0
- package/views/dashboard/data/teams.stx +275 -0
- package/views/dashboard/data/users.stx +279 -0
- package/views/dashboard/dependencies/index.stx +178 -0
- package/views/dashboard/deployments/[id].stx +234 -0
- package/views/dashboard/deployments/index.stx +9 -0
- package/views/dashboard/dns/index.stx +163 -0
- package/views/dashboard/environment/index.stx +283 -0
- package/views/dashboard/errors/index.stx +274 -0
- package/views/dashboard/forgot-password.stx +57 -0
- package/views/dashboard/functions/index.stx +159 -0
- package/views/dashboard/health/index.stx +248 -0
- package/views/dashboard/inbox/activity.stx +350 -0
- package/views/dashboard/inbox/index.stx +452 -0
- package/views/dashboard/inbox/settings.stx +290 -0
- package/views/dashboard/index.stx +252 -0
- package/views/dashboard/insights/index.stx +529 -0
- package/views/dashboard/jobs/[id].stx +430 -0
- package/views/dashboard/jobs/history.stx +222 -0
- package/views/dashboard/jobs/index.stx +214 -0
- package/views/dashboard/kanban/[id].stx +899 -0
- package/views/dashboard/kanban/index.stx +260 -0
- package/views/dashboard/layouts/default.stx +565 -0
- package/views/dashboard/layouts/guest.stx +10 -0
- package/views/dashboard/login.stx +48 -0
- package/views/dashboard/logs/index.stx +540 -0
- package/views/dashboard/mailboxes/index.stx +149 -0
- package/views/dashboard/management/permissions/index.stx +490 -0
- package/views/dashboard/marketing/campaigns/index.stx +604 -0
- package/views/dashboard/marketing/lists/index.stx +514 -0
- package/views/dashboard/marketing/reviews/index.stx +475 -0
- package/views/dashboard/marketing/social-posts/index.stx +560 -0
- package/views/dashboard/models/[model].stx +195 -0
- package/views/dashboard/models/index.stx +159 -0
- package/views/dashboard/monitoring/errors/index.stx +415 -0
- package/views/dashboard/notifications/dashboard.stx +383 -0
- package/views/dashboard/notifications/email.stx +336 -0
- package/views/dashboard/notifications/history.stx +373 -0
- package/views/dashboard/notifications/sms.stx +332 -0
- package/views/dashboard/packages/index.stx +195 -0
- package/views/dashboard/queries/[id].stx +381 -0
- package/views/dashboard/queries/history.stx +227 -0
- package/views/dashboard/queries/index.stx +335 -0
- package/views/dashboard/queries/slow.stx +318 -0
- package/views/dashboard/queue/index.stx +427 -0
- package/views/dashboard/realtime/index.stx +429 -0
- package/views/dashboard/register.stx +46 -0
- package/views/dashboard/releases/index.stx +389 -0
- package/views/dashboard/requests/index.stx +462 -0
- package/views/dashboard/serverless/index.stx +475 -0
- package/views/dashboard/servers/[id].stx +299 -0
- package/views/dashboard/servers/index.stx +483 -0
- package/views/dashboard/settings/billing.stx +50 -0
- package/views/dashboard/settings/index.stx +256 -0
- package/views/dashboard/settings/mail.stx +252 -0
- package/views/dashboard/stores/auth.ts +123 -0
- package/views/dashboard/stores/ci.ts +342 -0
- package/views/dashboard/stores/index.ts +129 -0
- package/views/dashboard/stores/kanban.ts +723 -0
- package/views/dashboard/stores/rbac.ts +350 -0
- package/views/dashboard/stx.config.ts +34 -0
- package/views/dashboard/teams/[id].stx +170 -0
- package/views/forum/category.stx +92 -0
- package/views/forum/index.stx +209 -0
- package/views/forum/new-topic.stx +113 -0
- package/views/forum/profile.stx +1 -0
- package/views/forum/topic.stx +143 -0
- package/views/hello-world/[name].stx +47 -0
- package/views/index.stx +21 -0
- 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
|