@stacksjs/defaults 0.70.362 → 0.70.365

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/ai/skills/stacks-browse/SKILL.md +2 -1
  2. package/ai/skills/stacks-browse/scripts/browse.ts +20 -2
  3. package/ai/skills/stacks-dashboard/SKILL.md +4 -0
  4. package/app/Actions/Auth/LogoutAction.ts +11 -4
  5. package/app/Actions/Auth/LogoutAllAction.ts +8 -4
  6. package/app/Actions/Dashboard/Models/ModelShowAction.ts +4 -1
  7. package/app/Actions/Dashboard/Models/model-write.ts +5 -0
  8. package/ide/vscode/package.json +1 -1
  9. package/package.json +1 -1
  10. package/resources/components/Buttons/Counter.stx +1 -1
  11. package/resources/components/Buttons/ToggleDark.stx +1 -1
  12. package/resources/components/Dashboard/App/RequestDetailsDialog.stx +42 -0
  13. package/resources/components/Dashboard/App/RequestsOverview.stx +1 -21
  14. package/resources/components/Dashboard/Auth/AccessTokenCreateDialog.stx +155 -0
  15. package/resources/components/Dashboard/Auth/AccessTokens.stx +41 -129
  16. package/resources/components/Dashboard/Ci/CiDashboard.stx +1 -157
  17. package/resources/components/Dashboard/Ci/CiRunHistoryDrawer.stx +127 -0
  18. package/resources/components/Dashboard/Commerce/CommerceCategoryDeleteDialog.stx +10 -8
  19. package/resources/components/Dashboard/Commerce/CommerceCategoryDetailsDialog.stx +22 -17
  20. package/resources/components/Dashboard/Commerce/CommerceCategoryDialog.stx +14 -13
  21. package/resources/components/Dashboard/Commerce/CommerceCouponDeleteDialog.stx +10 -7
  22. package/resources/components/Dashboard/Commerce/CommerceCouponDetailsDialog.stx +25 -19
  23. package/resources/components/Dashboard/Commerce/CommerceCouponDialog.stx +14 -11
  24. package/resources/components/Dashboard/Commerce/CommerceCustomerDeleteDialog.stx +10 -8
  25. package/resources/components/Dashboard/Commerce/CommerceCustomerDetailsDialog.stx +24 -16
  26. package/resources/components/Dashboard/Commerce/CommerceCustomerDialog.stx +14 -13
  27. package/resources/components/Dashboard/Commerce/CommerceGiftCardDeleteDialog.stx +10 -8
  28. package/resources/components/Dashboard/Commerce/CommerceGiftCardDetailsDialog.stx +16 -14
  29. package/resources/components/Dashboard/Commerce/CommerceGiftCardDialog.stx +17 -16
  30. package/resources/components/Dashboard/Commerce/CommerceManufacturerDeleteDialog.stx +14 -16
  31. package/resources/components/Dashboard/Commerce/CommerceManufacturerDialog.stx +17 -16
  32. package/resources/components/Dashboard/Commerce/CommerceOrderDeleteDialog.stx +10 -8
  33. package/resources/components/Dashboard/Commerce/CommerceOrderDetailsDialog.stx +15 -10
  34. package/resources/components/Dashboard/Commerce/CommerceOrderDialog.stx +14 -13
  35. package/resources/components/Dashboard/Commerce/CommercePosCheckoutDialog.stx +30 -25
  36. package/resources/components/Dashboard/Commerce/CommercePosReceiptDialog.stx +27 -20
  37. package/resources/components/Dashboard/Commerce/CommerceProductDeleteDialog.stx +14 -14
  38. package/resources/components/Dashboard/Commerce/CommerceProductDialog.stx +14 -13
  39. package/resources/components/Dashboard/Commerce/CommerceReviewDeleteDialog.stx +10 -18
  40. package/resources/components/Dashboard/Commerce/CommerceReviewEditDialog.stx +17 -16
  41. package/resources/components/Dashboard/Commerce/CommerceTaxDeleteDialog.stx +14 -14
  42. package/resources/components/Dashboard/Commerce/CommerceTaxDialog.stx +17 -16
  43. package/resources/components/Dashboard/Commerce/CommerceTaxesTable.stx +1 -1
  44. package/resources/components/Dashboard/Commerce/CommerceUnitDeleteDialog.stx +14 -17
  45. package/resources/components/Dashboard/Commerce/CommerceUnitDialog.stx +17 -16
  46. package/resources/components/Dashboard/Commerce/CommerceVariantDeleteDialog.stx +10 -8
  47. package/resources/components/Dashboard/Commerce/CommerceVariantDialog.stx +17 -16
  48. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDeleteDialog.stx +11 -15
  49. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDialog.stx +17 -16
  50. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryDeleteDialog.stx +11 -15
  51. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryDialog.stx +17 -16
  52. package/resources/components/Dashboard/Commerce/Delivery/DriverDeleteDialog.stx +11 -15
  53. package/resources/components/Dashboard/Commerce/Delivery/DriverDialog.stx +17 -16
  54. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeyDeleteDialog.stx +11 -15
  55. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeyDialog.stx +17 -16
  56. package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodDeleteDialog.stx +11 -15
  57. package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodDialog.stx +17 -16
  58. package/resources/components/Dashboard/Commerce/Delivery/ShippingRateDeleteDialog.stx +11 -15
  59. package/resources/components/Dashboard/Commerce/Delivery/ShippingRateDialog.stx +17 -16
  60. package/resources/components/Dashboard/Commerce/Delivery/ShippingZoneDeleteDialog.stx +11 -15
  61. package/resources/components/Dashboard/Commerce/Delivery/ShippingZoneDialog.stx +17 -16
  62. package/resources/components/Dashboard/Commerce/PaymentDetailsDialog.stx +16 -15
  63. package/resources/components/Dashboard/Commerce/PaymentRefundDialog.stx +16 -15
  64. package/resources/components/Dashboard/Commerce/PrintDeviceDeleteDialog.stx +10 -11
  65. package/resources/components/Dashboard/Commerce/PrintDeviceDetailsDialog.stx +16 -14
  66. package/resources/components/Dashboard/Commerce/PrintDeviceDialog.stx +17 -16
  67. package/resources/components/Dashboard/Commerce/PrintLogDeleteDialog.stx +10 -7
  68. package/resources/components/Dashboard/Commerce/PrintLogDetailsDialog.stx +13 -10
  69. package/resources/components/Dashboard/Commerce/ProductWaitlistDeleteDialog.stx +10 -18
  70. package/resources/components/Dashboard/Commerce/ProductWaitlistEntryDialog.stx +96 -105
  71. package/resources/components/Dashboard/Commerce/RestaurantWaitlistDeleteDialog.stx +10 -18
  72. package/resources/components/Dashboard/Commerce/RestaurantWaitlistEntryDialog.stx +92 -95
  73. package/resources/components/Dashboard/Content/AuthorEditorDialog.stx +94 -0
  74. package/resources/components/Dashboard/Content/AuthorsDashboard.stx +39 -31
  75. package/resources/components/Dashboard/Content/BlogDashboard.stx +87 -176
  76. package/resources/components/Dashboard/Content/BlogPostEditorDialog.stx +195 -0
  77. package/resources/components/Dashboard/Content/CommentsDashboard.stx +14 -4
  78. package/resources/components/Dashboard/Content/ContentTaxonomyDashboard.stx +40 -55
  79. package/resources/components/Dashboard/Content/CreateFolderDialog.stx +45 -0
  80. package/resources/components/Dashboard/Content/FileDetailsDrawer.stx +31 -0
  81. package/resources/components/Dashboard/Content/FileManagerDashboard.stx +47 -107
  82. package/resources/components/Dashboard/Content/FileUploadDialog.stx +89 -0
  83. package/resources/components/Dashboard/Content/PageEditorDialog.stx +93 -0
  84. package/resources/components/Dashboard/Content/PagesDashboard.stx +36 -26
  85. package/resources/components/Dashboard/Content/PostEditorDialog.stx +176 -0
  86. package/resources/components/Dashboard/Content/PostsDashboard.stx +40 -64
  87. package/resources/components/Dashboard/Content/SeoDashboard.stx +18 -84
  88. package/resources/components/Dashboard/Content/SeoEditorDialog.stx +108 -0
  89. package/resources/components/Dashboard/Content/TaxonomyEditorDialog.stx +106 -0
  90. package/resources/components/Dashboard/CreateRecordModal.stx +72 -83
  91. package/resources/components/Dashboard/Email/InboxMessageList.stx +1 -1
  92. package/resources/components/Dashboard/GlobalSearch.stx +3 -9
  93. package/resources/components/Dashboard/Infrastructure/CloudDetailsDialog.stx +2 -16
  94. package/resources/components/Dashboard/Infrastructure/DnsRecordDialog.stx +4 -16
  95. package/resources/components/Dashboard/Infrastructure/LogDetailsDialog.stx +4 -19
  96. package/resources/components/Dashboard/Infrastructure/MailboxDetailsDialog.stx +6 -16
  97. package/resources/components/Dashboard/Infrastructure/ServerInspectorDialog.stx +105 -0
  98. package/resources/components/Dashboard/Infrastructure/ServersDashboard.stx +5 -59
  99. package/resources/components/Dashboard/Jobs/JobHistory.stx +1 -11
  100. package/resources/components/Dashboard/Library/ComponentsDashboard.stx +11 -60
  101. package/resources/components/Dashboard/Library/FunctionsDashboard.stx +11 -15
  102. package/resources/components/Dashboard/Library/SourceScaffoldDialog.stx +95 -0
  103. package/resources/components/Dashboard/Management/AssignmentDrawer.stx +93 -0
  104. package/resources/components/Dashboard/Management/PermissionsDashboard.stx +47 -129
  105. package/resources/components/Dashboard/Marketing/CampaignDeliveryDialog.stx +5 -8
  106. package/resources/components/Dashboard/Marketing/CampaignDialog.stx +17 -17
  107. package/resources/components/Dashboard/Marketing/MarketingListDialog.stx +17 -17
  108. package/resources/components/Dashboard/Marketing/MarketingListsTable.stx +1 -1
  109. package/resources/components/Dashboard/Marketing/SocialPostDialog.stx +17 -16
  110. package/resources/components/Dashboard/Models/EditRecordModal.stx +81 -0
  111. package/resources/components/Dashboard/Models/ModelRecordActions.stx +30 -0
  112. package/resources/components/Dashboard/Models/ModelRecordsDashboard.stx +42 -94
  113. package/resources/components/Dashboard/Navbar.stx +5 -5
  114. package/resources/components/Dashboard/Notifications/NotificationDeliveryDialog.stx +40 -60
  115. package/resources/components/Dashboard/UI/Button.stx +4 -0
  116. package/resources/components/Dashboard/UI/ConfirmDialog.stx +4 -0
  117. package/resources/components/Dashboard/UI/Drawer.stx +114 -0
  118. package/resources/components/Dashboard/UI/Modal.stx +19 -12
  119. package/resources/components/Docs/Demo/ComboboxDemo.stx +4 -5
  120. package/resources/components/Docs/Demo/DropdownDemo.stx +12 -5
  121. package/resources/components/Docs/Demo/ListboxDemo.stx +14 -6
  122. package/resources/components/Docs/Demo/PopoverDemo.stx +10 -5
  123. package/resources/components/Docs/Demo/RadioGroupDemo.stx +14 -6
  124. package/resources/components/Docs/Demo/StepperDemo.stx +4 -5
  125. package/resources/components/Docs/TeamMember.stx +16 -9
  126. package/resources/components/Forum/ForumReplyForm.stx +7 -7
  127. package/resources/components/Forum/ForumSidebar.stx +10 -6
  128. package/resources/components/Marketing/Faqs.stx +5 -5
  129. package/resources/components/Marketing/Feature.stx +11 -6
  130. package/resources/components/Marketing/Layout.stx +12 -8
  131. package/resources/components/Marketing/Pricing.stx +11 -5
  132. package/resources/components/Marketing/PrimaryFeatures.stx +4 -5
  133. package/resources/components/Marketing/PrimaryFeatures2.stx +6 -5
  134. package/resources/components/Marketing/SecondaryFeatures.stx +10 -5
  135. package/resources/components/Marketing/Testimonials.stx +8 -5
  136. package/resources/views/index.stx +4 -4
  137. package/views/system-tray/index.stx +1 -1
@@ -9,20 +9,16 @@ const record = useReactiveProp('record', null as ShippingZoneRecord | null)
9
9
  const busy = useReactiveProp('busy', false)
10
10
  const error = useReactiveProp('error', '')
11
11
  const emit = defineEmits()
12
+ const description = derived(() => `Delete ${record()?.name || 'the selected shipping zone'} permanently. Zones referenced by shipping rates may be protected by the database.`)
12
13
  </script>
13
14
 
14
- <div :if="open() && record()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
15
- <button type="button" aria-label="Close delete confirmation" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
16
- <section role="alertdialog" aria-modal="true" aria-labelledby="shipping-zone-delete-title" class="relative max-w-md w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
17
- <div class="p-6">
18
- <div class="flex items-center justify-center h-10 w-10 text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-950/40 rounded-full"><span class="h-5 w-5 i-hugeicons-delete-02"></span></div>
19
- <h2 id="shipping-zone-delete-title" class="mt-4 font-semibold text-gray-900 text-lg dark:text-white">Delete shipping zone?</h2>
20
- <p class="mt-2 text-gray-500 text-sm dark:text-neutral-400">Delete {{ record()?.name }} permanently. Zones referenced by shipping rates may be protected by the database.</p>
21
- <div :if="error()" class="mt-4 p-3 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ error() }}</div>
22
- </div>
23
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
24
- <Button :disabled="busy()" variant="secondary" @click="emit('close')">Cancel</Button>
25
- <Button :loading="busy()" variant="danger" @click="emit('confirm')">Delete zone</Button>
26
- </footer>
27
- </section>
28
- </div>
15
+ <ConfirmDialog
16
+ :isOpen="open() && Boolean(record())"
17
+ title="Delete shipping zone?"
18
+ :description="description()"
19
+ confirmLabel="Delete zone"
20
+ :busy="busy()"
21
+ :error="error()"
22
+ @close="emit('close')"
23
+ @confirm="emit('confirm')"
24
+ />
@@ -107,16 +107,17 @@ function submit(): void {
107
107
  }
108
108
  </script>
109
109
 
110
- <div :if="open()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
111
- <button type="button" aria-label="Close shipping zone dialog" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
112
- <section role="dialog" aria-modal="true" aria-labelledby="shipping-zone-dialog-title" class="overflow-y-auto relative max-h-[92dvh] max-w-xl w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
113
- <form @submit.prevent="submit()">
114
- <div class="p-6">
115
- <h2 id="shipping-zone-dialog-title" class="font-semibold text-gray-900 text-lg dark:text-white">{{ mode() === 'edit' ? 'Edit shipping zone' : 'Add shipping zone' }}</h2>
116
- <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Separate list values with commas or new lines. Values are stored as normalized JSON arrays.</p>
117
- <div :if="error()" class="mt-4 p-3 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ error() }}</div>
110
+ <Modal
111
+ :isOpen="open()"
112
+ :title="mode() === 'edit' ? 'Edit shipping zone' : 'Add shipping zone'"
113
+ description="Separate list values with commas or new lines. Values are stored as normalized JSON arrays."
114
+ size="lg"
115
+ @close="emit('close')"
116
+ >
117
+ <form id="shipping-zone-form" @submit.prevent="submit()">
118
+ <div :if="error()" class="mb-5 p-3 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ error() }}</div>
118
119
 
119
- <div class="mt-5 space-y-4">
120
+ <div class="space-y-4">
120
121
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Zone name</span><input x-model="name" type="text" required maxlength="100" autocomplete="off" placeholder="North America" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
121
122
  <label class="block">
122
123
  <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Shipping method</span>
@@ -130,11 +131,11 @@ function submit(): void {
130
131
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Postal codes</span><textarea x-model="postalCodes" rows="2" maxlength="1000" placeholder="90001, 90002" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"></textarea></label>
131
132
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Status</span><select x-model="status" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"><option value="active">Active</option><option value="inactive">Inactive</option><option value="draft">Draft</option></select></label>
132
133
  </div>
133
- </div>
134
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
135
- <Button :disabled="busy()" variant="secondary" @click="emit('close')">Cancel</Button>
136
- <Button type="submit" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add zone' }}</Button>
137
- </footer>
138
134
  </form>
139
- </section>
140
- </div>
135
+ <template #footer>
136
+ <div class="flex gap-2 justify-end w-full">
137
+ <Button :disabled="busy()" variant="secondary" @click="emit('close')">Cancel</Button>
138
+ <Button type="submit" form="shipping-zone-form" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add zone' }}</Button>
139
+ </div>
140
+ </template>
141
+ </Modal>
@@ -40,16 +40,17 @@ function refundable(): boolean {
40
40
  }
41
41
  </script>
42
42
 
43
- <div :if="open() && record()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
44
- <button type="button" aria-label="Close payment details" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
45
- <section role="dialog" aria-modal="true" aria-labelledby="payment-details-title" class="relative max-w-xl w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
46
- <div class="p-6">
47
- <div class="flex items-start justify-between">
48
- <div><p class="text-gray-400 text-xs dark:text-neutral-500">Payment #{{ record()?.id }}</p><h2 id="payment-details-title" class="mt-1 font-semibold text-gray-900 text-lg dark:text-white">{{ money(record()?.amount || 0, record()?.currency || 'USD') }}</h2></div>
49
- <span class="px-2 py-1 capitalize font-medium text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ label(record()?.status || '') }}</span>
50
- </div>
51
-
52
- <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2 mt-6">
43
+ <Modal
44
+ :isOpen="open() && Boolean(record())"
45
+ :title="money(record()?.amount || 0, record()?.currency || 'USD')"
46
+ :description="`Payment #${record()?.id || 'not recorded'}`"
47
+ size="lg"
48
+ @close="emit('close')"
49
+ >
50
+ <template #header-trailing>
51
+ <span class="px-2 py-1 capitalize font-medium text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ label(record()?.status || '') }}</span>
52
+ </template>
53
+ <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2">
53
54
  <template :for="item in detailRows()" :key="item.label">
54
55
  <div><dt class="text-gray-400 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div>
55
56
  </template>
@@ -59,10 +60,10 @@ function refundable(): boolean {
59
60
 
60
61
  <div :if="record()?.notes" class="mt-5 p-3 text-gray-600 text-sm dark:text-neutral-300 bg-gray-50 dark:bg-neutral-900/60 rounded-lg">{{ record()?.notes }}</div>
61
62
  <div :if="refundable()" class="mt-5 p-3 text-amber-800 text-xs dark:text-amber-200 bg-amber-50 dark:bg-amber-950/30 border border-amber-200 rounded-lg dark:border-amber-900">Only record a refund after the payment processor confirms it. This updates the local ledger and does not contact the processor.</div>
62
- </div>
63
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
63
+ <template #footer>
64
+ <div class="flex gap-2 justify-end w-full">
64
65
  <Button variant="secondary" @click="emit('close')">Close</Button>
65
66
  <Button :if="refundable()" @click="emit('request-refund')">Record refund</Button>
66
- </footer>
67
- </section>
68
- </div>
67
+ </div>
68
+ </template>
69
+ </Modal>
@@ -51,20 +51,21 @@ function submit(): void {
51
51
  }
52
52
  </script>
53
53
 
54
- <div :if="open() && record()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
55
- <button type="button" aria-label="Close refund dialog" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
56
- <section role="dialog" aria-modal="true" aria-labelledby="payment-refund-title" class="relative max-w-md w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
57
- <form @submit.prevent="submit">
58
- <div class="p-6">
59
- <h2 id="payment-refund-title" class="font-semibold text-gray-900 text-lg dark:text-white">Record confirmed refund</h2>
60
- <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Payment #{{ record()?.id }} has {{ money(remaining(), record()?.currency || 'USD') }} remaining.</p>
61
- <label class="block mt-5"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Refund amount</span><input x-model="amount" type="number" min="0.01" :max="remaining() / 100" step="0.01" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
54
+ <Modal
55
+ :isOpen="open() && Boolean(record())"
56
+ title="Record confirmed refund"
57
+ :description="`Payment #${record()?.id || 'not recorded'} has ${money(remaining(), record()?.currency || 'USD')} remaining.`"
58
+ size="sm"
59
+ @close="emit('close')"
60
+ >
61
+ <form id="payment-refund-form" @submit.prevent="submit">
62
+ <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Refund amount</span><input x-model="amount" type="number" min="0.01" :max="remaining() / 100" step="0.01" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
62
63
  <p class="mt-2 text-amber-700 text-xs dark:text-amber-300">This records an already confirmed processor refund. It does not initiate money movement.</p>
63
- </div>
64
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
65
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
66
- <Button type="submit" :loading="busy()" :disabled="!valid()">Record refund</Button>
67
- </footer>
68
64
  </form>
69
- </section>
70
- </div>
65
+ <template #footer>
66
+ <div class="flex gap-2 justify-end w-full">
67
+ <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
68
+ <Button type="submit" form="payment-refund-form" :loading="busy()" :disabled="!valid()">Record refund</Button>
69
+ </div>
70
+ </template>
71
+ </Modal>
@@ -5,16 +5,15 @@ const open = useReactiveProp('open', false)
5
5
  const record = useReactiveProp('record', null as PrintDeviceRecord | null)
6
6
  const busy = useReactiveProp('busy', false)
7
7
  const emit = defineEmits()
8
+ const description = derived(() => `Delete "${record()?.name || 'Unnamed printer'}" permanently? Existing receipt logs remain separate records.`)
8
9
  </script>
9
10
 
10
- <div :if="open()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
11
- <button type="button" aria-label="Close delete print device dialog" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
12
- <section role="dialog" aria-modal="true" aria-labelledby="print-device-delete-title" class="relative p-6 max-w-md w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
13
- <h2 id="print-device-delete-title" class="font-semibold text-gray-900 text-lg dark:text-white">Delete print device</h2>
14
- <p class="mt-2 text-gray-500 text-sm dark:text-neutral-400">Delete "{{ record()?.name || 'Unnamed printer' }}" permanently? Existing receipt logs remain separate records.</p>
15
- <footer class="flex gap-2 justify-end mt-6">
16
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
17
- <Button variant="danger" :loading="busy()" @click="emit('confirm')">Delete printer</Button>
18
- </footer>
19
- </section>
20
- </div>
11
+ <ConfirmDialog
12
+ :isOpen="open()"
13
+ title="Delete print device"
14
+ :description="description()"
15
+ confirmLabel="Delete printer"
16
+ :busy="busy()"
17
+ @close="emit('close')"
18
+ @confirm="emit('confirm')"
19
+ />
@@ -38,15 +38,17 @@ function deleteRecord(): void {
38
38
  }
39
39
  </script>
40
40
 
41
- <div :if="open()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
42
- <button type="button" aria-label="Close print device details" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
43
- <section role="dialog" aria-modal="true" aria-labelledby="print-device-details-title" class="relative max-w-lg w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
44
- <div class="p-6">
45
- <div class="flex gap-4 items-start justify-between">
46
- <div><h2 id="print-device-details-title" class="font-semibold text-gray-900 text-lg dark:text-white">{{ record()?.name || 'Print device' }}</h2><p class="mt-1 font-mono text-gray-500 text-xs dark:text-neutral-400">{{ record()?.macAddress || 'No MAC address recorded' }}</p></div>
47
- <span class="px-2 py-1 capitalize font-semibold text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ label(record()?.status || '') }}</span>
48
- </div>
49
- <dl class="grid gap-4 grid-cols-2 mt-6">
41
+ <Modal
42
+ :isOpen="open()"
43
+ :title="record()?.name || 'Print device'"
44
+ :description="record()?.macAddress || 'No MAC address recorded'"
45
+ size="md"
46
+ @close="emit('close')"
47
+ >
48
+ <template #header-trailing>
49
+ <span class="px-2 py-1 capitalize font-semibold text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ label(record()?.status || '') }}</span>
50
+ </template>
51
+ <dl class="grid gap-4 grid-cols-2">
50
52
  <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Location</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ record()?.location || 'Not recorded' }}</dd></div>
51
53
  <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Terminal</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ record()?.terminal || 'Not recorded' }}</dd></div>
52
54
  <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Recorded prints</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ (record()?.printCount || 0).toLocaleString() }}</dd></div>
@@ -54,10 +56,10 @@ function deleteRecord(): void {
54
56
  <div class="col-span-2"><dt class="text-gray-400 text-xs dark:text-neutral-500">Last heartbeat</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.lastPing || 0) }}</dd></div>
55
57
  <div class="col-span-2"><dt class="text-gray-400 text-xs dark:text-neutral-500">Created</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.createdAt || '') }}</dd></div>
56
58
  </dl>
57
- </div>
58
- <footer class="flex gap-2 justify-between px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
59
+ <template #footer>
60
+ <div class="flex gap-2 justify-between w-full">
59
61
  <Button variant="danger" @click="deleteRecord()">Delete</Button>
60
62
  <div class="flex gap-2"><Button variant="secondary" @click="emit('close')">Close</Button><Button @click="editRecord()">Edit printer</Button></div>
61
- </footer>
62
- </section>
63
- </div>
63
+ </div>
64
+ </template>
65
+ </Modal>
@@ -58,28 +58,29 @@ function errorMessages(): string[] {
58
58
  }
59
59
  </script>
60
60
 
61
- <div :if="open()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
62
- <button type="button" aria-label="Close print device dialog" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
63
- <section role="dialog" aria-modal="true" aria-labelledby="print-device-dialog-title" class="relative max-w-lg w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
64
- <form @submit.prevent="submit">
65
- <div class="p-6">
66
- <h2 id="print-device-dialog-title" class="font-semibold text-gray-900 text-lg dark:text-white">{{ mode() === 'edit' ? 'Edit print device' : 'Add print device' }}</h2>
67
- <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Store fields declared by the PrintDevice model.</p>
68
- <ul :if="errorMessages().length > 0" class="mt-5 p-3 space-y-1 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">
61
+ <Modal
62
+ :isOpen="open()"
63
+ :title="mode() === 'edit' ? 'Edit print device' : 'Add print device'"
64
+ description="Store fields declared by the PrintDevice model."
65
+ size="md"
66
+ @close="emit('close')"
67
+ >
68
+ <form id="print-device-form" @submit.prevent="submit">
69
+ <ul :if="errorMessages().length > 0" class="mb-5 p-3 space-y-1 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">
69
70
  <template :for="message in errorMessages()" :key="message"><li>{{ message }}</li></template>
70
71
  </ul>
71
- <div class="grid gap-4 grid-cols-1 sm:grid-cols-2 mt-5">
72
+ <div class="grid gap-4 grid-cols-1 sm:grid-cols-2">
72
73
  <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Name</span><input x-model="name" type="text" maxlength="100" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
73
74
  <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">MAC address</span><input x-model="macAddress" type="text" maxlength="50" required spellcheck="false" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
74
75
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Location</span><input x-model="location" type="text" maxlength="100" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
75
76
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Terminal</span><input x-model="terminal" type="text" maxlength="50" required spellcheck="false" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
76
77
  <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Operational status</span><select x-model="status" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"><option value="online">Online</option><option value="warning">Warning</option><option value="offline">Offline</option></select></label>
77
78
  </div>
78
- </div>
79
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
80
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
81
- <Button type="submit" :loading="busy()" :disabled="!valid()">{{ mode() === 'edit' ? 'Save printer' : 'Add printer' }}</Button>
82
- </footer>
83
79
  </form>
84
- </section>
85
- </div>
80
+ <template #footer>
81
+ <div class="flex gap-2 justify-end w-full">
82
+ <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
83
+ <Button type="submit" form="print-device-form" :loading="busy()" :disabled="!valid()">{{ mode() === 'edit' ? 'Save printer' : 'Add printer' }}</Button>
84
+ </div>
85
+ </template>
86
+ </Modal>
@@ -5,12 +5,15 @@ const open = useReactiveProp('open', false)
5
5
  const record = useReactiveProp('record', null as PrintLogRecord | null)
6
6
  const busy = useReactiveProp('busy', false)
7
7
  const emit = defineEmits()
8
+ const description = derived(() => `This permanently deletes ${record()?.document || `print log #${record()?.id}`} from the native Receipt history. It does not affect the printed document.`)
8
9
  </script>
9
10
 
10
- <div :if="open() && record()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
11
- <button type="button" aria-label="Close delete print log dialog" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
12
- <section role="alertdialog" aria-modal="true" aria-labelledby="delete-print-log-title" aria-describedby="delete-print-log-description" class="relative max-w-md w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
13
- <div class="p-6"><div class="flex items-center justify-center h-10 w-10 text-red-600 dark:text-red-300 bg-red-50 dark:bg-red-950/40 rounded-full"><span class="h-5 w-5 i-hugeicons-waste"></span></div><h2 id="delete-print-log-title" class="mt-4 font-semibold text-gray-900 text-lg dark:text-white">Delete print log?</h2><p id="delete-print-log-description" class="mt-2 text-gray-500 text-sm dark:text-neutral-400">This permanently deletes {{ record()?.document || 'print log #' + record()?.id }} from the native Receipt history. It does not affect the printed document.</p></div>
14
- <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700"><Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button><Button variant="danger" :loading="busy()" @click="emit('confirm')">Delete print log</Button></footer>
15
- </section>
16
- </div>
11
+ <ConfirmDialog
12
+ :isOpen="open() && Boolean(record())"
13
+ title="Delete print log?"
14
+ :description="description()"
15
+ confirmLabel="Delete print log"
16
+ :busy="busy()"
17
+ @close="emit('close')"
18
+ @confirm="emit('confirm')"
19
+ />
@@ -29,14 +29,17 @@ function details(): Array<{ label: string, value: string }> {
29
29
  }
30
30
  </script>
31
31
 
32
- <div :if="open() && record()" class="flex fixed inset-0 z-50 items-center justify-center p-4 dashboard-modal-layer">
33
- <button type="button" aria-label="Close print log details" class="absolute inset-0 bg-black/45" @click="emit('close')"></button>
34
- <section role="dialog" aria-modal="true" aria-labelledby="print-log-details-title" class="relative max-w-xl w-full bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
35
- <div class="p-6">
36
- <div class="flex items-start justify-between"><div><p class="text-gray-400 text-xs dark:text-neutral-500">Print log #{{ record()?.id }}</p><h2 id="print-log-details-title" class="mt-1 font-semibold text-gray-900 text-lg dark:text-white">{{ record()?.document || 'Untitled print job' }}</h2></div><span class="px-2 py-1 capitalize font-medium text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ record()?.status }}</span></div>
37
- <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2 mt-6"><template :for="item in details()" :key="item.label"><div><dt class="text-gray-400 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div></template></dl>
32
+ <Modal
33
+ :isOpen="open() && Boolean(record())"
34
+ :title="record()?.document || 'Untitled print job'"
35
+ :description="`Print log #${record()?.id || 'not recorded'}`"
36
+ size="lg"
37
+ @close="emit('close')"
38
+ >
39
+ <template #header-trailing>
40
+ <span class="px-2 py-1 capitalize font-medium text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ record()?.status }}</span>
41
+ </template>
42
+ <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2"><template :for="item in details()" :key="item.label"><div><dt class="text-gray-400 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div></template></dl>
38
43
  <div :if="record()?.metadata && record()?.metadata !== '{}'" class="mt-5"><p class="text-gray-400 text-xs dark:text-neutral-500">Metadata</p><pre class="overflow-x-auto mt-1 p-3 text-gray-700 text-xs whitespace-pre-wrap dark:text-neutral-200 bg-gray-50 dark:bg-neutral-900/60 rounded-lg">{{ record()?.metadata }}</pre></div>
39
- </div>
40
- <footer class="flex justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700"><Button variant="secondary" @click="emit('close')">Close</Button></footer>
41
- </section>
42
- </div>
44
+ <template #footer><Button variant="secondary" @click="emit('close')">Close</Button></template>
45
+ </Modal>
@@ -5,23 +5,15 @@ const open = useReactiveProp('open', false)
5
5
  const record = useReactiveProp('record', null as ProductWaitlistRecord | null)
6
6
  const busy = useReactiveProp('busy', false)
7
7
  const emit = defineEmits()
8
+ const description = derived(() => `${record()?.name || 'This entry'} will be permanently removed from the WaitlistProduct model.`)
8
9
  </script>
9
10
 
10
- <div :show="open" role="alertdialog" aria-modal="true" aria-label="Delete product waitlist entry" class="fixed inset-0 overflow-y-auto z-40 dashboard-modal-layer">
11
- <div class="flex items-end justify-center sm:items-center p-4 min-h-full text-center">
12
- <button type="button" aria-label="Close delete confirmation" class="fixed inset-0 bg-gray-950/50" :disabled="busy()" @click="emit('close')"></button>
13
- <div class="relative p-5 sm:p-6 sm:max-w-md sm:w-full text-left bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl">
14
- <div class="flex items-center justify-center h-10 w-10 text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-950/30 rounded-full">
15
- <span class="h-5 w-5 i-hugeicons-waste"></span>
16
- </div>
17
- <h2 class="mt-4 font-semibold text-gray-900 text-lg dark:text-white">Delete waitlist entry?</h2>
18
- <p class="mt-2 text-gray-500 text-sm dark:text-neutral-400">
19
- {{ record()?.name || 'This entry' }} will be permanently removed from the WaitlistProduct model.
20
- </p>
21
- <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end mt-6">
22
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
23
- <Button variant="danger" :loading="busy()" @click="emit('confirm')">Delete entry</Button>
24
- </div>
25
- </div>
26
- </div>
27
- </div>
11
+ <ConfirmDialog
12
+ :isOpen="open()"
13
+ title="Delete waitlist entry?"
14
+ :description="description()"
15
+ confirmLabel="Delete entry"
16
+ :busy="busy()"
17
+ @close="emit('close')"
18
+ @confirm="emit('confirm')"
19
+ />