dineway 0.1.3 → 0.1.5

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 (296) hide show
  1. package/README.md +6 -3
  2. package/dist/{apply-CAPvMfoU.mjs → apply-iVSqz2qs.mjs} +132 -39
  3. package/dist/astro/index.d.mts +18 -9
  4. package/dist/astro/index.mjs +238 -16
  5. package/dist/astro/middleware/auth.d.mts +16 -5
  6. package/dist/astro/middleware/auth.mjs +74 -37
  7. package/dist/astro/middleware/redirect.mjs +24 -8
  8. package/dist/astro/middleware/request-context.mjs +18 -5
  9. package/dist/astro/middleware/setup.mjs +1 -1
  10. package/dist/astro/middleware.mjs +411 -169
  11. package/dist/astro/types.d.mts +25 -8
  12. package/dist/{byline-DeWCMU_i.mjs → byline-OhH2dlRu.mjs} +6 -21
  13. package/dist/{bylines-DyqBV9EQ.mjs → bylines-BGpD9_hy.mjs} +16 -6
  14. package/dist/cache-BdSY-gQN.mjs +42 -0
  15. package/dist/chunks--4F8ddV4.mjs +18 -0
  16. package/dist/cli/index.mjs +935 -15
  17. package/dist/client/external-auth-headers.d.mts +1 -1
  18. package/dist/client/index.d.mts +11 -3
  19. package/dist/client/index.mjs +4 -3
  20. package/dist/{connection-C9pxzuag.mjs → connection-BCNICDWN.mjs} +22 -5
  21. package/dist/{content-zSgdNmnt.mjs → content-DWi4d0rT.mjs} +41 -2
  22. package/dist/database/instrumentation.d.mts +34 -0
  23. package/dist/database/instrumentation.mjs +53 -0
  24. package/dist/db/index.d.mts +3 -3
  25. package/dist/db/index.mjs +2 -2
  26. package/dist/db/libsql.d.mts +1 -1
  27. package/dist/db/libsql.mjs +11 -5
  28. package/dist/db/postgres.d.mts +1 -1
  29. package/dist/db/sqlite.d.mts +1 -1
  30. package/dist/db/sqlite.mjs +7 -1
  31. package/dist/db-errors-CEqD7qH9.mjs +23 -0
  32. package/dist/{default-WYlzADZL.mjs → default-VjJyuuG9.mjs} +2 -0
  33. package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +3 -0
  34. package/dist/{error-DrxtnGPg.mjs → error-BmL6QipT.mjs} +7 -3
  35. package/dist/{index-C-jx21qs.d.mts → index-yvc6E_17.d.mts} +157 -30
  36. package/dist/index.d.mts +11 -11
  37. package/dist/index.mjs +24 -22
  38. package/dist/{loader-qKmo0wAY.mjs → loader-sMG4TZ-u.mjs} +9 -3
  39. package/dist/media/index.d.mts +1 -1
  40. package/dist/media/index.mjs +1 -1
  41. package/dist/media/local-runtime.d.mts +7 -7
  42. package/dist/page/index.d.mts +10 -2
  43. package/dist/page/index.mjs +22 -1
  44. package/dist/patterns-CrCYkMBb.mjs +92 -0
  45. package/dist/{placeholder-bOx1xCTY.d.mts → placeholder--wOi4TbO.d.mts} +1 -1
  46. package/dist/{placeholder-B3knXwNc.mjs → placeholder-Cp8g5Emj.mjs} +1 -1
  47. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  48. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  49. package/dist/{query-BiaPl_g2.mjs → query-kDmwCsHh.mjs} +118 -50
  50. package/dist/{redirect-JPqLAbxa.mjs → redirect-DnEWAkVg.mjs} +43 -99
  51. package/dist/{registry-DSd1GWB8.mjs → registry-C0zjeB9P.mjs} +191 -123
  52. package/dist/request-cache-Dk5qPSOx.mjs +66 -0
  53. package/dist/request-context.d.mts +4 -16
  54. package/dist/{runner-B5l1JfOj.d.mts → runner-CFI6B6J2.d.mts} +1 -1
  55. package/dist/{runner-BGUGywgG.mjs → runner-DWZm2KQm.mjs} +589 -137
  56. package/dist/runtime.d.mts +6 -6
  57. package/dist/runtime.mjs +2 -2
  58. package/dist/{search-BNruJHDL.mjs → search-ByRGV2pq.mjs} +570 -424
  59. package/dist/seed/index.d.mts +2 -2
  60. package/dist/seed/index.mjs +11 -10
  61. package/dist/seo/index.d.mts +1 -1
  62. package/dist/storage/local.d.mts +1 -1
  63. package/dist/storage/local.mjs +1 -1
  64. package/dist/storage/s3.d.mts +11 -3
  65. package/dist/storage/s3.mjs +78 -15
  66. package/dist/taxonomies-1s5PaS_8.mjs +266 -0
  67. package/dist/transaction-Cn2rjY78.mjs +27 -0
  68. package/dist/{types-BgQeVaPj.d.mts → types-BuMDPy5C.d.mts} +52 -3
  69. package/dist/{types-DuNbGKjF.mjs → types-COeOq9nK.mjs} +6 -1
  70. package/dist/{types-ju-_ORz7.d.mts → types-CWbdtiux.d.mts} +13 -5
  71. package/dist/{types-D38djUXv.d.mts → types-Cj0KMIZV.d.mts} +16 -3
  72. package/dist/{types-DkvMXalq.d.mts → types-DOrVigru.d.mts} +159 -0
  73. package/dist/{validate-CXnRKfJK.mjs → validate-BZ5wnLLp.mjs} +2 -1
  74. package/dist/{validate-DVKJJ-M_.d.mts → validate-IPf8n4Fj.d.mts} +4 -51
  75. package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +10 -10
  76. package/dist/version-BKXPsfmJ.mjs +6 -0
  77. package/package.json +53 -39
  78. package/src/astro/routes/PluginRegistry.tsx +21 -0
  79. package/src/astro/routes/admin.astro +99 -0
  80. package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
  81. package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
  82. package/src/astro/routes/api/admin/api-tokens/[id].ts +44 -0
  83. package/src/astro/routes/api/admin/api-tokens/index.ts +90 -0
  84. package/src/astro/routes/api/admin/briefing.ts +76 -0
  85. package/src/astro/routes/api/admin/bylines/[id]/index.ts +90 -0
  86. package/src/astro/routes/api/admin/bylines/index.ts +74 -0
  87. package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
  88. package/src/astro/routes/api/admin/comments/[id].ts +64 -0
  89. package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
  90. package/src/astro/routes/api/admin/comments/counts.ts +30 -0
  91. package/src/astro/routes/api/admin/comments/index.ts +46 -0
  92. package/src/astro/routes/api/admin/context/[id]/history.ts +35 -0
  93. package/src/astro/routes/api/admin/context/[id]/index.ts +35 -0
  94. package/src/astro/routes/api/admin/context/[id]/review.ts +57 -0
  95. package/src/astro/routes/api/admin/context/[id]/supersede.ts +58 -0
  96. package/src/astro/routes/api/admin/context/diff.ts +35 -0
  97. package/src/astro/routes/api/admin/context/index.ts +69 -0
  98. package/src/astro/routes/api/admin/context/stale.ts +35 -0
  99. package/src/astro/routes/api/admin/hitl-requests/[id]/index.ts +38 -0
  100. package/src/astro/routes/api/admin/hitl-requests/[id]/resolve.ts +54 -0
  101. package/src/astro/routes/api/admin/hitl-requests/index.ts +38 -0
  102. package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +132 -0
  103. package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
  104. package/src/astro/routes/api/admin/oauth-clients/[id].ts +137 -0
  105. package/src/astro/routes/api/admin/oauth-clients/index.ts +95 -0
  106. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +91 -0
  107. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +91 -0
  108. package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
  109. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +98 -0
  110. package/src/astro/routes/api/admin/plugins/[id]/update.ts +154 -0
  111. package/src/astro/routes/api/admin/plugins/index.ts +32 -0
  112. package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +62 -0
  113. package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
  114. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +135 -0
  115. package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
  116. package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
  117. package/src/astro/routes/api/admin/review-requests/[id]/index.ts +35 -0
  118. package/src/astro/routes/api/admin/review-requests/[id]/resolve.ts +52 -0
  119. package/src/astro/routes/api/admin/review-requests/index.ts +35 -0
  120. package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
  121. package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +62 -0
  122. package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
  123. package/src/astro/routes/api/admin/users/[id]/disable.ts +72 -0
  124. package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
  125. package/src/astro/routes/api/admin/users/[id]/index.ts +166 -0
  126. package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
  127. package/src/astro/routes/api/admin/users/index.ts +66 -0
  128. package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
  129. package/src/astro/routes/api/auth/invite/accept.ts +52 -0
  130. package/src/astro/routes/api/auth/invite/complete.ts +86 -0
  131. package/src/astro/routes/api/auth/invite/index.ts +99 -0
  132. package/src/astro/routes/api/auth/invite/register-options.ts +73 -0
  133. package/src/astro/routes/api/auth/logout.ts +40 -0
  134. package/src/astro/routes/api/auth/magic-link/send.ts +90 -0
  135. package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
  136. package/src/astro/routes/api/auth/me.ts +60 -0
  137. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +221 -0
  138. package/src/astro/routes/api/auth/oauth/[provider].ts +120 -0
  139. package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
  140. package/src/astro/routes/api/auth/passkey/index.ts +54 -0
  141. package/src/astro/routes/api/auth/passkey/options.ts +85 -0
  142. package/src/astro/routes/api/auth/passkey/register/options.ts +88 -0
  143. package/src/astro/routes/api/auth/passkey/register/verify.ts +119 -0
  144. package/src/astro/routes/api/auth/passkey/verify.ts +72 -0
  145. package/src/astro/routes/api/auth/signup/complete.ts +87 -0
  146. package/src/astro/routes/api/auth/signup/request.ts +89 -0
  147. package/src/astro/routes/api/auth/signup/verify.ts +53 -0
  148. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +310 -0
  149. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
  150. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +68 -0
  151. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +77 -0
  152. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +42 -0
  153. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
  154. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +100 -0
  155. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +64 -0
  156. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
  157. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +129 -0
  158. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +143 -0
  159. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +50 -0
  160. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +69 -0
  161. package/src/astro/routes/api/content/[collection]/[id].ts +173 -0
  162. package/src/astro/routes/api/content/[collection]/index.ts +103 -0
  163. package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
  164. package/src/astro/routes/api/dashboard.ts +32 -0
  165. package/src/astro/routes/api/dev/emails.ts +36 -0
  166. package/src/astro/routes/api/health.ts +54 -0
  167. package/src/astro/routes/api/import/probe.ts +47 -0
  168. package/src/astro/routes/api/import/wordpress/analyze.ts +523 -0
  169. package/src/astro/routes/api/import/wordpress/execute.ts +330 -0
  170. package/src/astro/routes/api/import/wordpress/media.ts +338 -0
  171. package/src/astro/routes/api/import/wordpress/prepare.ts +212 -0
  172. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +425 -0
  173. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
  174. package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
  175. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +399 -0
  176. package/src/astro/routes/api/manifest.ts +75 -0
  177. package/src/astro/routes/api/mcp.ts +125 -0
  178. package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
  179. package/src/astro/routes/api/media/[id].ts +145 -0
  180. package/src/astro/routes/api/media/file/[...key].ts +79 -0
  181. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +91 -0
  182. package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
  183. package/src/astro/routes/api/media/providers/index.ts +30 -0
  184. package/src/astro/routes/api/media/upload-url.ts +146 -0
  185. package/src/astro/routes/api/media.ts +204 -0
  186. package/src/astro/routes/api/menus/[name]/items.ts +206 -0
  187. package/src/astro/routes/api/menus/[name]/reorder.ts +79 -0
  188. package/src/astro/routes/api/menus/[name].ts +145 -0
  189. package/src/astro/routes/api/menus/index.ts +91 -0
  190. package/src/astro/routes/api/oauth/authorize.ts +430 -0
  191. package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
  192. package/src/astro/routes/api/oauth/device/code.ts +56 -0
  193. package/src/astro/routes/api/oauth/device/token.ts +70 -0
  194. package/src/astro/routes/api/oauth/register.ts +182 -0
  195. package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
  196. package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
  197. package/src/astro/routes/api/oauth/token.ts +195 -0
  198. package/src/astro/routes/api/openapi.json.ts +33 -0
  199. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +109 -0
  200. package/src/astro/routes/api/redirects/404s/index.ts +72 -0
  201. package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
  202. package/src/astro/routes/api/redirects/[id].ts +183 -0
  203. package/src/astro/routes/api/redirects/index.ts +100 -0
  204. package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
  205. package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
  206. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +104 -0
  207. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +67 -0
  208. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +45 -0
  209. package/src/astro/routes/api/schema/collections/[slug]/index.ts +107 -0
  210. package/src/astro/routes/api/schema/collections/index.ts +61 -0
  211. package/src/astro/routes/api/schema/index.ts +109 -0
  212. package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
  213. package/src/astro/routes/api/schema/orphans/index.ts +26 -0
  214. package/src/astro/routes/api/search/enable.ts +64 -0
  215. package/src/astro/routes/api/search/index.ts +52 -0
  216. package/src/astro/routes/api/search/rebuild.ts +72 -0
  217. package/src/astro/routes/api/search/stats.ts +35 -0
  218. package/src/astro/routes/api/search/suggest.ts +50 -0
  219. package/src/astro/routes/api/sections/[slug].ts +203 -0
  220. package/src/astro/routes/api/sections/index.ts +107 -0
  221. package/src/astro/routes/api/settings/email.ts +150 -0
  222. package/src/astro/routes/api/settings.ts +116 -0
  223. package/src/astro/routes/api/setup/admin-verify.ts +122 -0
  224. package/src/astro/routes/api/setup/admin.ts +104 -0
  225. package/src/astro/routes/api/setup/dev-bypass.ts +200 -0
  226. package/src/astro/routes/api/setup/dev-reset.ts +40 -0
  227. package/src/astro/routes/api/setup/index.ts +128 -0
  228. package/src/astro/routes/api/setup/status.ts +122 -0
  229. package/src/astro/routes/api/snapshot.ts +76 -0
  230. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +232 -0
  231. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +131 -0
  232. package/src/astro/routes/api/taxonomies/index.ts +114 -0
  233. package/src/astro/routes/api/themes/preview.ts +78 -0
  234. package/src/astro/routes/api/typegen.ts +114 -0
  235. package/src/astro/routes/api/well-known/auth.ts +71 -0
  236. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +48 -0
  237. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +39 -0
  238. package/src/astro/routes/api/widget-areas/[name]/reorder.ts +114 -0
  239. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +213 -0
  240. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +126 -0
  241. package/src/astro/routes/api/widget-areas/[name].ts +135 -0
  242. package/src/astro/routes/api/widget-areas/index.ts +149 -0
  243. package/src/astro/routes/api/widget-components.ts +22 -0
  244. package/src/astro/routes/robots.txt.ts +81 -0
  245. package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
  246. package/src/astro/routes/sitemap.xml.ts +92 -0
  247. package/src/components/Break.astro +45 -0
  248. package/src/components/Button.astro +71 -0
  249. package/src/components/Buttons.astro +49 -0
  250. package/src/components/Code.astro +59 -0
  251. package/src/components/Columns.astro +59 -0
  252. package/src/components/CommentForm.astro +315 -0
  253. package/src/components/Comments.astro +232 -0
  254. package/src/components/Cover.astro +128 -0
  255. package/src/components/DinewayBodyEnd.astro +32 -0
  256. package/src/components/DinewayBodyStart.astro +32 -0
  257. package/src/components/DinewayHead.astro +61 -0
  258. package/src/components/DinewayImage.astro +178 -0
  259. package/src/components/DinewayMedia.astro +167 -0
  260. package/src/components/Embed.astro +128 -0
  261. package/src/components/File.astro +122 -0
  262. package/src/components/Gallery.astro +93 -0
  263. package/src/components/HtmlBlock.astro +33 -0
  264. package/src/components/Image.astro +178 -0
  265. package/src/components/InlineEditor.astro +27 -0
  266. package/src/components/InlinePortableTextEditor.tsx +1937 -0
  267. package/src/components/LiveSearch.astro +614 -0
  268. package/src/components/PortableText.astro +51 -0
  269. package/src/components/Pullquote.astro +51 -0
  270. package/src/components/Table.astro +135 -0
  271. package/src/components/WidgetArea.astro +22 -0
  272. package/src/components/WidgetRenderer.astro +72 -0
  273. package/src/components/index.ts +106 -0
  274. package/src/components/marks/Link.astro +31 -0
  275. package/src/components/marks/StrikeThrough.astro +7 -0
  276. package/src/components/marks/Subscript.astro +7 -0
  277. package/src/components/marks/Superscript.astro +7 -0
  278. package/src/components/marks/Underline.astro +7 -0
  279. package/src/components/marks.ts +19 -0
  280. package/src/components/widgets/Archives.astro +65 -0
  281. package/src/components/widgets/Categories.astro +35 -0
  282. package/src/components/widgets/RecentPosts.astro +51 -0
  283. package/src/components/widgets/Search.astro +18 -0
  284. package/src/components/widgets/Tags.astro +38 -0
  285. package/src/ui.ts +75 -0
  286. package/LICENSE +0 -9
  287. /package/dist/{adapters-BlzWJG82.d.mts → adapters-C2ypTrZZ.d.mts} +0 -0
  288. /package/dist/{config-Cq8H0SfX.mjs → config-BXwuX8Bx.mjs} +0 -0
  289. /package/dist/{load-C6FCD1FU.mjs → load-Coc9HpHH.mjs} +0 -0
  290. /package/dist/{manifest-schema-CTSEyIJ3.mjs → manifest-schema-D1MSVnoI.mjs} +0 -0
  291. /package/dist/{mode-BlyYtIFO.mjs → mode-47goXBBK.mjs} +0 -0
  292. /package/dist/{tokens-4vgYuXsZ.mjs → tokens-CJz9ubV6.mjs} +0 -0
  293. /package/dist/{transport-C5FYnid7.mjs → transport-DB5eDN4x.mjs} +0 -0
  294. /package/dist/{transport-gIL-e43D.d.mts → transport-Wge_IzKl.d.mts} +0 -0
  295. /package/dist/{types-CLLdsG3g.d.mts → types-BzcUjoqg.d.mts} +0 -0
  296. /package/dist/{types-DShnjzb6.mjs → types-griIBQOQ.mjs} +0 -0
@@ -0,0 +1,232 @@
1
+ ---
2
+ /**
3
+ * Server-rendered comment list for a content item.
4
+ *
5
+ * Fetches approved comments directly from the repository (no API call).
6
+ * Renders semantic HTML with CSS custom properties for styling.
7
+ *
8
+ * @example
9
+ * ```astro
10
+ * ---
11
+ * import { Comments } from "dineway/ui";
12
+ * ---
13
+ * <Comments collection="posts" contentId={post.id} threaded />
14
+ * ```
15
+ */
16
+ import type { PublicComment } from "../database/repositories/comment.js";
17
+ import { getComments } from "../comments/query.js";
18
+ import { getCollectionInfo } from "../schema/query.js";
19
+
20
+ interface Props {
21
+ collection: string;
22
+ contentId: string;
23
+ threaded?: boolean;
24
+ class?: string;
25
+ }
26
+
27
+ const {
28
+ collection,
29
+ contentId,
30
+ threaded = false,
31
+ class: className,
32
+ } = Astro.props;
33
+
34
+ const collectionInfo = await getCollectionInfo(collection);
35
+ const enabled = collectionInfo?.commentsEnabled ?? false;
36
+ const { items, total } = enabled
37
+ ? await getComments({ collection, contentId, threaded })
38
+ : { items: [], total: 0 };
39
+
40
+ const URL_RE = /https?:\/\/[^\s<>"')\]]+/g;
41
+ const AMP_RE = /&/g;
42
+ const LT_RE = /</g;
43
+ const GT_RE = />/g;
44
+ const QUOT_RE = /"/g;
45
+
46
+ function autoLinkUrls(text: string): string {
47
+ return text.replace(
48
+ URL_RE,
49
+ (url) =>
50
+ `<a href="${url}" rel="nofollow ugc noopener" target="_blank">${url}</a>`
51
+ );
52
+ }
53
+
54
+ function escapeHtml(text: string): string {
55
+ return text
56
+ .replace(AMP_RE, "&amp;")
57
+ .replace(LT_RE, "&lt;")
58
+ .replace(GT_RE, "&gt;")
59
+ .replace(QUOT_RE, "&quot;");
60
+ }
61
+
62
+ function formatBody(text: string): string {
63
+ return autoLinkUrls(escapeHtml(text));
64
+ }
65
+ ---
66
+
67
+ {
68
+ enabled && (
69
+ <section
70
+ class:list={["ec-comments", className]}
71
+ data-ec-comments
72
+ data-collection={collection}
73
+ data-content-id={contentId}
74
+ >
75
+ <h3 class="ec-comments-heading">
76
+ {total === 0
77
+ ? "No comments yet"
78
+ : total === 1
79
+ ? "1 Comment"
80
+ : `${total} Comments`}
81
+ </h3>
82
+
83
+ {items.length > 0 && (
84
+ <ol class="ec-comments-list">
85
+ {items.map((comment: PublicComment) => (
86
+ <li>
87
+ <article
88
+ class="ec-comment"
89
+ id={`comment-${comment.id}`}
90
+ data-comment-id={comment.id}
91
+ >
92
+ <header class="ec-comment-header">
93
+ <span class="ec-comment-author">
94
+ {comment.authorName}
95
+ {comment.isRegisteredUser && (
96
+ <span class="ec-comment-badge" aria-label="Site member">
97
+ &#x2713;
98
+ </span>
99
+ )}
100
+ </span>
101
+ <time class="ec-comment-date" datetime={comment.createdAt}>
102
+ {new Date(comment.createdAt).toLocaleDateString("en-US", {
103
+ year: "numeric",
104
+ month: "long",
105
+ day: "numeric",
106
+ hour: "numeric",
107
+ minute: "2-digit",
108
+ })}
109
+ </time>
110
+ </header>
111
+ <div
112
+ class="ec-comment-body"
113
+ set:html={formatBody(comment.body)}
114
+ />
115
+ {threaded && comment.replies && comment.replies.length > 0 && (
116
+ <ol class="ec-comment-replies">
117
+ {comment.replies.map((reply: PublicComment) => (
118
+ <li>
119
+ <article
120
+ class="ec-comment ec-comment-reply"
121
+ id={`comment-${reply.id}`}
122
+ data-comment-id={reply.id}
123
+ >
124
+ <header class="ec-comment-header">
125
+ <span class="ec-comment-author">
126
+ {reply.authorName}
127
+ {reply.isRegisteredUser && (
128
+ <span
129
+ class="ec-comment-badge"
130
+ aria-label="Site member"
131
+ >
132
+ &#x2713;
133
+ </span>
134
+ )}
135
+ </span>
136
+ <time
137
+ class="ec-comment-date"
138
+ datetime={reply.createdAt}
139
+ >
140
+ {new Date(reply.createdAt).toLocaleDateString(
141
+ "en-US",
142
+ {
143
+ year: "numeric",
144
+ month: "long",
145
+ day: "numeric",
146
+ hour: "numeric",
147
+ minute: "2-digit",
148
+ }
149
+ )}
150
+ </time>
151
+ </header>
152
+ <div
153
+ class="ec-comment-body"
154
+ set:html={formatBody(reply.body)}
155
+ />
156
+ </article>
157
+ </li>
158
+ ))}
159
+ </ol>
160
+ )}
161
+ </article>
162
+ </li>
163
+ ))}
164
+ </ol>
165
+ )}
166
+ </section>
167
+ )
168
+ }
169
+
170
+ <style>
171
+ .ec-comments {
172
+ --ec-comment-gap: 1.5rem;
173
+ --ec-comment-indent: 2rem;
174
+ --ec-comment-border: 1px solid #e5e7eb;
175
+ }
176
+
177
+ .ec-comments-list,
178
+ .ec-comment-replies {
179
+ list-style: none;
180
+ padding: 0;
181
+ margin: 0;
182
+ }
183
+
184
+ .ec-comments-list > li + li {
185
+ margin-top: var(--ec-comment-gap);
186
+ }
187
+
188
+ .ec-comment {
189
+ padding-bottom: var(--ec-comment-gap);
190
+ border-bottom: var(--ec-comment-border);
191
+ }
192
+
193
+ .ec-comment-replies {
194
+ margin-top: var(--ec-comment-gap);
195
+ padding-left: var(--ec-comment-indent);
196
+ }
197
+
198
+ .ec-comment-replies > li + li {
199
+ margin-top: var(--ec-comment-gap);
200
+ }
201
+
202
+ .ec-comment-header {
203
+ display: flex;
204
+ align-items: baseline;
205
+ gap: 0.5rem;
206
+ flex-wrap: wrap;
207
+ }
208
+
209
+ .ec-comment-author {
210
+ font-weight: 600;
211
+ }
212
+
213
+ .ec-comment-author a {
214
+ color: inherit;
215
+ }
216
+
217
+ .ec-comment-badge {
218
+ font-size: 0.75em;
219
+ vertical-align: super;
220
+ }
221
+
222
+ .ec-comment-date {
223
+ font-size: 0.875em;
224
+ opacity: 0.6;
225
+ }
226
+
227
+ .ec-comment-body {
228
+ margin-top: 0.5rem;
229
+ white-space: pre-wrap;
230
+ word-break: break-word;
231
+ }
232
+ </style>
@@ -0,0 +1,128 @@
1
+ ---
2
+ /**
3
+ * Portable Text Cover block component
4
+ *
5
+ * Renders an image/video with text overlay from WordPress imports.
6
+ */
7
+ import { PortableText } from "astro-portabletext";
8
+
9
+ export interface Props {
10
+ node: {
11
+ _type: "cover";
12
+ _key: string;
13
+ backgroundImage?: string;
14
+ backgroundVideo?: string;
15
+ overlayColor?: string;
16
+ overlayOpacity?: number;
17
+ content: unknown[];
18
+ minHeight?: string;
19
+ alignment?: "left" | "center" | "right";
20
+ };
21
+ }
22
+
23
+ const { node } = Astro.props;
24
+ const {
25
+ backgroundImage,
26
+ backgroundVideo,
27
+ overlayColor,
28
+ overlayOpacity = 0.5,
29
+ content = [],
30
+ minHeight = "300px",
31
+ alignment = "center",
32
+ } = node ?? {};
33
+
34
+ const hasBackground = backgroundImage || backgroundVideo;
35
+ const overlayStyle = overlayColor
36
+ ? `background-color: ${overlayColor}; opacity: ${overlayOpacity};`
37
+ : `background-color: rgba(0, 0, 0, ${overlayOpacity});`;
38
+ ---
39
+
40
+ <div
41
+ class:list={["dineway-cover", `dineway-cover--align-${alignment}`]}
42
+ style={`min-height: ${minHeight};`}
43
+ >
44
+ {
45
+ backgroundImage && !backgroundVideo && (
46
+ <img src={backgroundImage} alt="" class="dineway-cover__background" loading="lazy" />
47
+ )
48
+ }
49
+ {
50
+ backgroundVideo && (
51
+ <video
52
+ class="dineway-cover__background dineway-cover__video"
53
+ autoplay
54
+ muted
55
+ loop
56
+ playsinline
57
+ >
58
+ <source src={backgroundVideo} />
59
+ </video>
60
+ )
61
+ }
62
+ {hasBackground && <div class="dineway-cover__overlay" style={overlayStyle} />}
63
+ <div class="dineway-cover__content">
64
+ <PortableText value={content} />
65
+ </div>
66
+ </div>
67
+
68
+ <style>
69
+ .dineway-cover {
70
+ position: relative;
71
+ display: flex;
72
+ align-items: center;
73
+ padding: 2rem;
74
+ margin: 1.5rem 0;
75
+ overflow: hidden;
76
+ border-radius: 4px;
77
+ background-color: var(--dineway-cover-fallback-bg, #333);
78
+ }
79
+
80
+ .dineway-cover__background {
81
+ position: absolute;
82
+ inset: 0;
83
+ width: 100%;
84
+ height: 100%;
85
+ object-fit: cover;
86
+ z-index: 0;
87
+ }
88
+
89
+ .dineway-cover__video {
90
+ object-fit: cover;
91
+ }
92
+
93
+ .dineway-cover__overlay {
94
+ position: absolute;
95
+ inset: 0;
96
+ z-index: 1;
97
+ }
98
+
99
+ .dineway-cover__content {
100
+ position: relative;
101
+ z-index: 2;
102
+ width: 100%;
103
+ color: var(--dineway-cover-text-color, #fff);
104
+ }
105
+
106
+ .dineway-cover--align-left {
107
+ justify-content: flex-start;
108
+ text-align: left;
109
+ }
110
+
111
+ .dineway-cover--align-center {
112
+ justify-content: center;
113
+ text-align: center;
114
+ }
115
+
116
+ .dineway-cover--align-right {
117
+ justify-content: flex-end;
118
+ text-align: right;
119
+ }
120
+
121
+ .dineway-cover__content :global(h1),
122
+ .dineway-cover__content :global(h2),
123
+ .dineway-cover__content :global(h3),
124
+ .dineway-cover__content :global(h4),
125
+ .dineway-cover__content :global(p) {
126
+ color: inherit;
127
+ }
128
+ </style>
@@ -0,0 +1,32 @@
1
+ ---
2
+ /**
3
+ * Renders trusted plugin fragments at the end of <body>.
4
+ *
5
+ * Usage:
6
+ * ```astro
7
+ * <body>
8
+ * <slot />
9
+ * <DinewayBodyEnd page={page} />
10
+ * </body>
11
+ * ```
12
+ */
13
+ import type { PublicPageContext } from "../plugins/types.js";
14
+ import { renderFragments } from "../page/fragments.js";
15
+ import { getPageRuntime } from "../page/index.js";
16
+
17
+ interface Props {
18
+ page: PublicPageContext;
19
+ }
20
+
21
+ const { page } = Astro.props;
22
+ const runtime = getPageRuntime(Astro.locals as Record<string, unknown>);
23
+
24
+ let html = "";
25
+
26
+ if (runtime) {
27
+ const contributions = await runtime.collectPageFragments(page);
28
+ html = renderFragments(contributions, "body:end");
29
+ }
30
+ ---
31
+
32
+ <Fragment set:html={html} />
@@ -0,0 +1,32 @@
1
+ ---
2
+ /**
3
+ * Renders trusted plugin fragments at the start of <body>.
4
+ *
5
+ * Usage:
6
+ * ```astro
7
+ * <body>
8
+ * <DinewayBodyStart page={page} />
9
+ * <slot />
10
+ * </body>
11
+ * ```
12
+ */
13
+ import type { PublicPageContext } from "../plugins/types.js";
14
+ import { renderFragments } from "../page/fragments.js";
15
+ import { getPageRuntime } from "../page/index.js";
16
+
17
+ interface Props {
18
+ page: PublicPageContext;
19
+ }
20
+
21
+ const { page } = Astro.props;
22
+ const runtime = getPageRuntime(Astro.locals as Record<string, unknown>);
23
+
24
+ let html = "";
25
+
26
+ if (runtime) {
27
+ const contributions = await runtime.collectPageFragments(page);
28
+ html = renderFragments(contributions, "body:start");
29
+ }
30
+ ---
31
+
32
+ <Fragment set:html={html} />
@@ -0,0 +1,61 @@
1
+ ---
2
+ /**
3
+ * Renders base SEO metadata, plugin-contributed metadata, and trusted head fragments.
4
+ *
5
+ * Base SEO metadata (meta tags, OG, Twitter Card, canonical, JSON-LD) is generated
6
+ * from the page context's seo/articleMeta/siteName fields. Plugin contributions
7
+ * come after, so they can override base tags via first-wins dedup in resolvePageMetadata().
8
+ *
9
+ * Usage:
10
+ * ```astro
11
+ * <head>
12
+ * <DinewayHead page={page} />
13
+ * </head>
14
+ * ```
15
+ */
16
+ import type { PublicPageContext, PageMetadataContribution } from "../plugins/types.js";
17
+ import { resolvePageMetadata, renderPageMetadata } from "../page/metadata.js";
18
+ import { renderFragments } from "../page/fragments.js";
19
+ import {
20
+ generateBaseSeoContributions,
21
+ generateSiteSeoContributions,
22
+ } from "../page/seo-contributions.js";
23
+ import { getPageRuntime } from "../page/index.js";
24
+ import { getSiteSetting } from "../settings/index.js";
25
+
26
+ interface Props {
27
+ page: PublicPageContext;
28
+ }
29
+
30
+ const { page } = Astro.props;
31
+ const runtime = getPageRuntime(Astro.locals as Record<string, unknown>);
32
+
33
+ // Base SEO contributions from page context (always generated)
34
+ const baseContributions: PageMetadataContribution[] = generateBaseSeoContributions(page);
35
+
36
+ let metadataHtml = "";
37
+ let fragmentsHtml = "";
38
+
39
+ if (runtime) {
40
+ // Plugin contributions come BEFORE site/base, so resolvePageMetadata's
41
+ // first-wins dedup lets plugins override defaults.
42
+ const [seoSettings, pluginContributions, fragments] = await Promise.all([
43
+ getSiteSetting("seo"),
44
+ runtime.collectPageMetadata(page),
45
+ runtime.collectPageFragments(page),
46
+ ]);
47
+
48
+ const siteContributions = generateSiteSeoContributions(seoSettings);
49
+ const allContributions = [...pluginContributions, ...siteContributions, ...baseContributions];
50
+ const resolved = resolvePageMetadata(allContributions);
51
+ metadataHtml = renderPageMetadata(resolved);
52
+ fragmentsHtml = renderFragments(fragments, "head");
53
+ } else {
54
+ // No runtime (Dineway not initialized) — still render base SEO
55
+ const resolved = resolvePageMetadata(baseContributions);
56
+ metadataHtml = renderPageMetadata(resolved);
57
+ }
58
+ ---
59
+
60
+ <Fragment set:html={metadataHtml} />
61
+ <Fragment set:html={fragmentsHtml} />
@@ -0,0 +1,178 @@
1
+ ---
2
+ /**
3
+ * Dineway Image component
4
+ *
5
+ * Renders images with responsive srcset for CDN providers that support it.
6
+ * Uses the provider's getSrc function for URL-based image transformations.
7
+ *
8
+ * Usage:
9
+ * ```astro
10
+ * ---
11
+ * import { Image } from "dineway/ui";
12
+ * ---
13
+ * <Image image={post.data.featured_image} />
14
+ *
15
+ * <!-- With overrides -->
16
+ * <Image image={post.data.featured_image} class="hero" />
17
+ * ```
18
+ */
19
+ import type { MediaValue } from "../fields/types.js";
20
+ import type { HTMLAttributes } from "astro/types";
21
+ import type { ImageEmbed } from "../media/types.js";
22
+ import { getMediaProvider } from "../media/provider-loader.js";
23
+ // Standard responsive breakpoints
24
+ const BREAKPOINTS = [640, 750, 828, 960, 1080, 1280, 1600, 1920];
25
+
26
+ interface Props extends Omit<
27
+ HTMLAttributes<"img">,
28
+ "src" | "width" | "height"
29
+ > {
30
+ /** Image value from content field or media library */
31
+ image: MediaValue | string | undefined | null;
32
+ /** Override alt text (uses image.alt by default) */
33
+ alt?: string;
34
+ /** Override width (uses image.width by default) */
35
+ width?: number;
36
+ /** Override height (uses image.height by default) */
37
+ height?: number;
38
+ /** Priority loading (disables lazy loading) */
39
+ priority?: boolean;
40
+ }
41
+
42
+ const { image, alt, width, height, priority, ...attrs } = Astro.props;
43
+
44
+ // Normalize string URLs to object form
45
+ function normalizeImage(
46
+ img: MediaValue | string | undefined | null
47
+ ): MediaValue | null {
48
+ if (!img) return null;
49
+ if (typeof img === "string") {
50
+ return { id: "", src: img };
51
+ }
52
+ return img;
53
+ }
54
+
55
+ /**
56
+ * Build the URL for a local image
57
+ */
58
+ function buildLocalImageUrl(img: MediaValue): string {
59
+ const storageKey = (img.meta?.storageKey as string) || img.id;
60
+ if (storageKey) {
61
+ return `/_dineway/api/media/file/${storageKey}`;
62
+ }
63
+ return "";
64
+ }
65
+
66
+ /**
67
+ * Generate srcset using provider's getSrc function
68
+ */
69
+ function generateSrcset(
70
+ getSrc: NonNullable<ImageEmbed["getSrc"]>,
71
+ maxWidth: number,
72
+ aspectRatio?: number
73
+ ): string {
74
+ return BREAKPOINTS.filter((w) => w <= maxWidth * 2) // Include up to 2x for retina
75
+ .map((w) => {
76
+ const h = aspectRatio ? Math.round(w / aspectRatio) : undefined;
77
+ return `${getSrc({ width: w, height: h })} ${w}w`;
78
+ })
79
+ .join(", ");
80
+ }
81
+
82
+ const img = normalizeImage(image);
83
+
84
+ // Determine final dimensions (props override image metadata)
85
+ const finalWidth = width ?? img?.width;
86
+ const finalHeight = height ?? img?.height;
87
+ const finalAlt = alt ?? img?.alt ?? "";
88
+ const aspectRatio =
89
+ finalWidth && finalHeight ? finalWidth / finalHeight : undefined;
90
+
91
+ // Get the image source URL and srcset
92
+ let src = "";
93
+ let srcset: string | undefined;
94
+ let sizes: string | undefined;
95
+
96
+ if (img) {
97
+ const providerId = img.provider ?? "local";
98
+
99
+ if (providerId === "local" || img.src) {
100
+ // Local provider or direct src URL
101
+ src = img.src || buildLocalImageUrl(img);
102
+ } else {
103
+ // External provider
104
+ try {
105
+ const provider = await getMediaProvider(providerId);
106
+ if (provider) {
107
+ const result = provider.getEmbed(img, {
108
+ width: finalWidth,
109
+ height: finalHeight,
110
+ });
111
+ const embed = result instanceof Promise ? await result : result;
112
+ if (embed.type === "image") {
113
+ src = embed.src;
114
+
115
+ // Generate srcset if provider supports dynamic sizing
116
+ if (embed.getSrc) {
117
+ // Use image width, or default to 1200 for responsive images
118
+ const maxWidth = finalWidth || 1200;
119
+ srcset = generateSrcset(embed.getSrc, maxWidth, aspectRatio);
120
+ sizes = finalWidth
121
+ ? `(min-width: ${finalWidth}px) ${finalWidth}px, 100vw`
122
+ : "100vw";
123
+ }
124
+ }
125
+ } else {
126
+ console.warn(`[DinewayImage] Provider not found: ${providerId}`);
127
+ }
128
+ } catch (error) {
129
+ console.error(
130
+ `[DinewayImage] Failed to get embed for image ${img.id}:`,
131
+ error
132
+ );
133
+ }
134
+
135
+ // Fallback to local URL if provider failed
136
+ if (!src) {
137
+ src = buildLocalImageUrl(img);
138
+ }
139
+ }
140
+ }
141
+
142
+ // Build placeholder background style
143
+ const blurhash =
144
+ typeof image === "object"
145
+ ? (image?.meta?.blurhash as string | undefined)
146
+ : undefined;
147
+ const dominantColor =
148
+ typeof image === "object"
149
+ ? (image?.meta?.dominantColor as string | undefined)
150
+ : undefined;
151
+
152
+ let placeholderStyle = "";
153
+ if (blurhash) {
154
+ const { blurhashToImageCssString } = await import("@unpic/placeholder");
155
+ placeholderStyle = blurhashToImageCssString(blurhash);
156
+ } else if (dominantColor) {
157
+ placeholderStyle = `background-color: ${dominantColor};`;
158
+ }
159
+
160
+ const baseStyle = aspectRatio
161
+ ? `aspect-ratio: ${aspectRatio}; max-width: 100%; height: auto;`
162
+ : "max-width: 100%; height: auto;";
163
+
164
+ const imgProps: Record<string, unknown> = {
165
+ src,
166
+ srcset,
167
+ sizes,
168
+ width: finalWidth,
169
+ height: finalHeight,
170
+ alt: finalAlt,
171
+ loading: priority ? "eager" : "lazy",
172
+ decoding: "async",
173
+ style: placeholderStyle ? `${baseStyle} ${placeholderStyle}` : baseStyle,
174
+ ...attrs,
175
+ };
176
+ ---
177
+
178
+ {img && src ? <img {...imgProps} /> : null}