@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
@@ -101,109 +101,100 @@ function errorMessages(): string[] {
101
101
  }
102
102
  </script>
103
103
 
104
- <div
105
- :show="open"
106
- role="dialog"
107
- aria-modal="true"
108
- :aria-label="mode() === 'edit' ? 'Edit product waitlist entry' : 'Add product waitlist entry'"
109
- class="fixed inset-0 overflow-y-auto z-30 dashboard-modal-layer"
104
+ <Modal
105
+ :isOpen="open()"
106
+ :title="mode() === 'edit' ? 'Edit waitlist entry' : 'Add waitlist entry'"
107
+ description="Save this entry through the WaitlistProduct model API."
108
+ size="lg"
109
+ :closable="!busy()"
110
+ @close="emit('close')"
110
111
  >
111
- <div class="flex items-end justify-center sm:items-center p-4 sm:p-6 min-h-full text-center">
112
- <button type="button" aria-label="Close product waitlist dialog" class="fixed inset-0 bg-gray-950/50" :disabled="busy()" @click="emit('close')"></button>
113
- <form class="overflow-hidden relative p-5 sm:p-6 sm:max-w-2xl sm:w-full text-left bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl" @submit.prevent="submitForm()">
114
- <div class="flex gap-4 items-start justify-between">
115
- <div>
116
- <h2 class="font-semibold text-gray-900 text-lg dark:text-white">{{ mode() === 'edit' ? 'Edit waitlist entry' : 'Add waitlist entry' }}</h2>
117
- <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Save this entry through the WaitlistProduct model API.</p>
118
- </div>
119
- <Button variant="ghost" size="sm" iconOnly ariaLabel="Close dialog" :disabled="busy()" @click="emit('close')">
120
- <span class="block h-5 w-5 i-hugeicons-cancel-01"></span>
121
- </Button>
122
- </div>
123
-
124
- <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">
125
- <template :for="message in errorMessages()" :key="message"><li>{{ message }}</li></template>
126
- </ul>
127
-
128
- <div class="grid gap-4 sm:grid-cols-2 mt-6">
129
- <label class="block sm:col-span-2">
130
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Product</span>
131
- <select x-model="productId" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
132
- <option value="">Select a product</option>
133
- <option :for="option in options().products" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
134
- </select>
135
- </label>
136
-
137
- <label class="block sm:col-span-2">
138
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Existing customer</span>
139
- <select x-model="customerId" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" @change="hydrateCustomer($event)">
140
- <option value="">No linked customer</option>
141
- <option :for="option in options().customers" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
142
- </select>
143
- </label>
144
-
145
- <label class="block">
146
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Name</span>
147
- <input type="text" x-model.trim="name" required maxlength="255" autocomplete="name" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
148
- </label>
149
-
150
- <label class="block">
151
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Email</span>
152
- <input type="email" x-model.trim="email" required maxlength="255" autocomplete="email" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
153
- </label>
154
-
155
- <label class="block">
156
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Phone</span>
157
- <input type="tel" x-model.trim="phone" maxlength="100" autocomplete="tel" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
158
- </label>
159
-
160
- <label class="block">
161
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Quantity</span>
162
- <input type="number" x-model.number="quantity" required min="1" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
163
- </label>
164
-
165
- <label class="block">
166
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Notification preference</span>
167
- <select x-model="notificationPreference" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
168
- <option value="email">Email</option>
169
- <option value="sms">SMS</option>
170
- <option value="both">Email and SMS</option>
171
- </select>
172
- </label>
173
-
174
- <label class="block">
175
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Source</span>
176
- <select x-model="source" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
177
- <option value="website">Website</option>
178
- <option value="social_media">Social media</option>
179
- <option value="in-store">In store</option>
180
- <option value="email">Email</option>
181
- <option value="app">App</option>
182
- <option value="referral">Referral</option>
183
- <option value="other">Other</option>
184
- </select>
185
- </label>
186
-
187
- <label class="block">
188
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Status</span>
189
- <select x-model="status" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
190
- <option value="waiting">Waiting</option>
191
- <option value="notified">Notified</option>
192
- <option value="purchased">Purchased</option>
193
- <option value="cancelled">Cancelled</option>
194
- </select>
195
- </label>
196
-
197
- <label class="block sm:col-span-2">
198
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Notes</span>
199
- <textarea x-model.trim="notes" maxlength="500" rows="3" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600"></textarea>
200
- </label>
201
- </div>
202
-
203
- <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end mt-6">
204
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
205
- <Button type="submit" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add entry' }}</Button>
206
- </div>
207
- </form>
208
- </div>
209
- </div>
112
+ <form id="product-waitlist-entry-form" @submit.prevent="submitForm()">
113
+ <ul :if="errorMessages().length > 0" class="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">
114
+ <template :for="message in errorMessages()" :key="message"><li>{{ message }}</li></template>
115
+ </ul>
116
+
117
+ <div class="grid gap-4 sm:grid-cols-2 mt-6">
118
+ <label class="block sm:col-span-2">
119
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Product</span>
120
+ <select x-model="productId" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
121
+ <option value="">Select a product</option>
122
+ <option :for="option in options().products" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
123
+ </select>
124
+ </label>
125
+
126
+ <label class="block sm:col-span-2">
127
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Existing customer</span>
128
+ <select x-model="customerId" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" @change="hydrateCustomer($event)">
129
+ <option value="">No linked customer</option>
130
+ <option :for="option in options().customers" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
131
+ </select>
132
+ </label>
133
+
134
+ <label class="block">
135
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Name</span>
136
+ <input type="text" x-model.trim="name" required maxlength="255" autocomplete="name" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
137
+ </label>
138
+
139
+ <label class="block">
140
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Email</span>
141
+ <input type="email" x-model.trim="email" required maxlength="255" autocomplete="email" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
142
+ </label>
143
+
144
+ <label class="block">
145
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Phone</span>
146
+ <input type="tel" x-model.trim="phone" maxlength="100" autocomplete="tel" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
147
+ </label>
148
+
149
+ <label class="block">
150
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Quantity</span>
151
+ <input type="number" x-model.number="quantity" required min="1" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
152
+ </label>
153
+
154
+ <label class="block">
155
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Notification preference</span>
156
+ <select x-model="notificationPreference" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
157
+ <option value="email">Email</option>
158
+ <option value="sms">SMS</option>
159
+ <option value="both">Email and SMS</option>
160
+ </select>
161
+ </label>
162
+
163
+ <label class="block">
164
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Source</span>
165
+ <select x-model="source" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
166
+ <option value="website">Website</option>
167
+ <option value="social_media">Social media</option>
168
+ <option value="in-store">In store</option>
169
+ <option value="email">Email</option>
170
+ <option value="app">App</option>
171
+ <option value="referral">Referral</option>
172
+ <option value="other">Other</option>
173
+ </select>
174
+ </label>
175
+
176
+ <label class="block">
177
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Status</span>
178
+ <select x-model="status" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
179
+ <option value="waiting">Waiting</option>
180
+ <option value="notified">Notified</option>
181
+ <option value="purchased">Purchased</option>
182
+ <option value="cancelled">Cancelled</option>
183
+ </select>
184
+ </label>
185
+
186
+ <label class="block sm:col-span-2">
187
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Notes</span>
188
+ <textarea x-model.trim="notes" maxlength="500" rows="3" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600"></textarea>
189
+ </label>
190
+ </div>
191
+
192
+ </form>
193
+
194
+ <template #footer>
195
+ <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end w-full">
196
+ <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
197
+ <Button type="submit" form="product-waitlist-entry-form" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add entry' }}</Button>
198
+ </div>
199
+ </template>
200
+ </Modal>
@@ -5,23 +5,15 @@ const open = useReactiveProp('open', false)
5
5
  const record = useReactiveProp('record', null as RestaurantWaitlistRecord | null)
6
6
  const busy = useReactiveProp('busy', false)
7
7
  const emit = defineEmits()
8
+ const description = derived(() => `${record()?.name || 'This party'} will be permanently removed from the WaitlistRestaurant model.`)
8
9
  </script>
9
10
 
10
- <div :show="open" role="alertdialog" aria-modal="true" aria-label="Delete restaurant 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 party?</h2>
18
- <p class="mt-2 text-gray-500 text-sm dark:text-neutral-400">
19
- {{ record()?.name || 'This party' }} will be permanently removed from the WaitlistRestaurant 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 party</Button>
24
- </div>
25
- </div>
26
- </div>
27
- </div>
11
+ <ConfirmDialog
12
+ :isOpen="open()"
13
+ title="Delete waitlist party?"
14
+ :description="description()"
15
+ confirmLabel="Delete party"
16
+ :busy="busy()"
17
+ @close="emit('close')"
18
+ @confirm="emit('confirm')"
19
+ />
@@ -111,98 +111,95 @@ function errorMessages(): string[] {
111
111
  }
112
112
  </script>
113
113
 
114
- <div :show="open" role="dialog" aria-modal="true" :aria-label="mode() === 'edit' ? 'Edit restaurant waitlist entry' : 'Add restaurant waitlist entry'" class="fixed inset-0 overflow-y-auto z-30 dashboard-modal-layer">
115
- <div class="flex items-end justify-center sm:items-center p-4 sm:p-6 min-h-full text-center">
116
- <button type="button" aria-label="Close restaurant waitlist dialog" class="fixed inset-0 bg-gray-950/50" :disabled="busy()" @click="emit('close')"></button>
117
- <form class="overflow-hidden relative p-5 sm:p-6 sm:max-w-2xl sm:w-full text-left bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700 shadow-xl" @submit.prevent="submitForm()">
118
- <div class="flex gap-4 items-start justify-between">
119
- <div>
120
- <h2 class="font-semibold text-gray-900 text-lg dark:text-white">{{ mode() === 'edit' ? 'Edit waitlist party' : 'Add waitlist party' }}</h2>
121
- <p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Save this party through the WaitlistRestaurant model API.</p>
122
- </div>
123
- <Button variant="ghost" size="sm" iconOnly ariaLabel="Close dialog" :disabled="busy()" @click="emit('close')">
124
- <span class="block h-5 w-5 i-hugeicons-cancel-01"></span>
125
- </Button>
126
- </div>
127
-
128
- <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">
129
- <template :for="message in errorMessages()" :key="message"><li>{{ message }}</li></template>
130
- </ul>
131
-
132
- <div class="grid gap-4 sm:grid-cols-2 mt-6">
133
- <label class="block sm:col-span-2">
134
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Existing customer</span>
135
- <select x-model="customerId" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" @change="hydrateCustomer($event)">
136
- <option value="">No linked customer</option>
137
- <option :for="option in options().customers" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
138
- </select>
139
- </label>
140
-
141
- <label class="block">
142
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Name</span>
143
- <input type="text" x-model.trim="name" required maxlength="255" autocomplete="name" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
144
- </label>
145
-
146
- <label class="block">
147
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Email</span>
148
- <input type="email" x-model.trim="email" required maxlength="255" autocomplete="email" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
149
- </label>
150
-
151
- <label class="block">
152
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Phone</span>
153
- <input type="tel" x-model.trim="phone" maxlength="100" autocomplete="tel" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
154
- </label>
155
-
156
- <label class="block">
157
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Party size</span>
158
- <input type="number" x-model.number="partySize" required min="1" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
159
- </label>
160
-
161
- <label class="block">
162
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Check in time</span>
163
- <input type="datetime-local" x-model="checkInTime" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
164
- </label>
165
-
166
- <label class="block">
167
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Quoted wait in minutes</span>
168
- <input type="number" x-model.number="quotedWaitTime" required min="0" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
169
- </label>
170
-
171
- <label class="block">
172
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Table preference</span>
173
- <select x-model="tablePreference" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
174
- <option value="no_preference">No preference</option>
175
- <option value="indoor">Indoor</option>
176
- <option value="bar">Bar</option>
177
- <option value="booth">Booth</option>
178
- </select>
179
- </label>
180
-
181
- <label class="block">
182
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Status</span>
183
- <select x-model="status" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
184
- <option value="waiting">Waiting</option>
185
- <option value="seated">Seated</option>
186
- <option value="cancelled">Cancelled</option>
187
- <option value="no_show">No show</option>
188
- </select>
189
- </label>
190
-
191
- <label class="block">
192
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Actual wait in minutes</span>
193
- <input type="number" x-model.number="actualWaitTime" min="0" step="1" placeholder="Not recorded" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
194
- </label>
195
-
196
- <label class="block">
197
- <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Queue position</span>
198
- <input type="number" x-model.number="queuePosition" min="1" step="1" placeholder="Not assigned" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
199
- </label>
200
- </div>
201
-
202
- <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end mt-6">
203
- <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
204
- <Button type="submit" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add party' }}</Button>
205
- </div>
206
- </form>
207
- </div>
208
- </div>
114
+ <Modal
115
+ :isOpen="open()"
116
+ :title="mode() === 'edit' ? 'Edit waitlist party' : 'Add waitlist party'"
117
+ description="Save this party through the WaitlistRestaurant model API."
118
+ size="lg"
119
+ :closable="!busy()"
120
+ @close="emit('close')"
121
+ >
122
+ <form id="restaurant-waitlist-entry-form" @submit.prevent="submitForm()">
123
+ <ul :if="errorMessages().length > 0" class="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">
124
+ <template :for="message in errorMessages()" :key="message"><li>{{ message }}</li></template>
125
+ </ul>
126
+
127
+ <div class="grid gap-4 sm:grid-cols-2 mt-6">
128
+ <label class="block sm:col-span-2">
129
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Existing customer</span>
130
+ <select x-model="customerId" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" @change="hydrateCustomer($event)">
131
+ <option value="">No linked customer</option>
132
+ <option :for="option in options().customers" :value="option.id">{{ option.label }}{{ option.detail ? ' · ' + option.detail : '' }}</option>
133
+ </select>
134
+ </label>
135
+
136
+ <label class="block">
137
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Name</span>
138
+ <input type="text" x-model.trim="name" required maxlength="255" autocomplete="name" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
139
+ </label>
140
+
141
+ <label class="block">
142
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Email</span>
143
+ <input type="email" x-model.trim="email" required maxlength="255" autocomplete="email" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
144
+ </label>
145
+
146
+ <label class="block">
147
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Phone</span>
148
+ <input type="tel" x-model.trim="phone" maxlength="100" autocomplete="tel" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
149
+ </label>
150
+
151
+ <label class="block">
152
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Party size</span>
153
+ <input type="number" x-model.number="partySize" required min="1" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
154
+ </label>
155
+
156
+ <label class="block">
157
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Check in time</span>
158
+ <input type="datetime-local" x-model="checkInTime" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
159
+ </label>
160
+
161
+ <label class="block">
162
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Quoted wait in minutes</span>
163
+ <input type="number" x-model.number="quotedWaitTime" required min="0" step="1" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
164
+ </label>
165
+
166
+ <label class="block">
167
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Table preference</span>
168
+ <select x-model="tablePreference" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
169
+ <option value="no_preference">No preference</option>
170
+ <option value="indoor">Indoor</option>
171
+ <option value="bar">Bar</option>
172
+ <option value="booth">Booth</option>
173
+ </select>
174
+ </label>
175
+
176
+ <label class="block">
177
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Status</span>
178
+ <select x-model="status" required class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
179
+ <option value="waiting">Waiting</option>
180
+ <option value="seated">Seated</option>
181
+ <option value="cancelled">Cancelled</option>
182
+ <option value="no_show">No show</option>
183
+ </select>
184
+ </label>
185
+
186
+ <label class="block">
187
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Actual wait in minutes</span>
188
+ <input type="number" x-model.number="actualWaitTime" min="0" step="1" placeholder="Not recorded" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
189
+ </label>
190
+
191
+ <label class="block">
192
+ <span class="block font-medium text-gray-900 text-sm dark:text-neutral-200">Queue position</span>
193
+ <input type="number" x-model.number="queuePosition" min="1" step="1" placeholder="Not assigned" class="block mt-2 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600" />
194
+ </label>
195
+ </div>
196
+
197
+ </form>
198
+
199
+ <template #footer>
200
+ <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end w-full">
201
+ <Button variant="secondary" :disabled="busy()" @click="emit('close')">Cancel</Button>
202
+ <Button type="submit" form="restaurant-waitlist-entry-form" :loading="busy()">{{ mode() === 'edit' ? 'Save changes' : 'Add party' }}</Button>
203
+ </div>
204
+ </template>
205
+ </Modal>
@@ -0,0 +1,94 @@
1
+ <script client>
2
+ interface AuthorRecord {
3
+ id: string
4
+ name: string
5
+ email: string
6
+ bio: string
7
+ avatar: string
8
+ }
9
+
10
+ interface AuthorDraft {
11
+ name: string
12
+ email: string
13
+ bio: string
14
+ avatar: string
15
+ }
16
+
17
+ const open = useReactiveProp('open', false)
18
+ const author = useReactiveProp('author', null as AuthorRecord | null)
19
+ const busy = useReactiveProp('busy', false)
20
+ const error = useReactiveProp('error', '')
21
+ const name = state('')
22
+ const email = state('')
23
+ const bio = state('')
24
+ const avatar = state('')
25
+ const emit = defineEmits()
26
+ let wasOpen = false
27
+
28
+ effect(() => {
29
+ const isOpen = open()
30
+ if (isOpen && !wasOpen) {
31
+ const record = author()
32
+ name.set(record?.name || '')
33
+ email.set(record?.email || '')
34
+ bio.set(record?.bio || '')
35
+ avatar.set(record?.avatar || '')
36
+ }
37
+ wasOpen = isOpen
38
+ })
39
+
40
+ function close(): void {
41
+ if (!busy())
42
+ emit('close')
43
+ }
44
+
45
+ function submit(): void {
46
+ const draft: AuthorDraft = {
47
+ name: name().trim(),
48
+ email: email().trim(),
49
+ bio: bio().trim(),
50
+ avatar: avatar().trim(),
51
+ }
52
+ emit('submit', draft)
53
+ }
54
+ </script>
55
+
56
+ <Modal
57
+ :isOpen="open()"
58
+ :title="author() ? 'Edit author' : 'New author'"
59
+ description="Keep author identity and publishing attribution up to date."
60
+ :closable="!busy()"
61
+ @close="close"
62
+ >
63
+ <form id="author-editor-form" class="grid gap-4" @submit.prevent="submit">
64
+ <label>
65
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Name</span>
66
+ <input x-model="name" name="name" required minlength="5" maxlength="255" autocomplete="name" 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" />
67
+ </label>
68
+ <label>
69
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Email</span>
70
+ <input x-model="email" name="email" type="email" required autocomplete="email" 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" />
71
+ </label>
72
+ <label>
73
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Bio</span>
74
+ <textarea x-model="bio" name="bio" maxlength="500" rows="3" 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>
75
+ </label>
76
+ <label>
77
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Avatar URL</span>
78
+ <input x-model="avatar" name="avatar" type="url" inputmode="url" placeholder="https://example.com/avatar.jpg" 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" />
79
+ </label>
80
+ </form>
81
+
82
+ <div :if="error()" role="alert" 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">
83
+ {{ error() }}
84
+ </div>
85
+
86
+ <template #footer>
87
+ <div class="flex gap-2 justify-end w-full">
88
+ <Button :disabled="busy()" variant="secondary" @click="close">Cancel</Button>
89
+ <Button type="submit" form="author-editor-form" :disabled="name().trim().length < 5 || !email().trim()" :loading="busy()">
90
+ {{ author() ? 'Save changes' : 'Create author' }}
91
+ </Button>
92
+ </div>
93
+ </template>
94
+ </Modal>