@stacksjs/defaults 0.72.97 → 0.72.99
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/ai/skills/stacks-auth/SKILL.md +35 -5
- package/ai/skills/stacks-config/SKILL.md +11 -1
- package/ai/skills/stacks-desktop/SKILL.md +46 -0
- package/ai/skills/stacks-env/SKILL.md +26 -0
- package/ai/skills/stacks-events/SKILL.md +76 -60
- package/ai/skills/stacks-jobs/SKILL.md +3 -0
- package/ai/skills/stacks-listeners/SKILL.md +39 -9
- package/ai/skills/stacks-middleware/SKILL.md +50 -12
- package/ai/skills/stacks-queue/SKILL.md +5 -0
- package/ai/skills/stacks-router/SKILL.md +17 -7
- package/ai/skills/stacks-scheduler/SKILL.md +1 -1
- package/app/Actions/Dashboard/Commerce/CommerceCustomersAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommerceDeliveryAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommerceOrdersAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommercePosAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommercePosCheckoutAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommerceProductDetailAction.ts +1 -1
- package/app/Actions/Dashboard/Commerce/CommerceProductsAction.ts +1 -1
- package/app/Actions/Dashboard/Content/content-input.ts +2 -2
- package/app/Actions/Dashboard/Content/post-input.ts +4 -4
- package/app/Actions/Dashboard/Email/inbox-request.ts +1 -1
- package/app/Actions/Dashboard/Email/mail-preference.ts +1 -1
- package/app/Actions/Dashboard/Marketing/CampaignIndexAction.ts +1 -1
- package/app/Actions/Dashboard/Marketing/CampaignStoreAction.ts +1 -1
- package/app/Actions/Dashboard/Marketing/CampaignUpdateAction.ts +1 -1
- package/app/Actions/Dashboard/Teams/TeamInvitationDestroyAction.ts +2 -2
- package/app/Actions/Dashboard/Teams/TeamInvitationResendAction.ts +2 -2
- package/app/Actions/Dashboard/Teams/TeamInviteAction.ts +5 -5
- package/app/Actions/Dashboard/Teams/TeamMemberDestroyAction.ts +2 -2
- package/app/Actions/Dashboard/Teams/TeamMemberUpdateAction.ts +2 -2
- package/app/Actions/Dashboard/Teams/TeamPeopleIndexAction.ts +2 -2
- package/app/Actions/Dashboard/Teams/team-invitation-delivery.ts +2 -2
- package/app/Events.ts +9 -4
- package/app/Gates.ts +83 -85
- package/app/Listener.ts +34 -81
- package/app/Middleware.ts +22 -7
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/project/storage/framework/server/tsconfig.docker.json +1 -2
- package/resources/components/Buttons/Counter.stx +30 -21
- package/resources/components/Dashboard/Analytics/WebAnalyticsDashboard.stx +1 -3
- package/resources/components/Dashboard/Auth/ForgotPasswordDashboard.stx +1 -1
- package/resources/components/Dashboard/Auth/LoginDashboard.stx +2 -1
- package/resources/components/Dashboard/Auth/RegisterDashboard.stx +2 -1
- package/resources/components/Dashboard/Auth/ResetPasswordDashboard.stx +1 -1
- package/resources/components/Dashboard/Ci/CiDashboard.stx +9 -9
- package/resources/components/Dashboard/Ci/CiRunHistoryDrawer.stx +7 -7
- package/resources/components/Dashboard/Commerce/CommerceOverviewCharts.stx +2 -1
- package/resources/components/Dashboard/Commerce/CommercePaymentsDashboard.stx +1 -1
- package/resources/components/Dashboard/Content/BlogDashboard.stx +37 -15
- package/resources/components/Dashboard/Content/ContentDashboard.stx +3 -26
- package/resources/components/Dashboard/Email/EmailActivityDashboard.stx +2 -15
- package/resources/components/Dashboard/Environment/EnvironmentDashboard.stx +9 -1
- package/resources/components/Dashboard/Kanban/KanbanBoardDashboard.stx +15 -13
- package/resources/components/Dashboard/Kanban/KanbanBoardsDashboard.stx +10 -8
- package/resources/components/Dashboard/Kanban/KanbanCardDialog.stx +10 -10
- package/resources/components/Dashboard/Management/PermissionsDashboard.stx +3 -3
- package/resources/components/Dashboard/Modals/Popups/Alert.stx +4 -1
- package/resources/components/Dashboard/Navbar.stx +1 -1
- package/resources/components/Dashboard/Settings/AppearanceSettingsDashboard.stx +11 -6
- package/resources/components/Dashboard/Settings/SettingsDashboard.stx +2 -2
- package/resources/components/Dashboard/Transaction/index.stx +6 -6
- package/resources/components/Dashboard/UI/Avatar.stx +2 -2
- package/resources/components/Dashboard/UI/DropdownItem.stx +4 -4
- package/resources/components/Dashboard/UI/WindowControls.stx +17 -2
- package/resources/components/Docs/Demo/ComboboxDemo.stx +8 -3
- package/resources/components/Docs/Demo/DropdownDemo.stx +3 -3
- package/resources/components/Docs/Demo/StepperDemo.stx +1 -1
- package/resources/components/Forum/ForumLayout.stx +1 -1
- package/resources/components/Forum/ForumReplyForm.stx +1 -1
- package/resources/components/Marketing/ComingSoon.stx +5 -5
- package/resources/components/Storefront/CartDrawer.stx +44 -22
- package/resources/components/Storefront/ProductGallery.stx +3 -2
- package/resources/components/Storefront/QuantitySelector.stx +12 -7
- package/resources/functions/storefront/cart-cookie.ts +58 -0
- package/resources/layouts/storefront.stx +3 -2
- package/resources/views/cart.stx +19 -3
- package/resources/views/checkout/contact.stx +14 -3
- package/resources/views/checkout/payment.stx +14 -3
- package/resources/views/checkout/shipping.stx +14 -3
- package/resources/views/cms/blocks/form.stx +16 -11
- package/resources/views/cms/page.stx +28 -0
- package/resources/views/coming-soon.stx +0 -6
- package/resources/views/orders/[id].stx +19 -3
- package/views/dashboard/composables/index.ts +1 -1
- package/views/dashboard/composables/useChart.ts +26 -14
- package/views/dashboard/layouts/default.stx +42 -25
|
@@ -13,29 +13,41 @@
|
|
|
13
13
|
* lifecycle for pages that should defer the chart library.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import type { Chart, ChartConfig, ChartData, ChartDataset, ChartOptions, ChartType } from '@stacksjs/charts'
|
|
16
17
|
import { onDestroy, onMount } from '@stacksjs/stx'
|
|
17
18
|
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
export type { ChartConfig, ChartData, ChartDataset, ChartOptions, ChartType }
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The part of a chart instance this codebase touches, taken from the class
|
|
23
|
+
* rather than restated.
|
|
24
|
+
*
|
|
25
|
+
* `data` is included because every dashboard that refreshes a chart writes
|
|
26
|
+
* through it - replacing `labels` and each dataset's `data`, then calling
|
|
27
|
+
* `update()` - rather than destroying and rebuilding.
|
|
28
|
+
*
|
|
29
|
+
* This used to be a hand-written interface, deliberately not importing
|
|
30
|
+
* `@stacksjs/charts` "to keep this composable dep-free at the type level".
|
|
31
|
+
* The import is type-only and erases, so it costs nothing at runtime, and
|
|
32
|
+
* writing the shape out by hand cost plenty: it omitted `data`, so three
|
|
33
|
+
* dashboards each declared their own local `ChartLike` in three slightly
|
|
34
|
+
* different shapes to get at it, and every page then needed
|
|
35
|
+
* `Chart as unknown as ChartCtor` to get the real constructor past a
|
|
36
|
+
* signature that described it imprecisely.
|
|
37
|
+
*/
|
|
38
|
+
export type ChartLike = Pick<Chart, 'data' | 'update' | 'destroy'>
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// dep-free at the type level; pages pass the constructor in.
|
|
26
|
-
export type ChartCtor = new (
|
|
27
|
-
canvas: HTMLCanvasElement | HTMLElement,
|
|
28
|
-
config: { type: string, data: unknown, options?: unknown },
|
|
29
|
-
) => ChartLike
|
|
40
|
+
/** `new Chart(canvas, config)`, taken from the class itself. */
|
|
41
|
+
export type ChartCtor = new (..._args: ConstructorParameters<typeof Chart>) => ChartLike
|
|
30
42
|
|
|
31
43
|
export interface UseChartOptions {
|
|
32
44
|
/** Chart constructor (`new Chart(...)`). Pages import lazily and pass it in. */
|
|
33
45
|
Chart: ChartCtor
|
|
34
46
|
/** Element id, e.g. `'chart_1'`. */
|
|
35
47
|
id: string
|
|
36
|
-
type:
|
|
37
|
-
data:
|
|
38
|
-
options?:
|
|
48
|
+
type: ChartType
|
|
49
|
+
data: ChartData
|
|
50
|
+
options?: ChartOptions
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
export interface ChartHandle {
|
|
@@ -21,15 +21,25 @@ export const sidebarSections = buildWebSidebarSections()
|
|
|
21
21
|
// viewers who hold none of them. Emitted as an id-keyed map rather than a
|
|
22
22
|
// `data-required-roles` attribute on each row, which keeps the generic
|
|
23
23
|
// Sidebar component free of Stacks-specific attributes.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
// Published as an object, not as JSON text. The server-to-client bridge
|
|
25
|
+
// serializes what it publishes, so a value stringified here arrived on the
|
|
26
|
+
// client double-encoded - as the JSON string rather than the map. The client
|
|
27
|
+
// then ran `Object.entries` over that string, which yields index/character
|
|
28
|
+
// pairs, and called `.some()` on a single character. Every dashboard load
|
|
29
|
+
// threw inside applyRoleFilter before it could filter anything.
|
|
30
|
+
export const sidebarRoleMap: Record<string, string[]> = Object.fromEntries(
|
|
31
|
+
sidebarSections.flatMap(section =>
|
|
32
|
+
section.items.flatMap(item =>
|
|
33
|
+
item.roles && item.roles.length > 0
|
|
34
|
+
? [[item.id, item.roles] as const]
|
|
35
|
+
: [],
|
|
30
36
|
),
|
|
31
37
|
),
|
|
32
38
|
)
|
|
39
|
+
|
|
40
|
+
// Declared, so the client block below gets the map typed rather than inferred
|
|
41
|
+
// off the implicit bridge - which is what let the mismatch above go unseen.
|
|
42
|
+
defineClientPayload({ sidebarRoleMap })
|
|
33
43
|
</script>
|
|
34
44
|
|
|
35
45
|
@head
|
|
@@ -389,6 +399,8 @@ html[data-appearance="arc"] [data-sidebar-section] > div:first-child {
|
|
|
389
399
|
// fixed-position container below the <main> slot. Mounted in the
|
|
390
400
|
// layout so every dashboard page picks it up without opting in.
|
|
391
401
|
// `~/`-anchored for the same reason as the sidebar import above.
|
|
402
|
+
import type { ToastType } from '~/storage/framework/defaults/functions/toasts'
|
|
403
|
+
import type { CraftSidebarSelectEvent } from '~/storage/framework/defaults/functions/craft'
|
|
392
404
|
import { useToasts, dismissToast } from '~/storage/framework/defaults/functions/toasts'
|
|
393
405
|
import { ensureCraftNativeSidebarMarker, useCraftSidebarSelection } from '~/storage/framework/defaults/functions/craft'
|
|
394
406
|
import { readStoredAppearance, useAppearance } from '~/storage/framework/defaults/views/dashboard/composables/useAppearance'
|
|
@@ -401,14 +413,14 @@ registerStoresClient({ authStore, kanbanStore, rbacStore })
|
|
|
401
413
|
// Helpers below return COMPLETE class strings (static + dynamic) and are
|
|
402
414
|
// applied via `:class="fn(...)"` because stx's `{{ ... }}` placeholder is
|
|
403
415
|
// not reactively bound inside a `class` attribute - only inside text content.
|
|
404
|
-
const toastIconClass = (type) => `flex-shrink-0 h-5 w-5 mt-0.5 ${({
|
|
416
|
+
const toastIconClass = (type: ToastType) => `flex-shrink-0 h-5 w-5 mt-0.5 ${({
|
|
405
417
|
success: 'i-hugeicons-checkmark-circle-02 text-green-500 dark:text-green-400',
|
|
406
418
|
error: 'i-hugeicons-alert-02 text-red-500 dark:text-red-400',
|
|
407
419
|
warning: 'i-hugeicons-alert-circle text-yellow-500 dark:text-yellow-400',
|
|
408
420
|
info: 'i-hugeicons-information-circle text-blue-500 dark:text-blue-400',
|
|
409
421
|
}[type] || 'i-hugeicons-information-circle text-gray-500 dark:text-neutral-400')}`
|
|
410
422
|
|
|
411
|
-
const toastWrapperClass = (type) => `pointer-events-auto overflow-hidden bg-white dark:bg-neutral-800 ring-1 ${({
|
|
423
|
+
const toastWrapperClass = (type: ToastType) => `pointer-events-auto overflow-hidden bg-white dark:bg-neutral-800 ring-1 ${({
|
|
412
424
|
success: 'ring-green-500/20',
|
|
413
425
|
error: 'ring-red-500/30',
|
|
414
426
|
warning: 'ring-yellow-500/20',
|
|
@@ -434,10 +446,10 @@ let removeCraftSidebarSelection = () => {}
|
|
|
434
446
|
ensureCraftNativeSidebarMarker()
|
|
435
447
|
auth.load()
|
|
436
448
|
|
|
437
|
-
function sidebarPanes() {
|
|
449
|
+
function sidebarPanes(): HTMLElement[] {
|
|
438
450
|
return [sidebarHost.current, mobileSidebarHost.current]
|
|
439
|
-
.map(host => host?.querySelector('[data-stx-sidebar]'))
|
|
440
|
-
.filter(Boolean)
|
|
451
|
+
.map(host => host?.querySelector<HTMLElement>('[data-stx-sidebar]'))
|
|
452
|
+
.filter((pane): pane is HTMLElement => Boolean(pane))
|
|
441
453
|
}
|
|
442
454
|
|
|
443
455
|
function applyRoleFilter() {
|
|
@@ -445,7 +457,7 @@ function applyRoleFilter() {
|
|
|
445
457
|
const unauth = auth.unauthenticated()
|
|
446
458
|
for (const pane of sidebarPanes()) {
|
|
447
459
|
for (const [itemId, required] of Object.entries(sidebarRoles)) {
|
|
448
|
-
const row = pane.querySelector(`[data-sidebar-row][data-item-id="${itemId}"]`)
|
|
460
|
+
const row = pane.querySelector<HTMLElement>(`[data-sidebar-row][data-item-id="${itemId}"]`)
|
|
449
461
|
if (!row) continue
|
|
450
462
|
// Unauthenticated viewers see everything, which keeps the dev dashboard
|
|
451
463
|
// usable. Once authenticated, role membership is authoritative. CSS
|
|
@@ -495,7 +507,7 @@ function applySectionVisibility() {
|
|
|
495
507
|
// do nothing until a reload.
|
|
496
508
|
const hidden = appearance.hiddenSections()
|
|
497
509
|
for (const pane of sidebarPanes()) {
|
|
498
|
-
for (const section of pane.querySelectorAll('[data-sidebar-section]')) {
|
|
510
|
+
for (const section of pane.querySelectorAll<HTMLElement>('[data-sidebar-section]')) {
|
|
499
511
|
const id = section.dataset.sectionId || ''
|
|
500
512
|
section.setAttribute('data-viewer-hidden', String(hidden.includes(id)))
|
|
501
513
|
}
|
|
@@ -522,14 +534,14 @@ useEventListener('storage', (event) => {
|
|
|
522
534
|
appearance.apply()
|
|
523
535
|
})
|
|
524
536
|
|
|
525
|
-
function normalizeRoutePath(path) {
|
|
537
|
+
function normalizeRoutePath(path: string | null | undefined): string {
|
|
526
538
|
return (path || '/').replace(/\/+$/, '') || '/'
|
|
527
539
|
}
|
|
528
540
|
|
|
529
541
|
// Highlight the current route. Longest-prefix matching keeps a detail page
|
|
530
542
|
// such as /commerce/products/42 attached to its /commerce/products row while
|
|
531
543
|
// preventing /health from matching /health-check.
|
|
532
|
-
function syncActiveSidebarRow(url) {
|
|
544
|
+
function syncActiveSidebarRow(url?: string): void {
|
|
533
545
|
let path = route.path
|
|
534
546
|
if (url) {
|
|
535
547
|
try {
|
|
@@ -566,7 +578,7 @@ function syncActiveSidebarRow(url) {
|
|
|
566
578
|
}
|
|
567
579
|
}
|
|
568
580
|
|
|
569
|
-
function handleSidebarItemClick(payload) {
|
|
581
|
+
function handleSidebarItemClick(payload: { item?: { href?: string }, event?: { preventDefault: () => void } } | undefined): void {
|
|
570
582
|
const href = payload?.item?.href
|
|
571
583
|
if (!href || href.startsWith('http')) return
|
|
572
584
|
payload.event?.preventDefault()
|
|
@@ -578,10 +590,10 @@ function syncMobileSidebar() {
|
|
|
578
590
|
syncActiveSidebarRow()
|
|
579
591
|
}
|
|
580
592
|
|
|
581
|
-
function handleCraftSidebarSelection(event) {
|
|
593
|
+
function handleCraftSidebarSelection(event: CraftSidebarSelectEvent | undefined): void {
|
|
582
594
|
if (!event?.itemId) return
|
|
583
595
|
for (const pane of sidebarPanes()) {
|
|
584
|
-
const row = [...pane.querySelectorAll('[data-sidebar-row]')].find(
|
|
596
|
+
const row = [...pane.querySelectorAll<HTMLElement>('[data-sidebar-row]')].find(
|
|
585
597
|
candidate => candidate.dataset.itemId === event.itemId,
|
|
586
598
|
)
|
|
587
599
|
const link = row?.querySelector('a[data-sidebar-item][href]')
|
|
@@ -598,7 +610,7 @@ function attachCraftSidebarSelection() {
|
|
|
598
610
|
removeCraftSidebarSelection = useCraftSidebarSelection(handleCraftSidebarSelection)
|
|
599
611
|
}
|
|
600
612
|
|
|
601
|
-
useEventListener('stx:navigate', event => syncActiveSidebarRow(event
|
|
613
|
+
useEventListener('stx:navigate', (event: Event) => syncActiveSidebarRow((event as CustomEvent<{ url?: string }>).detail?.url))
|
|
602
614
|
useEventListener('stx:hydrated', () => syncActiveSidebarRow(), { once: true })
|
|
603
615
|
useEventListener('craft:ready', () => {
|
|
604
616
|
ensureCraftNativeSidebarMarker()
|
|
@@ -629,11 +641,14 @@ onDestroy(() => {
|
|
|
629
641
|
@itemClick="handleSidebarItemClick($event)"
|
|
630
642
|
>
|
|
631
643
|
<template #header>
|
|
632
|
-
<!-- Chrome strip. The traffic lights are
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
644
|
+
<!-- Chrome strip. The traffic lights are the platform's, so this draws
|
|
645
|
+
none and reserves whatever room the host says they need: 62px in a
|
|
646
|
+
titlebarHidden window where they float over this sidebar, nothing in
|
|
647
|
+
a window that keeps them in a titlebar, and nothing in a browser,
|
|
648
|
+
which has no window buttons at all. It is also the window drag
|
|
649
|
+
region, and in a browser it is the same empty strip macOS sidebars
|
|
650
|
+
carry above their first row. -->
|
|
651
|
+
<SidebarHeader windowControls="native" />
|
|
637
652
|
</template>
|
|
638
653
|
</Sidebar>
|
|
639
654
|
</div>
|
|
@@ -649,7 +664,9 @@ onDestroy(() => {
|
|
|
649
664
|
@itemClick="handleSidebarItemClick($event)"
|
|
650
665
|
>
|
|
651
666
|
<template #header>
|
|
652
|
-
|
|
667
|
+
<!-- A drawer, not the window edge: no window buttons land on it, so
|
|
668
|
+
there is nothing to draw and nothing to reserve. -->
|
|
669
|
+
<SidebarHeader windowControls="none" />
|
|
653
670
|
</template>
|
|
654
671
|
</Sidebar>
|
|
655
672
|
</div>
|