@stacksjs/defaults 0.70.54

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 (286) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +2 -0
  3. package/package.json +20 -0
  4. package/resources/assets/fonts/013717e9.woff +0 -0
  5. package/resources/assets/fonts/03355817.woff2 +0 -0
  6. package/resources/assets/fonts/0380de7e.woff2 +0 -0
  7. package/resources/assets/fonts/0ba5d32a.woff +0 -0
  8. package/resources/assets/fonts/0bd57ddf.woff2 +0 -0
  9. package/resources/assets/fonts/19de0a60.woff2 +0 -0
  10. package/resources/assets/fonts/20b87e84.woff +0 -0
  11. package/resources/assets/fonts/4bbc67e1.woff +0 -0
  12. package/resources/assets/fonts/576fb0d7.woff +0 -0
  13. package/resources/assets/fonts/5ea10ee5.woff2 +0 -0
  14. package/resources/assets/fonts/6413fc0a.woff +0 -0
  15. package/resources/assets/fonts/72c114cf.woff +0 -0
  16. package/resources/assets/fonts/73c57e73.woff2 +0 -0
  17. package/resources/assets/fonts/813dca6c.woff +0 -0
  18. package/resources/assets/fonts/8a9b0995.woff2 +0 -0
  19. package/resources/assets/fonts/90b4832f.woff +0 -0
  20. package/resources/assets/fonts/9394ab85.woff2 +0 -0
  21. package/resources/assets/fonts/9b3c7d7f.woff2 +0 -0
  22. package/resources/assets/fonts/Monaco.ttf +0 -0
  23. package/resources/assets/fonts/b1b36d74.woff +0 -0
  24. package/resources/assets/fonts/b5d74798.woff2 +0 -0
  25. package/resources/assets/fonts/b9f81a4d.woff +0 -0
  26. package/resources/assets/fonts/c9784008.woff2 +0 -0
  27. package/resources/assets/fonts/cf692227.woff +0 -0
  28. package/resources/assets/fonts/d1c6ab51.woff2 +0 -0
  29. package/resources/assets/fonts/e2eb62fc.woff +0 -0
  30. package/resources/assets/fonts/fe21f8d8.woff2 +0 -0
  31. package/resources/assets/fonts/nps/CampmateScript-Regular.woff2 +0 -0
  32. package/resources/assets/fonts/nps/NPS_2026-variable.woff2 +0 -0
  33. package/resources/assets/fonts/nps/RedwoodSerif-Regular.woff2 +0 -0
  34. package/resources/assets/fonts/nps/SequoiaSans-Regular.woff2 +0 -0
  35. package/resources/assets/fonts/nps/Switchback-Regular.woff2 +0 -0
  36. package/resources/assets/images/app-icon.png +0 -0
  37. package/resources/assets/images/bg-img.png +0 -0
  38. package/resources/assets/images/park-ridge.svg +15 -0
  39. package/resources/assets/images/topography.svg +1 -0
  40. package/resources/assets/scripts/main.ts +2153 -0
  41. package/resources/assets/styles/README.md +19 -0
  42. package/resources/assets/styles/docs/main.css +1 -0
  43. package/resources/assets/styles/docs/overrides.css +1 -0
  44. package/resources/assets/styles/docs/vars.css +8 -0
  45. package/resources/assets/styles/main.css +1419 -0
  46. package/resources/components/Button.stx +70 -0
  47. package/resources/components/Buttons/BaseButton.stx +39 -0
  48. package/resources/components/Buttons/Counter.stx +28 -0
  49. package/resources/components/Buttons/ToggleDark.stx +11 -0
  50. package/resources/components/Container.stx +10 -0
  51. package/resources/components/Dashboard/.gitkeep +0 -0
  52. package/resources/components/Dashboard/Auth/ForgotPassword.stx +127 -0
  53. package/resources/components/Dashboard/Auth/Login.stx +212 -0
  54. package/resources/components/Dashboard/Auth/Register.stx +306 -0
  55. package/resources/components/Dashboard/Avatar.stx +123 -0
  56. package/resources/components/Dashboard/Billing/ActivePlan.stx +57 -0
  57. package/resources/components/Dashboard/Billing/CardBrands.stx +32 -0
  58. package/resources/components/Dashboard/Billing/CardForm.stx +34 -0
  59. package/resources/components/Dashboard/Billing/OneTimePayment.stx +28 -0
  60. package/resources/components/Dashboard/Billing/PaymentForm.stx +33 -0
  61. package/resources/components/Dashboard/Billing/PaymentMethod.stx +66 -0
  62. package/resources/components/Dashboard/Billing/PaymentMethodList.stx +52 -0
  63. package/resources/components/Dashboard/Billing/Plans.stx +136 -0
  64. package/resources/components/Dashboard/Buttons/AppButton.stx +48 -0
  65. package/resources/components/Dashboard/Buttons/IconButton.stx +20 -0
  66. package/resources/components/Dashboard/Card.stx +78 -0
  67. package/resources/components/Dashboard/Chart.stx +75 -0
  68. package/resources/components/Dashboard/CodeEditor.stx +41 -0
  69. package/resources/components/Dashboard/Commerce/BulkActionBar.stx +70 -0
  70. package/resources/components/Dashboard/Commerce/CategoriesTable.stx +133 -0
  71. package/resources/components/Dashboard/Commerce/CouponsTable.stx +161 -0
  72. package/resources/components/Dashboard/Commerce/CustomersTable.stx +142 -0
  73. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +80 -0
  74. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryTable.stx +85 -0
  75. package/resources/components/Dashboard/Commerce/Delivery/DriversTable.stx +99 -0
  76. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysTable.stx +92 -0
  77. package/resources/components/Dashboard/Commerce/Delivery/LicenseTemplatesTable.stx +88 -0
  78. package/resources/components/Dashboard/Commerce/Delivery/Pagination.stx +122 -0
  79. package/resources/components/Dashboard/Commerce/Delivery/SearchFilter.stx +23 -0
  80. package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsTable.stx +80 -0
  81. package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesTable.stx +59 -0
  82. package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesTable.stx +71 -0
  83. package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +36 -0
  84. package/resources/components/Dashboard/Commerce/Forms/CouponsForm.stx +191 -0
  85. package/resources/components/Dashboard/Commerce/OrdersTable.stx +131 -0
  86. package/resources/components/Dashboard/Commerce/ProductsTable.stx +170 -0
  87. package/resources/components/Dashboard/CreateRecordModal.stx +363 -0
  88. package/resources/components/Dashboard/DashboardLayout.stx +155 -0
  89. package/resources/components/Dashboard/Deployments/ActivityFeed.stx +54 -0
  90. package/resources/components/Dashboard/Deployments/DeployScript.stx +23 -0
  91. package/resources/components/Dashboard/Deployments/DeploymentHistory.stx +97 -0
  92. package/resources/components/Dashboard/Deployments/DeploymentList.stx +94 -0
  93. package/resources/components/Dashboard/Deployments/LiveTerminalOutput.stx +18 -0
  94. package/resources/components/Dashboard/Elements/Dropdown.stx +57 -0
  95. package/resources/components/Dashboard/Email/EmailActivityChart.stx +111 -0
  96. package/resources/components/Dashboard/Email/EmailCompose.stx +72 -0
  97. package/resources/components/Dashboard/Email/EmailDetail.stx +105 -0
  98. package/resources/components/Dashboard/Email/EmailList.stx +117 -0
  99. package/resources/components/Dashboard/Email/EmailSearch.stx +40 -0
  100. package/resources/components/Dashboard/Email/EmailSidebar.stx +133 -0
  101. package/resources/components/Dashboard/GlobalSearch.stx +124 -0
  102. package/resources/components/Dashboard/MobileSidebar.stx +47 -0
  103. package/resources/components/Dashboard/Modals/BaseModal.stx +50 -0
  104. package/resources/components/Dashboard/Modals/Popups/Alert.stx +112 -0
  105. package/resources/components/Dashboard/Modals/Popups/Toast.stx +70 -0
  106. package/resources/components/Dashboard/Modals/ToastWrapper.stx +35 -0
  107. package/resources/components/Dashboard/Monitoring/ErrorDetailModal.stx +228 -0
  108. package/resources/components/Dashboard/Monitoring/ErrorsTable.stx +184 -0
  109. package/resources/components/Dashboard/Navbar.stx +194 -0
  110. package/resources/components/Dashboard/NavbarModern.stx +188 -0
  111. package/resources/components/Dashboard/NotificationErrorModal.stx +105 -0
  112. package/resources/components/Dashboard/NotificationStatusBadge.stx +20 -0
  113. package/resources/components/Dashboard/Pagination.stx +90 -0
  114. package/resources/components/Dashboard/Queue/QueueTable.stx +127 -0
  115. package/resources/components/Dashboard/Settings/Forms/AIForm.stx +126 -0
  116. package/resources/components/Dashboard/Settings/Forms/AnalyticsForm.stx +52 -0
  117. package/resources/components/Dashboard/Settings/Forms/AppForm.stx +157 -0
  118. package/resources/components/Dashboard/Settings/Forms/CLIForm.stx +66 -0
  119. package/resources/components/Dashboard/Settings/Forms/CacheForm.stx +253 -0
  120. package/resources/components/Dashboard/Settings/Forms/CloudForm.stx +441 -0
  121. package/resources/components/Dashboard/Settings/Forms/DNSForm.stx +307 -0
  122. package/resources/components/Dashboard/Settings/Forms/DatabaseForm.stx +168 -0
  123. package/resources/components/Dashboard/Settings/Forms/EmailForm.stx +100 -0
  124. package/resources/components/Dashboard/Settings/Forms/FileSystemForm.stx +259 -0
  125. package/resources/components/Dashboard/Settings/Forms/HashingForm.stx +119 -0
  126. package/resources/components/Dashboard/Settings/Forms/LibraryForm.stx +389 -0
  127. package/resources/components/Dashboard/Settings/Forms/QueueForm.stx +219 -0
  128. package/resources/components/Dashboard/Settings/Forms/SearchEngineForm.stx +48 -0
  129. package/resources/components/Dashboard/Settings/Forms/SecurityForm.stx +143 -0
  130. package/resources/components/Dashboard/Settings/Forms/ServicesForm.stx +194 -0
  131. package/resources/components/Dashboard/Settings/Forms/StorageForm.stx +191 -0
  132. package/resources/components/Dashboard/Settings/Forms/TeamsForm.stx +33 -0
  133. package/resources/components/Dashboard/Settings/SettingsFormManager.stx +181 -0
  134. package/resources/components/Dashboard/SettingsHeader.stx +88 -0
  135. package/resources/components/Dashboard/SettingsSidebar.stx +234 -0
  136. package/resources/components/Dashboard/Sidebar.stx +23 -0
  137. package/resources/components/Dashboard/SidebarModern.stx +249 -0
  138. package/resources/components/Dashboard/Skeleton/LoadingCard.stx +15 -0
  139. package/resources/components/Dashboard/Skeleton/LoadingDetails.stx +26 -0
  140. package/resources/components/Dashboard/Table.stx +82 -0
  141. package/resources/components/Dashboard/TerminalContainer.stx +97 -0
  142. package/resources/components/Dashboard/Tooltip.stx +166 -0
  143. package/resources/components/Dashboard/Transaction/index.stx +88 -0
  144. package/resources/components/Dashboard/UI/ActivityTable.stx +54 -0
  145. package/resources/components/Dashboard/UI/Avatar.stx +102 -0
  146. package/resources/components/Dashboard/UI/Badge.stx +66 -0
  147. package/resources/components/Dashboard/UI/Button.stx +73 -0
  148. package/resources/components/Dashboard/UI/Card.stx +51 -0
  149. package/resources/components/Dashboard/UI/ChartCard.stx +36 -0
  150. package/resources/components/Dashboard/UI/Checkbox.stx +74 -0
  151. package/resources/components/Dashboard/UI/ConfirmDialog.stx +74 -0
  152. package/resources/components/Dashboard/UI/DataTable.stx +45 -0
  153. package/resources/components/Dashboard/UI/Dropdown.stx +72 -0
  154. package/resources/components/Dashboard/UI/DropdownItem.stx +80 -0
  155. package/resources/components/Dashboard/UI/EmptyState.stx +50 -0
  156. package/resources/components/Dashboard/UI/FilterBar.stx +48 -0
  157. package/resources/components/Dashboard/UI/Input.stx +77 -0
  158. package/resources/components/Dashboard/UI/Modal.stx +75 -0
  159. package/resources/components/Dashboard/UI/PageHeader.stx +69 -0
  160. package/resources/components/Dashboard/UI/PageLayout.stx +84 -0
  161. package/resources/components/Dashboard/UI/Pagination.stx +126 -0
  162. package/resources/components/Dashboard/UI/QuickLinks.stx +31 -0
  163. package/resources/components/Dashboard/UI/RouterLink.stx +31 -0
  164. package/resources/components/Dashboard/UI/Select.stx +84 -0
  165. package/resources/components/Dashboard/UI/ServiceHealth.stx +38 -0
  166. package/resources/components/Dashboard/UI/StatsCard.stx +79 -0
  167. package/resources/components/Dashboard/UI/Table.stx +143 -0
  168. package/resources/components/Dashboard/UI/Tabs.stx +45 -0
  169. package/resources/components/Dashboard/UI/Textarea.stx +93 -0
  170. package/resources/components/Dashboard/UI/Toggle.stx +84 -0
  171. package/resources/components/Dashboard/UI/WindowControls.stx +135 -0
  172. package/resources/components/Dashboard/Widget.stx +89 -0
  173. package/resources/components/Dashboard/WindowControls.stx +119 -0
  174. package/resources/components/Dashboard/index.ts +106 -0
  175. package/resources/components/Docs/Demo/ComboboxCode.md +114 -0
  176. package/resources/components/Docs/Demo/ComboboxDemo.stx +91 -0
  177. package/resources/components/Docs/Demo/DialogCode.md +42 -0
  178. package/resources/components/Docs/Demo/DialogDemo.stx +76 -0
  179. package/resources/components/Docs/Demo/DocsPlayground.stx +39 -0
  180. package/resources/components/Docs/Demo/DropdownCode.md +109 -0
  181. package/resources/components/Docs/Demo/DropdownDemo.stx +82 -0
  182. package/resources/components/Docs/Demo/Hero.stx +100 -0
  183. package/resources/components/Docs/Demo/ListboxCode.md +87 -0
  184. package/resources/components/Docs/Demo/ListboxDemo.stx +59 -0
  185. package/resources/components/Docs/Demo/NotificationCode.md +173 -0
  186. package/resources/components/Docs/Demo/NotificationDemo.stx +99 -0
  187. package/resources/components/Docs/Demo/PopoverCode.md +161 -0
  188. package/resources/components/Docs/Demo/PopoverDemo.stx +96 -0
  189. package/resources/components/Docs/Demo/RadioGroupCode.md +98 -0
  190. package/resources/components/Docs/Demo/RadioGroupDemo.stx +53 -0
  191. package/resources/components/Docs/Demo/StepperCode.md +216 -0
  192. package/resources/components/Docs/Demo/StepperDemo.stx +137 -0
  193. package/resources/components/Docs/Demo/SwitchCode.md +24 -0
  194. package/resources/components/Docs/Demo/SwitchDemo.stx +28 -0
  195. package/resources/components/Docs/Home.stx +7 -0
  196. package/resources/components/Docs/HomeContributors.stx +23 -0
  197. package/resources/components/Docs/HomeSponsors.stx +17 -0
  198. package/resources/components/Docs/HomeTeam.stx +18 -0
  199. package/resources/components/Docs/TeamMember.stx +79 -0
  200. package/resources/components/Email/EmailButton.stx +32 -0
  201. package/resources/components/Email/EmailDivider.stx +20 -0
  202. package/resources/components/Email/EmailImage.stx +24 -0
  203. package/resources/components/Email/EmailLayout.stx +55 -0
  204. package/resources/components/Email/EmailLink.stx +22 -0
  205. package/resources/components/Email/EmailSection.stx +20 -0
  206. package/resources/components/Email/EmailText.stx +30 -0
  207. package/resources/components/Forum/ForumBreadcrumb.stx +38 -0
  208. package/resources/components/Forum/ForumCategory.stx +16 -0
  209. package/resources/components/Forum/ForumCategoryItem.stx +46 -0
  210. package/resources/components/Forum/ForumLayout.stx +36 -0
  211. package/resources/components/Forum/ForumPagination.stx +39 -0
  212. package/resources/components/Forum/ForumPost.stx +71 -0
  213. package/resources/components/Forum/ForumReplyForm.stx +76 -0
  214. package/resources/components/Forum/ForumSidebar.stx +86 -0
  215. package/resources/components/Forum/ForumTopicItem.stx +77 -0
  216. package/resources/components/Forum/ForumTopicList.stx +23 -0
  217. package/resources/components/HelloWorld.stx +253 -0
  218. package/resources/components/Logo.stx +10 -0
  219. package/resources/components/Marketing/CallToAction.stx +30 -0
  220. package/resources/components/Marketing/ComingSoon.stx +155 -0
  221. package/resources/components/Marketing/Faqs.stx +99 -0
  222. package/resources/components/Marketing/Feature.stx +32 -0
  223. package/resources/components/Marketing/Fields.stx +28 -0
  224. package/resources/components/Marketing/Footer.stx +33 -0
  225. package/resources/components/Marketing/Header.stx +51 -0
  226. package/resources/components/Marketing/Hero.stx +46 -0
  227. package/resources/components/Marketing/Layout.stx +26 -0
  228. package/resources/components/Marketing/NavLink.stx +13 -0
  229. package/resources/components/Marketing/Plan.stx +43 -0
  230. package/resources/components/Marketing/Pricing.stx +120 -0
  231. package/resources/components/Marketing/PrimaryFeatures.stx +80 -0
  232. package/resources/components/Marketing/PrimaryFeatures2.stx +98 -0
  233. package/resources/components/Marketing/SecondaryFeatures.stx +80 -0
  234. package/resources/components/Marketing/Testimonials.stx +120 -0
  235. package/resources/components/Pagination.stx +149 -0
  236. package/resources/components/Playground.stx +9 -0
  237. package/resources/components/README.md +87 -0
  238. package/resources/components/Storefront/AnnouncementBar.stx +17 -0
  239. package/resources/components/Storefront/CartDrawer.stx +227 -0
  240. package/resources/components/Storefront/CheckoutSteps.stx +50 -0
  241. package/resources/components/Storefront/Footer.stx +81 -0
  242. package/resources/components/Storefront/Header.stx +66 -0
  243. package/resources/components/Storefront/OrderSummary.stx +79 -0
  244. package/resources/components/Storefront/ProductCard.stx +63 -0
  245. package/resources/components/Storefront/ProductGallery.stx +88 -0
  246. package/resources/components/Storefront/QuantitySelector.stx +97 -0
  247. package/resources/components/index.ts +13 -0
  248. package/resources/emails/email-verification.stx +46 -0
  249. package/resources/emails/layouts/base.html +113 -0
  250. package/resources/emails/password-changed.stx +55 -0
  251. package/resources/emails/password-reset.stx +43 -0
  252. package/resources/emails/subscription-confirmation.stx +99 -0
  253. package/resources/emails/welcome.stx +48 -0
  254. package/resources/functions/README.md +28 -0
  255. package/resources/functions/counter.ts +13 -0
  256. package/resources/functions/dark.ts +4 -0
  257. package/resources/functions/dashboard/analytics.ts +238 -0
  258. package/resources/functions/dashboard/config-io.ts +316 -0
  259. package/resources/functions/dashboard/data.ts +375 -0
  260. package/resources/functions/dashboard/library.ts +250 -0
  261. package/resources/functions/dashboard/sidebar.ts +537 -0
  262. package/resources/functions/dashboard/system.ts +150 -0
  263. package/resources/layouts/403.stx +188 -0
  264. package/resources/layouts/404.stx +34 -0
  265. package/resources/layouts/README.md +14 -0
  266. package/resources/layouts/dashboard/default.stx +20 -0
  267. package/resources/layouts/dashboard/guest.stx +10 -0
  268. package/resources/layouts/default.stx +3 -0
  269. package/resources/layouts/maintenance.stx +11 -0
  270. package/resources/layouts/storefront.stx +73 -0
  271. package/resources/layouts/system-tray/default.stx +3 -0
  272. package/resources/modules/.gitkeep +0 -0
  273. package/resources/plugins/.gitkeep +0 -0
  274. package/resources/plugins/preloader.ts +308 -0
  275. package/resources/types/README.md +3 -0
  276. package/resources/views/cart.stx +149 -0
  277. package/resources/views/checkout/contact.stx +101 -0
  278. package/resources/views/checkout/payment.stx +114 -0
  279. package/resources/views/checkout/shipping.stx +120 -0
  280. package/resources/views/coming-soon.stx +9 -0
  281. package/resources/views/dashboard/custom-page.stx +45 -0
  282. package/resources/views/dashboard/index.stx +24 -0
  283. package/resources/views/emails/welcome.stx +0 -0
  284. package/resources/views/errors/tester.stx +26 -0
  285. package/resources/views/index.stx +2865 -0
  286. package/resources/views/orders/[id].stx +130 -0
@@ -0,0 +1,363 @@
1
+ <script server>
2
+ /**
3
+ * Create Record Modal
4
+ * Native-styled dialog for creating new model records
5
+ *
6
+ * Props passed from parent via attributes:
7
+ * - modalId: Unique identifier for the modal
8
+ * - modelName: Display name of the model (e.g., "User")
9
+ * - tableName: Database table name (e.g., "users")
10
+ * - columns: Array of column definitions from PRAGMA table_info
11
+ *
12
+ * These are passed directly as template variables, no need to redeclare.
13
+ */
14
+
15
+ // Use the passed variables directly (they're already in scope from props)
16
+ // Just ensure defaults for safety
17
+ const _modalId = typeof modalId !== 'undefined' ? modalId : 'create-record-modal'
18
+ const _modelName = typeof modelName !== 'undefined' ? modelName : 'Record'
19
+ const _tableName = typeof tableName !== 'undefined' ? tableName : ''
20
+ const _columns = typeof columns !== 'undefined' ? columns : []
21
+
22
+ // Filter out auto-generated columns that shouldn't be in the form
23
+ const formColumns = _columns.filter(col => {
24
+ const name = col.name.toLowerCase()
25
+ // Skip auto-generated fields
26
+ if (name === 'id') return false
27
+ if (name === 'created_at' || name === 'updated_at') return false
28
+ if (name === 'deleted_at') return false
29
+ return true
30
+ }
31
+
32
+ // Determine input type based on column type and name
33
+ function getInputType(col) {
34
+ const name = col.name.toLowerCase()
35
+ const type = (col.type || '').toUpperCase()
36
+
37
+ // Name-based detection
38
+ if (name.includes('email')) return 'email'
39
+ if (name.includes('password')) return 'password'
40
+ if (name.includes('phone') || name.includes('tel')) return 'tel'
41
+ if (name.includes('url') || name.includes('website') || name.includes('link')) return 'url'
42
+ if (name.includes('date') && !name.includes('_at')) return 'date'
43
+ if (name.includes('time') && !name.includes('_at')) return 'time'
44
+ if (name.includes('color')) return 'color'
45
+
46
+ // Type-based detection
47
+ if (type.includes('INT') || type.includes('NUMERIC') || type.includes('REAL') || type.includes('FLOAT') || type.includes('DOUBLE')) {
48
+ return 'number'
49
+ }
50
+ if (type.includes('BOOL')) return 'checkbox'
51
+ if (type.includes('TEXT') && (name.includes('description') || name.includes('content') || name.includes('body') || name.includes('bio'))) {
52
+ return 'textarea'
53
+ }
54
+
55
+ return 'text'
56
+ }
57
+
58
+ // Check if field should be a select/dropdown
59
+ function isSelectField(col) {
60
+ const name = col.name.toLowerCase()
61
+ return name === 'status' || name === 'type' || name === 'role' || name.includes('_type') || name.includes('_status')
62
+ }
63
+ </script>
64
+ <!-- Native-styled Modal Dialog -->
65
+ <div ref="pageRoot">
66
+ <dialog
67
+ id="{{ modalId }}"
68
+ class="p-0 max-w-lg w-full bg-white backdrop:bg-black/50 dark:bg-neutral-900 border-0 rounded-xl shadow-2xl backdrop:backdrop-blur-sm modal-dialog"
69
+ >
70
+ <form method="dialog" class="modal-form">
71
+ <!-- Header - macOS style with vibrancy effect -->
72
+ <div class="flex items-center justify-between px-5 py-4 bg-neutral-50/80 dark:bg-neutral-800/80 border-b border-neutral-200 rounded-t-xl dark:border-neutral-700">
73
+ <div>
74
+ <h2 class="font-semibold text-base text-neutral-900 dark:text-white">
75
+ Create {{ modelName }}
76
+ </h2>
77
+ <p class="mt-0.5 text-neutral-500 text-xs dark:text-neutral-400">
78
+ Add a new record to {{ tableName }}
79
+ </p>
80
+ </div>
81
+ <button
82
+ type="button"
83
+ class="p-1.5 text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 hover:bg-neutral-200 dark:hover:bg-neutral-700 rounded-lg transition-colors modal-close-btn"
84
+ aria-label="Close"
85
+ >
86
+ <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
87
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
88
+ </svg>
89
+ </button>
90
+ </div>
91
+
92
+ <!-- Body - Form Fields -->
93
+ <div class="overflow-y-auto px-5 py-4 space-y-4 max-h-[60vh]">
94
+ @foreach(formColumns as col)
95
+ <div class="form-field">
96
+ <label
97
+ for="{{ modalId }}-{{ col.name }}"
98
+ class="block mb-1.5 font-medium text-neutral-700 text-sm dark:text-neutral-300"
99
+ >
100
+ {{ col.label }}
101
+ @if(col.notnull && col.dflt_value === null)
102
+ <span class="ml-0.5 text-red-500">*</span>
103
+ @endif
104
+ </label>
105
+
106
+ @if(isSelectField(col))
107
+ <!-- Select dropdown for status/type fields -->
108
+ <select
109
+ id="{{ modalId }}-{{ col.name }}"
110
+ name="{{ col.name }}"
111
+ class="px-3 py-2 w-full text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-800 border border-neutral-300 rounded-lg dark:border-neutral-600 focus:border-transparent focus:ring-2 focus:ring-blue-500 transition-shadow"
112
+ {{ col.notnull && col.dflt_value === null ? 'required' : '' }}
113
+ >
114
+ <option value="">Select {{ col.label }}</option>
115
+ @if(col.name === 'status')
116
+ <option value="active">Active</option>
117
+ <option value="inactive">Inactive</option>
118
+ <option value="pending">Pending</option>
119
+ <option value="draft">Draft</option>
120
+ @elseif(col.name === 'role')
121
+ <option value="user">User</option>
122
+ <option value="admin">Admin</option>
123
+ <option value="moderator">Moderator</option>
124
+ @else
125
+ <option value="default">Default</option>
126
+ @endif
127
+ </select>
128
+
129
+ @elseif(getInputType(col) === 'textarea')
130
+ <!-- Textarea for long text -->
131
+ <textarea
132
+ id="{{ modalId }}-{{ col.name }}"
133
+ name="{{ col.name }}"
134
+ rows="3"
135
+ class="px-3 py-2 w-full text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-800 border border-neutral-300 rounded-lg dark:border-neutral-600 focus:border-transparent focus:ring-2 focus:ring-blue-500 transition-shadow resize-none"
136
+ placeholder="Enter {{ col.label.toLowerCase() }}"
137
+ {{ col.notnull && col.dflt_value === null ? 'required' : '' }}
138
+ ></textarea>
139
+
140
+ @elseif(getInputType(col) === 'checkbox')
141
+ <!-- Checkbox toggle -->
142
+ <label class="flex gap-3 items-center cursor-pointer">
143
+ <input
144
+ type="checkbox"
145
+ id="{{ modalId }}-{{ col.name }}"
146
+ name="{{ col.name }}"
147
+ value="1"
148
+ class="h-4 w-4 text-blue-600 border-neutral-300 rounded dark:border-neutral-600 focus:ring-2 focus:ring-blue-500 focus:ring-offset-0"
149
+ />
150
+ <span class="text-neutral-600 text-sm dark:text-neutral-400">Enable {{ col.label.toLowerCase() }}</span>
151
+ </label>
152
+
153
+ @else
154
+ <!-- Standard input -->
155
+ <input
156
+ type="{{ getInputType(col) }}"
157
+ id="{{ modalId }}-{{ col.name }}"
158
+ name="{{ col.name }}"
159
+ class="px-3 py-2 w-full text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-800 border border-neutral-300 rounded-lg dark:border-neutral-600 focus:border-transparent focus:ring-2 focus:ring-blue-500 transition-shadow"
160
+ placeholder="Enter {{ col.label.toLowerCase() }}"
161
+ {{ col.notnull && col.dflt_value === null ? 'required' : '' }}
162
+ {{ getInputType(col) === 'number' ? 'step="any"' : '' }}
163
+ />
164
+ @endif
165
+
166
+ @if(col.dflt_value !== null)
167
+ <p class="mt-1 text-neutral-400 text-xs dark:text-neutral-500">
168
+ Default: {{ col.dflt_value }}
169
+ </p>
170
+ @endif
171
+ </div>
172
+ @endforeach
173
+
174
+ @if(formColumns.length === 0)
175
+ <div class="py-8 text-center text-neutral-500 dark:text-neutral-400">
176
+ <p>No editable fields available for this model.</p>
177
+ </div>
178
+ @endif
179
+ </div>
180
+
181
+ <!-- Footer - Action buttons -->
182
+ <div class="flex gap-3 items-center justify-end px-5 py-4 bg-neutral-50/50 dark:bg-neutral-800/50 border-neutral-200 border-t rounded-b-xl dark:border-neutral-700">
183
+ <button
184
+ type="button"
185
+ class="px-4 py-2 font-medium text-neutral-700 text-sm dark:text-neutral-300 bg-white dark:bg-neutral-700 hover:bg-neutral-50 dark:hover:bg-neutral-600 border border-neutral-300 rounded-lg dark:border-neutral-600 transition-colors modal-close-btn"
186
+ >
187
+ Cancel
188
+ </button>
189
+ <button
190
+ type="submit"
191
+ class="px-4 py-2 font-medium text-sm text-white bg-blue-600 hover:bg-blue-700 rounded-lg focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-neutral-900 disabled:opacity-50 transition-colors disabled:cursor-not-allowed modal-submit-btn"
192
+ {{ formColumns.length === 0 ? 'disabled' : '' }}
193
+ >
194
+ Create {{ modelName }}
195
+ </button>
196
+ </div>
197
+ </form>
198
+ </dialog>
199
+ </div>
200
+ <script client>
201
+ var _root = useRef('pageRoot')
202
+ onMount(function() {
203
+ var el = _root.current;
204
+ if (!el) return;
205
+ // Initialize all create record modals
206
+ el.querySelectorAll('.modal-dialog').forEach(dialog => {
207
+ const form = dialog.querySelector('.modal-form');
208
+ const closeButtons = dialog.querySelectorAll('.modal-close-btn');
209
+ const submitBtn = dialog.querySelector('.modal-submit-btn');
210
+
211
+ // Close on close button click
212
+ closeButtons.forEach(btn => {
213
+ btn.addEventListener('click', () => {
214
+ dialog.close();
215
+ });
216
+ });
217
+
218
+ // Close on backdrop click
219
+ dialog.addEventListener('click', (e) => {
220
+ if (e.target === dialog) {
221
+ dialog.close();
222
+ }
223
+ });
224
+
225
+ // Close on Escape key
226
+ dialog.addEventListener('keydown', (e) => {
227
+ if (e.key === 'Escape') {
228
+ dialog.close();
229
+ }
230
+ });
231
+
232
+ // Handle form submission
233
+ form.addEventListener('submit', async (e) => {
234
+ e.preventDefault();
235
+
236
+ const formData = new FormData(form);
237
+ const data = Object.fromEntries(formData.entries());
238
+
239
+ // Get table name from the modal's data attribute or hidden field
240
+ const tableName = dialog.dataset.table || '';
241
+ const modelName = dialog.dataset.model || 'Record';
242
+
243
+ // Show loading state
244
+ submitBtn.disabled = true;
245
+ submitBtn.innerHTML = `
246
+ <svg class="inline -ml-1 mr-2 h-4 w-4 text-white animate-spin" fill="none" viewBox="0 0 24 24">
247
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
248
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
249
+ </svg>
250
+ Creating...
251
+ `;
252
+
253
+ try {
254
+ // Post to API endpoint
255
+ const response = await fetch(`/api/data/${tableName}`, {
256
+ method: 'POST',
257
+ headers: {
258
+ 'Content-Type': 'application/json',
259
+ },
260
+ body: JSON.stringify(data),
261
+ });
262
+
263
+ if (response.ok) {
264
+ // Show success via Craft native alert if available
265
+ if (window.webkit?.messageHandlers?.craft) {
266
+ window.webkit.messageHandlers.craft.postMessage({
267
+ type: 'dialog',
268
+ action: 'showAlert',
269
+ data: {
270
+ title: `${modelName} Created`,
271
+ message: 'The record was created successfully.',
272
+ style: 'info'
273
+ }
274
+ });
275
+ }
276
+
277
+ dialog.close();
278
+ form.reset();
279
+
280
+ // Reload the page to show the new record
281
+ location.reload();
282
+ } else {
283
+ const errorData = await response.json().catch(() => ({}));
284
+ throw new Error(errorData.message || 'Failed to create record');
285
+ }
286
+ } catch (error) {
287
+ // Show error via Craft native alert if available
288
+ if (window.webkit?.messageHandlers?.craft) {
289
+ window.webkit.messageHandlers.craft.postMessage({
290
+ type: 'dialog',
291
+ action: 'showAlert',
292
+ data: {
293
+ title: 'Error',
294
+ message: error.message || 'Failed to create the record.',
295
+ style: 'critical'
296
+ }
297
+ });
298
+ } else {
299
+ alert('Error: ' + (error.message || 'Failed to create the record.'));
300
+ }
301
+ } finally {
302
+ // Reset button state
303
+ submitBtn.disabled = false;
304
+ submitBtn.innerHTML = `Create ${modelName}`;
305
+ }
306
+ });
307
+ });
308
+ });
309
+ </script>
310
+
311
+ <style>
312
+ /* Native macOS-style dialog animations */
313
+ .modal-dialog {
314
+ animation: modal-appear 0.2s ease-out;
315
+ }
316
+
317
+ .modal-dialog::backdrop {
318
+ animation: backdrop-fade 0.2s ease-out;
319
+ }
320
+
321
+ @keyframes modal-appear {
322
+ from {
323
+ opacity: 0;
324
+ transform: scale(0.95) translateY(-10px);
325
+ }
326
+ to {
327
+ opacity: 1;
328
+ transform: scale(1) translateY(0);
329
+ }
330
+ }
331
+
332
+ @keyframes backdrop-fade {
333
+ from {
334
+ opacity: 0;
335
+ }
336
+ to {
337
+ opacity: 1;
338
+ }
339
+ }
340
+
341
+ /* Focus styles for accessibility */
342
+ .modal-dialog:focus {
343
+ outline: none;
344
+ }
345
+
346
+ /* Scrollbar styling for the form area */
347
+ .modal-dialog .max-h-\[60vh\]::-webkit-scrollbar {
348
+ width: 6px;
349
+ }
350
+
351
+ .modal-dialog .max-h-\[60vh\]::-webkit-scrollbar-track {
352
+ background: transparent;
353
+ }
354
+
355
+ .modal-dialog .max-h-\[60vh\]::-webkit-scrollbar-thumb {
356
+ background-color: rgba(0, 0, 0, 0.2);
357
+ border-radius: 3px;
358
+ }
359
+
360
+ .dark .modal-dialog .max-h-\[60vh\]::-webkit-scrollbar-thumb {
361
+ background-color: rgba(255, 255, 255, 0.2);
362
+ }
363
+ </style>
@@ -0,0 +1,155 @@
1
+ <script>
2
+ interface DashboardLayoutProps {
3
+ isMobileMenuOpen?: boolean
4
+ isMobile?: boolean
5
+ currentPath?: string
6
+ isDark?: boolean
7
+ fullWidth?: boolean
8
+ pageTitle?: string
9
+ pageDescription?: string
10
+ noPadding?: boolean
11
+ showSidebar?: boolean
12
+ showNavbar?: boolean
13
+ showWindowControls?: boolean
14
+ isSidebarCollapsed?: boolean
15
+ }
16
+
17
+ const { isMobileMenuOpen, isMobile, currentPath = '/', isDark = false, fullWidth, pageTitle, pageDescription, noPadding, showSidebar = true, showNavbar = true, showWindowControls = false, isSidebarCollapsed = false } = defineProps<DashboardLayoutProps>()
18
+
19
+ /**
20
+ * Dashboard Layout Component
21
+ * A unified layout wrapper that combines the modern sidebar and navbar
22
+ * for consistent dashboard page structure.
23
+ *
24
+ * When running inside Craft with --native-sidebar, the native macOS
25
+ * sidebar is rendered by Craft - we skip the web sidebar in that case.
26
+ */
27
+
28
+ // Sidebar width calculation (matches Sidebar width)
29
+ function getSidebarWidth() {
30
+ if (isMobile) return 0
31
+ return isSidebarCollapsed ? 64 : 240
32
+ }
33
+
34
+ function getMainContentStyle() {
35
+ if (!showSidebar || isMobile) return ''
36
+ return `padding-left: ${getSidebarWidth()}px`
37
+ }
38
+
39
+ // Determine if we should show the web sidebar
40
+ function shouldShowWebSidebar() {
41
+ return showSidebar
42
+ }
43
+ </script>
44
+ <script>
45
+ (function() {
46
+ if (typeof window === 'undefined') return;
47
+
48
+ // Detect native sidebar via multiple signals:
49
+ // 1. Craft bridge flag (WKUserScript injection)
50
+ // 2. Craft window API
51
+ // 3. URL parameter (reliable fallback when WKUserScript timing is off)
52
+ var hasNativeSidebarFlag = Boolean(window.__craftNativeSidebar);
53
+ var hasCraftWindowApi = Boolean(window.craft && window.craft.window);
54
+ var hasUrlParam = window.location.search.indexOf('native-sidebar=1') !== -1;
55
+ var hasNativeSidebar = hasNativeSidebarFlag || hasCraftWindowApi || hasUrlParam;
56
+
57
+ if (hasNativeSidebar) {
58
+ window.__craftNativeSidebar = true;
59
+ document.documentElement.setAttribute('data-craft-native-sidebar', 'true');
60
+ }
61
+ })();
62
+ </script>
63
+ <!-- macOS-inspired layout with subtle background -->
64
+ <div class="min-h-screen bg-white dark:bg-neutral-950">
65
+ <!-- Mobile sidebar overlay -->
66
+ @if(isMobileMenuOpen && isMobile)
67
+ <div
68
+ class="lg:hidden fixed inset-0 z-40 bg-black/50 backdrop-blur-sm duration-300 transition-opacity"
69
+ data-action="close-mobile-menu"
70
+ ></div>
71
+ @endif
72
+
73
+ <!-- Mobile sidebar (web-based, only when no native sidebar) -->
74
+ @if(isMobileMenuOpen && isMobile && shouldShowWebSidebar())
75
+ <div class="lg:hidden fixed inset-y-0 left-0 z-50 w-64 duration-300 transition-transform dashboard-web-sidebar">
76
+ <Sidebar />
77
+ </div>
78
+ @endif
79
+
80
+ <!-- Desktop sidebar (web-based, only when no native sidebar) -->
81
+ @if(shouldShowWebSidebar() && !isMobile)
82
+ <div class="dashboard-web-sidebar">
83
+ <Sidebar />
84
+ </div>
85
+ @endif
86
+
87
+ <!-- Main content area -->
88
+ <div
89
+ class="flex flex-col min-h-screen duration-300 transition-all dashboard-main-content"
90
+ style="{{ getMainContentStyle() }}"
91
+ >
92
+ <!-- Navbar -->
93
+ @if(showNavbar)
94
+ <NavbarModern
95
+ showWindowControls="{{ showWindowControls }}"
96
+ currentPath="{{ currentPath || '/' }}"
97
+ isDark="{{ isDark || false }}"
98
+ />
99
+ @endif
100
+
101
+ <!-- Page header slot -->
102
+ @if($slots.header)
103
+ <div class="bg-white dark:bg-neutral-900 border-b border-neutral-200 dark:border-neutral-800">
104
+ <div class="px-4 lg:px-6 py-4 {{ fullWidth ? '' : 'max-w-7xl mx-auto' }}">
105
+ <slot name="header">
106
+ <!-- Default page header -->
107
+ @if(pageTitle)
108
+ <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
109
+ <div>
110
+ <h1 class="font-semibold text-2xl text-neutral-900 dark:text-white">
111
+ {{ pageTitle }}
112
+ </h1>
113
+ @if(pageDescription)
114
+ <p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">
115
+ {{ pageDescription }}
116
+ </p>
117
+ @endif
118
+ </div>
119
+ <slot name="header-actions" />
120
+ </div>
121
+ @endif
122
+ </slot>
123
+ </div>
124
+ </div>
125
+ @endif
126
+
127
+ <!-- Main content -->
128
+ <main class="{{ noPadding ? '' : 'px-4 lg:px-6 py-6' }} flex-1">
129
+ <div class="{{ fullWidth ? '' : 'max-w-7xl mx-auto' }}">
130
+ <slot />
131
+ </div>
132
+ </main>
133
+
134
+ <!-- Footer slot -->
135
+ @if($slots.footer)
136
+ <footer class="bg-white dark:bg-neutral-900 border-neutral-200 border-t dark:border-neutral-800">
137
+ <div class="px-4 lg:px-6 py-4 {{ fullWidth ? '' : 'max-w-7xl mx-auto' }}">
138
+ <slot name="footer" />
139
+ </div>
140
+ </footer>
141
+ @endif
142
+ </div>
143
+
144
+ <!-- Global overlays/modals slot -->
145
+ <slot name="overlays" />
146
+ </div>
147
+ <style>
148
+ html[data-craft-native-sidebar='true'] .dashboard-web-sidebar {
149
+ display: none !important;
150
+ }
151
+
152
+ html[data-craft-native-sidebar='true'] .dashboard-main-content {
153
+ padding-left: 0 !important;
154
+ }
155
+ </style>
@@ -0,0 +1,54 @@
1
+ <script>
2
+ interface ActivityFeedProps {
3
+ commits?: any[]
4
+ }
5
+
6
+ const { commits = [] } = defineProps<ActivityFeedProps>()
7
+
8
+ function getTimeDifference(dateString) {
9
+ const date = new Date(dateString)
10
+ const now = new Date()
11
+ const diffMs = now.getTime() - date.getTime()
12
+ const diffMins = Math.floor(diffMs / (1000 * 60))
13
+ const diffHours = Math.floor(diffMins / 60)
14
+ const diffDays = Math.floor(diffHours / 24)
15
+
16
+ if (diffDays > 0) return `${diffDays}d ago`
17
+ if (diffHours > 0) return `${diffHours}h ago`
18
+ if (diffMins > 0) return `${diffMins}m ago`
19
+ return 'Just now'
20
+ }
21
+ </script>
22
+ <aside class="lg:bottom-0 lg:fixed lg:overflow-y-auto lg:right-0 lg:top-16 lg:w-96 bg-black/2 lg:border-l lg:border-white/5">
23
+ <header class="flex items-center justify-between px-4 py-4 sm:px-6 sm:py-6 lg:px-8 border-b border-white/5">
24
+ <h2 class="font-semibold leading-7 text-base dark:text-white">
25
+ Activity feed
26
+ </h2>
27
+ </header>
28
+
29
+ @if(commits.length > 0)
30
+ <ul role="list" class="divide-gray-200 divide-y">
31
+ @foreach(commits as commit, index)
32
+ <li class="px-4 py-4 sm:px-6 lg:px-8">
33
+ <div class="flex gap-x-3 items-center">
34
+ <a target="_new" href="{{ commit.author.html_url }}">
35
+ <img src="{{ commit.author.avatar_url }}" alt="" class="flex-none h-6 w-6 bg-gray-800 rounded-full">
36
+ </a>
37
+ <a target="_new" href="{{ commit.author.html_url }}" class="flex-auto font-semibold leading-6 text-sm truncate dark:text-white">
38
+ {{ commit.author.login }}
39
+ </a>
40
+ <time datetime="{{ commit.commit.committer.date }}" class="flex-none text-gray-600 text-xs">
41
+ {{ getTimeDifference(commit.commit.committer.date) }}
42
+ </time>
43
+ </div>
44
+ <p class="mt-3 text-gray-500 text-sm">
45
+ <a href="{{ commit.commit.url }}" class="font-mono text-gray-400 truncate hover:text-gray-500">
46
+ {{ commit.sha.slice(0, 10) }}
47
+ </a>
48
+ on <span class="text-gray-400">main</span>
49
+ </p>
50
+ </li>
51
+ @endforeach
52
+ </ul>
53
+ @endif
54
+ </aside>
@@ -0,0 +1,23 @@
1
+ <div class="pt-12 px-4 sm:px-6 lg:px-8">
2
+ <div class="sm:flex sm:items-center">
3
+ <div class="sm:flex-auto">
4
+ <h1 class="font-semibold leading-6 text-base text-gray-900">
5
+ Deploy Script
6
+ </h1>
7
+
8
+ <p class="mt-2 text-gray-700 text-sm">
9
+ If you need a custom deploy script, you may specify it here.
10
+ </p>
11
+ </div>
12
+ </div>
13
+
14
+ <div class="flow-root mt-8">
15
+ <div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
16
+ <div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
17
+ <div class="overflow-hidden">
18
+ <slot />
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </div>