@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,535 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Commerce Payments')
|
|
5
|
+
<PageLayout>
|
|
6
|
+
<div class="sm:flex sm:items-center sm:justify-between">
|
|
7
|
+
<PageHeader title="Payments" description="Manage payment transactions for your store" />
|
|
8
|
+
<div class="mt-4 sm:mt-0">
|
|
9
|
+
<button
|
|
10
|
+
type="button"
|
|
11
|
+
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"
|
|
12
|
+
>
|
|
13
|
+
<div class="mr-1 h-5 w-5 i-hugeicons-download-04"></div>
|
|
14
|
+
Export transactions
|
|
15
|
+
</button>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<!-- Time range selector -->
|
|
20
|
+
<div class="flex items-center justify-between mt-4">
|
|
21
|
+
<p class="text-gray-500 text-sm dark:text-neutral-400">
|
|
22
|
+
Overview of your payment transactions
|
|
23
|
+
</p>
|
|
24
|
+
<div class="relative">
|
|
25
|
+
<select x-model="timeRange" class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600">
|
|
26
|
+
@foreach(timeRanges as range)
|
|
27
|
+
<option value="{{ range }}">{{ range }}</option>
|
|
28
|
+
@endforeach
|
|
29
|
+
</select>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<!-- Stats -->
|
|
34
|
+
<dl class="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mt-5">
|
|
35
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
36
|
+
<dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Transactions</dt>
|
|
37
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ paymentStats().totalTransactions }}</dd>
|
|
38
|
+
<dd class="flex items-center mt-2 text-green-600 text-sm dark:text-green-400">
|
|
39
|
+
<div class="mr-1 h-4 w-4 i-hugeicons-analytics-up"></div>
|
|
40
|
+
<span>8.2% increase</span>
|
|
41
|
+
</dd>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
45
|
+
<dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Success Rate</dt>
|
|
46
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ paymentStats().successRate }}%</dd>
|
|
47
|
+
<dd class="flex items-center mt-2 text-green-600 text-sm dark:text-green-400">
|
|
48
|
+
<div class="mr-1 h-4 w-4 i-hugeicons-analytics-up"></div>
|
|
49
|
+
<span>1.2% increase</span>
|
|
50
|
+
</dd>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
54
|
+
<dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Total Revenue</dt>
|
|
55
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">${{ Number.parseFloat(paymentStats().totalAmount).toLocaleString() }}</dd>
|
|
56
|
+
<dd class="flex items-center mt-2 text-green-600 text-sm dark:text-green-400">
|
|
57
|
+
<div class="mr-1 h-4 w-4 i-hugeicons-analytics-up"></div>
|
|
58
|
+
<span>12.5% increase</span>
|
|
59
|
+
</dd>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
63
|
+
<dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-300">Avg. Transaction</dt>
|
|
64
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">${{ paymentStats().avgTransactionValue }}</dd>
|
|
65
|
+
<dd class="flex items-center mt-2 text-green-600 text-sm dark:text-green-400">
|
|
66
|
+
<div class="mr-1 h-4 w-4 i-hugeicons-analytics-up"></div>
|
|
67
|
+
<span>3.7% increase</span>
|
|
68
|
+
</dd>
|
|
69
|
+
</div>
|
|
70
|
+
</dl>
|
|
71
|
+
|
|
72
|
+
<!-- Charts -->
|
|
73
|
+
<div class="grid gap-5 grid-cols-1 lg:grid-cols-2 mt-8">
|
|
74
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
75
|
+
<div class="p-6">
|
|
76
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Transaction Count</h3>
|
|
77
|
+
<div class="mt-2 h-80">
|
|
78
|
+
<canvas id="chart_1"></canvas>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
84
|
+
<div class="p-6">
|
|
85
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Revenue</h3>
|
|
86
|
+
<div class="mt-2 h-80">
|
|
87
|
+
<canvas id="chart_2"></canvas>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Filters -->
|
|
94
|
+
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mt-8">
|
|
95
|
+
<div class="relative max-w-sm">
|
|
96
|
+
<div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
|
|
97
|
+
<div class="h-5 w-5 text-gray-400 i-hugeicons-search-01"></div>
|
|
98
|
+
</div>
|
|
99
|
+
<input
|
|
100
|
+
x-model="searchQuery"
|
|
101
|
+
type="text"
|
|
102
|
+
class="block pl-10 pr-3 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:placeholder:text-neutral-500 dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
|
|
103
|
+
placeholder="Search transactions..."
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="flex flex-col gap-4 sm:flex-row">
|
|
108
|
+
<select
|
|
109
|
+
x-model="statusFilter"
|
|
110
|
+
class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
|
|
111
|
+
>
|
|
112
|
+
@foreach(statuses as status)
|
|
113
|
+
<option value="{{ status }}">{{ status === 'all' ? 'All Statuses' : status }}</option>
|
|
114
|
+
@endforeach
|
|
115
|
+
</select>
|
|
116
|
+
|
|
117
|
+
<select
|
|
118
|
+
x-model="methodFilter"
|
|
119
|
+
class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
|
|
120
|
+
>
|
|
121
|
+
@foreach(methods as method)
|
|
122
|
+
<option value="{{ method }}">{{ method === 'all' ? 'All Payment Methods' : method }}</option>
|
|
123
|
+
@endforeach
|
|
124
|
+
</select>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<!-- Transactions table -->
|
|
129
|
+
<div class="flow-root mt-6">
|
|
130
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-4">
|
|
131
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">All Transactions</h3>
|
|
132
|
+
<p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">
|
|
133
|
+
A list of all payment transactions including order ID, customer, amount, and status.
|
|
134
|
+
</p>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
|
|
137
|
+
<div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
|
|
138
|
+
<div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
|
|
139
|
+
<table class="min-w-full divide-gray-300 divide-y dark:divide-neutral-700">
|
|
140
|
+
<thead class="bg-gray-50 dark:bg-neutral-700">
|
|
141
|
+
<tr>
|
|
142
|
+
<th scope="col" class="pl-4 pr-3 py-3.5 sm:pl-6 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
|
|
143
|
+
<button @click="toggleSort('orderId')" class="inline-flex items-center group">
|
|
144
|
+
Order ID
|
|
145
|
+
<span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
|
|
146
|
+
<div class="h-4 w-4 {{ sortBy() === 'orderId' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
|
|
147
|
+
</span>
|
|
148
|
+
</button>
|
|
149
|
+
</th>
|
|
150
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
|
|
151
|
+
<button @click="toggleSort('customer')" class="inline-flex items-center group">
|
|
152
|
+
Customer
|
|
153
|
+
<span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
|
|
154
|
+
<div class="h-4 w-4 {{ sortBy() === 'customer' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
|
|
155
|
+
</span>
|
|
156
|
+
</button>
|
|
157
|
+
</th>
|
|
158
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
|
|
159
|
+
<button @click="toggleSort('amount')" class="inline-flex items-center group">
|
|
160
|
+
Amount
|
|
161
|
+
<span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
|
|
162
|
+
<div class="h-4 w-4 {{ sortBy() === 'amount' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
|
|
163
|
+
</span>
|
|
164
|
+
</button>
|
|
165
|
+
</th>
|
|
166
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Method</th>
|
|
167
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">Status</th>
|
|
168
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-200">
|
|
169
|
+
<button @click="toggleSort('date')" class="inline-flex items-center group">
|
|
170
|
+
Date
|
|
171
|
+
<span class="group-focus:visible group-hover:visible flex-none ml-2 text-gray-400 rounded">
|
|
172
|
+
<div class="h-4 w-4 {{ sortBy() === 'date' ? (sortOrder() === 'asc' ? 'i-hugeicons-arrow-up-02' : 'i-hugeicons-arrow-down-02') : 'i-hugeicons-arrows-up-down' }}"></div>
|
|
173
|
+
</span>
|
|
174
|
+
</button>
|
|
175
|
+
</th>
|
|
176
|
+
<th scope="col" class="relative pl-3 pr-4 py-3.5 sm:pr-6">
|
|
177
|
+
<span class="sr-only">Actions</span>
|
|
178
|
+
</th>
|
|
179
|
+
</tr>
|
|
180
|
+
</thead>
|
|
181
|
+
<tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
|
|
182
|
+
<template :for="transaction in paginatedTransactions">
|
|
183
|
+
<tr>
|
|
184
|
+
<td class="pl-4 pr-3 py-4 sm:pl-6 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">
|
|
185
|
+
{{ transaction.orderId }}
|
|
186
|
+
</td>
|
|
187
|
+
<td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-300">
|
|
188
|
+
<div>{{ transaction.customer }}</div>
|
|
189
|
+
<div class="text-gray-400 text-xs">{{ transaction.email }}</div>
|
|
190
|
+
</td>
|
|
191
|
+
<td class="px-3 py-4 font-medium text-gray-900 text-sm whitespace-nowrap dark:text-white">
|
|
192
|
+
${{ transaction.amount.toFixed(2) }}
|
|
193
|
+
</td>
|
|
194
|
+
<td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">
|
|
195
|
+
<div class="flex items-center">
|
|
196
|
+
<div class="{{ getPaymentMethodIcon(transaction.method) }} h-5 w-5 mr-1.5 text-gray-500 dark:text-neutral-400"></div>
|
|
197
|
+
<span>{{ transaction.method }}</span>
|
|
198
|
+
@if(transaction.last4)
|
|
199
|
+
<span class="ml-1 text-gray-400 text-xs">
|
|
200
|
+
({{ transaction.cardType }} •••• {{ transaction.last4 }})
|
|
201
|
+
</span>
|
|
202
|
+
@endif
|
|
203
|
+
</div>
|
|
204
|
+
</td>
|
|
205
|
+
<td class="px-3 py-4 text-sm whitespace-nowrap">
|
|
206
|
+
<span class="inline-flex items-center px-2 py-1 font-medium text-xs rounded-md {{ getStatusClass(transaction.status) }}">
|
|
207
|
+
{{ transaction.status }}
|
|
208
|
+
</span>
|
|
209
|
+
</td>
|
|
210
|
+
<td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-300">
|
|
211
|
+
{{ transaction.date }}
|
|
212
|
+
</td>
|
|
213
|
+
<td class="relative pl-3 pr-4 py-4 sm:pr-6 font-medium text-right text-sm whitespace-nowrap">
|
|
214
|
+
<div class="flex items-center justify-end space-x-2">
|
|
215
|
+
<button type="button" class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300">
|
|
216
|
+
<div class="h-5 w-5 i-hugeicons-view"></div>
|
|
217
|
+
</button>
|
|
218
|
+
<button type="button" class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300">
|
|
219
|
+
<div class="h-5 w-5 i-hugeicons-receipt-dollar"></div>
|
|
220
|
+
</button>
|
|
221
|
+
</div>
|
|
222
|
+
</td>
|
|
223
|
+
</tr>
|
|
224
|
+
</template>
|
|
225
|
+
@if(paginatedTransactions().length === 0)
|
|
226
|
+
<tr>
|
|
227
|
+
<td colspan="7" class="px-6 py-4 text-center text-gray-500 text-sm dark:text-neutral-400">
|
|
228
|
+
No transactions found matching your criteria
|
|
229
|
+
</td>
|
|
230
|
+
</tr>
|
|
231
|
+
@endif
|
|
232
|
+
</tbody>
|
|
233
|
+
</table>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<!-- Pagination -->
|
|
240
|
+
<div :show="totalPages() > 1" class="flex items-center justify-between mt-6">
|
|
241
|
+
<div class="flex sm:hidden flex-1 justify-between">
|
|
242
|
+
<button
|
|
243
|
+
@click="changePage(Math.max(1, currentPage() - 1))"
|
|
244
|
+
:disabled="currentPage() === 1"
|
|
245
|
+
class="{{ currentPage() === 1 ? 'cursor-not-allowed opacity-50' : '' }} relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-neutral-600 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
|
|
246
|
+
>
|
|
247
|
+
Previous
|
|
248
|
+
</button>
|
|
249
|
+
<button
|
|
250
|
+
@click="changePage(Math.min(totalPages(), currentPage() + 1))"
|
|
251
|
+
:disabled="currentPage() === totalPages()"
|
|
252
|
+
class="{{ currentPage() === totalPages() ? 'cursor-not-allowed opacity-50' : '' }} relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-neutral-600 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
|
|
253
|
+
>
|
|
254
|
+
Next
|
|
255
|
+
</button>
|
|
256
|
+
</div>
|
|
257
|
+
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
258
|
+
<div>
|
|
259
|
+
<p class="text-gray-700 text-sm dark:text-neutral-300">
|
|
260
|
+
Showing <span class="font-medium">{{ ((currentPage() - 1) * itemsPerPage()) + 1 }}</span> to <span class="font-medium">{{ Math.min(currentPage() * itemsPerPage(), filteredTransactions().length) }}</span> of <span class="font-medium">{{ filteredTransactions().length }}</span> results
|
|
261
|
+
</p>
|
|
262
|
+
</div>
|
|
263
|
+
<div>
|
|
264
|
+
<nav class="inline-flex -space-x-px rounded-md shadow-sm isolate" aria-label="Pagination">
|
|
265
|
+
<button
|
|
266
|
+
@click="changePage(Math.max(1, currentPage() - 1))"
|
|
267
|
+
:disabled="currentPage() === 1"
|
|
268
|
+
class="inline-flex relative focus:z-20 items-center px-2 py-2 text-gray-400 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset rounded-l-md dark:ring-neutral-600 focus:outline-offset-0 {{ currentPage() === 1 ? 'cursor-not-allowed opacity-50' : '' }}"
|
|
269
|
+
>
|
|
270
|
+
<span class="sr-only">Previous</span>
|
|
271
|
+
<div class="h-5 w-5 i-hugeicons-arrow-left-01"></div>
|
|
272
|
+
</button>
|
|
273
|
+
|
|
274
|
+
<template :for="page in visiblePages">
|
|
275
|
+
@if(page === '...')
|
|
276
|
+
<span class="inline-flex relative items-center px-4 py-2 font-semibold text-gray-700 text-sm dark:text-neutral-400 ring-1 ring-gray-300 ring-inset dark:ring-neutral-600 focus:outline-offset-0">
|
|
277
|
+
...
|
|
278
|
+
</span>
|
|
279
|
+
@else
|
|
280
|
+
<button
|
|
281
|
+
@click="changePage(page)"
|
|
282
|
+
class="{{ page === currentPage() ? 'relative z-10 inline-flex items-center bg-blue-600 px-4 py-2 text-sm font-semibold text-white focus:z-20 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600' : 'relative inline-flex items-center px-4 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0 dark:text-neutral-200 dark:ring-neutral-600 dark:hover:bg-neutral-700' }}"
|
|
283
|
+
>
|
|
284
|
+
{{ page }}
|
|
285
|
+
</button>
|
|
286
|
+
@endif
|
|
287
|
+
</template>
|
|
288
|
+
|
|
289
|
+
<button
|
|
290
|
+
@click="changePage(Math.min(totalPages(), currentPage() + 1))"
|
|
291
|
+
:disabled="currentPage() === totalPages()"
|
|
292
|
+
class="inline-flex relative focus:z-20 items-center px-2 py-2 text-gray-400 hover:bg-gray-50 dark:hover:bg-neutral-700 ring-1 ring-gray-300 ring-inset rounded-r-md dark:ring-neutral-600 focus:outline-offset-0 {{ currentPage() === totalPages() ? 'cursor-not-allowed opacity-50' : '' }}"
|
|
293
|
+
>
|
|
294
|
+
<span class="sr-only">Next</span>
|
|
295
|
+
<div class="h-5 w-5 i-hugeicons-arrow-right-01"></div>
|
|
296
|
+
</button>
|
|
297
|
+
</nav>
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
</PageLayout>
|
|
302
|
+
<script client>
|
|
303
|
+
// Filter options — moved out of the former `<script server>` block
|
|
304
|
+
// (stacksjs/stacks#1838).
|
|
305
|
+
const statuses = ['all', 'Completed', 'Pending', 'Failed', 'Refunded'] as const
|
|
306
|
+
const methods = ['all', 'Credit Card', 'PayPal', 'Apple Pay', 'Google Pay', 'Bank Transfer'] as const
|
|
307
|
+
const timeRanges = ['Today', 'Last 7 days', 'Last 30 days', 'Last 90 days', 'Last year', 'All time'] as const
|
|
308
|
+
|
|
309
|
+
interface PaymentTransaction {
|
|
310
|
+
id: number
|
|
311
|
+
orderId: string
|
|
312
|
+
customer: string
|
|
313
|
+
email: string
|
|
314
|
+
amount: number
|
|
315
|
+
method: string
|
|
316
|
+
status: string
|
|
317
|
+
date: string
|
|
318
|
+
cardType?: string
|
|
319
|
+
last4?: string
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const initialTransactions: PaymentTransaction[] = [
|
|
323
|
+
{ id: 1, orderId: 'ORD-12345', customer: 'John Smith', email: 'john.smith@example.com', amount: 129.99, method: 'Credit Card', status: 'Completed', date: '2023-11-15', cardType: 'Visa', last4: '4242' },
|
|
324
|
+
{ id: 2, orderId: 'ORD-12346', customer: 'Emily Davis', email: 'emily.davis@example.com', amount: 79.50, method: 'PayPal', status: 'Completed', date: '2023-11-16' },
|
|
325
|
+
{ id: 3, orderId: 'ORD-12347', customer: 'Michael Johnson', email: 'mjohnson@example.com', amount: 249.99, method: 'Credit Card', status: 'Failed', date: '2023-11-17', cardType: 'Mastercard', last4: '5678' },
|
|
326
|
+
{ id: 4, orderId: 'ORD-12348', customer: 'Sarah Williams', email: 'swilliams@example.com', amount: 59.99, method: 'Credit Card', status: 'Pending', date: '2023-11-18', cardType: 'Amex', last4: '9876' },
|
|
327
|
+
{ id: 5, orderId: 'ORD-12349', customer: 'David Brown', email: 'dbrown@example.com', amount: 149.95, method: 'Apple Pay', status: 'Completed', date: '2023-11-19' },
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
const transactions = state(initialTransactions)
|
|
331
|
+
const timeRange = state<string>('Last 30 days')
|
|
332
|
+
const searchQuery = state('')
|
|
333
|
+
const sortBy = state<'orderId' | 'customer' | 'amount' | 'date'>('date')
|
|
334
|
+
const sortOrder = state<'asc' | 'desc'>('desc')
|
|
335
|
+
const statusFilter = state<string>('all')
|
|
336
|
+
const methodFilter = state<string>('all')
|
|
337
|
+
const currentPage = state(1)
|
|
338
|
+
const itemsPerPage = state(10)
|
|
339
|
+
|
|
340
|
+
const chartOptions = {
|
|
341
|
+
responsive: true,
|
|
342
|
+
maintainAspectRatio: false,
|
|
343
|
+
plugins: { legend: { display: false } },
|
|
344
|
+
scales: {
|
|
345
|
+
y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
|
|
346
|
+
x: { grid: { display: false } },
|
|
347
|
+
},
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function monthlyChartData(): { transactionCountChartData: unknown, revenueChartData: unknown } {
|
|
351
|
+
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
|
352
|
+
const transactionCountData = [45, 52, 49, 60, 72, 68, 80, 91, 87, 94, 102, 110]
|
|
353
|
+
const revenueData = [5500, 6200, 5900, 7500, 8800, 8200, 9600, 11000, 10500, 11800, 12500, 13800]
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
transactionCountChartData: {
|
|
357
|
+
labels: months,
|
|
358
|
+
datasets: [{
|
|
359
|
+
label: 'Transaction Count',
|
|
360
|
+
backgroundColor: 'rgba(59, 130, 246, 0.2)',
|
|
361
|
+
borderColor: 'rgba(59, 130, 246, 1)',
|
|
362
|
+
borderWidth: 2,
|
|
363
|
+
pointBackgroundColor: 'rgba(59, 130, 246, 1)',
|
|
364
|
+
pointBorderColor: '#fff',
|
|
365
|
+
pointHoverBackgroundColor: '#fff',
|
|
366
|
+
pointHoverBorderColor: 'rgba(59, 130, 246, 1)',
|
|
367
|
+
fill: true,
|
|
368
|
+
tension: 0.4,
|
|
369
|
+
data: transactionCountData,
|
|
370
|
+
}],
|
|
371
|
+
},
|
|
372
|
+
revenueChartData: {
|
|
373
|
+
labels: months,
|
|
374
|
+
datasets: [{
|
|
375
|
+
label: 'Revenue',
|
|
376
|
+
backgroundColor: 'rgba(16, 185, 129, 0.8)',
|
|
377
|
+
borderColor: 'rgba(16, 185, 129, 1)',
|
|
378
|
+
borderWidth: 1,
|
|
379
|
+
borderRadius: 4,
|
|
380
|
+
data: revenueData,
|
|
381
|
+
}],
|
|
382
|
+
},
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function paymentStats(): { totalTransactions: number, completedTransactions: number, pendingTransactions: number, failedTransactions: number, totalAmount: string, avgTransactionValue: string, successRate: string, mostPopularMethod: string } {
|
|
387
|
+
const list = transactions()
|
|
388
|
+
const completedTransactions = list.filter(t => t.status === 'Completed').length
|
|
389
|
+
const pendingTransactions = list.filter(t => t.status === 'Pending').length
|
|
390
|
+
const failedTransactions = list.filter(t => t.status === 'Failed').length
|
|
391
|
+
|
|
392
|
+
const totalAmount = list.reduce(
|
|
393
|
+
(sum, t) => t.status === 'Completed' ? sum + t.amount : sum,
|
|
394
|
+
0,
|
|
395
|
+
)
|
|
396
|
+
const avgTransactionValue = completedTransactions > 0
|
|
397
|
+
? (totalAmount / completedTransactions).toFixed(2)
|
|
398
|
+
: '0.00'
|
|
399
|
+
const totalProcessed = completedTransactions + failedTransactions
|
|
400
|
+
const successRate = totalProcessed > 0
|
|
401
|
+
? ((completedTransactions / totalProcessed) * 100).toFixed(1)
|
|
402
|
+
: '0.0'
|
|
403
|
+
|
|
404
|
+
const methodCounts = list.reduce<Record<string, number>>((counts, t) => {
|
|
405
|
+
counts[t.method] = (counts[t.method] || 0) + 1
|
|
406
|
+
return counts
|
|
407
|
+
}, {})
|
|
408
|
+
let mostPopularMethod = 'Credit Card'
|
|
409
|
+
let maxCount = 0
|
|
410
|
+
for (const [method, count] of Object.entries(methodCounts)) {
|
|
411
|
+
if (count > maxCount) { maxCount = count; mostPopularMethod = method }
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
totalTransactions: list.length,
|
|
416
|
+
completedTransactions,
|
|
417
|
+
pendingTransactions,
|
|
418
|
+
failedTransactions,
|
|
419
|
+
totalAmount: totalAmount.toFixed(2),
|
|
420
|
+
avgTransactionValue,
|
|
421
|
+
successRate,
|
|
422
|
+
mostPopularMethod,
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const filteredTransactions = derived(() => {
|
|
427
|
+
const q = searchQuery().toLowerCase()
|
|
428
|
+
const sFilter = statusFilter()
|
|
429
|
+
const mFilter = methodFilter()
|
|
430
|
+
const by = sortBy()
|
|
431
|
+
const dir = sortOrder()
|
|
432
|
+
|
|
433
|
+
return transactions()
|
|
434
|
+
.filter((t) => {
|
|
435
|
+
const matchesSearch
|
|
436
|
+
= t.orderId.toLowerCase().includes(q)
|
|
437
|
+
|| t.customer.toLowerCase().includes(q)
|
|
438
|
+
|| t.email.toLowerCase().includes(q)
|
|
439
|
+
const matchesStatus = sFilter === 'all' || t.status === sFilter
|
|
440
|
+
const matchesMethod = mFilter === 'all' || t.method === mFilter
|
|
441
|
+
return matchesSearch && matchesStatus && matchesMethod
|
|
442
|
+
})
|
|
443
|
+
.sort((a, b) => {
|
|
444
|
+
let cmp = 0
|
|
445
|
+
if (by === 'date')
|
|
446
|
+
cmp = new Date(a.date).getTime() - new Date(b.date).getTime()
|
|
447
|
+
else if (by === 'amount')
|
|
448
|
+
cmp = a.amount - b.amount
|
|
449
|
+
else if (by === 'orderId')
|
|
450
|
+
cmp = a.orderId.localeCompare(b.orderId)
|
|
451
|
+
else if (by === 'customer')
|
|
452
|
+
cmp = a.customer.localeCompare(b.customer)
|
|
453
|
+
return dir === 'asc' ? cmp : -cmp
|
|
454
|
+
})
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
const totalPages = derived(() => Math.ceil(filteredTransactions().length / itemsPerPage()))
|
|
458
|
+
|
|
459
|
+
const paginatedTransactions = derived(() => {
|
|
460
|
+
const start = (currentPage() - 1) * itemsPerPage()
|
|
461
|
+
return filteredTransactions().slice(start, start + itemsPerPage())
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
// Page numbers to render in the desktop pagination — first/last + a window
|
|
465
|
+
// of 3 around current, with '…' ellipsis where the gap is bigger than 1.
|
|
466
|
+
const visiblePages = derived<(number | '...')[]>(() => {
|
|
467
|
+
const total = totalPages()
|
|
468
|
+
const cur = currentPage()
|
|
469
|
+
const out: (number | '...')[] = []
|
|
470
|
+
for (let p = 1; p <= total; p++) {
|
|
471
|
+
if (p === cur || p === 1 || p === total || (p >= cur - 1 && p <= cur + 1)) {
|
|
472
|
+
out.push(p)
|
|
473
|
+
}
|
|
474
|
+
else if ((p === cur - 2 && cur > 3) || (p === cur + 2 && cur < total - 2)) {
|
|
475
|
+
out.push('...')
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return out
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
function toggleSort(column: 'orderId' | 'customer' | 'amount' | 'date'): void {
|
|
482
|
+
if (sortBy() === column) {
|
|
483
|
+
sortOrder.update(d => d === 'asc' ? 'desc' : 'asc')
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
sortBy.set(column)
|
|
487
|
+
sortOrder.set('desc')
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function changePage(page: number): void {
|
|
492
|
+
currentPage.set(page)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function getStatusClass(status: string): string {
|
|
496
|
+
switch (status) {
|
|
497
|
+
case 'Completed':
|
|
498
|
+
return 'bg-green-50 text-green-700 ring-1 ring-inset ring-green-600/20 dark:bg-green-900/30 dark:text-green-400'
|
|
499
|
+
case 'Pending':
|
|
500
|
+
return 'bg-yellow-50 text-yellow-700 ring-1 ring-inset ring-yellow-600/20 dark:bg-yellow-900/30 dark:text-yellow-400'
|
|
501
|
+
case 'Failed':
|
|
502
|
+
return 'bg-red-50 text-red-700 ring-1 ring-inset ring-red-600/20 dark:bg-red-900/30 dark:text-red-400'
|
|
503
|
+
case 'Refunded':
|
|
504
|
+
return 'bg-blue-50 text-blue-700 ring-1 ring-inset ring-blue-600/20 dark:bg-blue-900/30 dark:text-blue-400'
|
|
505
|
+
default:
|
|
506
|
+
return 'bg-gray-50 text-gray-700 ring-1 ring-inset ring-gray-600/20 dark:bg-neutral-900/30 dark:text-neutral-400'
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function getPaymentMethodIcon(method: string): string {
|
|
511
|
+
switch (method) {
|
|
512
|
+
case 'Credit Card': return 'i-hugeicons-credit-card'
|
|
513
|
+
case 'PayPal': return 'i-hugeicons-paypal'
|
|
514
|
+
case 'Apple Pay': return 'i-hugeicons-apple'
|
|
515
|
+
case 'Google Pay': return 'i-hugeicons-google'
|
|
516
|
+
case 'Bank Transfer': return 'i-hugeicons-bank'
|
|
517
|
+
default: return 'i-hugeicons-credit-card'
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const { Chart, registerables } = await import('@stacksjs/charts')
|
|
522
|
+
Chart.register(...registerables)
|
|
523
|
+
|
|
524
|
+
const chartData = monthlyChartData()
|
|
525
|
+
const { destroyAll } = useCharts([
|
|
526
|
+
{ Chart, id: 'chart_1', type: 'line', data: chartData.transactionCountChartData, options: chartOptions },
|
|
527
|
+
{ Chart, id: 'chart_2', type: 'bar', data: chartData.revenueChartData, options: chartOptions },
|
|
528
|
+
])
|
|
529
|
+
|
|
530
|
+
onDestroy(() => {
|
|
531
|
+
destroyAll()
|
|
532
|
+
})
|
|
533
|
+
</script>
|
|
534
|
+
|
|
535
|
+
@endsection
|