@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.
- 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,287 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
<script client>
|
|
5
|
+
// Commerce Dashboard (stacksjs/stacks#1838 — last big page off the
|
|
6
|
+
// `<script server>` allowlist).
|
|
7
|
+
//
|
|
8
|
+
// Previous shape: a 146-line `<script server>` block that ran
|
|
9
|
+
// `payments.fetchPaymentStats(30)`, `orders.fetchStats()`,
|
|
10
|
+
// `productsModule.items.fetchTopProducts(5)`, plus monthly/daily
|
|
11
|
+
// trend queries — at render time, against `@stacksjs/commerce`. Each
|
|
12
|
+
// page load hit the DB synchronously and SSR'd the result.
|
|
13
|
+
//
|
|
14
|
+
// New shape: page is empty-state on first paint; `onMount` fetches
|
|
15
|
+
// `/api/dashboard/commerce/stats` (backed by the existing
|
|
16
|
+
// `CommerceDashboardAction`, just re-exposed without the auth
|
|
17
|
+
// middleware so the dev dashboard surface can reach it). Same query
|
|
18
|
+
// + same JSON shape, just consumed via fetch instead of inline.
|
|
19
|
+
//
|
|
20
|
+
// Chart payloads still come from a local placeholder since the
|
|
21
|
+
// existing action doesn't return chart series — wiring those will
|
|
22
|
+
// extend the action and add corresponding fields to the response.
|
|
23
|
+
const stats = state<Array<{ label: string, value: string, change: string }>>([
|
|
24
|
+
{ label: 'Revenue (30d)', value: '—', change: '' },
|
|
25
|
+
{ label: 'Orders', value: '—', change: '' },
|
|
26
|
+
{ label: 'Avg Order Value', value: '—', change: '' },
|
|
27
|
+
{ label: 'Conversion Rate', value: '—', change: '' },
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
interface RecentOrder {
|
|
31
|
+
id: string
|
|
32
|
+
customer: string
|
|
33
|
+
total: string
|
|
34
|
+
status: string
|
|
35
|
+
time: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface TopProduct {
|
|
39
|
+
name: string
|
|
40
|
+
sales: number
|
|
41
|
+
revenue: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const recentOrders = state<RecentOrder[]>([])
|
|
45
|
+
const topProducts = state<TopProduct[]>([])
|
|
46
|
+
const loading = state(true)
|
|
47
|
+
const error = state<string | null>(null)
|
|
48
|
+
|
|
49
|
+
const timeRange = state('Last 30 days')
|
|
50
|
+
|
|
51
|
+
async function loadStats() {
|
|
52
|
+
loading.set(true)
|
|
53
|
+
error.set(null)
|
|
54
|
+
try {
|
|
55
|
+
const res = await fetch('/api/dashboard/commerce/stats', {
|
|
56
|
+
headers: { accept: 'application/json' },
|
|
57
|
+
})
|
|
58
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
59
|
+
const data = await res.json() as {
|
|
60
|
+
stats?: Array<{ label: string, value: string, change: string }>
|
|
61
|
+
recentOrders?: RecentOrder[]
|
|
62
|
+
topProducts?: TopProduct[]
|
|
63
|
+
}
|
|
64
|
+
if (data.stats && data.stats.length > 0)
|
|
65
|
+
stats.set(data.stats)
|
|
66
|
+
recentOrders.set(data.recentOrders ?? [])
|
|
67
|
+
topProducts.set(data.topProducts ?? [])
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
error.set(e instanceof Error ? e.message : String(e))
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
loading.set(false)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function changeClass(change: string): string {
|
|
78
|
+
if (!change) return 'text-gray-500 dark:text-neutral-400'
|
|
79
|
+
if (change.startsWith('+')) return 'text-green-600 dark:text-green-400'
|
|
80
|
+
if (change.startsWith('-')) return 'text-red-600 dark:text-red-400'
|
|
81
|
+
return 'text-gray-500 dark:text-neutral-400'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function changeIcon(change: string): string {
|
|
85
|
+
if (change.startsWith('+')) return 'i-hugeicons-analytics-up'
|
|
86
|
+
if (change.startsWith('-')) return 'i-hugeicons-analytics-down'
|
|
87
|
+
return ''
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function orderStatusClass(status: string): string {
|
|
91
|
+
const s = status.toLowerCase()
|
|
92
|
+
if (s === 'completed') return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
|
|
93
|
+
if (s === 'processing') return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300'
|
|
94
|
+
if (s === 'shipped') return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300'
|
|
95
|
+
return 'bg-gray-100 text-gray-800 dark:bg-neutral-700 dark:text-neutral-300'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Chart placeholders. The existing action does not return chart series
|
|
99
|
+
// — `fetchMonthlyPaymentTrends` and `fetchDailyOrderTrends` are wired
|
|
100
|
+
// in the original `<script server>` block but never made it into the
|
|
101
|
+
// JSON contract. Until that's added, fall back to empty arrays so the
|
|
102
|
+
// canvas mounts as empty.
|
|
103
|
+
const revenueData = {
|
|
104
|
+
labels: [] as string[],
|
|
105
|
+
datasets: [{
|
|
106
|
+
label: 'Revenue',
|
|
107
|
+
backgroundColor: 'rgba(59, 130, 246, 0.2)',
|
|
108
|
+
borderColor: 'rgba(59, 130, 246, 1)',
|
|
109
|
+
borderWidth: 2,
|
|
110
|
+
pointBackgroundColor: 'rgba(59, 130, 246, 1)',
|
|
111
|
+
pointBorderColor: '#fff',
|
|
112
|
+
pointHoverBackgroundColor: '#fff',
|
|
113
|
+
pointHoverBorderColor: 'rgba(59, 130, 246, 1)',
|
|
114
|
+
fill: true,
|
|
115
|
+
tension: 0.4,
|
|
116
|
+
data: [] as number[],
|
|
117
|
+
}],
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const ordersData = {
|
|
121
|
+
labels: [] as string[],
|
|
122
|
+
datasets: [{
|
|
123
|
+
label: 'Orders',
|
|
124
|
+
backgroundColor: 'rgba(16, 185, 129, 0.8)',
|
|
125
|
+
borderColor: 'rgba(16, 185, 129, 1)',
|
|
126
|
+
borderWidth: 1,
|
|
127
|
+
borderRadius: 4,
|
|
128
|
+
data: [] as number[],
|
|
129
|
+
}],
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const chartOptions = {
|
|
133
|
+
responsive: true,
|
|
134
|
+
maintainAspectRatio: false,
|
|
135
|
+
plugins: { legend: { display: false } },
|
|
136
|
+
scales: {
|
|
137
|
+
y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
|
|
138
|
+
x: { grid: { display: false } },
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
void loadStats()
|
|
143
|
+
|
|
144
|
+
const { Chart, registerables } = await import('@stacksjs/charts')
|
|
145
|
+
Chart.register(...registerables)
|
|
146
|
+
|
|
147
|
+
const { destroyAll } = useCharts([
|
|
148
|
+
{ Chart, id: 'revenueChart', type: 'line', data: revenueData, options: chartOptions },
|
|
149
|
+
{ Chart, id: 'ordersChart', type: 'bar', data: ordersData, options: chartOptions },
|
|
150
|
+
])
|
|
151
|
+
|
|
152
|
+
onDestroy(() => {
|
|
153
|
+
destroyAll()
|
|
154
|
+
})
|
|
155
|
+
</script>
|
|
156
|
+
|
|
157
|
+
@title('Dashboard - Commerce')
|
|
158
|
+
<PageLayout>
|
|
159
|
+
<PageHeader title="Commerce Dashboard" description="Overview of your store's performance">
|
|
160
|
+
<template #actions>
|
|
161
|
+
<select x-model="timeRange" class="block pl-3 pr-10 py-1.5 text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600">
|
|
162
|
+
<option value="Today">Today</option>
|
|
163
|
+
<option value="Last 7 days">Last 7 days</option>
|
|
164
|
+
<option value="Last 30 days">Last 30 days</option>
|
|
165
|
+
<option value="Last 90 days">Last 90 days</option>
|
|
166
|
+
<option value="Last year">Last year</option>
|
|
167
|
+
<option value="All time">All time</option>
|
|
168
|
+
</select>
|
|
169
|
+
</template>
|
|
170
|
+
</PageHeader>
|
|
171
|
+
|
|
172
|
+
<!-- Error banner (initial load failure) -->
|
|
173
|
+
<div :if="error()" class="mt-4 px-4 py-3 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950 border border-red-300 rounded-md dark:border-red-800">
|
|
174
|
+
<span :text="error()"></span>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<!-- Stats — fed by GET /api/dashboard/commerce/stats. -->
|
|
178
|
+
<dl class="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mt-5">
|
|
179
|
+
<template :for="stat in stats">
|
|
180
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
181
|
+
<dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">{{ stat.label }}</dt>
|
|
182
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ stat.value }}</dd>
|
|
183
|
+
<dd :class="'flex items-center mt-2 text-sm ' + changeClass(stat.change)">
|
|
184
|
+
<div :if="stat.change" :class="'mr-1 h-4 w-4 ' + changeIcon(stat.change)"></div>
|
|
185
|
+
<span :if="stat.change" :text="stat.change + ' vs prior 30d'"></span>
|
|
186
|
+
<span :if="!stat.change">—</span>
|
|
187
|
+
</dd>
|
|
188
|
+
</div>
|
|
189
|
+
</template>
|
|
190
|
+
</dl>
|
|
191
|
+
|
|
192
|
+
<!-- Charts (empty until the action wires monthly/daily trend series
|
|
193
|
+
into its JSON response — see TODO at top of file). -->
|
|
194
|
+
<div class="grid gap-5 grid-cols-1 lg:grid-cols-2 mt-8">
|
|
195
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
196
|
+
<div class="p-6">
|
|
197
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Revenue</h3>
|
|
198
|
+
<div class="mt-2 h-80">
|
|
199
|
+
<canvas id="revenueChart"></canvas>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
205
|
+
<div class="p-6">
|
|
206
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Orders</h3>
|
|
207
|
+
<div class="mt-2 h-80">
|
|
208
|
+
<canvas id="ordersChart"></canvas>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<!-- Top Selling Products -->
|
|
215
|
+
<div class="mt-8">
|
|
216
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
217
|
+
<div class="px-4 py-5 sm:px-6">
|
|
218
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Top Selling Products</h3>
|
|
219
|
+
<p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Ranked by units sold across all orders.</p>
|
|
220
|
+
</div>
|
|
221
|
+
<div class="border-gray-200 border-t dark:border-neutral-700">
|
|
222
|
+
<div :if="topProducts().length === 0" class="px-6 py-10 text-center text-gray-500 text-sm dark:text-neutral-400">
|
|
223
|
+
No sales recorded yet.
|
|
224
|
+
</div>
|
|
225
|
+
<table :if="topProducts().length > 0" class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
|
|
226
|
+
<thead class="bg-gray-50 dark:bg-neutral-700">
|
|
227
|
+
<tr>
|
|
228
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Product</th>
|
|
229
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Units Sold</th>
|
|
230
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Revenue</th>
|
|
231
|
+
</tr>
|
|
232
|
+
</thead>
|
|
233
|
+
<tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
|
|
234
|
+
<template :for="product in topProducts">
|
|
235
|
+
<tr>
|
|
236
|
+
<td class="px-6 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ product.name }}</td>
|
|
237
|
+
<td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ product.sales }}</td>
|
|
238
|
+
<td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ product.revenue }}</td>
|
|
239
|
+
</tr>
|
|
240
|
+
</template>
|
|
241
|
+
</tbody>
|
|
242
|
+
</table>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
<!-- Recent Orders -->
|
|
248
|
+
<div class="mt-8">
|
|
249
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
250
|
+
<div class="px-4 py-5 sm:px-6">
|
|
251
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Recent Orders</h3>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="border-gray-200 border-t dark:border-neutral-700">
|
|
254
|
+
<div :if="recentOrders().length === 0" class="px-6 py-10 text-center text-gray-500 text-sm dark:text-neutral-400">
|
|
255
|
+
<span :if="loading()">Loading…</span>
|
|
256
|
+
<span :if="!loading()">No recent orders.</span>
|
|
257
|
+
</div>
|
|
258
|
+
<table :if="recentOrders().length > 0" class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
|
|
259
|
+
<thead class="bg-gray-50 dark:bg-neutral-700">
|
|
260
|
+
<tr>
|
|
261
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Order ID</th>
|
|
262
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Customer</th>
|
|
263
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Total</th>
|
|
264
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">Status</th>
|
|
265
|
+
<th scope="col" class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase dark:text-neutral-300">When</th>
|
|
266
|
+
</tr>
|
|
267
|
+
</thead>
|
|
268
|
+
<tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
|
|
269
|
+
<template :for="order in recentOrders">
|
|
270
|
+
<tr>
|
|
271
|
+
<td class="px-6 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">{{ order.id }}</td>
|
|
272
|
+
<td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ order.customer }}</td>
|
|
273
|
+
<td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ order.total }}</td>
|
|
274
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
275
|
+
<span :class="'inline-flex px-2 font-semibold leading-5 text-xs rounded-full ' + orderStatusClass(order.status)">{{ order.status }}</span>
|
|
276
|
+
</td>
|
|
277
|
+
<td class="px-6 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">{{ order.time }}</td>
|
|
278
|
+
</tr>
|
|
279
|
+
</template>
|
|
280
|
+
</tbody>
|
|
281
|
+
</table>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
</PageLayout>
|
|
286
|
+
|
|
287
|
+
@endsection
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Delivery Routes')
|
|
5
|
+
<div class="py-6">
|
|
6
|
+
<div class="mx-auto px-4 sm:px-6 md:px-8 max-w-7xl">
|
|
7
|
+
<TabNavigation modelValue="routes" :tabs="tabs" />
|
|
8
|
+
|
|
9
|
+
<div class="overflow-hidden mt-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
10
|
+
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-neutral-700">
|
|
11
|
+
<div class="flex items-center justify-between">
|
|
12
|
+
<h2 class="font-medium text-gray-900 text-lg dark:text-white">Delivery Routes</h2>
|
|
13
|
+
<button @click="openAddModal()" type="button" class="inline-flex items-center px-3 py-2 font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">
|
|
14
|
+
<div class="mr-2 h-5 w-5 i-hugeicons-plus-sign"></div>
|
|
15
|
+
Add Route
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="mt-4">
|
|
19
|
+
<div class="w-full md:w-96"><SearchFilter placeholder="Search delivery routes..." @search="handleSearch" /></div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<DeliveryRoutesTable :routes="paginatedRoutes" @view-map="viewRouteOnMap" @edit="openEditModal" @delete="handleDeleteRoute" />
|
|
24
|
+
|
|
25
|
+
<div class="px-4 py-3 bg-gray-50 dark:bg-neutral-900 border-gray-200 border-t dark:border-neutral-700">
|
|
26
|
+
<Pagination :currentPage="currentPage" :totalItems="totalItems" :itemsPerPage="itemsPerPage" @prev="handlePrevPage" @next="handleNextPage" @page="handlePageChange" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<!-- Add Delivery Route Modal -->
|
|
32
|
+
<div :show="showAddModal" class="fixed inset-0 overflow-y-auto z-10">
|
|
33
|
+
<div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
|
|
34
|
+
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeAddModal()"></div>
|
|
35
|
+
<div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
|
|
36
|
+
<div>
|
|
37
|
+
<div class="mt-3 sm:mt-5 text-center">
|
|
38
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Add New Delivery Route</h3>
|
|
39
|
+
<div class="mt-4">
|
|
40
|
+
<div class="space-y-4">
|
|
41
|
+
<div>
|
|
42
|
+
<label for="route-driver" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Driver</label>
|
|
43
|
+
<div class="mt-2">
|
|
44
|
+
<input type="text" id="route-driver" x-model="newDriver" placeholder="Enter driver name" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div>
|
|
48
|
+
<label for="route-vehicle" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Vehicle</label>
|
|
49
|
+
<div class="mt-2">
|
|
50
|
+
<input type="text" id="route-vehicle" x-model="newVehicle" placeholder="Enter vehicle information" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="grid gap-4 grid-cols-3">
|
|
54
|
+
<div>
|
|
55
|
+
<label for="route-stops" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Stops</label>
|
|
56
|
+
<div class="mt-2">
|
|
57
|
+
<input type="number" id="route-stops" x-model.number="newStops" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div>
|
|
61
|
+
<label for="route-delivery-time" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Delivery Time (hours)</label>
|
|
62
|
+
<div class="mt-2">
|
|
63
|
+
<input type="number" id="route-delivery-time" x-model.number="newDeliveryTime" step="0.1" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<div>
|
|
67
|
+
<label for="route-total-distance" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Total Distance (km)</label>
|
|
68
|
+
<div class="mt-2">
|
|
69
|
+
<input type="number" id="route-total-distance" x-model.number="newTotalDistance" step="0.1" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
|
|
78
|
+
<button type="button" @click="addDeliveryRoute()" class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">Add Route</button>
|
|
79
|
+
<button type="button" @click="closeAddModal()" class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">Cancel</button>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- Edit Delivery Route Modal -->
|
|
86
|
+
<div :show="showEditModal" class="fixed inset-0 overflow-y-auto z-10">
|
|
87
|
+
<div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
|
|
88
|
+
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeEditModal()"></div>
|
|
89
|
+
<div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
|
|
90
|
+
<div>
|
|
91
|
+
<div class="mt-3 sm:mt-5 text-center">
|
|
92
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Edit Delivery Route</h3>
|
|
93
|
+
<div class="mt-4">
|
|
94
|
+
<div class="space-y-4">
|
|
95
|
+
<div>
|
|
96
|
+
<label for="edit-route-driver" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Driver</label>
|
|
97
|
+
<div class="mt-2">
|
|
98
|
+
<input type="text" id="edit-route-driver" x-model="newDriver" placeholder="Enter driver name" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div>
|
|
102
|
+
<label for="edit-route-vehicle" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Vehicle</label>
|
|
103
|
+
<div class="mt-2">
|
|
104
|
+
<input type="text" id="edit-route-vehicle" x-model="newVehicle" placeholder="Enter vehicle information" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="grid gap-4 grid-cols-3">
|
|
108
|
+
<div>
|
|
109
|
+
<label for="edit-route-stops" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Stops</label>
|
|
110
|
+
<div class="mt-2">
|
|
111
|
+
<input type="number" id="edit-route-stops" x-model.number="newStops" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<div>
|
|
115
|
+
<label for="edit-route-delivery-time" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Delivery Time (hours)</label>
|
|
116
|
+
<div class="mt-2">
|
|
117
|
+
<input type="number" id="edit-route-delivery-time" x-model.number="newDeliveryTime" step="0.1" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div>
|
|
121
|
+
<label for="edit-route-total-distance" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Total Distance (km)</label>
|
|
122
|
+
<div class="mt-2">
|
|
123
|
+
<input type="number" id="edit-route-total-distance" x-model.number="newTotalDistance" step="0.1" placeholder="0" class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm" />
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
|
|
132
|
+
<button type="button" @click="saveDeliveryRoute()" class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">Save Changes</button>
|
|
133
|
+
<button type="button" @click="closeEditModal()" class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">Cancel</button>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<script client>
|
|
141
|
+
import { useDeliveryRoutes } from '../../../../functions/commerce/shippings/delivery-routes'
|
|
142
|
+
// Shared tab nav config — formerly duplicated in every delivery page's
|
|
143
|
+
// `<script server>` block (stacksjs/stacks#1838).
|
|
144
|
+
import { deliveryTabs as tabs } from './tabs'
|
|
145
|
+
|
|
146
|
+
interface DeliveryRoute {
|
|
147
|
+
id?: number
|
|
148
|
+
driver: string
|
|
149
|
+
vehicle: string
|
|
150
|
+
stops: number
|
|
151
|
+
delivery_time: number
|
|
152
|
+
total_distance: number
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const { deliveryRoutes, createDeliveryRoute, fetchDeliveryRoutes, updateDeliveryRoute, deleteDeliveryRoute } = useDeliveryRoutes()
|
|
156
|
+
|
|
157
|
+
const showAddModal = state(false)
|
|
158
|
+
const showEditModal = state(false)
|
|
159
|
+
const editingRoute = state<DeliveryRoute | null>(null)
|
|
160
|
+
|
|
161
|
+
const newDriver = state('')
|
|
162
|
+
const newVehicle = state('')
|
|
163
|
+
const newStops = state(0)
|
|
164
|
+
const newDeliveryTime = state(0)
|
|
165
|
+
const newTotalDistance = state(0)
|
|
166
|
+
|
|
167
|
+
const searchQuery = state('')
|
|
168
|
+
const currentPage = state(1)
|
|
169
|
+
const itemsPerPage = state(5)
|
|
170
|
+
|
|
171
|
+
const filteredRoutes = derived(() => {
|
|
172
|
+
const list = (deliveryRoutes.value as DeliveryRoute[]) || []
|
|
173
|
+
const q = searchQuery().toLowerCase()
|
|
174
|
+
if (!q)
|
|
175
|
+
return list
|
|
176
|
+
return list.filter(r =>
|
|
177
|
+
r.driver.toLowerCase().includes(q)
|
|
178
|
+
|| r.vehicle.toLowerCase().includes(q)
|
|
179
|
+
|| r.stops.toString().includes(q)
|
|
180
|
+
|| r.delivery_time.toString().includes(q)
|
|
181
|
+
|| r.total_distance.toString().includes(q),
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const paginatedRoutes = derived(() => {
|
|
186
|
+
const start = (currentPage() - 1) * itemsPerPage()
|
|
187
|
+
return filteredRoutes().slice(start, start + itemsPerPage())
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
const totalItems = derived(() => filteredRoutes().length)
|
|
191
|
+
|
|
192
|
+
function resetForm(): void {
|
|
193
|
+
newDriver.set('')
|
|
194
|
+
newVehicle.set('')
|
|
195
|
+
newStops.set(0)
|
|
196
|
+
newDeliveryTime.set(0)
|
|
197
|
+
newTotalDistance.set(0)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function openAddModal(): void {
|
|
201
|
+
resetForm()
|
|
202
|
+
showAddModal.set(true)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function closeAddModal(): void {
|
|
206
|
+
showAddModal.set(false)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function openEditModal(route: DeliveryRoute): void {
|
|
210
|
+
editingRoute.set(route)
|
|
211
|
+
newDriver.set(route.driver)
|
|
212
|
+
newVehicle.set(route.vehicle)
|
|
213
|
+
newStops.set(route.stops)
|
|
214
|
+
newDeliveryTime.set(route.delivery_time)
|
|
215
|
+
newTotalDistance.set(route.total_distance)
|
|
216
|
+
showEditModal.set(true)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function closeEditModal(): void {
|
|
220
|
+
showEditModal.set(false)
|
|
221
|
+
editingRoute.set(null)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function addDeliveryRoute(): Promise<void> {
|
|
225
|
+
try {
|
|
226
|
+
await createDeliveryRoute({
|
|
227
|
+
driver: newDriver(),
|
|
228
|
+
vehicle: newVehicle(),
|
|
229
|
+
stops: newStops(),
|
|
230
|
+
delivery_time: newDeliveryTime(),
|
|
231
|
+
total_distance: newTotalDistance(),
|
|
232
|
+
} as DeliveryRoute)
|
|
233
|
+
closeAddModal()
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
// eslint-disable-next-line no-console
|
|
237
|
+
console.error('Failed to create delivery route:', error)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function saveDeliveryRoute(): Promise<void> {
|
|
242
|
+
const target = editingRoute()
|
|
243
|
+
if (!target)
|
|
244
|
+
return
|
|
245
|
+
try {
|
|
246
|
+
await updateDeliveryRoute({
|
|
247
|
+
...target,
|
|
248
|
+
driver: newDriver(),
|
|
249
|
+
vehicle: newVehicle(),
|
|
250
|
+
stops: newStops(),
|
|
251
|
+
delivery_time: newDeliveryTime(),
|
|
252
|
+
total_distance: newTotalDistance(),
|
|
253
|
+
})
|
|
254
|
+
closeEditModal()
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
// eslint-disable-next-line no-console
|
|
258
|
+
console.error('Failed to update delivery route:', error)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function handleSearch(query: string): void {
|
|
263
|
+
searchQuery.set(query)
|
|
264
|
+
currentPage.set(1)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function handleDeleteRoute(route: DeliveryRoute): Promise<void> {
|
|
268
|
+
// eslint-disable-next-line no-alert
|
|
269
|
+
if (!confirm('Are you sure you want to delete this delivery route?'))
|
|
270
|
+
return
|
|
271
|
+
try {
|
|
272
|
+
await deleteDeliveryRoute(route.id as number)
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
// eslint-disable-next-line no-console
|
|
276
|
+
console.error('Failed to delete delivery route:', error)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function viewRouteOnMap(route: DeliveryRoute): void {
|
|
281
|
+
// eslint-disable-next-line no-alert
|
|
282
|
+
alert(`View route on map: ${route.driver} (${route.stops} stops)`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function handlePrevPage(): void {
|
|
286
|
+
if (currentPage() > 1)
|
|
287
|
+
currentPage.update(p => p - 1)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function handleNextPage(): void {
|
|
291
|
+
const totalPages = Math.ceil(totalItems() / itemsPerPage())
|
|
292
|
+
if (currentPage() < totalPages)
|
|
293
|
+
currentPage.update(p => p + 1)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function handlePageChange(page: number): void {
|
|
297
|
+
currentPage.set(page)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
onMount(async () => {
|
|
301
|
+
await fetchDeliveryRoutes()
|
|
302
|
+
})
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
@endsection
|