@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,55 @@
1
+ <script server>
2
+ // Outermost email scaffold (stacksjs/stacks#1901 B1).
3
+ //
4
+ // Wraps content in the table-based body that Outlook + Gmail (Android)
5
+ // require, plus the standard meta block (charset / viewport /
6
+ // X-UA-Compatible / colour-scheme). Two-tone bodyBg / contentBg
7
+ // mirrors the bundled templates: muted page colour outside, white
8
+ // card inside. Named slots: head / header / footer. See README for
9
+ // usage examples.
10
+ //
11
+ // Notes on `defineProps()`: stx fills missing props with an empty
12
+ // string (not `undefined`), so destructure defaults silently no-op
13
+ // for absent props. Use `props.x || fallback` instead — that's the
14
+ // pattern used elsewhere in the bundled email templates.
15
+ interface EmailLayoutProps {
16
+ title?: string
17
+ width?: number | string
18
+ bodyBg?: string
19
+ contentBg?: string
20
+ }
21
+
22
+ const props = defineProps<EmailLayoutProps>()
23
+ const title = props.title || ''
24
+ const width = props.width || 600
25
+ const bodyBg = props.bodyBg || '#f4f4f5'
26
+ const contentBg = props.contentBg || '#ffffff'
27
+ </script>
28
+
29
+ <!DOCTYPE html>
30
+ <html lang="en">
31
+ <head>
32
+ <meta charset="UTF-8">
33
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
34
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
35
+ <meta name="color-scheme" content="light dark">
36
+ <meta name="supported-color-schemes" content="light dark">
37
+ <title>{{ title }}</title>
38
+ <slot name="head" />
39
+ </head>
40
+ <body style="margin:0;padding:0;background-color:{{ bodyBg }};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;line-height:1.6;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;">
41
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:100%;border-collapse:collapse;background-color:{{ bodyBg }};">
42
+ <tr>
43
+ <td align="center" style="padding:40px 20px;">
44
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="max-width:{{ width }}px;width:100%;background-color:{{ contentBg }};border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.1);">
45
+ <slot name="header" />
46
+ <tr><td style="padding:40px;">
47
+ <slot />
48
+ </td></tr>
49
+ <slot name="footer" />
50
+ </table>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+ </body>
55
+ </html>
@@ -0,0 +1,22 @@
1
+ <script server>
2
+ // Inline email link (stacksjs/stacks#1901 B1).
3
+ //
4
+ // For inline mentions inside paragraphs / sentences — use
5
+ // `<EmailButton>` for CTAs. The brand colour is set explicitly
6
+ // because Gmail / Outlook ignore `<style>` blocks, so unstyled
7
+ // `<a>` falls back to client-default blue / purple.
8
+ interface EmailLinkProps {
9
+ href: string
10
+ color?: string
11
+ underline?: boolean
12
+ }
13
+
14
+ const props = defineProps<EmailLinkProps>()
15
+ const href = props.href || '#'
16
+ const color = props.color || '#3451b2'
17
+ const underline = props.underline === false ? false : true
18
+ const decoration = underline ? 'underline' : 'none'
19
+ </script>
20
+ <a href="{{ href }}" style="color:{{ color }};text-decoration:{{ decoration }};">
21
+ <slot />
22
+ </a>
@@ -0,0 +1,20 @@
1
+ <script server>
2
+ // Email content section (stacksjs/stacks#1901 B1) — a table row used
3
+ // to group content vertically. Stack several to split an email into
4
+ // header / body / CTA / footer blocks.
5
+ interface EmailSectionProps {
6
+ padding?: string
7
+ background?: string
8
+ }
9
+
10
+ const props = defineProps<EmailSectionProps>()
11
+ const padding = props.padding || '0'
12
+ const background = props.background || 'transparent'
13
+ </script>
14
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:100%;border-collapse:collapse;background-color:{{ background }};">
15
+ <tr>
16
+ <td style="padding:{{ padding }};">
17
+ <slot />
18
+ </td>
19
+ </tr>
20
+ </table>
@@ -0,0 +1,30 @@
1
+ <script server>
2
+ // Email paragraph (stacksjs/stacks#1901 B1).
3
+ //
4
+ // Wraps text in a paragraph with normalised line-height + colour,
5
+ // and a `size` enum covering the 80% case (sm / md / lg / heading).
6
+ // For arbitrary styling override `color` / `spacing` directly.
7
+ interface EmailTextProps {
8
+ align?: 'left' | 'center' | 'right'
9
+ size?: 'sm' | 'md' | 'lg' | 'heading'
10
+ color?: string
11
+ spacing?: string
12
+ }
13
+
14
+ const props = defineProps<EmailTextProps>()
15
+ const align = props.align || 'left'
16
+ const size = props.size || 'md'
17
+ const color = props.color || (size === 'heading' ? '#111827' : '#4b5563')
18
+ const spacing = props.spacing || '16px'
19
+
20
+ const sizeStyles: Record<string, string> = {
21
+ sm: 'font-size:14px;line-height:1.5;',
22
+ md: 'font-size:16px;line-height:1.6;',
23
+ lg: 'font-size:18px;line-height:1.6;',
24
+ heading: 'font-size:20px;line-height:1.4;font-weight:600;',
25
+ }
26
+ const sizeStyle = sizeStyles[size] || sizeStyles.md
27
+ </script>
28
+ <p style="margin:0 0 {{ spacing }} 0;text-align:{{ align }};color:{{ color }};{{ sizeStyle }}">
29
+ <slot />
30
+ </p>
@@ -0,0 +1,38 @@
1
+ <script>
2
+ interface ForumBreadcrumbProps {
3
+ items?: any[]
4
+ }
5
+
6
+ const { items = [] } = defineProps<ForumBreadcrumbProps>()
7
+ </script>
8
+ <div class="mb-4">
9
+ <nav class="flex" aria-label="Breadcrumb">
10
+ <ol class="inline-flex items-center space-x-1 md:space-x-2">
11
+ @foreach(items as item)
12
+ <li class="inline-flex items-center">
13
+ @if(loop.index > 0)
14
+ <div class="flex items-center">
15
+ <svg class="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
16
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
17
+ </svg>
18
+ </div>
19
+ @endif
20
+ @if(item.link)
21
+ <a
22
+ href="{{ item.link }}"
23
+ class="font-medium text-gray-700 text-sm hover:text-blue-600 : ? '' 'ml-1' {{ }} > 0 loop.index"
24
+ >
25
+ {{ item.label }}
26
+ </a>
27
+ @else
28
+ <span
29
+ class="font-medium text-gray-500 text-sm : ? '' 'ml-1' {{ }} > 0 loop.index"
30
+ >
31
+ {{ item.label }}
32
+ </span>
33
+ @endif
34
+ </li>
35
+ @endforeach
36
+ </ol>
37
+ </nav>
38
+ </div>
@@ -0,0 +1,16 @@
1
+ <script>
2
+ interface ForumCategoryProps {
3
+ title?: string
4
+ }
5
+
6
+ const { title = '' } = defineProps<ForumCategoryProps>()
7
+ </script>
8
+ <div class="mb-8">
9
+ <div class="flex items-center px-4 py-3 bg-gray-100 rounded-t-md">
10
+ <h2 class="font-bold text-lg">{{ title }}</h2>
11
+ </div>
12
+
13
+ <div class="border divide-y rounded-b-md">
14
+ <slot />
15
+ </div>
16
+ </div>
@@ -0,0 +1,46 @@
1
+ <script>
2
+ interface ForumCategoryItemProps {
3
+ title?: string
4
+ description?: string
5
+ link?: string
6
+ topicCount?: number
7
+ postCount?: number
8
+ icon?: string
9
+ latestTopic?: any
10
+ }
11
+
12
+ const { title = '', description = '', link = '', topicCount = 0, postCount = 0, icon = 'i-hugeicons-chat', latestTopic = null } = defineProps<ForumCategoryItemProps>()
13
+ </script>
14
+ <div class="flex items-start p-4 hover:bg-gray-50">
15
+ <div class="flex-shrink-0 mr-4">
16
+ <div class="flex items-center justify-center h-10 w-10 text-gray-500 bg-gray-100 rounded-full {{ }} icon"></div>
17
+ </div>
18
+
19
+ <div class="flex-grow min-w-0">
20
+ <h3 class="font-medium">
21
+ <a href="{{ link }}" class="text-primary hover:underline">{{ title }}</a>
22
+ </h3>
23
+ <p class="mt-1 text-gray-600 text-sm">{{ description }}</p>
24
+
25
+ <div class="flex gap-4 items-center mt-2 text-gray-500 text-xs">
26
+ <div class="flex gap-1 items-center">
27
+ <div class="i-hugeicons-file"></div>
28
+ <span>{{ topicCount }} topics</span>
29
+ </div>
30
+ <div class="flex gap-1 items-center">
31
+ <div class="i-hugeicons-chat"></div>
32
+ <span>{{ postCount }} posts</span>
33
+ </div>
34
+ </div>
35
+ </div>
36
+
37
+ @if(latestTopic)
38
+ <div class="flex-shrink-0 ml-4 text-right">
39
+ <a href="{{ latestTopic.link }}" class="font-medium line-clamp-1 text-primary text-sm hover:underline">{{ latestTopic.title }}</a>
40
+ <div class="mt-1 text-gray-500 text-xs">
41
+ {{ latestTopic.timeAgo }} by
42
+ <a href="{{ latestTopic.authorLink }}" class="hover:underline">{{ latestTopic.author }}</a>
43
+ </div>
44
+ </div>
45
+ @endif
46
+ </div>
@@ -0,0 +1,36 @@
1
+ <script>
2
+ interface ForumLayoutProps {
3
+ route?: string
4
+ }
5
+
6
+ const { route = 'forum' } = defineProps<ForumLayoutProps>()
7
+
8
+ function isActiveRoute(currentRoute, targetRoute) {
9
+ return currentRoute === targetRoute
10
+ }
11
+ </script>
12
+ <div class="container mx-auto px-4 py-8">
13
+ <header class="mb-6">
14
+ <div class="flex items-center justify-between mb-4">
15
+ <h1 class="font-bold text-2xl">Stacks Community</h1>
16
+ <div class="flex gap-2 items-center">
17
+ <a href="/forum/new-topic" class="px-4 py-2 text-white bg-primary rounded-md hover:opacity-90">New Topic</a>
18
+ <a href="#" class="px-4 py-2 hover:bg-gray-100 border border-gray-300 rounded-md">Sign In</a>
19
+ </div>
20
+ </div>
21
+ <nav class="flex gap-1 text-sm">
22
+ <a href="/forum" class="px-3 py-2 font-medium' 'hover:bg-gray-100 rounded-md rounded-md' : ? 'bg-gray-100 'forum') {{ }} isActiveRoute(route,">All Discussions</a>
23
+ <a href="/forum?filter=popular" class="px-3 py-2 font-medium' 'hover:bg-gray-100 rounded-md rounded-md' : ? 'bg-gray-100 'forum-popular') {{ }} isActiveRoute(route,">Popular</a>
24
+ <a href="/forum?filter=recent" class="px-3 py-2 font-medium' 'hover:bg-gray-100 rounded-md rounded-md' : ? 'bg-gray-100 'forum-recent') {{ }} isActiveRoute(route,">Recent</a>
25
+ <a href="/forum?filter=solved" class="px-3 py-2 font-medium' 'hover:bg-gray-100 rounded-md rounded-md' : ? 'bg-gray-100 'forum-solved') {{ }} isActiveRoute(route,">Solved</a>
26
+ </nav>
27
+ </header>
28
+
29
+ <main>
30
+ <slot />
31
+ </main>
32
+
33
+ <footer class="mt-12 py-6 text-center text-gray-500 text-sm border-t">
34
+ <p>Stacks Community Forum</p>
35
+ </footer>
36
+ </div>
@@ -0,0 +1,39 @@
1
+ <script>
2
+ interface ForumPaginationProps {
3
+ currentPage?: number
4
+ totalPages?: number
5
+ pages?: any[]
6
+ }
7
+
8
+ const { currentPage = 1, totalPages = 1, pages = [] } = defineProps<ForumPaginationProps>()
9
+ </script>
10
+ <div class="flex items-center justify-center mt-8">
11
+ <nav class="flex gap-1 items-center">
12
+ <a
13
+ href="#"
14
+ class="flex items-center justify-center h-10 w-10 hover:bg-gray-100 border rounded-md cursor-not-allowed' : ? '' 'opacity-50 {{ }} == 1 currentPage"
15
+ data-action="prev-page"
16
+ >
17
+ <span class="i-hugeicons-arrow-left"></span>
18
+ </a>
19
+
20
+ @foreach(pages as page)
21
+ <a
22
+ href="#"
23
+ class="flex items-center justify-center h-10 w-10 text-white' hover:bg-gray-100' rounded-md : ? 'bg-primary 'border {{ }} == currentPage page"
24
+ data-action="go-to-page"
25
+ data-page="{{ page }}"
26
+ >
27
+ {{ page }}
28
+ </a>
29
+ @endforeach
30
+
31
+ <a
32
+ href="#"
33
+ class="flex items-center justify-center h-10 w-10 hover:bg-gray-100 border rounded-md cursor-not-allowed' : ? '' 'opacity-50 {{ }} == currentPage totalPages"
34
+ data-action="next-page"
35
+ >
36
+ <span class="i-hugeicons-arrow-right"></span>
37
+ </a>
38
+ </nav>
39
+ </div>
@@ -0,0 +1,71 @@
1
+ <script>
2
+ interface ForumPostProps {
3
+ id?: string
4
+ authorName?: string
5
+ authorAvatar?: string
6
+ createdAt?: string
7
+ likeCount?: number
8
+ isOriginalPost?: boolean
9
+ title?: string
10
+ isSolved?: boolean
11
+ }
12
+
13
+ const { id = '', authorName = '', authorAvatar = '', createdAt = '', likeCount = 0, isOriginalPost = false, title = '', isSolved = false } = defineProps<ForumPostProps>()
14
+ </script>
15
+ <div id="post-{{ id }}" class="mb-6 border rounded-md">
16
+ <div class="flex items-center justify-between px-4 py-3 bg-gray-50 rounded-t-md">
17
+ <div class="flex gap-2 items-center">
18
+ <img src="{{ authorAvatar }}" alt="{{ authorName }}" class="h-6 w-6 rounded-full">
19
+ <span class="font-medium">{{ authorName }}</span>
20
+ <span class="text-gray-500 text-xs">{{ createdAt }}</span>
21
+ </div>
22
+
23
+ <div class="flex gap-2 items-center">
24
+ @if(isOriginalPost)
25
+ <button class="px-2 py-1 text-xs hover:bg-gray-100 border rounded" data-action="bookmark">
26
+ <span class="mr-1 i-hugeicons-bookmark"></span>
27
+ Bookmark
28
+ </button>
29
+ @endif
30
+ <button class="px-2 py-1 text-xs hover:bg-gray-100 border rounded" data-action="share">
31
+ <span class="mr-1 i-hugeicons-share"></span>
32
+ Share
33
+ </button>
34
+ </div>
35
+ </div>
36
+
37
+ <div class="p-4">
38
+ @if(isOriginalPost)
39
+ <h1 class="mb-4 font-bold text-xl">{{ title }}</h1>
40
+ @endif
41
+ <div class="max-w-none prose">
42
+ <slot />
43
+ </div>
44
+ </div>
45
+
46
+ <div class="flex items-center justify-between px-4 py-3 bg-gray-50 rounded-b-md">
47
+ <div class="flex gap-3 items-center text-gray-500">
48
+ <button class="flex gap-1 items-center hover:text-primary" data-action="like" data-post-id="{{ id }}">
49
+ <span class="i-hugeicons-heart"></span>
50
+ <span>{{ likeCount }}</span>
51
+ </button>
52
+
53
+ <button class="flex gap-1 items-center hover:text-primary" data-action="reply" data-post-id="{{ id }}">
54
+ <span class="i-hugeicons-chat"></span>
55
+ <span>Reply</span>
56
+ </button>
57
+ </div>
58
+
59
+ <div class="flex gap-2 items-center">
60
+ @if(isOriginalPost && !isSolved)
61
+ <button class="px-2 py-1 text-dark text-xs bg-success rounded hover:opacity-90" data-action="mark-solution" data-post-id="{{ id }}">
62
+ Mark as Solution
63
+ </button>
64
+ @endif
65
+ <button class="px-2 py-1 text-xs hover:bg-gray-100 border rounded" data-action="report" data-post-id="{{ id }}">
66
+ <span class="mr-1 i-hugeicons-flag"></span>
67
+ Report
68
+ </button>
69
+ </div>
70
+ </div>
71
+ </div>
@@ -0,0 +1,76 @@
1
+ <script>
2
+ interface ForumReplyFormProps {
3
+ replyContent?: string
4
+ notifyOnReply?: boolean
5
+ }
6
+
7
+ const { replyContent = '', notifyOnReply = true } = defineProps<ForumReplyFormProps>()
8
+
9
+ function canSubmit(content) {
10
+ return content.trim().length > 0
11
+ }
12
+ </script>
13
+ <div class="mb-6 border rounded-md">
14
+ <div class="flex items-center px-4 py-3 bg-gray-50 rounded-t-md">
15
+ <h3 class="font-medium">Post a Reply</h3>
16
+ </div>
17
+
18
+ <div class="p-4">
19
+ <div class="mb-4">
20
+ <div class="flex gap-2 mb-2">
21
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Bold" data-action="format" data-format="bold">B</button>
22
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Italic" data-action="format" data-format="italic">I</button>
23
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Link" data-action="format" data-format="link">
24
+ <span class="i-hugeicons-link"></span>
25
+ </button>
26
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Code" data-action="format" data-format="code">
27
+ <span class="i-hugeicons-code"></span>
28
+ </button>
29
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Image" data-action="format" data-format="image">
30
+ <span class="i-hugeicons-image"></span>
31
+ </button>
32
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="Quote" data-action="format" data-format="quote">
33
+ <span class="i-hugeicons-quote"></span>
34
+ </button>
35
+ <button class="px-2 py-1 text-sm hover:bg-gray-100 border rounded" title="List" data-action="format" data-format="list">
36
+ <span class="i-hugeicons-list"></span>
37
+ </button>
38
+ </div>
39
+ <textarea
40
+ name="replyContent"
41
+ class="p-3 min-h-32 w-full border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
42
+ placeholder="Write your reply here..."
43
+ >{{ replyContent }}</textarea>
44
+ <div class="flex justify-between mt-1 text-gray-500 text-xs">
45
+ <span>Markdown formatting supported</span>
46
+ <span class="character-count">0 characters</span>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="flex items-center justify-between">
51
+ <div class="flex gap-4 items-center">
52
+ <label class="flex items-center text-gray-600 text-sm">
53
+ <input type="checkbox" class="mr-2" name="notifyOnReply" {{ notifyOnReply ? 'checked' : '' }}>
54
+ Notify me of follow-up replies
55
+ </label>
56
+
57
+ <button class="text-gray-600 text-sm hover:text-primary" data-action="formatting-help">
58
+ Formatting Help
59
+ </button>
60
+ </div>
61
+
62
+ <div class="flex gap-2">
63
+ <button class="px-3 py-2 hover:bg-gray-100 border rounded-md" data-action="preview">
64
+ Preview
65
+ </button>
66
+ <button
67
+ class="px-4 py-2 text-white bg-primary rounded-md hover:opacity-90 cursor-not-allowed' : ? '' 'opacity-50 {{ }} canSubmit(replyContent)"
68
+ data-action="submit-reply"
69
+ {{ canSubmit(replyContent) ? '' : 'disabled' }}
70
+ >
71
+ Post Reply
72
+ </button>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </div>
@@ -0,0 +1,86 @@
1
+ <script>
2
+ interface ForumSidebarProps {
3
+ stats?: string
4
+ popularTopics?: any[]
5
+ onlineUsers?: any[]
6
+ }
7
+
8
+ const { stats = {, popularTopics = [], onlineUsers = [] } = defineProps<ForumSidebarProps>()
9
+
10
+ topics: 0,
11
+ posts: 0,
12
+ members: 0,
13
+ newestMember: ''
14
+ }
15
+ </script>
16
+ <div class="space-y-6">
17
+ <!-- Search -->
18
+ <div class="p-4 border rounded-md">
19
+ <h3 class="mb-3 font-medium">Search</h3>
20
+ <div class="relative">
21
+ <input
22
+ type="text"
23
+ placeholder="Search topics..."
24
+ class="pl-3 pr-10 py-2 w-full border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
25
+ name="search"
26
+ >
27
+ <button class="absolute right-3 top-2" data-action="search">
28
+ <span class="i-hugeicons-search"></span>
29
+ </button>
30
+ </div>
31
+ </div>
32
+
33
+ <!-- Stats -->
34
+ <div class="p-4 border rounded-md">
35
+ <h3 class="mb-3 font-medium">Forum Stats</h3>
36
+ <div class="space-y-2">
37
+ <div class="flex justify-between">
38
+ <span class="text-gray-600">Topics:</span>
39
+ <span class="font-medium">{{ stats.topics }}</span>
40
+ </div>
41
+ <div class="flex justify-between">
42
+ <span class="text-gray-600">Posts:</span>
43
+ <span class="font-medium">{{ stats.posts }}</span>
44
+ </div>
45
+ <div class="flex justify-between">
46
+ <span class="text-gray-600">Members:</span>
47
+ <span class="font-medium">{{ stats.members }}</span>
48
+ </div>
49
+ <div class="flex justify-between">
50
+ <span class="text-gray-600">Newest Member:</span>
51
+ <a href="#" class="text-primary hover:underline">{{ stats.newestMember }}</a>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <!-- Popular Topics -->
57
+ <div class="p-4 border rounded-md">
58
+ <h3 class="mb-3 font-medium">Popular Topics</h3>
59
+ <ul class="space-y-3">
60
+ @foreach(popularTopics as topic)
61
+ <li>
62
+ <a href="{{ topic.link }}" class="block line-clamp-1 text-primary hover:underline">{{ topic.title }}</a>
63
+ <div class="mt-1 text-gray-500 text-xs">
64
+ {{ topic.replyCount }} replies • {{ topic.viewCount }} views
65
+ </div>
66
+ </li>
67
+ @endforeach
68
+ </ul>
69
+ </div>
70
+
71
+ <!-- Online Users -->
72
+ <div class="p-4 border rounded-md">
73
+ <h3 class="mb-3 font-medium">Online Now</h3>
74
+ <div class="flex flex-wrap gap-2">
75
+ @foreach(onlineUsers as user)
76
+ <div class="relative">
77
+ <img src="{{ user.avatar }}" alt="{{ user.name }}" class="h-8 w-8 rounded-full">
78
+ <span class="absolute bottom-0 right-0 h-2.5 w-2.5 bg-green-500 border-2 border-white rounded-full"></span>
79
+ </div>
80
+ @endforeach
81
+ </div>
82
+ <div class="mt-3 text-gray-500 text-xs">
83
+ {{ onlineUsers.length }} users online now
84
+ </div>
85
+ </div>
86
+ </div>
@@ -0,0 +1,77 @@
1
+ <script>
2
+ interface ForumTopicItemProps {
3
+ title?: string
4
+ link?: string
5
+ authorName?: string
6
+ authorAvatar?: string
7
+ createdAt?: string
8
+ viewCount?: number
9
+ replyCount?: number
10
+ likeCount?: number
11
+ isPinned?: boolean
12
+ isSolved?: boolean
13
+ category?: string
14
+ categoryLink?: string
15
+ excerpt?: string
16
+ lastReplyAuthorName?: string
17
+ lastReplyAuthorAvatar?: string
18
+ lastReplyAt?: string
19
+ }
20
+
21
+ const { title = '', link = '', authorName = '', authorAvatar = '', createdAt = '', viewCount = 0, replyCount = 0, likeCount = 0, isPinned = false, isSolved = false, category = '', categoryLink = '', excerpt = '', lastReplyAuthorName = '', lastReplyAuthorAvatar = '', lastReplyAt = '' } = defineProps<ForumTopicItemProps>()
22
+ </script>
23
+ <div class="flex items-start p-4 hover:bg-gray-50">
24
+ <div class="flex-shrink-0 mr-4">
25
+ <img src="{{ authorAvatar }}" alt="{{ authorName }}" class="h-10 w-10 rounded-full">
26
+ </div>
27
+
28
+ <div class="flex-grow min-w-0">
29
+ <div class="flex gap-2 items-center">
30
+ <h3 class="font-medium text-primary hover:underline">
31
+ <a href="{{ link }}">{{ title }}</a>
32
+ </h3>
33
+ @if(isPinned)
34
+ <span class="px-2 py-0.5 text-gray-700 text-xs bg-gray-200 rounded">Pinned</span>
35
+ @endif
36
+ @if(isSolved)
37
+ <span class="px-2 py-0.5 text-dark text-xs bg-success rounded">Solved</span>
38
+ @endif
39
+ </div>
40
+
41
+ <div class="flex items-center mt-1 text-gray-500 text-xs">
42
+ <span>{{ authorName }}</span>
43
+ <span class="mx-1">•</span>
44
+ <span>{{ createdAt }}</span>
45
+ @if(category)
46
+ <span class="mx-1">•</span>
47
+ <a href="{{ categoryLink }}" class="text-gray-700 hover:underline">{{ category }}</a>
48
+ @endif
49
+ </div>
50
+
51
+ @if(excerpt)
52
+ <p class="mt-2 line-clamp-2 text-gray-600 text-sm">{{ excerpt }}</p>
53
+ @endif
54
+
55
+ <div class="flex gap-4 items-center mt-2 text-gray-500 text-xs">
56
+ <div class="flex gap-1 items-center">
57
+ <div class="i-hugeicons-eye"></div>
58
+ <span>{{ viewCount }}</span>
59
+ </div>
60
+ <div class="flex gap-1 items-center">
61
+ <div class="i-hugeicons-chat"></div>
62
+ <span>{{ replyCount }}</span>
63
+ </div>
64
+ <div class="flex gap-1 items-center">
65
+ <div class="i-hugeicons-heart"></div>
66
+ <span>{{ likeCount }}</span>
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ @if(lastReplyAuthorAvatar)
72
+ <div class="flex-shrink-0 ml-4 text-right">
73
+ <img src="{{ lastReplyAuthorAvatar }}" alt="{{ lastReplyAuthorName }}" class="inline-block h-6 w-6 rounded-full">
74
+ <div class="mt-1 text-gray-500 text-xs">{{ lastReplyAt }}</div>
75
+ </div>
76
+ @endif
77
+ </div>
@@ -0,0 +1,23 @@
1
+ <script>
2
+ interface ForumTopicListProps {
3
+ title?: string
4
+ }
5
+
6
+ const { title = '' } = defineProps<ForumTopicListProps>()
7
+ </script>
8
+ <div class="mb-8">
9
+ <div class="flex items-center justify-between px-4 py-3 bg-gray-100 rounded-t-md">
10
+ <h2 class="font-bold text-lg">{{ title }}</h2>
11
+ <div class="flex gap-2 items-center">
12
+ <select class="px-2 py-1 text-sm border rounded" name="sort" data-action="sort-topics">
13
+ <option value="latest">Sort by Latest</option>
14
+ <option value="popular">Sort by Popular</option>
15
+ <option value="unanswered">Sort by Unanswered</option>
16
+ </select>
17
+ </div>
18
+ </div>
19
+
20
+ <div class="border divide-y rounded-b-md">
21
+ <slot />
22
+ </div>
23
+ </div>