@carlonicora/nextjs-jsonapi 5.3.0 → 5.5.0

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 (233) hide show
  1. package/dist/{BlockNoteEditor-WTSQANKI.mjs → BlockNoteEditor-GVQCKRMU.mjs} +9 -8
  2. package/dist/BlockNoteEditor-GVQCKRMU.mjs.map +1 -0
  3. package/dist/{BlockNoteEditor-UJ6363LC.js → BlockNoteEditor-THBJH2UR.js} +24 -23
  4. package/dist/BlockNoteEditor-THBJH2UR.js.map +1 -0
  5. package/dist/{BlockNoteViewer-JVKWJZ6J.mjs → BlockNoteViewer-U6E3DS4F.mjs} +3 -3
  6. package/dist/{BlockNoteViewer-EL4JFB6P.js → BlockNoteViewer-VZOVKTFO.js} +4 -4
  7. package/dist/{BlockNoteViewer-EL4JFB6P.js.map → BlockNoteViewer-VZOVKTFO.js.map} +1 -1
  8. package/dist/BlogCategoryFields-DO48vOTE.d.mts +14 -0
  9. package/dist/BlogCategoryFields-DO48vOTE.d.ts +14 -0
  10. package/dist/BlogPostInterface-BB_4wcDR.d.mts +124 -0
  11. package/dist/BlogPostInterface-bWAT1rfR.d.ts +124 -0
  12. package/dist/billing/index.js +442 -442
  13. package/dist/billing/index.mjs +4 -4
  14. package/dist/blog-public.types-BbrzsC1c.d.mts +30 -0
  15. package/dist/blog-public.types-BbrzsC1c.d.ts +30 -0
  16. package/dist/chunk-3CGROPF3.mjs +107 -0
  17. package/dist/chunk-3CGROPF3.mjs.map +1 -0
  18. package/dist/{chunk-QKZUE5OF.mjs → chunk-3YW35YHQ.mjs} +1 -101
  19. package/dist/chunk-3YW35YHQ.mjs.map +1 -0
  20. package/dist/{chunk-6WU74VFU.mjs → chunk-6SQYXUVP.mjs} +2 -2
  21. package/dist/{chunk-CRI4T47Y.js → chunk-G6UE6MEP.js} +814 -59
  22. package/dist/chunk-G6UE6MEP.js.map +1 -0
  23. package/dist/{chunk-XGTQWBDJ.js → chunk-KSYQEKJX.js} +11 -111
  24. package/dist/chunk-KSYQEKJX.js.map +1 -0
  25. package/dist/{chunk-EO75CV76.js → chunk-S4YJ5WCW.js} +8 -8
  26. package/dist/{chunk-EO75CV76.js.map → chunk-S4YJ5WCW.js.map} +1 -1
  27. package/dist/{chunk-3BAM23VA.js → chunk-TY5FYP3G.js} +930 -883
  28. package/dist/chunk-TY5FYP3G.js.map +1 -0
  29. package/dist/{chunk-JQWI62NV.mjs → chunk-VC5A3AUZ.mjs} +776 -21
  30. package/dist/chunk-VC5A3AUZ.mjs.map +1 -0
  31. package/dist/{chunk-FNTQQFLH.mjs → chunk-W7F5BDSV.mjs} +2 -2
  32. package/dist/{chunk-QQQE3N2X.js → chunk-WPYT4UKJ.js} +3 -3
  33. package/dist/{chunk-QQQE3N2X.js.map → chunk-WPYT4UKJ.js.map} +1 -1
  34. package/dist/{chunk-MIZTWBPX.mjs → chunk-X5WIUUNG.mjs} +1485 -1438
  35. package/dist/chunk-X5WIUUNG.mjs.map +1 -0
  36. package/dist/chunk-YDYVJM4I.js +107 -0
  37. package/dist/chunk-YDYVJM4I.js.map +1 -0
  38. package/dist/client/index.js +5 -5
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/index.mjs +4 -4
  41. package/dist/components/editors/server.d.mts +15 -0
  42. package/dist/components/editors/server.d.ts +15 -0
  43. package/dist/components/editors/server.js +38 -0
  44. package/dist/components/editors/server.js.map +1 -0
  45. package/dist/components/editors/server.mjs +38 -0
  46. package/dist/components/editors/server.mjs.map +1 -0
  47. package/dist/components/index.d.mts +46 -12
  48. package/dist/components/index.d.ts +46 -12
  49. package/dist/components/index.js +7 -5
  50. package/dist/components/index.js.map +1 -1
  51. package/dist/components/index.mjs +8 -6
  52. package/dist/contexts/index.d.mts +9 -1
  53. package/dist/contexts/index.d.ts +9 -1
  54. package/dist/contexts/index.js +5 -5
  55. package/dist/contexts/index.mjs +4 -4
  56. package/dist/core/index.d.mts +214 -3
  57. package/dist/core/index.d.ts +214 -3
  58. package/dist/core/index.js +38 -4
  59. package/dist/core/index.js.map +1 -1
  60. package/dist/core/index.mjs +37 -3
  61. package/dist/email-automations/index.d.mts +3 -0
  62. package/dist/email-automations/index.d.ts +3 -0
  63. package/dist/email-automations/index.js +99 -95
  64. package/dist/email-automations/index.js.map +1 -1
  65. package/dist/email-automations/index.mjs +30 -26
  66. package/dist/email-automations/index.mjs.map +1 -1
  67. package/dist/features/analytics/index.d.mts +11 -4
  68. package/dist/features/analytics/index.d.ts +11 -4
  69. package/dist/features/analytics/index.js +127 -135
  70. package/dist/features/analytics/index.js.map +1 -1
  71. package/dist/features/analytics/index.mjs +16 -24
  72. package/dist/features/analytics/index.mjs.map +1 -1
  73. package/dist/features/analytics/server.d.mts +5 -2
  74. package/dist/features/analytics/server.d.ts +5 -2
  75. package/dist/features/analytics/server.js +9 -8
  76. package/dist/features/analytics/server.js.map +1 -1
  77. package/dist/features/analytics/server.mjs +7 -6
  78. package/dist/features/analytics/server.mjs.map +1 -1
  79. package/dist/features/blog/index.css +30 -0
  80. package/dist/features/blog/index.css.map +1 -0
  81. package/dist/features/blog/index.d.mts +276 -0
  82. package/dist/features/blog/index.d.ts +276 -0
  83. package/dist/features/blog/index.js +1810 -0
  84. package/dist/features/blog/index.js.map +1 -0
  85. package/dist/features/blog/index.mjs +1810 -0
  86. package/dist/features/blog/index.mjs.map +1 -0
  87. package/dist/features/blog/server.d.mts +36 -0
  88. package/dist/features/blog/server.d.ts +36 -0
  89. package/dist/features/blog/server.js +167 -0
  90. package/dist/features/blog/server.js.map +1 -0
  91. package/dist/features/blog/server.mjs +167 -0
  92. package/dist/features/blog/server.mjs.map +1 -0
  93. package/dist/features/help/index.js +38 -38
  94. package/dist/features/help/index.mjs +4 -4
  95. package/dist/features/tokenusage/index.d.mts +1 -3
  96. package/dist/features/tokenusage/index.d.ts +1 -3
  97. package/dist/features/tokenusage/index.js +127 -135
  98. package/dist/features/tokenusage/index.js.map +1 -1
  99. package/dist/features/tokenusage/index.mjs +10 -18
  100. package/dist/features/tokenusage/index.mjs.map +1 -1
  101. package/dist/index.d.mts +4 -2
  102. package/dist/index.d.ts +4 -2
  103. package/dist/index.js +39 -5
  104. package/dist/index.js.map +1 -1
  105. package/dist/index.mjs +38 -4
  106. package/dist/{s3.service-CY-jgOAM.d.ts → s3.service-Bz_K-tjz.d.ts} +11 -0
  107. package/dist/{s3.service-Sri0QP7Z.d.mts → s3.service-D5zNCEW3.d.mts} +11 -0
  108. package/dist/server/index.d.mts +1 -1
  109. package/dist/server/index.d.ts +1 -1
  110. package/dist/server/index.js +9 -7
  111. package/dist/server/index.js.map +1 -1
  112. package/dist/server/index.mjs +13 -11
  113. package/messages/en.json +93 -0
  114. package/messages/it.json +93 -0
  115. package/package.json +19 -1
  116. package/src/components/editors/BlockNoteEditor.tsx +13 -3
  117. package/src/components/editors/server/BlockNoteServerContent.tsx +28 -0
  118. package/src/components/editors/server/__tests__/renderBlockNoteHTML.spec.ts +44 -0
  119. package/src/components/editors/server/renderBlockNoteHTML.ts +26 -0
  120. package/src/components/editors/server-entry.ts +7 -0
  121. package/src/components/forms/FormBlockNote.tsx +4 -0
  122. package/src/components/index.ts +1 -0
  123. package/src/components/navigations/ContentTitle.tsx +14 -3
  124. package/src/components/viewers/BlockNoteStaticViewer.tsx +44 -0
  125. package/src/core/index.ts +4 -0
  126. package/src/core/registry/ModuleRegistry.ts +6 -0
  127. package/src/features/administration/components/AdminIndexContainer.tsx +61 -33
  128. package/src/features/administration/components/__tests__/AdminIndexContainer.spec.tsx +61 -1
  129. package/src/features/administration/components/index.ts +2 -1
  130. package/src/features/administration/contexts/AdministrationContext.tsx +11 -3
  131. package/src/features/administration/contexts/__tests__/AdministrationContext.spec.tsx +40 -0
  132. package/src/features/ai-connection/ai-connection.module.ts +2 -0
  133. package/src/features/ai-connection/contexts/AiConnectionsContext.tsx +3 -16
  134. package/src/features/ai-connection/contexts/__tests__/AiConnectionsContext.spec.tsx +33 -0
  135. package/src/features/analytics/__tests__/server-entry.spec.tsx +2 -1
  136. package/src/features/analytics/analytics.modules.ts +22 -5
  137. package/src/features/analytics/components/AnalyticsAdminContainer.tsx +4 -3
  138. package/src/features/analytics/components/AnalyticsAdminPageContainer.tsx +6 -3
  139. package/src/features/analytics/components/AnalyticsJourneyContainer.tsx +4 -3
  140. package/src/features/analytics/components/__tests__/AnalyticsJourneyContainer.spec.tsx +11 -0
  141. package/src/features/analytics/components/__tests__/AnalyticsPageContainers.spec.tsx +12 -1
  142. package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +6 -3
  143. package/src/features/analytics/contexts/AnalyticsAdminContext.tsx +8 -17
  144. package/src/features/analytics/contexts/__tests__/AnalyticsAdminContext.spec.tsx +17 -0
  145. package/src/features/billing/stripe-price/stripe-price.module.ts +2 -0
  146. package/src/features/billing/stripe-product/stripe-product.module.ts +2 -0
  147. package/src/features/blog/BlogModules.ts +49 -0
  148. package/src/features/blog/components/admin/BlogAdminContainer.tsx +39 -0
  149. package/src/features/blog/components/admin/BlogCategoriesList.tsx +56 -0
  150. package/src/features/blog/components/admin/BlogCategoryEditor.tsx +230 -0
  151. package/src/features/blog/components/admin/BlogCoverImageField.tsx +123 -0
  152. package/src/features/blog/components/admin/BlogLayoutSetting.tsx +86 -0
  153. package/src/features/blog/components/admin/BlogPostComparison.tsx +54 -0
  154. package/src/features/blog/components/admin/BlogPostContainer.tsx +101 -0
  155. package/src/features/blog/components/admin/BlogPostDeleter.tsx +35 -0
  156. package/src/features/blog/components/admin/BlogPostEditor.tsx +216 -0
  157. package/src/features/blog/components/admin/BlogPostPublishButton.tsx +50 -0
  158. package/src/features/blog/components/admin/BlogPostTranslationEditor.tsx +118 -0
  159. package/src/features/blog/components/admin/BlogPostTranslationPanel.tsx +136 -0
  160. package/src/features/blog/components/admin/BlogPostsList.tsx +58 -0
  161. package/src/features/blog/components/admin/BlogTranslationStatus.tsx +104 -0
  162. package/src/features/blog/components/admin/__tests__/BlogPostTranslationPanel.spec.tsx +100 -0
  163. package/src/features/blog/components/admin/__tests__/BlogPostsList.spec.tsx +30 -0
  164. package/src/features/blog/components/admin/index.ts +14 -0
  165. package/src/features/blog/components/public/BlogCategoryChips.tsx +59 -0
  166. package/src/features/blog/components/public/BlogList.tsx +21 -0
  167. package/src/features/blog/components/public/BlogListColumn.tsx +53 -0
  168. package/src/features/blog/components/public/BlogListFeatured.tsx +57 -0
  169. package/src/features/blog/components/public/BlogListParts.tsx +74 -0
  170. package/src/features/blog/components/public/BlogListRail.tsx +62 -0
  171. package/src/features/blog/components/public/BlogPostCard.tsx +125 -0
  172. package/src/features/blog/components/public/BlogPostMeta.tsx +49 -0
  173. package/src/features/blog/components/public/BlogPostView.tsx +80 -0
  174. package/src/features/blog/components/public/BlogSearchBox.tsx +52 -0
  175. package/src/features/blog/components/public/__tests__/BlogList.spec.tsx +175 -0
  176. package/src/features/blog/components/public/__tests__/BlogPostView.spec.tsx +134 -0
  177. package/src/features/blog/components/public/blogPublicHelpers.ts +30 -0
  178. package/src/features/blog/components/public/index.ts +3 -0
  179. package/src/features/blog/contexts/BlogPostContext.tsx +66 -0
  180. package/src/features/blog/contexts/index.ts +1 -0
  181. package/src/features/blog/data/BlogCategory.ts +93 -0
  182. package/src/features/blog/data/BlogCategoryFields.ts +4 -0
  183. package/src/features/blog/data/BlogCategoryInterface.ts +24 -0
  184. package/src/features/blog/data/BlogCategoryService.ts +54 -0
  185. package/src/features/blog/data/BlogCategoryTranslation.ts +90 -0
  186. package/src/features/blog/data/BlogCategoryTranslationInterface.ts +22 -0
  187. package/src/features/blog/data/BlogCategoryTranslationService.ts +30 -0
  188. package/src/features/blog/data/BlogPost.spec.ts +123 -0
  189. package/src/features/blog/data/BlogPost.ts +159 -0
  190. package/src/features/blog/data/BlogPostFields.ts +7 -0
  191. package/src/features/blog/data/BlogPostInterface.ts +39 -0
  192. package/src/features/blog/data/BlogPostService.ts +82 -0
  193. package/src/features/blog/data/BlogPostTranslation.spec.ts +73 -0
  194. package/src/features/blog/data/BlogPostTranslation.ts +110 -0
  195. package/src/features/blog/data/BlogPostTranslationInterface.ts +27 -0
  196. package/src/features/blog/data/BlogPostTranslationService.ts +30 -0
  197. package/src/features/blog/data/BlogSettings.ts +37 -0
  198. package/src/features/blog/data/BlogSettingsInterface.ts +11 -0
  199. package/src/features/blog/data/BlogSettingsService.ts +24 -0
  200. package/src/features/blog/data/index.ts +17 -0
  201. package/src/features/blog/hooks/index.ts +3 -0
  202. package/src/features/blog/hooks/useBlogCategoryNames.ts +34 -0
  203. package/src/features/blog/hooks/useBlogCategoryTableStructure.tsx +84 -0
  204. package/src/features/blog/hooks/useBlogPostTableStructure.tsx +126 -0
  205. package/src/features/blog/index.ts +15 -0
  206. package/src/features/blog/server/fetchers.ts +169 -0
  207. package/src/features/blog/server/toPublic.spec.ts +91 -0
  208. package/src/features/blog/server/toPublic.ts +36 -0
  209. package/src/features/blog/server-entry.ts +17 -0
  210. package/src/features/blog/types/blog-public.types.ts +34 -0
  211. package/src/features/blog/types/blog.constants.ts +40 -0
  212. package/src/features/email-automation/components/containers/EmailAutomationsListContainer.tsx +12 -3
  213. package/src/features/rbac/contexts/RbacContext.tsx +4 -7
  214. package/src/features/rbac/contexts/__tests__/RbacContext.spec.tsx +42 -0
  215. package/src/features/s3/data/s3.service.ts +17 -0
  216. package/src/features/tokenusage/components/TokenUsageAdminContainer.tsx +4 -3
  217. package/src/features/tokenusage/contexts/TokenUsageAdminContext.tsx +3 -18
  218. package/src/features/tokenusage/contexts/__tests__/TokenUsageAdminContext.spec.tsx +17 -0
  219. package/src/features/tokenusage/tokenusage-admin.module.ts +4 -3
  220. package/src/features/tokenusage/tokenusage.modules.ts +12 -2
  221. package/src/features/user/contexts/UserContext.tsx +18 -3
  222. package/src/features/user/contexts/__tests__/UserContext.spec.tsx +95 -0
  223. package/dist/BlockNoteEditor-UJ6363LC.js.map +0 -1
  224. package/dist/BlockNoteEditor-WTSQANKI.mjs.map +0 -1
  225. package/dist/chunk-3BAM23VA.js.map +0 -1
  226. package/dist/chunk-CRI4T47Y.js.map +0 -1
  227. package/dist/chunk-JQWI62NV.mjs.map +0 -1
  228. package/dist/chunk-MIZTWBPX.mjs.map +0 -1
  229. package/dist/chunk-QKZUE5OF.mjs.map +0 -1
  230. package/dist/chunk-XGTQWBDJ.js.map +0 -1
  231. /package/dist/{BlockNoteViewer-JVKWJZ6J.mjs.map → BlockNoteViewer-U6E3DS4F.mjs.map} +0 -0
  232. /package/dist/{chunk-6WU74VFU.mjs.map → chunk-6SQYXUVP.mjs.map} +0 -0
  233. /package/dist/{chunk-FNTQQFLH.mjs.map → chunk-W7F5BDSV.mjs.map} +0 -0
@@ -0,0 +1,1810 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ var _chunkTY5FYP3Gjs = require('../../chunk-TY5FYP3G.js');
41
+ require('../../chunk-S4YJ5WCW.js');
42
+ require('../../chunk-G4JR3SFV.js');
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+ var _chunkG6UE6MEPjs = require('../../chunk-G6UE6MEP.js');
68
+ require('../../chunk-GHE4VT2R.js');
69
+ require('../../chunk-LXKSUWAV.js');
70
+ require('../../chunk-JTPRJNT2.js');
71
+ require('../../chunk-3EPNHTMH.js');
72
+
73
+
74
+ var _chunk7QVYU63Ejs = require('../../chunk-7QVYU63E.js');
75
+
76
+ // src/features/blog/components/admin/BlogAdminContainer.tsx
77
+ var _nextintl = require('next-intl');
78
+
79
+ // src/features/blog/components/admin/BlogCategoriesList.tsx
80
+ var _lucidereact = require('lucide-react');
81
+
82
+
83
+ // src/features/blog/hooks/useBlogCategoryTableStructure.tsx
84
+
85
+ var _react = require('react');
86
+
87
+ // src/features/blog/components/admin/BlogCategoryEditor.tsx
88
+ var _zod = require('@hookform/resolvers/zod');
89
+
90
+
91
+
92
+ var _reacthookform = require('react-hook-form');
93
+ var _uuid = require('uuid');
94
+ var _zod3 = require('zod');
95
+
96
+ // src/features/blog/components/admin/BlogCoverImageField.tsx
97
+
98
+ var _image = require('next/image'); var _image2 = _interopRequireDefault(_image);
99
+
100
+ var _jsxruntime = require('react/jsx-runtime');
101
+ var dropzone = {
102
+ multiple: false,
103
+ maxSize: 100 * 1024 * 1024,
104
+ preventDropOnDocument: false,
105
+ accept: {
106
+ "application/images": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"]
107
+ }
108
+ };
109
+ async function uploadBlogImage(params) {
110
+ if (!params.selection || !params.key) return;
111
+ await _chunkG6UE6MEPjs.S3Service.upload({
112
+ key: params.key,
113
+ contentType: params.selection.contentType,
114
+ file: params.selection.file,
115
+ isPublic: true
116
+ });
117
+ }
118
+ _chunk7QVYU63Ejs.__name.call(void 0, uploadBlogImage, "uploadBlogImage");
119
+ function BlogCoverImageField({
120
+ form,
121
+ id,
122
+ label,
123
+ keyPrefix,
124
+ entityId,
125
+ currentUrl,
126
+ alt,
127
+ selection,
128
+ onSelectionChange
129
+ }) {
130
+ const [files, setFiles] = _react.useState.call(void 0, null);
131
+ _react.useEffect.call(void 0, () => {
132
+ if (selection === null) setFiles(null);
133
+ }, [selection]);
134
+ const previewUrl = _react.useMemo.call(void 0, () => selection ? URL.createObjectURL(selection.file) : void 0, [selection]);
135
+ _react.useEffect.call(void 0, () => {
136
+ return () => {
137
+ if (previewUrl) URL.revokeObjectURL(previewUrl);
138
+ };
139
+ }, [previewUrl]);
140
+ const src = _nullishCoalesce(previewUrl, () => ( currentUrl));
141
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormFieldWrapper, { form, name: id, label, children: (field) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
142
+ _chunkTY5FYP3Gjs.FileUploader,
143
+ {
144
+ value: files,
145
+ onValueChange: (value) => {
146
+ setFiles(value);
147
+ const file = _optionalChain([value, 'optionalAccess', _ => _[0]]);
148
+ if (!file) return;
149
+ const extension = _nullishCoalesce(file.type.split("/").pop(), () => ( ""));
150
+ field.onChange(`${keyPrefix}/${entityId}/${entityId}.${Date.now()}.${extension}`);
151
+ onSelectionChange({ file, contentType: file.type });
152
+ },
153
+ dropzoneOptions: dropzone,
154
+ className: "w-full",
155
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FileInput, { className: "text-muted-foreground/50 rounded-lg outline-1 outline-dashed", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex w-full flex-col items-center justify-center p-4", children: src ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
156
+ _image2.default,
157
+ {
158
+ src,
159
+ alt: _nullishCoalesce(alt, () => ( label)),
160
+ width: 320,
161
+ height: 180,
162
+ className: "h-auto max-h-48 w-auto max-w-full rounded-md object-cover",
163
+ unoptimized: _chunkG6UE6MEPjs.isRemoteImageSrc.call(void 0, previewUrl ? void 0 : currentUrl)
164
+ }
165
+ ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
166
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.UploadIcon, { className: "my-4 h-8 w-8" }),
167
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: label })
168
+ ] }) }) })
169
+ }
170
+ ) });
171
+ }
172
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogCoverImageField, "BlogCoverImageField");
173
+
174
+ // src/features/blog/components/admin/BlogTranslationStatus.tsx
175
+
176
+
177
+
178
+
179
+ var BLOG_STATUS_BADGE = {
180
+ draft: "softGray",
181
+ published: "softGreen",
182
+ unpublished: "softAmber"
183
+ };
184
+ function blogCategoryAdminName(category) {
185
+ return _nullishCoalesce(_nullishCoalesce(_optionalChain([category, 'access', _2 => _2.original, 'optionalAccess', _3 => _3.name]), () => ( category.name)), () => ( ""));
186
+ }
187
+ _chunk7QVYU63Ejs.__name.call(void 0, blogCategoryAdminName, "blogCategoryAdminName");
188
+ function useBlogLanguageName() {
189
+ const locale = _chunkG6UE6MEPjs.useI18nLocale.call(void 0, );
190
+ const names = _react.useMemo.call(void 0, () => {
191
+ try {
192
+ return new Intl.DisplayNames([locale], { type: "language" });
193
+ } catch (e) {
194
+ return void 0;
195
+ }
196
+ }, [locale]);
197
+ return _react.useCallback.call(void 0,
198
+ (language) => {
199
+ const name = _optionalChain([names, 'optionalAccess', _4 => _4.of, 'call', _5 => _5(language)]);
200
+ if (!name) return language;
201
+ return name.charAt(0).toLocaleUpperCase(locale) + name.slice(1);
202
+ },
203
+ [names, locale]
204
+ );
205
+ }
206
+ _chunk7QVYU63Ejs.__name.call(void 0, useBlogLanguageName, "useBlogLanguageName");
207
+ function useBlogDateFormatter() {
208
+ const locale = _chunkG6UE6MEPjs.useI18nLocale.call(void 0, );
209
+ return _react.useCallback.call(void 0, (date) => date ? date.toLocaleDateString(locale, { dateStyle: "medium" }) : "", [locale]);
210
+ }
211
+ _chunk7QVYU63Ejs.__name.call(void 0, useBlogDateFormatter, "useBlogDateFormatter");
212
+ function BlogTranslationStatus({ aiStatus, onRetranslate }) {
213
+ const t = _nextintl.useTranslations.call(void 0, );
214
+ const [isRetrying, setIsRetrying] = _react.useState.call(void 0, false);
215
+ if (aiStatus === "completed") return null;
216
+ if (aiStatus === "pending" || aiStatus === "in_progress") {
217
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-x-2", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softBlue", children: [
218
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircleIcon, { className: "animate-spin" }),
219
+ aiStatus === "pending" ? t("blog.translation.pending") : t("blog.translation.translating")
220
+ ] }) });
221
+ }
222
+ const retranslate = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, async () => {
223
+ if (!onRetranslate) return;
224
+ setIsRetrying(true);
225
+ try {
226
+ await onRetranslate();
227
+ } catch (error) {
228
+ _chunkTY5FYP3Gjs.errorToast.call(void 0, { title: t("common.errors.error"), error });
229
+ } finally {
230
+ setIsRetrying(false);
231
+ }
232
+ }, "retranslate");
233
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-x-2", children: [
234
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softRed", children: t("blog.translation.failed") }),
235
+ onRetranslate && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.Button, { type: "button", size: "sm", variant: "outline", onClick: () => void retranslate(), disabled: isRetrying, children: [
236
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.RotateCcwIcon, {}),
237
+ t("blog.actions.translateAgain")
238
+ ] })
239
+ ] });
240
+ }
241
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogTranslationStatus, "BlogTranslationStatus");
242
+
243
+ // src/features/blog/components/admin/BlogCategoryEditor.tsx
244
+
245
+ var buildTranslationSchema = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (t) => _zod3.z.object({
246
+ id: _zod3.z.string(),
247
+ name: _zod3.z.string().min(1, { message: t("blog.errors.name") }),
248
+ slug: _zod3.z.string().optional(),
249
+ description: _zod3.z.string().optional()
250
+ }), "buildTranslationSchema");
251
+ var buildFormSchema = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (t) => _zod3.z.object({
252
+ id: _zod3.z.string().uuid(),
253
+ originalLanguage: _zod3.z.string().min(1, { message: t("blog.errors.language") }),
254
+ name: _zod3.z.string().min(1, { message: t("blog.errors.name") }),
255
+ slug: _zod3.z.string().optional(),
256
+ description: _zod3.z.string().optional(),
257
+ image: _zod3.z.string().optional(),
258
+ translations: _zod3.z.array(buildTranslationSchema(t))
259
+ }), "buildFormSchema");
260
+ var sameTranslation = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (a, b) => !!b && a.name === b.name && (_nullishCoalesce(a.slug, () => ( ""))) === (_nullishCoalesce(b.slug, () => ( ""))) && (_nullishCoalesce(a.description, () => ( ""))) === (_nullishCoalesce(b.description, () => ( ""))), "sameTranslation");
261
+ function BlogCategoryEditor({ category, trigger, onSuccess }) {
262
+ const t = _nextintl.useTranslations.call(void 0, );
263
+ const formSchema = _react.useMemo.call(void 0, () => buildFormSchema(t), [t]);
264
+ const locale = _chunkG6UE6MEPjs.useI18nLocale.call(void 0, );
265
+ const languageName = useBlogLanguageName();
266
+ const [image, setImage] = _react.useState.call(void 0, null);
267
+ const languages = _react.useMemo.call(void 0, () => _chunkG6UE6MEPjs.getI18nSupportedLocales.call(void 0, ), []);
268
+ const original = _optionalChain([category, 'optionalAccess', _6 => _6.original]);
269
+ const translations = _react.useMemo.call(void 0,
270
+ () => (_nullishCoalesce(_optionalChain([category, 'optionalAccess', _7 => _7.translations]), () => ( []))).filter((translation) => !translation.isOriginal),
271
+ [category]
272
+ );
273
+ const getDefaultValues = _react.useCallback.call(void 0,
274
+ () => ({
275
+ id: _optionalChain([category, 'optionalAccess', _8 => _8.id]) || _uuid.v4.call(void 0, ),
276
+ originalLanguage: _nullishCoalesce(_optionalChain([category, 'optionalAccess', _9 => _9.originalLanguage]), () => ( (languages.includes(locale) ? locale : languages[0]))),
277
+ name: _nullishCoalesce(_nullishCoalesce(_optionalChain([original, 'optionalAccess', _10 => _10.name]), () => ( _optionalChain([category, 'optionalAccess', _11 => _11.name]))), () => ( "")),
278
+ slug: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _12 => _12.slug]), () => ( "")),
279
+ description: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _13 => _13.description]), () => ( "")),
280
+ // The stored value is a signed URL, not a key: only a newly picked file writes a key.
281
+ image: "",
282
+ translations: translations.map((translation) => ({
283
+ id: translation.id,
284
+ name: _nullishCoalesce(translation.name, () => ( "")),
285
+ slug: _nullishCoalesce(translation.slug, () => ( "")),
286
+ description: _nullishCoalesce(translation.description, () => ( ""))
287
+ }))
288
+ }),
289
+ [category, original, translations, languages, locale]
290
+ );
291
+ const form = _reacthookform.useForm.call(void 0, {
292
+ resolver: _zod.zodResolver.call(void 0, formSchema),
293
+ defaultValues: getDefaultValues()
294
+ });
295
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
296
+ _chunkTY5FYP3Gjs.EditorSheet,
297
+ {
298
+ form,
299
+ entityType: t("blog.entities.category"),
300
+ entityName: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _14 => _14.name]), () => ( _optionalChain([category, 'optionalAccess', _15 => _15.name]))),
301
+ title: category ? t("blog.admin.editCategory") : t("blog.admin.newCategory"),
302
+ isEdit: !!category,
303
+ module: _chunkG6UE6MEPjs.Modules.BlogCategory,
304
+ size: "md",
305
+ onSubmit: async (values) => {
306
+ if (values.image && image) await uploadBlogImage({ key: values.image, selection: image });
307
+ const imageKey = values.image && image ? values.image : void 0;
308
+ if (!category) {
309
+ return _chunkG6UE6MEPjs.BlogCategoryService.create({
310
+ id: values.id,
311
+ originalLanguage: values.originalLanguage,
312
+ name: values.name,
313
+ description: values.description,
314
+ image: imageKey
315
+ });
316
+ }
317
+ const defaults = getDefaultValues();
318
+ const originalChanged = !!imageKey || !sameTranslation(
319
+ { id: values.id, name: values.name, slug: values.slug, description: values.description },
320
+ { id: defaults.id, name: defaults.name, slug: defaults.slug, description: defaults.description }
321
+ );
322
+ if (originalChanged) {
323
+ await _chunkG6UE6MEPjs.BlogCategoryService.update({
324
+ id: values.id,
325
+ originalLanguage: _optionalChain([category, 'optionalAccess', _16 => _16.originalLanguage]),
326
+ name: values.name,
327
+ slug: values.slug || void 0,
328
+ description: values.description,
329
+ image: imageKey
330
+ });
331
+ }
332
+ for (const translation of values.translations) {
333
+ const before = defaults.translations.find((candidate) => candidate.id === translation.id);
334
+ if (sameTranslation(translation, before)) continue;
335
+ await _chunkG6UE6MEPjs.BlogCategoryTranslationService.update({
336
+ id: translation.id,
337
+ name: translation.name,
338
+ slug: translation.slug || void 0,
339
+ description: translation.description
340
+ });
341
+ }
342
+ return { id: values.id };
343
+ },
344
+ onReset: () => {
345
+ setImage(null);
346
+ return getDefaultValues();
347
+ },
348
+ onSuccess: _nullishCoalesce(onSuccess, () => ( (() => {
349
+ }))),
350
+ trigger,
351
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-y-4", children: [
352
+ !category && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
353
+ _chunkTY5FYP3Gjs.FormSelect,
354
+ {
355
+ form,
356
+ id: "originalLanguage",
357
+ name: t("blog.fields.originalLanguage"),
358
+ values: languages.map((language) => ({ id: language, text: languageName(language) })),
359
+ isRequired: true
360
+ }
361
+ ),
362
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "name", name: t("blog.fields.name"), isRequired: true }),
363
+ category && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "slug", name: t("blog.fields.slug"), description: t("blog.fields.slugHelp") }),
364
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormTextarea, { form, id: "description", name: t("blog.fields.description") }),
365
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
366
+ BlogCoverImageField,
367
+ {
368
+ form,
369
+ id: "image",
370
+ label: t("blog.fields.image"),
371
+ keyPrefix: _chunkG6UE6MEPjs.BLOG_CATEGORY_UPLOAD_PREFIX,
372
+ entityId: form.getValues("id"),
373
+ currentUrl: _optionalChain([category, 'optionalAccess', _17 => _17.image]),
374
+ selection: image,
375
+ onSelectionChange: setImage
376
+ }
377
+ ),
378
+ translations.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-2", children: [
379
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.SectionHeader, { className: "mt-2", children: t("blog.fields.languages") }),
380
+ translations.map((translation, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.Collapsible, { className: "rounded-md border", children: [
381
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.CollapsibleTrigger, { className: "flex w-full items-center justify-between gap-x-2 px-3 py-2 text-start", children: [
382
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-x-2 text-sm font-medium", children: [
383
+ languageName(translation.language),
384
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogTranslationStatus, { aiStatus: translation.aiStatus })
385
+ ] }),
386
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronDownIcon, { className: "text-muted-foreground size-4" })
387
+ ] }),
388
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.CollapsibleContent, { className: "flex flex-col gap-y-4 border-t p-3", children: [
389
+ translation.aiStatus === "failed" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
390
+ BlogTranslationStatus,
391
+ {
392
+ aiStatus: translation.aiStatus,
393
+ onRetranslate: async () => {
394
+ await _chunkG6UE6MEPjs.BlogCategoryTranslationService.retranslate({ id: translation.id });
395
+ await _optionalChain([onSuccess, 'optionalCall', _18 => _18()]);
396
+ }
397
+ }
398
+ ),
399
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: `translations.${index}.name`, name: t("blog.fields.name"), isRequired: true }),
400
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
401
+ _chunkTY5FYP3Gjs.FormInput,
402
+ {
403
+ form,
404
+ id: `translations.${index}.slug`,
405
+ name: t("blog.fields.slug"),
406
+ description: t("blog.fields.slugHelp")
407
+ }
408
+ ),
409
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
410
+ _chunkTY5FYP3Gjs.FormTextarea,
411
+ {
412
+ form,
413
+ id: `translations.${index}.description`,
414
+ name: t("blog.fields.description")
415
+ }
416
+ )
417
+ ] })
418
+ ] }, translation.id))
419
+ ] })
420
+ ] })
421
+ }
422
+ );
423
+ }
424
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogCategoryEditor, "BlogCategoryEditor");
425
+
426
+ // src/features/blog/hooks/useBlogCategoryTableStructure.tsx
427
+
428
+ var useBlogCategoryTableStructure = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (params) => {
429
+ const t = _nextintl.useTranslations.call(void 0, );
430
+ const refresh = _optionalChain([params, 'access', _19 => _19.dataRetriever, 'optionalAccess', _20 => _20.refresh]);
431
+ const tableData = _react.useMemo.call(void 0, () => {
432
+ return params.data.map((category) => {
433
+ const entry = { jsonApiData: category };
434
+ params.fields.forEach((field) => {
435
+ entry[field] = category[field];
436
+ });
437
+ return entry;
438
+ });
439
+ }, [params.data, params.fields]);
440
+ const fieldColumnMap = {
441
+ ["name" /* name */]: () => ({
442
+ id: "name" /* name */,
443
+ accessorKey: "name" /* name */,
444
+ header: t("blog.fields.name"),
445
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
446
+ const category = row.original.jsonApiData;
447
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
448
+ BlogCategoryEditor,
449
+ {
450
+ category,
451
+ onSuccess: refresh,
452
+ trigger: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "text-primary text-start font-medium", children: blogCategoryAdminName(category) || category.id })
453
+ }
454
+ );
455
+ }, "cell"),
456
+ enableSorting: false,
457
+ enableHiding: false
458
+ }),
459
+ ["languages" /* languages */]: () => ({
460
+ id: "languages" /* languages */,
461
+ accessorKey: "languages" /* languages */,
462
+ header: t("blog.fields.languages"),
463
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
464
+ const category = row.original.jsonApiData;
465
+ const total = category.translations.length;
466
+ if (total === 0) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: "\u2014" });
467
+ const ready = category.translations.filter((translation) => translation.aiStatus === "completed").length;
468
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "block text-xs tabular-nums text-end", children: [
469
+ ready,
470
+ "/",
471
+ total
472
+ ] });
473
+ }, "cell"),
474
+ enableSorting: false,
475
+ enableHiding: false
476
+ })
477
+ };
478
+ const columns = _react.useMemo.call(void 0, () => {
479
+ return params.fields.map((field) => _optionalChain([fieldColumnMap, 'access', _21 => _21[field], 'optionalCall', _22 => _22()])).filter((col) => col !== void 0);
480
+ }, [params.fields, fieldColumnMap, t, refresh]);
481
+ return _react.useMemo.call(void 0, () => ({ data: tableData, columns }), [tableData, columns]);
482
+ }, "useBlogCategoryTableStructure");
483
+ _chunkTY5FYP3Gjs.registerTableGenerator.call(void 0, "blog-categories", useBlogCategoryTableStructure);
484
+
485
+ // src/features/blog/components/admin/BlogCategoriesList.tsx
486
+
487
+ function BlogCategoriesList({ fullWidth } = {}) {
488
+ const t = _nextintl.useTranslations.call(void 0, );
489
+ const data = _chunkTY5FYP3Gjs.useDataListRetriever.call(void 0, {
490
+ retriever: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (params) => _chunkG6UE6MEPjs.BlogCategoryService.findMany(params), "retriever"),
491
+ retrieverParams: {},
492
+ module: _chunkG6UE6MEPjs.Modules.BlogCategory
493
+ });
494
+ const functions = [
495
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
496
+ BlogCategoryEditor,
497
+ {
498
+ onSuccess: data.refresh,
499
+ trigger: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Button, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}), nativeButton: false, size: "sm", variant: "outline", children: t("blog.admin.newCategory") })
500
+ },
501
+ "create-blog-category"
502
+ )
503
+ ];
504
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
505
+ _chunkTY5FYP3Gjs.ContentListTable,
506
+ {
507
+ data,
508
+ fields: ["name" /* name */, "languages" /* languages */],
509
+ tableGeneratorType: _chunkG6UE6MEPjs.Modules.BlogCategory,
510
+ functions,
511
+ fullWidth,
512
+ title: t("blog.entities.categories"),
513
+ emptyState: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.EmptyState, { icon: _lucidereact.TagIcon, title: t("blog.admin.emptyCategories") })
514
+ }
515
+ );
516
+ }
517
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogCategoriesList, "BlogCategoriesList");
518
+
519
+ // src/features/blog/components/admin/BlogLayoutSetting.tsx
520
+
521
+
522
+
523
+ function BlogLayoutSetting() {
524
+ const t = _nextintl.useTranslations.call(void 0, );
525
+ const [layout, setLayout] = _react.useState.call(void 0, void 0);
526
+ const [saving, setSaving] = _react.useState.call(void 0, false);
527
+ _react.useEffect.call(void 0, () => {
528
+ let active = true;
529
+ _chunkG6UE6MEPjs.BlogSettingsService.get().then((settings) => {
530
+ if (active) setLayout(_nullishCoalesce(_optionalChain([settings, 'optionalAccess', _23 => _23.listLayout]), () => ( "featured")));
531
+ }).catch(() => {
532
+ if (active) setLayout("featured");
533
+ });
534
+ return () => {
535
+ active = false;
536
+ };
537
+ }, []);
538
+ const options = {
539
+ featured: { label: t("blog.layout.featured"), description: t("blog.layout.featuredDescription") },
540
+ column: { label: t("blog.layout.column"), description: t("blog.layout.columnDescription") },
541
+ rail: { label: t("blog.layout.rail"), description: t("blog.layout.railDescription") }
542
+ };
543
+ const save = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, async (next) => {
544
+ const previous = layout;
545
+ setLayout(next);
546
+ setSaving(true);
547
+ try {
548
+ await _chunkG6UE6MEPjs.BlogSettingsService.save({ id: _chunkG6UE6MEPjs.BLOG_SETTINGS_ID, listLayout: next });
549
+ _chunkG6UE6MEPjs.showToast.call(void 0, t("blog.layout.saved"));
550
+ } catch (error) {
551
+ setLayout(previous);
552
+ _chunkTY5FYP3Gjs.errorToast.call(void 0, { title: t("common.errors.error"), error });
553
+ } finally {
554
+ setSaving(false);
555
+ }
556
+ }, "save");
557
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full max-w-3xl flex-col gap-y-4 p-4", children: [
558
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.SectionHeader, { children: t("blog.layout.title") }),
559
+ layout && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
560
+ _chunkTY5FYP3Gjs.RadioGroup,
561
+ {
562
+ value: layout,
563
+ onValueChange: (value) => {
564
+ if (!value || value === layout) return;
565
+ void save(value);
566
+ },
567
+ disabled: saving,
568
+ className: "grid grid-cols-1 gap-3 md:grid-cols-3",
569
+ children: _chunkG6UE6MEPjs.BLOG_LIST_LAYOUTS.map((option) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
570
+ "label",
571
+ {
572
+ htmlFor: `blog-layout-${option}`,
573
+ className: "has-data-checked:border-primary flex cursor-pointer items-start gap-x-3 rounded-lg border p-4",
574
+ children: [
575
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.RadioGroupItem, { value: option, id: `blog-layout-${option}`, className: "mt-0.5" }),
576
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex flex-col gap-y-1", children: [
577
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-medium", children: options[option].label }),
578
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs/relaxed", children: options[option].description })
579
+ ] })
580
+ ]
581
+ },
582
+ option
583
+ ))
584
+ }
585
+ )
586
+ ] });
587
+ }
588
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogLayoutSetting, "BlogLayoutSetting");
589
+
590
+ // src/features/blog/components/admin/BlogPostsList.tsx
591
+
592
+
593
+
594
+ // src/features/blog/hooks/useBlogPostTableStructure.tsx
595
+
596
+
597
+
598
+ // src/features/blog/hooks/useBlogCategoryNames.ts
599
+
600
+ function useBlogCategoryNames() {
601
+ const [names, setNames] = _react.useState.call(void 0, {});
602
+ _react.useEffect.call(void 0, () => {
603
+ let cancelled = false;
604
+ _chunkG6UE6MEPjs.BlogCategoryService.findMany({ fetchAll: true }).then((categories) => {
605
+ if (cancelled) return;
606
+ setNames(Object.fromEntries(categories.map((category) => [category.id, blogCategoryAdminName(category)])));
607
+ }).catch(() => {
608
+ });
609
+ return () => {
610
+ cancelled = true;
611
+ };
612
+ }, []);
613
+ return _react.useCallback.call(void 0, (categoryId) => _nullishCoalesce(names[categoryId], () => ( "")), [names]);
614
+ }
615
+ _chunk7QVYU63Ejs.__name.call(void 0, useBlogCategoryNames, "useBlogCategoryNames");
616
+
617
+ // src/features/blog/hooks/useBlogPostTableStructure.tsx
618
+
619
+ var useBlogPostTableStructure = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (params) => {
620
+ const t = _nextintl.useTranslations.call(void 0, );
621
+ const locale = _chunkG6UE6MEPjs.useI18nLocale.call(void 0, );
622
+ const generateUrl = _chunkTY5FYP3Gjs.usePageUrlGenerator.call(void 0, );
623
+ const categoryName = useBlogCategoryNames();
624
+ const tableData = _react.useMemo.call(void 0, () => {
625
+ return params.data.map((post) => {
626
+ const entry = { jsonApiData: post };
627
+ params.fields.forEach((field) => {
628
+ entry[field] = post[field];
629
+ });
630
+ return entry;
631
+ });
632
+ }, [params.data, params.fields]);
633
+ const fieldColumnMap = {
634
+ ["title" /* title */]: () => ({
635
+ id: "title" /* title */,
636
+ accessorKey: "title" /* title */,
637
+ header: t("blog.fields.title"),
638
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
639
+ const post = row.original.jsonApiData;
640
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Link, { href: generateUrl({ page: _chunkG6UE6MEPjs.Modules.BlogPost, id: post.id }), children: _nullishCoalesce(_nullishCoalesce(_optionalChain([post, 'access', _24 => _24.original, 'optionalAccess', _25 => _25.title]), () => ( post.title)), () => ( post.id)) });
641
+ }, "cell"),
642
+ enableSorting: false,
643
+ enableHiding: false
644
+ }),
645
+ ["status" /* status */]: () => ({
646
+ id: "status" /* status */,
647
+ accessorKey: "status" /* status */,
648
+ header: t("blog.fields.status"),
649
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
650
+ const post = row.original.jsonApiData;
651
+ const label = {
652
+ draft: t("blog.status.draft"),
653
+ published: t("blog.status.published"),
654
+ unpublished: t("blog.status.unpublished")
655
+ }[post.status];
656
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: _nullishCoalesce(BLOG_STATUS_BADGE[post.status], () => ( "softGray")), children: _nullishCoalesce(label, () => ( post.status)) });
657
+ }, "cell"),
658
+ enableSorting: false,
659
+ enableHiding: false
660
+ }),
661
+ ["categories" /* categories */]: () => ({
662
+ id: "categories" /* categories */,
663
+ accessorKey: "categories" /* categories */,
664
+ header: t("blog.fields.categories"),
665
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
666
+ const post = row.original.jsonApiData;
667
+ const names = post.categories.map((category) => categoryName(category.id)).filter(Boolean);
668
+ if (names.length === 0) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: "\u2014" });
669
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-xs", children: names.join(", ") });
670
+ }, "cell"),
671
+ enableSorting: false,
672
+ enableHiding: false
673
+ }),
674
+ ["publishedAt" /* publishedAt */]: () => ({
675
+ id: "publishedAt" /* publishedAt */,
676
+ accessorKey: "publishedAt" /* publishedAt */,
677
+ header: t("blog.fields.publishedAt"),
678
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
679
+ const post = row.original.jsonApiData;
680
+ if (!post.publishedAt) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: "\u2014" });
681
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-xs tabular-nums", children: post.publishedAt.toLocaleDateString(locale, { dateStyle: "medium" }) });
682
+ }, "cell"),
683
+ enableSorting: false,
684
+ enableHiding: false
685
+ }),
686
+ ["languages" /* languages */]: () => ({
687
+ id: "languages" /* languages */,
688
+ accessorKey: "languages" /* languages */,
689
+ header: t("blog.fields.languages"),
690
+ cell: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ row }) => {
691
+ const post = row.original.jsonApiData;
692
+ const total = post.translations.length;
693
+ if (total === 0) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: "\u2014" });
694
+ const ready = post.translations.filter((translation) => translation.aiStatus === "completed").length;
695
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "block text-xs tabular-nums text-end", children: [
696
+ ready,
697
+ "/",
698
+ total
699
+ ] });
700
+ }, "cell"),
701
+ enableSorting: false,
702
+ enableHiding: false
703
+ })
704
+ };
705
+ const columns = _react.useMemo.call(void 0, () => {
706
+ return params.fields.map((field) => _optionalChain([fieldColumnMap, 'access', _26 => _26[field], 'optionalCall', _27 => _27()])).filter((col) => col !== void 0);
707
+ }, [params.fields, fieldColumnMap, t, generateUrl, locale, categoryName]);
708
+ return _react.useMemo.call(void 0, () => ({ data: tableData, columns }), [tableData, columns]);
709
+ }, "useBlogPostTableStructure");
710
+ _chunkTY5FYP3Gjs.registerTableGenerator.call(void 0, "blog-posts", useBlogPostTableStructure);
711
+
712
+ // src/features/blog/components/admin/BlogPostEditor.tsx
713
+
714
+
715
+
716
+
717
+
718
+
719
+
720
+ var isBodyEmpty = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (body) => !body || Array.isArray(body) && body.length === 0, "isBodyEmpty");
721
+ function BlogPostEditor({ post, trigger, onSuccess }) {
722
+ const t = _nextintl.useTranslations.call(void 0, );
723
+ const categoryName = useBlogCategoryNames();
724
+ const router = _chunkG6UE6MEPjs.useI18nRouter.call(void 0, );
725
+ const locale = _chunkG6UE6MEPjs.useI18nLocale.call(void 0, );
726
+ const languageName = useBlogLanguageName();
727
+ const original = _optionalChain([post, 'optionalAccess', _28 => _28.original]);
728
+ const [cover, setCover] = _react.useState.call(void 0, null);
729
+ const [isBodyEmptyState, setIsBodyEmptyState] = _react.useState.call(void 0, isBodyEmpty(_optionalChain([original, 'optionalAccess', _29 => _29.body])));
730
+ const languages = _react.useMemo.call(void 0, () => _chunkG6UE6MEPjs.getI18nSupportedLocales.call(void 0, ), []);
731
+ const formSchema = _react.useMemo.call(void 0,
732
+ () => _zod3.z.object({
733
+ id: _zod3.z.string().uuid(),
734
+ originalLanguage: _zod3.z.string().min(1, { message: t("blog.errors.language") }),
735
+ title: _zod3.z.string().min(1, { message: t("blog.errors.title") }),
736
+ slug: _zod3.z.string().optional(),
737
+ summary: _zod3.z.string().optional(),
738
+ body: _zod3.z.any(),
739
+ coverImage: _zod3.z.string().optional(),
740
+ coverImageAlt: _zod3.z.string().optional(),
741
+ categories: _zod3.z.array(_zod3.z.object({ id: _zod3.z.string(), name: _zod3.z.string() }))
742
+ }),
743
+ []
744
+ );
745
+ const getDefaultValues = _react.useCallback.call(void 0,
746
+ () => ({
747
+ id: _optionalChain([post, 'optionalAccess', _30 => _30.id]) || _uuid.v4.call(void 0, ),
748
+ originalLanguage: _nullishCoalesce(_optionalChain([post, 'optionalAccess', _31 => _31.originalLanguage]), () => ( (languages.includes(locale) ? locale : languages[0]))),
749
+ title: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _32 => _32.title]), () => ( "")),
750
+ slug: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _33 => _33.slug]), () => ( "")),
751
+ summary: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _34 => _34.summary]), () => ( "")),
752
+ body: _optionalChain([original, 'optionalAccess', _35 => _35.body]) || [],
753
+ // The stored value is a signed URL, not a key: only a newly picked file
754
+ // writes a key here, and only then is the field sent.
755
+ coverImage: "",
756
+ coverImageAlt: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _36 => _36.coverImageAlt]), () => ( "")),
757
+ categories: (_nullishCoalesce(_optionalChain([post, 'optionalAccess', _37 => _37.categories]), () => ( []))).map((category) => ({
758
+ id: category.id,
759
+ name: blogCategoryAdminName(category)
760
+ }))
761
+ }),
762
+ [post, original, languages, locale]
763
+ );
764
+ const form = _reacthookform.useForm.call(void 0, {
765
+ resolver: _zod.zodResolver.call(void 0, formSchema),
766
+ defaultValues: getDefaultValues()
767
+ });
768
+ const { dirtyFields } = form.formState;
769
+ const isFormDirty = _react.useCallback.call(void 0, () => {
770
+ const dirty = { ...dirtyFields };
771
+ if (dirty.body && isBodyEmptyState) delete dirty.body;
772
+ return Object.keys(dirty).length > 0;
773
+ }, [dirtyFields, isBodyEmptyState]);
774
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
775
+ _chunkTY5FYP3Gjs.EditorSheet,
776
+ {
777
+ form,
778
+ entityType: t("blog.entities.post"),
779
+ entityName: _optionalChain([original, 'optionalAccess', _38 => _38.title]),
780
+ title: post ? t("blog.admin.editPost") : t("blog.admin.newPost"),
781
+ isEdit: !!post,
782
+ module: _chunkG6UE6MEPjs.Modules.BlogPost,
783
+ size: "lg",
784
+ isFormDirty,
785
+ onSubmit: async (values) => {
786
+ if (values.coverImage && cover) await uploadBlogImage({ key: values.coverImage, selection: cover });
787
+ const payload = {
788
+ id: values.id,
789
+ title: values.title,
790
+ // An empty summary lets the worker write one; on edit the summary is
791
+ // sent only when changed here, so an untouched AI summary is regenerated.
792
+ summary: post ? form.getFieldState("summary").isDirty ? values.summary : void 0 : values.summary || void 0,
793
+ body: values.body,
794
+ coverImage: values.coverImage && cover ? values.coverImage : void 0,
795
+ coverImageAlt: values.coverImageAlt,
796
+ categoryIds: values.categories.map((category) => category.id)
797
+ };
798
+ if (post) {
799
+ return _chunkG6UE6MEPjs.BlogPostService.update({
800
+ ...payload,
801
+ originalLanguage: post.originalLanguage,
802
+ slug: values.slug || void 0
803
+ });
804
+ }
805
+ return _chunkG6UE6MEPjs.BlogPostService.create({ ...payload, originalLanguage: values.originalLanguage });
806
+ },
807
+ onReset: () => {
808
+ setCover(null);
809
+ setIsBodyEmptyState(isBodyEmpty(_optionalChain([original, 'optionalAccess', _39 => _39.body])));
810
+ return getDefaultValues();
811
+ },
812
+ onSuccess,
813
+ onNavigate: (url) => router.push(url),
814
+ trigger,
815
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full min-h-0 w-full flex-col gap-y-4", children: [
816
+ !post && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
817
+ _chunkTY5FYP3Gjs.FormSelect,
818
+ {
819
+ form,
820
+ id: "originalLanguage",
821
+ name: t("blog.fields.originalLanguage"),
822
+ values: languages.map((language) => ({ id: language, text: languageName(language) })),
823
+ isRequired: true
824
+ }
825
+ ),
826
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "title", name: t("blog.fields.title"), isRequired: true }),
827
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
828
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-4", children: [
829
+ post && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "slug", name: t("blog.fields.slug"), description: t("blog.fields.slugHelp") }),
830
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
831
+ _chunkTY5FYP3Gjs.EntityMultiSelector,
832
+ {
833
+ id: "categories",
834
+ form,
835
+ label: t("blog.fields.categories"),
836
+ retriever: (params) => _chunkG6UE6MEPjs.BlogCategoryService.findMany(params),
837
+ module: _chunkG6UE6MEPjs.Modules.BlogCategory,
838
+ getLabel: blogCategoryAdminName,
839
+ getFormValueLabel: (value) => value.name || categoryName(value.id)
840
+ }
841
+ ),
842
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
843
+ _chunkTY5FYP3Gjs.FormTextarea,
844
+ {
845
+ form,
846
+ id: "summary",
847
+ name: t("blog.fields.summary"),
848
+ description: t("blog.fields.summaryHelp"),
849
+ className: "min-h-24"
850
+ }
851
+ )
852
+ ] }),
853
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-4", children: [
854
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
855
+ BlogCoverImageField,
856
+ {
857
+ form,
858
+ id: "coverImage",
859
+ label: t("blog.fields.coverImage"),
860
+ keyPrefix: _chunkG6UE6MEPjs.BLOG_POST_UPLOAD_PREFIX,
861
+ entityId: form.getValues("id"),
862
+ currentUrl: _optionalChain([post, 'optionalAccess', _40 => _40.coverImage]),
863
+ alt: _optionalChain([original, 'optionalAccess', _41 => _41.coverImageAlt]),
864
+ selection: cover,
865
+ onSelectionChange: setCover
866
+ }
867
+ ),
868
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "coverImageAlt", name: t("blog.fields.coverImageAlt") })
869
+ ] })
870
+ ] }),
871
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
872
+ _chunkTY5FYP3Gjs.FormBlockNote,
873
+ {
874
+ uploadKeyPrefix: _chunkG6UE6MEPjs.BLOG_POST_UPLOAD_PREFIX,
875
+ form,
876
+ id: "body",
877
+ name: t("blog.fields.body"),
878
+ type: "blog-post",
879
+ isRequired: true,
880
+ stretch: true,
881
+ className: "min-h-96",
882
+ onEmptyChange: setIsBodyEmptyState
883
+ }
884
+ )
885
+ ] })
886
+ }
887
+ );
888
+ }
889
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostEditor, "BlogPostEditor");
890
+
891
+ // src/features/blog/components/admin/BlogPostsList.tsx
892
+
893
+ function BlogPostsList({ fullWidth } = {}) {
894
+ const t = _nextintl.useTranslations.call(void 0, );
895
+ const data = _chunkTY5FYP3Gjs.useDataListRetriever.call(void 0, {
896
+ retriever: /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (params) => _chunkG6UE6MEPjs.BlogPostService.findMany(params), "retriever"),
897
+ retrieverParams: {},
898
+ module: _chunkG6UE6MEPjs.Modules.BlogPost
899
+ });
900
+ const functions = [
901
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
902
+ BlogPostEditor,
903
+ {
904
+ trigger: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Button, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}), nativeButton: false, size: "sm", variant: "outline", children: t("blog.admin.newPost") })
905
+ },
906
+ "create-blog-post"
907
+ )
908
+ ];
909
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
910
+ _chunkTY5FYP3Gjs.ContentListTable,
911
+ {
912
+ data,
913
+ fields: [
914
+ "title" /* title */,
915
+ "status" /* status */,
916
+ "categories" /* categories */,
917
+ "publishedAt" /* publishedAt */,
918
+ "languages" /* languages */
919
+ ],
920
+ tableGeneratorType: _chunkG6UE6MEPjs.Modules.BlogPost,
921
+ functions,
922
+ fullWidth,
923
+ title: t("blog.entities.posts"),
924
+ emptyState: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.EmptyState, { icon: _lucidereact.NewspaperIcon, title: t("blog.admin.empty") })
925
+ }
926
+ );
927
+ }
928
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostsList, "BlogPostsList");
929
+
930
+ // src/features/blog/components/admin/BlogAdminContainer.tsx
931
+
932
+ function BlogAdminContainer() {
933
+ const t = _nextintl.useTranslations.call(void 0, );
934
+ const breadcrumbs = [{ name: t("blog.admin.title") }];
935
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.SharedProvider, { value: { breadcrumbs, title: { type: t("blog.admin.title") } }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
936
+ _chunkTY5FYP3Gjs.RoundPageContainer,
937
+ {
938
+ module: _chunkG6UE6MEPjs.Modules.BlogPost,
939
+ tabs: [
940
+ { sectionKey: "posts", label: t("blog.tabs.posts"), content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostsList, {}) },
941
+ { sectionKey: "categories", label: t("blog.tabs.categories"), content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogCategoriesList, {}) },
942
+ { sectionKey: "layout", label: t("blog.tabs.layout"), content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogLayoutSetting, {}) }
943
+ ]
944
+ }
945
+ ) });
946
+ }
947
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogAdminContainer, "BlogAdminContainer");
948
+
949
+ // src/features/blog/components/admin/BlogPostContainer.tsx
950
+
951
+
952
+
953
+ // src/features/blog/contexts/BlogPostContext.tsx
954
+
955
+
956
+ var TRANSLATION_POLL_MS = 5e3;
957
+ var BlogPostContext = _react.createContext.call(void 0, void 0);
958
+ var BlogPostProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({ postId, children }) => {
959
+ const [post, setPost] = _react.useState.call(void 0, void 0);
960
+ const reload = _react.useCallback.call(void 0, async () => {
961
+ const loaded = await _chunkG6UE6MEPjs.BlogPostService.findOne({ id: postId });
962
+ setPost(loaded);
963
+ }, [postId]);
964
+ _react.useEffect.call(void 0, () => {
965
+ void reload();
966
+ }, [reload]);
967
+ const isTranslating = _react.useMemo.call(void 0,
968
+ () => (_nullishCoalesce(_optionalChain([post, 'optionalAccess', _42 => _42.translations]), () => ( []))).some(
969
+ (translation) => translation.aiStatus === "pending" || translation.aiStatus === "in_progress"
970
+ ),
971
+ [post]
972
+ );
973
+ _react.useEffect.call(void 0, () => {
974
+ if (!isTranslating) return;
975
+ const handle = setInterval(() => {
976
+ reload().catch(() => {
977
+ });
978
+ }, TRANSLATION_POLL_MS);
979
+ return () => clearInterval(handle);
980
+ }, [isTranslating, reload]);
981
+ const value = _react.useMemo.call(void 0, () => ({ post, reload }), [post, reload]);
982
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostContext.Provider, { value, children });
983
+ }, "BlogPostProvider");
984
+ var useBlogPost = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => {
985
+ const context = _react.useContext.call(void 0, BlogPostContext);
986
+ if (context === void 0) {
987
+ throw new Error("useBlogPost must be used within a BlogPostProvider");
988
+ }
989
+ return context;
990
+ }, "useBlogPost");
991
+
992
+ // src/features/blog/components/admin/BlogPostDeleter.tsx
993
+
994
+
995
+ function BlogPostDeleter() {
996
+ const t = _nextintl.useTranslations.call(void 0, );
997
+ const generateUrl = _chunkTY5FYP3Gjs.usePageUrlGenerator.call(void 0, );
998
+ const { post } = useBlogPost();
999
+ if (!post) return null;
1000
+ const type = t("blog.entities.post");
1001
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1002
+ _chunkTY5FYP3Gjs.CommonDeleter,
1003
+ {
1004
+ title: t("common.delete.title", { type }),
1005
+ subtitle: t("common.delete.subtitle", { type }),
1006
+ description: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-destructive p-4 text-sm", children: t("common.delete.description", { type }) }),
1007
+ showLabel: true,
1008
+ deleteFunction: () => _chunkG6UE6MEPjs.BlogPostService.delete({ id: post.id }),
1009
+ redirectTo: generateUrl({ page: _chunkG6UE6MEPjs.Modules.BlogPost })
1010
+ }
1011
+ );
1012
+ }
1013
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostDeleter, "BlogPostDeleter");
1014
+
1015
+ // src/features/blog/components/admin/BlogPostPublishButton.tsx
1016
+
1017
+
1018
+
1019
+
1020
+ function BlogPostPublishButton() {
1021
+ const t = _nextintl.useTranslations.call(void 0, );
1022
+ const { post, reload } = useBlogPost();
1023
+ const [saving, setSaving] = _react.useState.call(void 0, false);
1024
+ if (!post) return null;
1025
+ const isPublished = post.status === "published";
1026
+ const toggle = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, async () => {
1027
+ setSaving(true);
1028
+ try {
1029
+ if (isPublished) await _chunkG6UE6MEPjs.BlogPostService.unpublish({ id: post.id });
1030
+ else await _chunkG6UE6MEPjs.BlogPostService.publish({ id: post.id });
1031
+ await reload();
1032
+ } catch (error) {
1033
+ _chunkTY5FYP3Gjs.errorToast.call(void 0, { title: t("common.errors.error"), error });
1034
+ } finally {
1035
+ setSaving(false);
1036
+ }
1037
+ }, "toggle");
1038
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1039
+ _chunkTY5FYP3Gjs.Button,
1040
+ {
1041
+ type: "button",
1042
+ size: "sm",
1043
+ variant: isPublished ? "outline" : "default",
1044
+ onClick: () => void toggle(),
1045
+ disabled: saving,
1046
+ children: [
1047
+ isPublished ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.EyeOffIcon, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.EyeIcon, {}),
1048
+ isPublished ? t("blog.actions.unpublish") : t("blog.actions.publish")
1049
+ ]
1050
+ }
1051
+ );
1052
+ }
1053
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostPublishButton, "BlogPostPublishButton");
1054
+
1055
+ // src/features/blog/components/admin/BlogPostTranslationPanel.tsx
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+ // src/features/blog/components/admin/BlogPostComparison.tsx
1062
+
1063
+
1064
+ function BlogPostTranslationFields({ translation }) {
1065
+ const t = _nextintl.useTranslations.call(void 0, );
1066
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-4", children: [
1067
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.title"), value: translation.title }),
1068
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.slug"), value: translation.slug }),
1069
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.summary"), value: translation.summary }),
1070
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.coverImageAlt"), value: translation.coverImageAlt }),
1071
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.body"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.BlockNoteEditorContainer, { id: translation.id, type: "blog-post", initialContent: translation.body }) })
1072
+ ] });
1073
+ }
1074
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostTranslationFields, "BlogPostTranslationFields");
1075
+ function BlogPostComparison({ original, translation }) {
1076
+ const t = _nextintl.useTranslations.call(void 0, );
1077
+ const languageName = useBlogLanguageName();
1078
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
1079
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "bg-muted/40 flex flex-col gap-y-4 rounded-lg border p-4", children: [
1080
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-x-2", children: [
1081
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.MicroLabel, { as: "h3", children: languageName(original.language) }),
1082
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softGray", children: t("blog.translation.original") })
1083
+ ] }),
1084
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationFields, { translation: original })
1085
+ ] }),
1086
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-4 rounded-lg border p-4", children: [
1087
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-x-2", children: [
1088
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.MicroLabel, { as: "h3", children: languageName(translation.language) }),
1089
+ translation.source === "manual" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softAmber", children: t("blog.translation.editedByHand") })
1090
+ ] }),
1091
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationFields, { translation })
1092
+ ] })
1093
+ ] });
1094
+ }
1095
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostComparison, "BlogPostComparison");
1096
+
1097
+ // src/features/blog/components/admin/BlogPostTranslationEditor.tsx
1098
+
1099
+
1100
+
1101
+
1102
+
1103
+
1104
+ var isBodyEmpty2 = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (body) => !body || Array.isArray(body) && body.length === 0, "isBodyEmpty");
1105
+ var buildFormSchema2 = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (t) => _zod3.z.object({
1106
+ id: _zod3.z.string().uuid(),
1107
+ title: _zod3.z.string().min(1, { message: t("blog.errors.title") }),
1108
+ slug: _zod3.z.string().optional(),
1109
+ summary: _zod3.z.string().optional(),
1110
+ body: _zod3.z.any(),
1111
+ coverImageAlt: _zod3.z.string().optional()
1112
+ }), "buildFormSchema");
1113
+ function BlogPostTranslationEditor({ translation, trigger, onSuccess }) {
1114
+ const t = _nextintl.useTranslations.call(void 0, );
1115
+ const formSchema = _react.useMemo.call(void 0, () => buildFormSchema2(t), [t]);
1116
+ const languageName = useBlogLanguageName();
1117
+ const [isBodyEmptyState, setIsBodyEmptyState] = _react.useState.call(void 0, isBodyEmpty2(translation.body));
1118
+ const getDefaultValues = _react.useCallback.call(void 0,
1119
+ () => ({
1120
+ id: translation.id,
1121
+ title: _nullishCoalesce(translation.title, () => ( "")),
1122
+ slug: _nullishCoalesce(translation.slug, () => ( "")),
1123
+ summary: _nullishCoalesce(translation.summary, () => ( "")),
1124
+ body: translation.body || [],
1125
+ coverImageAlt: _nullishCoalesce(translation.coverImageAlt, () => ( ""))
1126
+ }),
1127
+ [translation]
1128
+ );
1129
+ const form = _reacthookform.useForm.call(void 0, {
1130
+ resolver: _zod.zodResolver.call(void 0, formSchema),
1131
+ defaultValues: getDefaultValues()
1132
+ });
1133
+ const { dirtyFields } = form.formState;
1134
+ const isFormDirty = _react.useCallback.call(void 0, () => {
1135
+ const dirty = { ...dirtyFields };
1136
+ if (dirty.body && isBodyEmptyState) delete dirty.body;
1137
+ return Object.keys(dirty).length > 0;
1138
+ }, [dirtyFields, isBodyEmptyState]);
1139
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1140
+ _chunkTY5FYP3Gjs.EditorSheet,
1141
+ {
1142
+ form,
1143
+ entityType: t("blog.entities.post"),
1144
+ entityName: translation.title,
1145
+ title: `${t("blog.admin.editPost")} \xB7 ${languageName(translation.language)}`,
1146
+ isEdit: true,
1147
+ module: _chunkG6UE6MEPjs.Modules.BlogPostTranslation,
1148
+ size: "lg",
1149
+ isFormDirty,
1150
+ onSubmit: async (values) => _chunkG6UE6MEPjs.BlogPostTranslationService.update({
1151
+ id: values.id,
1152
+ title: values.title,
1153
+ slug: values.slug || void 0,
1154
+ summary: values.summary,
1155
+ body: values.body,
1156
+ coverImageAlt: values.coverImageAlt
1157
+ }),
1158
+ onReset: () => {
1159
+ setIsBodyEmptyState(isBodyEmpty2(translation.body));
1160
+ return getDefaultValues();
1161
+ },
1162
+ onSuccess: _nullishCoalesce(onSuccess, () => ( (() => {
1163
+ }))),
1164
+ trigger,
1165
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full min-h-0 w-full flex-col gap-y-4", children: [
1166
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "title", name: t("blog.fields.title"), isRequired: true }),
1167
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
1168
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-4", children: [
1169
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "slug", name: t("blog.fields.slug"), description: t("blog.fields.slugHelp") }),
1170
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormTextarea, { form, id: "summary", name: t("blog.fields.summary"), className: "min-h-24" })
1171
+ ] }),
1172
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col gap-y-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.FormInput, { form, id: "coverImageAlt", name: t("blog.fields.coverImageAlt") }) })
1173
+ ] }),
1174
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1175
+ _chunkTY5FYP3Gjs.FormBlockNote,
1176
+ {
1177
+ uploadKeyPrefix: _chunkG6UE6MEPjs.BLOG_POST_UPLOAD_PREFIX,
1178
+ form,
1179
+ id: "body",
1180
+ name: t("blog.fields.body"),
1181
+ type: "blog-post",
1182
+ isRequired: true,
1183
+ stretch: true,
1184
+ className: "min-h-96",
1185
+ onEmptyChange: setIsBodyEmptyState
1186
+ }
1187
+ )
1188
+ ] })
1189
+ }
1190
+ );
1191
+ }
1192
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostTranslationEditor, "BlogPostTranslationEditor");
1193
+
1194
+ // src/features/blog/components/admin/BlogPostTranslationPanel.tsx
1195
+
1196
+ function BlogPostTranslationPanel({ post, translation, onChanged }) {
1197
+ const t = _nextintl.useTranslations.call(void 0, );
1198
+ const categoryName = useBlogCategoryNames();
1199
+ const languageName = useBlogLanguageName();
1200
+ const formatDate = useBlogDateFormatter();
1201
+ const [isComparing, setIsComparing] = _react.useState.call(void 0, false);
1202
+ const original = post.original;
1203
+ const reload = _nullishCoalesce(onChanged, () => ( (async () => {
1204
+ })));
1205
+ const editTrigger = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.Button, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}), nativeButton: false, size: "sm", variant: "outline", children: [
1206
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.PencilIcon, {}),
1207
+ t("blog.actions.edit")
1208
+ ] });
1209
+ if (translation.isOriginal) {
1210
+ const statusLabel = {
1211
+ draft: t("blog.status.draft"),
1212
+ published: t("blog.status.published"),
1213
+ unpublished: t("blog.status.unpublished")
1214
+ }[post.status];
1215
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-y-6 p-4", children: [
1216
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-x-4", children: [
1217
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softGray", children: t("blog.translation.original") }),
1218
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostEditor, { post, trigger: editTrigger, onSuccess: reload })
1219
+ ] }),
1220
+ post.coverImage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1221
+ _image2.default,
1222
+ {
1223
+ src: post.coverImage,
1224
+ alt: _nullishCoalesce(translation.coverImageAlt, () => ( translation.title)),
1225
+ width: 640,
1226
+ height: 360,
1227
+ className: "h-auto max-h-72 w-auto rounded-lg object-cover",
1228
+ unoptimized: _chunkG6UE6MEPjs.isRemoteImageSrc.call(void 0, post.coverImage)
1229
+ }
1230
+ ),
1231
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-4 md:grid-cols-3", children: [
1232
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.status"), value: statusLabel }),
1233
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.DetailField, { label: t("blog.fields.publishedAt"), value: formatDate(post.publishedAt) || "\u2014" }),
1234
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1235
+ _chunkTY5FYP3Gjs.DetailField,
1236
+ {
1237
+ label: t("blog.fields.categories"),
1238
+ value: post.categories.map((category) => categoryName(category.id)).filter(Boolean).join(", ") || "\u2014"
1239
+ }
1240
+ )
1241
+ ] }),
1242
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationFields, { translation })
1243
+ ] });
1244
+ }
1245
+ const isWorking = translation.aiStatus === "pending" || translation.aiStatus === "in_progress";
1246
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-y-6 p-4", children: [
1247
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Alert, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.AlertDescription, { className: "flex flex-col gap-y-2", children: [
1248
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2", children: [
1249
+ translation.source === "manual" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: "softAmber", children: t("blog.translation.editedByHand") }),
1250
+ original && translation.translatedAt && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: t("blog.translation.translatedFrom", {
1251
+ language: languageName(original.language),
1252
+ date: formatDate(translation.translatedAt)
1253
+ }) })
1254
+ ] }),
1255
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: t("blog.translation.overwriteWarning") }),
1256
+ original && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Button, { type: "button", size: "sm", variant: "ghost", onClick: () => setIsComparing((value) => !value), children: isComparing ? t("blog.actions.hideComparison") : t("blog.actions.compareWithOriginal") }) })
1257
+ ] }) }),
1258
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-x-4", children: [
1259
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1260
+ BlogTranslationStatus,
1261
+ {
1262
+ aiStatus: translation.aiStatus,
1263
+ onRetranslate: async () => {
1264
+ await _chunkG6UE6MEPjs.BlogPostTranslationService.retranslate({ id: translation.id });
1265
+ await reload();
1266
+ }
1267
+ }
1268
+ ),
1269
+ !isWorking && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationEditor, { translation, trigger: editTrigger, onSuccess: reload })
1270
+ ] }),
1271
+ isComparing && original ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostComparison, { original, translation }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationFields, { translation })
1272
+ ] });
1273
+ }
1274
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostTranslationPanel, "BlogPostTranslationPanel");
1275
+
1276
+ // src/features/blog/components/admin/BlogPostContainer.tsx
1277
+
1278
+ function BlogPostContainer({ postId }) {
1279
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostProvider, { postId, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostShell, {}) });
1280
+ }
1281
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostContainer, "BlogPostContainer");
1282
+ function BlogPostShell() {
1283
+ const t = _nextintl.useTranslations.call(void 0, );
1284
+ const generateUrl = _chunkTY5FYP3Gjs.usePageUrlGenerator.call(void 0, );
1285
+ const languageName = useBlogLanguageName();
1286
+ const { post, reload } = useBlogPost();
1287
+ const translations = _react.useMemo.call(void 0, () => {
1288
+ const all = _nullishCoalesce(_optionalChain([post, 'optionalAccess', _43 => _43.translations]), () => ( []));
1289
+ return [
1290
+ ...all.filter((translation) => translation.isOriginal),
1291
+ ...all.filter((translation) => !translation.isOriginal)
1292
+ ];
1293
+ }, [post]);
1294
+ if (!post) return null;
1295
+ const title = _nullishCoalesce(_nullishCoalesce(_optionalChain([post, 'access', _44 => _44.original, 'optionalAccess', _45 => _45.title]), () => ( post.title)), () => ( ""));
1296
+ const breadcrumbs = [
1297
+ { name: t("blog.admin.title"), href: generateUrl({ page: _chunkG6UE6MEPjs.Modules.BlogPost }) },
1298
+ { name: title }
1299
+ ];
1300
+ const statusLabel = {
1301
+ draft: t("blog.status.draft"),
1302
+ published: t("blog.status.published"),
1303
+ unpublished: t("blog.status.unpublished")
1304
+ }[post.status];
1305
+ const tabLabel = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (translation) => {
1306
+ const parts = [languageName(translation.language)];
1307
+ if (translation.isOriginal) parts.push(t("blog.translation.original"));
1308
+ if (translation.aiStatus === "pending" || translation.aiStatus === "in_progress")
1309
+ parts.push(t("blog.translation.translating"));
1310
+ if (translation.aiStatus === "failed") parts.push(t("blog.translation.failed"));
1311
+ return parts.join(" \xB7 ");
1312
+ }, "tabLabel");
1313
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1314
+ _chunkTY5FYP3Gjs.SharedProvider,
1315
+ {
1316
+ value: {
1317
+ breadcrumbs,
1318
+ title: {
1319
+ type: t("blog.admin.title"),
1320
+ element: title,
1321
+ functions: [
1322
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Badge, { variant: BLOG_STATUS_BADGE[post.status], children: statusLabel }, "blogPostStatus"),
1323
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostPublishButton, {}, "blogPostPublish"),
1324
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostDeleter, {}, "blogPostDeleter")
1325
+ ]
1326
+ }
1327
+ },
1328
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1329
+ _chunkTY5FYP3Gjs.RoundPageContainer,
1330
+ {
1331
+ module: _chunkG6UE6MEPjs.Modules.BlogPost,
1332
+ id: post.id,
1333
+ forceHeader: true,
1334
+ tabs: translations.map((translation) => ({
1335
+ sectionKey: translation.language,
1336
+ label: tabLabel(translation),
1337
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostTranslationPanel, { post, translation, onChanged: reload })
1338
+ }))
1339
+ }
1340
+ )
1341
+ }
1342
+ );
1343
+ }
1344
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostShell, "BlogPostShell");
1345
+
1346
+ // src/features/blog/components/public/BlogCategoryChips.tsx
1347
+
1348
+
1349
+ // src/features/blog/components/public/blogPublicHelpers.ts
1350
+ function blogListHref(basePath, params) {
1351
+ const search = new URLSearchParams();
1352
+ if (params.category) search.set("category", params.category);
1353
+ if (params.q) search.set("q", params.q);
1354
+ if (params.page && params.page > 1) search.set("page", String(params.page));
1355
+ const query = search.toString();
1356
+ return query ? `${basePath}?${query}` : basePath;
1357
+ }
1358
+ _chunk7QVYU63Ejs.__name.call(void 0, blogListHref, "blogListHref");
1359
+ function blogPostHref(basePath, slug) {
1360
+ return `${basePath}/${encodeURIComponent(slug)}`;
1361
+ }
1362
+ _chunk7QVYU63Ejs.__name.call(void 0, blogPostHref, "blogPostHref");
1363
+ function resolvePostCategory(post, categories) {
1364
+ for (const id of post.categoryIds) {
1365
+ const category = categories.find((c) => c.id === id);
1366
+ if (category) return category;
1367
+ }
1368
+ return void 0;
1369
+ }
1370
+ _chunk7QVYU63Ejs.__name.call(void 0, resolvePostCategory, "resolvePostCategory");
1371
+
1372
+ // src/features/blog/components/public/BlogCategoryChips.tsx
1373
+
1374
+ function BlogCategoryChips(props) {
1375
+ const { categories, basePath, activeCategorySlug, query, variant = "chips", className } = props;
1376
+ const t = _nextintl.useTranslations.call(void 0, );
1377
+ const items = [
1378
+ {
1379
+ key: "all",
1380
+ label: t("blog.public.all"),
1381
+ href: blogListHref(basePath, { q: query }),
1382
+ active: !activeCategorySlug
1383
+ },
1384
+ ...categories.map((category) => ({
1385
+ key: category.id,
1386
+ label: category.name,
1387
+ href: blogListHref(basePath, { category: category.slug, q: query }),
1388
+ active: category.slug === activeCategorySlug
1389
+ }))
1390
+ ];
1391
+ const inactiveVariant = variant === "chips" ? "outline" : "ghost";
1392
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "nav", { "aria-label": t("blog.entities.categories"), className, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: variant === "chips" ? "flex flex-wrap items-center gap-2" : "flex flex-col items-start gap-2", children: items.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "li", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1393
+ _chunkTY5FYP3Gjs.Badge,
1394
+ {
1395
+ variant: item.active ? "default" : inactiveVariant,
1396
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Link, { href: item.href, "aria-current": item.active ? "page" : void 0 }),
1397
+ children: item.label
1398
+ }
1399
+ ) }, item.key)) }) });
1400
+ }
1401
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogCategoryChips, "BlogCategoryChips");
1402
+
1403
+ // src/features/blog/components/public/BlogListParts.tsx
1404
+
1405
+
1406
+ function BlogListHeader(props) {
1407
+ const { align = "start", showSubtitle = true } = props;
1408
+ const t = _nextintl.useTranslations.call(void 0, );
1409
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "header", { className: align === "center" ? "text-center" : void 0, children: [
1410
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1411
+ _chunkTY5FYP3Gjs.ContentTitle,
1412
+ {
1413
+ type: t("blog.public.eyebrow"),
1414
+ element: t("blog.public.title"),
1415
+ headingLevel: 1,
1416
+ className: _chunkG6UE6MEPjs.cn.call(void 0, "mb-0", align === "center" && "[&_div]:justify-center")
1417
+ }
1418
+ ),
1419
+ showSubtitle ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground mt-3 text-sm leading-relaxed", children: t("blog.public.subtitle") }) : null
1420
+ ] });
1421
+ }
1422
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogListHeader, "BlogListHeader");
1423
+ function BlogListEmpty(props) {
1424
+ const t = _nextintl.useTranslations.call(void 0, );
1425
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: _chunkG6UE6MEPjs.cn.call(void 0, "text-muted-foreground py-12 text-center text-sm", props.className), children: props.query ? t("blog.public.noResults") : t("blog.public.empty") });
1426
+ }
1427
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogListEmpty, "BlogListEmpty");
1428
+ function BlogLoadMore(props) {
1429
+ const { basePath, page, activeCategorySlug, query, className } = props;
1430
+ const t = _nextintl.useTranslations.call(void 0, );
1431
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkG6UE6MEPjs.cn.call(void 0, "flex justify-center", className), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1432
+ _chunkTY5FYP3Gjs.Link,
1433
+ {
1434
+ href: blogListHref(basePath, { category: activeCategorySlug, q: query, page: page + 1 }),
1435
+ scroll: false,
1436
+ className: _chunkTY5FYP3Gjs.buttonVariants.call(void 0, { variant: "outline" }),
1437
+ children: t("blog.public.loadMore")
1438
+ }
1439
+ ) });
1440
+ }
1441
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogLoadMore, "BlogLoadMore");
1442
+
1443
+ // src/features/blog/components/public/BlogPostCard.tsx
1444
+
1445
+
1446
+ // src/features/blog/components/public/BlogPostMeta.tsx
1447
+
1448
+
1449
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
1450
+ function BlogPostMeta(props) {
1451
+ const { post, showAuthor, showDate, showUpdated, className } = props;
1452
+ const t = _nextintl.useTranslations.call(void 0, );
1453
+ const format = _nextintl.useFormatter.call(void 0, );
1454
+ const parts = [];
1455
+ if (showAuthor && post.authorName) parts.push(t("blog.public.by", { author: post.authorName }));
1456
+ if (showDate && post.publishedAt) {
1457
+ parts.push(format.dateTime(new Date(post.publishedAt), { dateStyle: "medium" }));
1458
+ }
1459
+ if (showUpdated && post.publishedAt && post.updatedAt && new Date(post.updatedAt).getTime() - new Date(post.publishedAt).getTime() > ONE_DAY_MS) {
1460
+ parts.push(t("blog.public.updated", { date: format.dateTime(new Date(post.updatedAt), { dateStyle: "medium" }) }));
1461
+ }
1462
+ parts.push(t("blog.public.readingTime", { minutes: post.readingMinutes }));
1463
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: _chunkG6UE6MEPjs.cn.call(void 0, "text-muted-foreground text-xs", className), children: parts.map((part, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
1464
+ index > 0 ? " \xB7 " : null,
1465
+ part
1466
+ ] }, index)) });
1467
+ }
1468
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostMeta, "BlogPostMeta");
1469
+
1470
+ // src/features/blog/components/public/BlogPostCard.tsx
1471
+
1472
+ function BlogPostCover(props) {
1473
+ const { src, alt, sizes, priority, className } = props;
1474
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkG6UE6MEPjs.cn.call(void 0, "border-border bg-primary/10 relative overflow-hidden rounded-lg border", className), children: src ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1475
+ _image2.default,
1476
+ {
1477
+ src,
1478
+ alt: _nullishCoalesce(alt, () => ( "")),
1479
+ fill: true,
1480
+ sizes,
1481
+ priority,
1482
+ className: "object-cover",
1483
+ unoptimized: _chunkG6UE6MEPjs.isRemoteImageSrc.call(void 0, src)
1484
+ }
1485
+ ) : null });
1486
+ }
1487
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostCover, "BlogPostCover");
1488
+ function BlogPostCard(props) {
1489
+ const { post, categories, basePath, variant = "card", priority, headingLevel = "h2" } = props;
1490
+ const category = resolvePostCategory(post, categories);
1491
+ const isProminent = variant === "hero" || variant === "large";
1492
+ const eyebrow = _optionalChain([category, 'optionalAccess', _46 => _46.name]);
1493
+ const text = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-col", children: [
1494
+ eyebrow ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.MicroLabel, { as: "span", children: eyebrow }) : null,
1495
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.SectionHeader, { level: headingLevel === "h3" ? 3 : 2, className: "mt-1.5", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.Link, { href: blogPostHref(basePath, post.slug), className: "after:absolute after:inset-0", children: post.title }) }),
1496
+ post.summary ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground mt-2 text-sm leading-relaxed", children: post.summary }) : null,
1497
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostMeta, { post, showAuthor: isProminent, className: "mt-3" })
1498
+ ] });
1499
+ if (variant === "hero") {
1500
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "article", { className: "group relative grid items-center gap-6 md:grid-cols-[1.4fr_1fr] md:gap-10", children: [
1501
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1502
+ BlogPostCover,
1503
+ {
1504
+ src: post.coverImage,
1505
+ alt: post.coverImageAlt,
1506
+ sizes: "(min-width: 1024px) 560px, (min-width: 768px) 58vw, 100vw",
1507
+ priority,
1508
+ className: "aspect-[16/10]"
1509
+ }
1510
+ ),
1511
+ text
1512
+ ] });
1513
+ }
1514
+ if (variant === "row") {
1515
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "article", { className: "group relative grid items-center gap-4 sm:grid-cols-[10rem_1fr] sm:gap-6", children: [
1516
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1517
+ BlogPostCover,
1518
+ {
1519
+ src: post.coverImage,
1520
+ alt: post.coverImageAlt,
1521
+ sizes: "(min-width: 640px) 160px, 100vw",
1522
+ priority,
1523
+ className: "aspect-[16/10]"
1524
+ }
1525
+ ),
1526
+ text
1527
+ ] });
1528
+ }
1529
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "article", { className: "group relative flex flex-col gap-4", children: [
1530
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1531
+ BlogPostCover,
1532
+ {
1533
+ src: post.coverImage,
1534
+ alt: post.coverImageAlt,
1535
+ sizes: variant === "large" ? "(min-width: 1024px) 760px, 100vw" : "(min-width: 1024px) 320px, (min-width: 640px) 50vw, 100vw",
1536
+ priority,
1537
+ className: variant === "large" ? "aspect-[16/8]" : "aspect-[16/10]"
1538
+ }
1539
+ ),
1540
+ text
1541
+ ] });
1542
+ }
1543
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostCard, "BlogPostCard");
1544
+
1545
+ // src/features/blog/components/public/BlogSearchBox.tsx
1546
+
1547
+
1548
+
1549
+
1550
+ function BlogSearchBox(props) {
1551
+ const { basePath, query, activeCategorySlug, className } = props;
1552
+ const t = _nextintl.useTranslations.call(void 0, );
1553
+ const router = _chunkG6UE6MEPjs.useI18nRouter.call(void 0, );
1554
+ const [value, setValue] = _react.useState.call(void 0, _nullishCoalesce(query, () => ( "")));
1555
+ _react.useEffect.call(void 0, () => setValue(_nullishCoalesce(query, () => ( ""))), [query]);
1556
+ const onSubmit = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (event) => {
1557
+ event.preventDefault();
1558
+ const q = value.trim();
1559
+ router.push(blogListHref(basePath, { category: activeCategorySlug, q: q || void 0 }));
1560
+ }, "onSubmit");
1561
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "form", { role: "search", onSubmit, className, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.InputGroup, { children: [
1562
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.InputGroupAddon, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.SearchIcon, {}) }),
1563
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1564
+ _chunkTY5FYP3Gjs.InputGroupInput,
1565
+ {
1566
+ type: "search",
1567
+ name: "q",
1568
+ value,
1569
+ onChange: (event) => setValue(event.target.value),
1570
+ placeholder: t("blog.public.searchPlaceholder"),
1571
+ "aria-label": t("blog.public.search")
1572
+ }
1573
+ )
1574
+ ] }) });
1575
+ }
1576
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogSearchBox, "BlogSearchBox");
1577
+
1578
+ // src/features/blog/components/public/BlogListColumn.tsx
1579
+
1580
+ function BlogListColumn(props) {
1581
+ const { list, categories, activeCategorySlug, query, page, basePath } = props;
1582
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "section", { className: "px-4 pt-16 pb-20 md:pt-20", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mx-auto max-w-2xl", children: [
1583
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListHeader, { align: "center" }),
1584
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1585
+ BlogCategoryChips,
1586
+ {
1587
+ categories,
1588
+ basePath,
1589
+ activeCategorySlug,
1590
+ query,
1591
+ className: "mt-8 [&>ul]:justify-center"
1592
+ }
1593
+ ),
1594
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogSearchBox, { basePath, query, activeCategorySlug, className: "mt-4" }),
1595
+ list.posts.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListEmpty, { query }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "divide-border mt-10 flex flex-col divide-y", children: list.posts.map((post, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "py-6 first:pt-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1596
+ BlogPostCard,
1597
+ {
1598
+ post,
1599
+ categories,
1600
+ basePath,
1601
+ variant: "row",
1602
+ priority: index === 0
1603
+ }
1604
+ ) }, post.id)) }),
1605
+ list.hasMore ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1606
+ BlogLoadMore,
1607
+ {
1608
+ basePath,
1609
+ page,
1610
+ activeCategorySlug,
1611
+ query,
1612
+ className: "mt-10"
1613
+ }
1614
+ ) : null
1615
+ ] }) });
1616
+ }
1617
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogListColumn, "BlogListColumn");
1618
+
1619
+ // src/features/blog/components/public/BlogListFeatured.tsx
1620
+
1621
+ function BlogListFeatured(props) {
1622
+ const { list, categories, activeCategorySlug, query, page, basePath } = props;
1623
+ const [hero, ...rest] = list.posts;
1624
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "section", { className: "px-4 pt-16 pb-20 md:pt-20", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mx-auto max-w-5xl", children: [
1625
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListHeader, {}),
1626
+ hero ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-10", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostCard, { post: hero, categories, basePath, variant: "hero", priority: true }) }) : null,
1627
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-12 flex flex-col gap-3 md:flex-row md:items-center", children: [
1628
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1629
+ BlogCategoryChips,
1630
+ {
1631
+ categories,
1632
+ basePath,
1633
+ activeCategorySlug,
1634
+ query,
1635
+ className: "flex-1"
1636
+ }
1637
+ ),
1638
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1639
+ BlogSearchBox,
1640
+ {
1641
+ basePath,
1642
+ query,
1643
+ activeCategorySlug,
1644
+ className: "md:w-64"
1645
+ }
1646
+ )
1647
+ ] }),
1648
+ list.posts.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListEmpty, { query }) : null,
1649
+ rest.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-8 grid gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3", children: rest.map((post) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostCard, { post, categories, basePath }, post.id)) }) : null,
1650
+ list.hasMore ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1651
+ BlogLoadMore,
1652
+ {
1653
+ basePath,
1654
+ page,
1655
+ activeCategorySlug,
1656
+ query,
1657
+ className: "mt-12"
1658
+ }
1659
+ ) : null
1660
+ ] }) });
1661
+ }
1662
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogListFeatured, "BlogListFeatured");
1663
+
1664
+ // src/features/blog/components/public/BlogListRail.tsx
1665
+
1666
+
1667
+ function BlogListRail(props) {
1668
+ const { list, categories, activeCategorySlug, query, page, basePath } = props;
1669
+ const t = _nextintl.useTranslations.call(void 0, );
1670
+ const [first, ...rest] = list.posts;
1671
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "section", { className: "px-4 pt-16 pb-20 md:pt-20", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mx-auto grid max-w-5xl gap-10 md:grid-cols-[13rem_1fr] md:gap-12", children: [
1672
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "aside", { className: "flex flex-col gap-6", children: [
1673
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListHeader, { showSubtitle: false }),
1674
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogSearchBox, { basePath, query, activeCategorySlug }),
1675
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1676
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.MicroLabel, { as: "span", className: "block", children: t("blog.entities.categories") }),
1677
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1678
+ BlogCategoryChips,
1679
+ {
1680
+ categories,
1681
+ basePath,
1682
+ activeCategorySlug,
1683
+ query,
1684
+ variant: "list",
1685
+ className: "mt-3"
1686
+ }
1687
+ )
1688
+ ] })
1689
+ ] }),
1690
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0", children: [
1691
+ first ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostCard, { post: first, categories, basePath, variant: "large", priority: true }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListEmpty, { query }),
1692
+ rest.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "border-border mt-10 grid gap-x-6 gap-y-10 border-t pt-10 sm:grid-cols-2", children: rest.map((post) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostCard, { post, categories, basePath }, post.id)) }) : null,
1693
+ list.hasMore ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1694
+ BlogLoadMore,
1695
+ {
1696
+ basePath,
1697
+ page,
1698
+ activeCategorySlug,
1699
+ query,
1700
+ className: "mt-12"
1701
+ }
1702
+ ) : null
1703
+ ] })
1704
+ ] }) });
1705
+ }
1706
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogListRail, "BlogListRail");
1707
+
1708
+ // src/features/blog/components/public/BlogList.tsx
1709
+
1710
+ function BlogList(props) {
1711
+ switch (props.layout) {
1712
+ case "column":
1713
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListColumn, { ...props });
1714
+ case "rail":
1715
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListRail, { ...props });
1716
+ case "featured":
1717
+ default:
1718
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogListFeatured, { ...props });
1719
+ }
1720
+ }
1721
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogList, "BlogList");
1722
+
1723
+ // src/features/blog/components/public/BlogPostView.tsx
1724
+
1725
+
1726
+
1727
+ function BlogPostView(props) {
1728
+ const { post, categories, related, basePath, body } = props;
1729
+ const t = _nextintl.useTranslations.call(void 0, );
1730
+ const category = resolvePostCategory(post, categories);
1731
+ const more = related.slice(0, 3);
1732
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "article", { className: "px-4 pt-12 pb-20 md:pt-16", children: [
1733
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mx-auto max-w-3xl", children: [
1734
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTY5FYP3Gjs.Link, { href: basePath, className: "inline-flex items-center gap-1.5", children: [
1735
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ArrowLeftIcon, { className: "size-4 rtl:rotate-180" }),
1736
+ t("blog.public.back")
1737
+ ] }),
1738
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "header", { className: "mt-8", children: [
1739
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.ContentTitle, { type: _optionalChain([category, 'optionalAccess', _47 => _47.name]), element: post.title, headingLevel: 1, className: "mb-0" }),
1740
+ post.summary ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground mt-3 text-sm leading-relaxed", children: post.summary }) : null,
1741
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlogPostMeta, { post, showAuthor: true, className: "mt-4" })
1742
+ ] }),
1743
+ post.coverImage ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1744
+ BlogPostCover,
1745
+ {
1746
+ src: post.coverImage,
1747
+ alt: post.coverImageAlt,
1748
+ sizes: "(min-width: 768px) 768px, 100vw",
1749
+ priority: true,
1750
+ className: "mt-8 aspect-[16/9]"
1751
+ }
1752
+ ) : null,
1753
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-8", children: _nullishCoalesce(body, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.BlockNoteEditorContainer, { id: post.id, type: "blog-post", initialContent: post.body }))) })
1754
+ ] }),
1755
+ more.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "section", { className: "mx-auto mt-16 max-w-5xl", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "border-border border-t pt-10", children: [
1756
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTY5FYP3Gjs.SectionHeader, { level: 2, children: t("blog.public.moreIn", { category: _nullishCoalesce(_optionalChain([category, 'optionalAccess', _48 => _48.name]), () => ( "")) }) }),
1757
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-6 grid gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3", children: more.map((relatedPost) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1758
+ BlogPostCard,
1759
+ {
1760
+ post: relatedPost,
1761
+ categories,
1762
+ basePath,
1763
+ headingLevel: "h3"
1764
+ },
1765
+ relatedPost.id
1766
+ )) })
1767
+ ] }) }) : null
1768
+ ] });
1769
+ }
1770
+ _chunk7QVYU63Ejs.__name.call(void 0, BlogPostView, "BlogPostView");
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+
1777
+
1778
+
1779
+
1780
+
1781
+
1782
+
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+
1805
+
1806
+
1807
+
1808
+
1809
+ exports.BLOG_ACTION = _chunkG6UE6MEPjs.BLOG_ACTION; exports.BLOG_CATEGORY_UPLOAD_PREFIX = _chunkG6UE6MEPjs.BLOG_CATEGORY_UPLOAD_PREFIX; exports.BLOG_LIST_LAYOUTS = _chunkG6UE6MEPjs.BLOG_LIST_LAYOUTS; exports.BLOG_MODULE_ID = _chunkG6UE6MEPjs.BLOG_MODULE_ID; exports.BLOG_POST_STATUSES = _chunkG6UE6MEPjs.BLOG_POST_STATUSES; exports.BLOG_POST_UPLOAD_PREFIX = _chunkG6UE6MEPjs.BLOG_POST_UPLOAD_PREFIX; exports.BLOG_PUBLIC_PREFIX = _chunkG6UE6MEPjs.BLOG_PUBLIC_PREFIX; exports.BLOG_SETTINGS_ID = _chunkG6UE6MEPjs.BLOG_SETTINGS_ID; exports.BLOG_STATUS_BADGE = BLOG_STATUS_BADGE; exports.BLOG_TRANSLATION_SOURCES = _chunkG6UE6MEPjs.BLOG_TRANSLATION_SOURCES; exports.BLOG_UPLOAD_ROOT = _chunkG6UE6MEPjs.BLOG_UPLOAD_ROOT; exports.BlogAdminContainer = BlogAdminContainer; exports.BlogCategoriesList = BlogCategoriesList; exports.BlogCategoryEditor = BlogCategoryEditor; exports.BlogCoverImageField = BlogCoverImageField; exports.BlogLayoutSetting = BlogLayoutSetting; exports.BlogList = BlogList; exports.BlogPostComparison = BlogPostComparison; exports.BlogPostContainer = BlogPostContainer; exports.BlogPostDeleter = BlogPostDeleter; exports.BlogPostEditor = BlogPostEditor; exports.BlogPostProvider = BlogPostProvider; exports.BlogPostPublishButton = BlogPostPublishButton; exports.BlogPostTranslationEditor = BlogPostTranslationEditor; exports.BlogPostTranslationFields = BlogPostTranslationFields; exports.BlogPostTranslationPanel = BlogPostTranslationPanel; exports.BlogPostView = BlogPostView; exports.BlogPostsList = BlogPostsList; exports.BlogTranslationStatus = BlogTranslationStatus; exports.blogCategoryAdminName = blogCategoryAdminName; exports.uploadBlogImage = uploadBlogImage; exports.useBlogCategoryNames = useBlogCategoryNames; exports.useBlogCategoryTableStructure = useBlogCategoryTableStructure; exports.useBlogDateFormatter = useBlogDateFormatter; exports.useBlogLanguageName = useBlogLanguageName; exports.useBlogPost = useBlogPost; exports.useBlogPostTableStructure = useBlogPostTableStructure;
1810
+ //# sourceMappingURL=index.js.map