@oktis-works/admin 0.3.3 → 0.4.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 (95) hide show
  1. package/dist/client/_astro/ActivityWidget.B1PK1jNM.js +16 -0
  2. package/dist/client/_astro/AdminBar.DGqkNINI.js +234 -0
  3. package/dist/client/_astro/AtGlanceWidget.CbAM9D09.js +43 -0
  4. package/dist/client/_astro/BaseLayout.B2MfKf6B.css +1 -0
  5. package/dist/client/_astro/ContentEditor.BG7DWach.js +1 -0
  6. package/dist/client/_astro/ContentList.CfGc6HN5.js +1 -0
  7. package/dist/client/_astro/DashboardHome._7yIrBzf.js +1 -0
  8. package/dist/client/_astro/DashboardLayout.DrKf2Klk.css +1 -0
  9. package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.BrC4PbPa.js +1 -0
  10. package/dist/client/_astro/Footer.CjhzORqz.js +74 -0
  11. package/dist/client/_astro/GeneralSettings.BwnPXbvc.js +1 -0
  12. package/dist/client/_astro/HelpTabs.Ddud8gs3.js +103 -0
  13. package/dist/client/_astro/LanguageSelector.Dx6zaHYm.js +14 -0
  14. package/dist/client/_astro/MediaLibrary.BXUJ5yFA.js +1 -0
  15. package/dist/client/_astro/PostTypesManager.CA2yTVB_.js +1 -0
  16. package/dist/client/_astro/QuickDraftWidget.CCKwWLpX.js +17 -0
  17. package/dist/client/_astro/ScreenOptions.Dgiw-9ow.js +70 -0
  18. package/dist/client/_astro/TaxonomiesManager.D3HNo_oM.js +1 -0
  19. package/dist/client/_astro/UserCreateForm.CTv1Gd43.js +1 -0
  20. package/dist/client/_astro/UsersManager.DPpSVGNe.js +1 -0
  21. package/dist/client/_astro/api.DTNuyqvx.js +1 -0
  22. package/dist/client/_astro/ar.CzsjUutD.js +1 -0
  23. package/dist/client/_astro/{client.BY0Z100j.js → client.C7p516_9.js} +1 -1
  24. package/dist/client/_astro/en.DmN7xy_a.js +1 -0
  25. package/dist/client/_astro/es-ES.p2TLEMlZ.js +1 -0
  26. package/dist/client/_astro/{extensions.JQggUqT5.js → extensions.DfxrGzbo.js} +1 -1
  27. package/dist/client/_astro/he.BnYHiYpn.js +1 -0
  28. package/dist/client/_astro/i18n.CLOpd2JA.js +1 -0
  29. package/dist/client/_astro/it.WrWKBEAD.js +1 -0
  30. package/dist/client/_astro/ja.DxnfhIdt.js +1 -0
  31. package/dist/client/_astro/login.astro_astro_type_script_index_0_lang.CLM9X6sQ.js +1 -0
  32. package/dist/client/_astro/pl.jUj-RfZS.js +1 -0
  33. package/dist/client/_astro/pt-BR.DtNwEO0i.js +1 -0
  34. package/dist/client/_astro/ru.KFSfdjWn.js +1 -0
  35. package/dist/client/_astro/{src.DX_xrAwd.js → src.Cgonpfb5.js} +1 -1
  36. package/dist/client/_astro/sw.3jlAOLOv.js +1 -0
  37. package/dist/client/_astro/tr.tnLMnGPg.js +1 -0
  38. package/dist/client/_astro/uk.VquHY_xc.js +1 -0
  39. package/dist/client/_astro/version.BAM_tCGw.js +1 -0
  40. package/dist/client/_astro/{web.D_vCtCLj.js → web.D1H9RxZL.js} +1 -1
  41. package/dist/client/_astro/yo.Cr8hCb5u.js +1 -0
  42. package/dist/client/_astro/zh-CN.E32QqP4v.js +1 -0
  43. package/dist/server/chunks/{BaseLayout_CcUFilW5.mjs → BaseLayout_GUKuUGNt.mjs} +4 -1
  44. package/dist/server/chunks/{ContentEditor_DtKBw5Nv.mjs → ContentEditor_D_mc9cIc.mjs} +38 -24
  45. package/dist/server/chunks/DashboardLayout_DVdPm1iI.mjs +2084 -0
  46. package/dist/server/chunks/{MediaLibrary_BDyBahZ3.mjs → MediaLibrary_BV1YB_7x.mjs} +90 -65
  47. package/dist/server/chunks/{_slug__DNJwUFYD.mjs → _slug__D0xMd1Ym.mjs} +1 -1
  48. package/dist/server/chunks/ar_DBjdWIJ0.mjs +408 -0
  49. package/dist/server/chunks/{edit_CSA-bTD0.mjs → edit_DmKkdawE.mjs} +8 -4
  50. package/dist/server/chunks/en_C750mYKk.mjs +408 -0
  51. package/dist/server/chunks/es-ES_TJ4oK1yi.mjs +408 -0
  52. package/dist/server/chunks/{general_D8esOFBG.mjs → general_CfZaFpuy.mjs} +50 -39
  53. package/dist/server/chunks/he_TWsuTphz.mjs +408 -0
  54. package/dist/server/chunks/index_BHrVcd5b.mjs +27 -0
  55. package/dist/server/chunks/{index_BzJtUv3l.mjs → index_BjydUJNY.mjs} +9 -5
  56. package/dist/server/chunks/{index__EF7aYFm.mjs → index_BoeLyrhK.mjs} +91 -45
  57. package/dist/server/chunks/{index_CSD_Oyb4.mjs → index_D_aAiDE0.mjs} +61 -38
  58. package/dist/server/chunks/index_GAl799IJ.mjs +152 -0
  59. package/dist/server/chunks/it_CEVFVWh1.mjs +408 -0
  60. package/dist/server/chunks/ja_CqDirMqf.mjs +408 -0
  61. package/dist/server/chunks/login_B7FSWUaM.mjs +24 -0
  62. package/dist/server/chunks/{new_C7iXK0wp.mjs → new_BRMGHdiW.mjs} +8 -4
  63. package/dist/server/chunks/{new_Dg7GlHuV.mjs → new_DkKhl-3k.mjs} +30 -14
  64. package/dist/server/chunks/pl_ChIKxfZG.mjs +408 -0
  65. package/dist/server/chunks/post-types_B7f9RrsE.mjs +158 -0
  66. package/dist/server/chunks/pt-BR_4d4jZWL0.mjs +408 -0
  67. package/dist/server/chunks/ru_CIc6O5Q7.mjs +408 -0
  68. package/dist/server/chunks/sw_Bs3iYVDM.mjs +408 -0
  69. package/dist/server/chunks/{taxonomies_BJehVfgw.mjs → taxonomies_DadZj79u.mjs} +31 -14
  70. package/dist/server/chunks/tr_C7JbXuoQ.mjs +408 -0
  71. package/dist/server/chunks/uk_Dibs8Wkc.mjs +408 -0
  72. package/dist/server/chunks/{upload_CeK7uSwz.mjs → upload_CMYjz_4a.mjs} +9 -5
  73. package/dist/server/chunks/yo_B6MPvz_U.mjs +408 -0
  74. package/dist/server/chunks/zh-CN_G1Dc2b28.mjs +408 -0
  75. package/dist/server/entry.mjs +15 -15
  76. package/package.json +4 -4
  77. package/dist/client/_astro/BaseLayout.BPkaFsmK.css +0 -1
  78. package/dist/client/_astro/ContentEditor.Buc5ptK0.js +0 -1
  79. package/dist/client/_astro/ContentList.Bo_ok2oa.js +0 -1
  80. package/dist/client/_astro/DashboardHome.DKuoH-SO.js +0 -1
  81. package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.DfB7XHS-.js +0 -1
  82. package/dist/client/_astro/GeneralSettings.BNzHpRY6.js +0 -1
  83. package/dist/client/_astro/MediaLibrary.Dn4DRbZb.js +0 -1
  84. package/dist/client/_astro/PostTypesManager.6GQ4vWY1.js +0 -1
  85. package/dist/client/_astro/TaxonomiesManager.B25xOjSO.js +0 -1
  86. package/dist/client/_astro/UserCreateForm.DtBifGTo.js +0 -1
  87. package/dist/client/_astro/UsersManager.-5jU3GxA.js +0 -1
  88. package/dist/client/_astro/api.BEC1o0dT.js +0 -1
  89. package/dist/client/_astro/login.astro_astro_type_script_index_0_lang.CWNQruNb.js +0 -1
  90. package/dist/server/chunks/DashboardLayout_Bpur473M.mjs +0 -442
  91. package/dist/server/chunks/api_i8T-MI6L.mjs +0 -278
  92. package/dist/server/chunks/index_BCUHGT54.mjs +0 -133
  93. package/dist/server/chunks/index_X49R9glL.mjs +0 -23
  94. package/dist/server/chunks/login_BTd7KCCx.mjs +0 -23
  95. package/dist/server/chunks/post-types_CJt6sMSh.mjs +0 -137
@@ -0,0 +1,2084 @@
1
+ import "./rolldown-runtime_BMI-E3GI.mjs";
2
+ import { S as createAstro, d as maybeRenderHead, i as renderComponent, p as addAttribute, s as renderSlot, u as renderTemplate } from "./server_B5N27szj.mjs";
3
+ import { t as createComponent$1 } from "./compiler_O7J1rlsi.mjs";
4
+ import { n as renderScript, t as $$BaseLayout } from "./BaseLayout_GUKuUGNt.mjs";
5
+ import { t as require_semver } from "./semver_WbqCUY_o.mjs";
6
+ import { createComponent, escape, ssr, ssrAttribute, ssrHydrationKey, ssrStyle } from "solid-js/web";
7
+ import { For, For as For2, Show, Show as Show2, createMemo as createMemo$1, createSignal, createSignal as createSignal$1, onCleanup, onMount, onMount as onMount$1 } from "solid-js";
8
+ require_semver();
9
+ //#endregion
10
+ //#region ../../packages/ui/dist/server.js
11
+ var _tmpl$$10 = ["<span", " class=\"spinner\" aria-label=\"Carregando\"></span>"];
12
+ var _tmpl$2$9 = [
13
+ "<button",
14
+ "",
15
+ ">",
16
+ "</button>"
17
+ ];
18
+ var _tmpl$3$7 = [
19
+ "<label",
20
+ " class=\"field__label\"><!--$-->",
21
+ "<!--/--><!--$-->",
22
+ "<!--/--><input class=\"input\"",
23
+ "",
24
+ "",
25
+ "></label>"
26
+ ];
27
+ var _tmpl$4$6 = [
28
+ "<input",
29
+ " class=\"input\"",
30
+ "",
31
+ "",
32
+ ">"
33
+ ];
34
+ var _tmpl$5$3 = [
35
+ "<p",
36
+ " class=\"field__error notice--error\">",
37
+ "</p>"
38
+ ];
39
+ var _tmpl$6$3 = [
40
+ "<div",
41
+ "><!--$-->",
42
+ "<!--/--><!--$-->",
43
+ "<!--/--><!--$-->",
44
+ "<!--/--></div>"
45
+ ];
46
+ var _tmpl$7$2 = ["<span", " aria-hidden=\"true\"> *</span>"];
47
+ var _tmpl$8$2 = [
48
+ "<option",
49
+ " value>",
50
+ "</option>"
51
+ ];
52
+ var _tmpl$9$1 = [
53
+ "<label",
54
+ " class=\"field__label\"><!--$-->",
55
+ "<!--/--><select class=\"input\"",
56
+ "",
57
+ "><!--$-->",
58
+ "<!--/--><!--$-->",
59
+ "<!--/--></select></label>"
60
+ ];
61
+ var _tmpl$0$1 = [
62
+ "<select",
63
+ " class=\"input\"",
64
+ "",
65
+ "><!--$-->",
66
+ "<!--/--><!--$-->",
67
+ "<!--/--></select>"
68
+ ];
69
+ var _tmpl$1$1 = [
70
+ "<div",
71
+ "><!--$-->",
72
+ "<!--/--><!--$-->",
73
+ "<!--/--></div>"
74
+ ];
75
+ var _tmpl$10 = [
76
+ "<option",
77
+ ">",
78
+ "</option>"
79
+ ];
80
+ var _tmpl$11 = [
81
+ "<div",
82
+ " class=\"card-header\"><h3>",
83
+ "</h3></div>"
84
+ ];
85
+ var _tmpl$12 = [
86
+ "<span",
87
+ " class=\"",
88
+ "\">",
89
+ "</span>"
90
+ ];
91
+ var _tmpl$15 = [
92
+ "<table",
93
+ " class=\"table\"><thead><tr>",
94
+ "</tr></thead><tbody>",
95
+ "</tbody></table>"
96
+ ];
97
+ var _tmpl$16 = ["<div", " class=\"table-loading\"><span class=\"spinner\" aria-label=\"Carregando\"></span></div>"];
98
+ var _tmpl$17 = [
99
+ "<p",
100
+ " class=\"muted\">",
101
+ "</p>"
102
+ ];
103
+ var _tmpl$18 = [
104
+ "<th",
105
+ " style=\"",
106
+ "\">",
107
+ "</th>"
108
+ ];
109
+ var _tmpl$19 = [
110
+ "<tr",
111
+ ">",
112
+ "</tr>"
113
+ ];
114
+ var _tmpl$20 = [
115
+ "<td",
116
+ ">",
117
+ "</td>"
118
+ ];
119
+ var _tmpl$21 = [
120
+ "<div",
121
+ " class=\"pagination\"><button class=\"btn btn-secondary btn-sm\" type=\"button\"",
122
+ ">← Anterior</button><span class=\"muted\">Página <!--$-->",
123
+ "<!--/--> de <!--$-->",
124
+ "<!--/--></span><button class=\"btn btn-secondary btn-sm\" type=\"button\"",
125
+ ">Próxima →</button></div>"
126
+ ];
127
+ var BTN_VARIANTS = [
128
+ "primary",
129
+ "secondary",
130
+ "danger",
131
+ "ghost"
132
+ ];
133
+ function Button(props) {
134
+ const variant = BTN_VARIANTS.includes(props.variant) ? props.variant : "secondary";
135
+ const classes = () => [
136
+ "btn",
137
+ `btn-${variant}`,
138
+ props.size === "sm" ? "btn-sm" : "",
139
+ props.class ?? ""
140
+ ].filter(Boolean).join(" ");
141
+ return ssr(_tmpl$2$9, ssrHydrationKey() + ssrAttribute("type", escape(props.type ?? "button", true), false) + ssrAttribute("class", escape(classes(), true), false), ssrAttribute("disabled", props.disabled || props.loading, true), escape(createComponent(Show, {
142
+ get when() {
143
+ return props.loading;
144
+ },
145
+ get fallback() {
146
+ return props.children;
147
+ },
148
+ get children() {
149
+ return ssr(_tmpl$$10, ssrHydrationKey());
150
+ }
151
+ })));
152
+ }
153
+ function Input(props) {
154
+ return ssr(_tmpl$6$3, ssrHydrationKey() + ssrAttribute("class", escape(`field ${props.class ?? ""}`.trim(), true), false), escape(createComponent(Show, {
155
+ get when() {
156
+ return props.label;
157
+ },
158
+ get children() {
159
+ return ssr(_tmpl$3$7, ssrHydrationKey(), escape(props.label), props.required ? _tmpl$7$2[0] + ssrHydrationKey() + _tmpl$7$2[1] : escape(null), ssrAttribute("type", escape(props.type ?? "text", true), false) + ssrAttribute("name", escape(props.name, true), false) + ssrAttribute("value", escape(props.value ?? "", true), false) + ssrAttribute("placeholder", escape(props.placeholder, true), false), ssrAttribute("disabled", props.disabled, true), ssrAttribute("required", props.required, true));
160
+ }
161
+ })), escape(createComponent(Show, {
162
+ get when() {
163
+ return !props.label;
164
+ },
165
+ get children() {
166
+ return ssr(_tmpl$4$6, ssrHydrationKey(), ssrAttribute("type", escape(props.type ?? "text", true), false) + ssrAttribute("name", escape(props.name, true), false) + ssrAttribute("value", escape(props.value ?? "", true), false) + ssrAttribute("placeholder", escape(props.placeholder, true), false), ssrAttribute("disabled", props.disabled, true), ssrAttribute("required", props.required, true));
167
+ }
168
+ })), escape(createComponent(Show, {
169
+ get when() {
170
+ return props.error;
171
+ },
172
+ get children() {
173
+ return ssr(_tmpl$5$3, ssrHydrationKey(), escape(props.error));
174
+ }
175
+ })));
176
+ }
177
+ function Select(props) {
178
+ const options = props.options;
179
+ return ssr(_tmpl$1$1, ssrHydrationKey() + ssrAttribute("class", escape(`field ${props.class ?? ""}`.trim(), true), false), escape(createComponent(Show, {
180
+ get when() {
181
+ return props.label;
182
+ },
183
+ get children() {
184
+ return ssr(_tmpl$9$1, ssrHydrationKey(), escape(props.label), ssrAttribute("name", escape(props.name, true), false) + ssrAttribute("value", escape(props.value ?? "", true), false), ssrAttribute("disabled", props.disabled, true), escape(createComponent(Show, {
185
+ get when() {
186
+ return props.placeholder;
187
+ },
188
+ get children() {
189
+ return ssr(_tmpl$8$2, ssrHydrationKey(), escape(props.placeholder));
190
+ }
191
+ })), escape(createComponent(For, {
192
+ each: options,
193
+ children: (option) => ssr(_tmpl$10, ssrHydrationKey() + ssrAttribute("value", escape(option.value, true), false), escape(option.label))
194
+ })));
195
+ }
196
+ })), escape(createComponent(Show, {
197
+ get when() {
198
+ return !props.label;
199
+ },
200
+ get children() {
201
+ return ssr(_tmpl$0$1, ssrHydrationKey(), ssrAttribute("name", escape(props.name, true), false) + ssrAttribute("value", escape(props.value ?? "", true), false), ssrAttribute("disabled", props.disabled, true), escape(createComponent(Show, {
202
+ get when() {
203
+ return props.placeholder;
204
+ },
205
+ get children() {
206
+ return ssr(_tmpl$8$2, ssrHydrationKey(), escape(props.placeholder));
207
+ }
208
+ })), escape(createComponent(For, {
209
+ each: options,
210
+ children: (option) => ssr(_tmpl$10, ssrHydrationKey() + ssrAttribute("value", escape(option.value, true), false), escape(option.label))
211
+ })));
212
+ }
213
+ })));
214
+ }
215
+ function Card(props) {
216
+ return ssr(_tmpl$1$1, ssrHydrationKey() + ssrAttribute("class", escape(`card ${props.class ?? ""}`.trim(), true), false), escape(createComponent(Show, {
217
+ get when() {
218
+ return props.title;
219
+ },
220
+ get children() {
221
+ return ssr(_tmpl$11, ssrHydrationKey(), escape(props.title));
222
+ }
223
+ })), escape(props.children));
224
+ }
225
+ function Badge(props) {
226
+ const variant = props.variant ?? "secondary";
227
+ return ssr(_tmpl$12, ssrHydrationKey(), `badge badge-${escape(variant, true)}`, escape(props.children));
228
+ }
229
+ function Table(props) {
230
+ const columns = props.columns;
231
+ return createComponent(Show, {
232
+ get when() {
233
+ return !props.loading;
234
+ },
235
+ get fallback() {
236
+ return ssr(_tmpl$16, ssrHydrationKey());
237
+ },
238
+ get children() {
239
+ return createComponent(Show, {
240
+ get when() {
241
+ return props.data.length > 0;
242
+ },
243
+ get fallback() {
244
+ return ssr(_tmpl$17, ssrHydrationKey(), escape(props.emptyMessage ?? "Nenhum registro."));
245
+ },
246
+ get children() {
247
+ return ssr(_tmpl$15, ssrHydrationKey(), escape(createComponent(For, {
248
+ each: columns,
249
+ children: (column) => ssr(_tmpl$18, ssrHydrationKey(), ssrStyle(column.width ? { width: column.width } : void 0), escape(column.label))
250
+ })), escape(createComponent(For, {
251
+ get each() {
252
+ return props.data;
253
+ },
254
+ children: (row) => ssr(_tmpl$19, ssrHydrationKey(), escape(createComponent(For, {
255
+ each: columns,
256
+ children: (column) => ssr(_tmpl$20, ssrHydrationKey(), escape(createComponent(Show, {
257
+ get when() {
258
+ return column.render;
259
+ },
260
+ get fallback() {
261
+ return String(row[column.key] ?? "");
262
+ },
263
+ get children() {
264
+ var _a;
265
+ return (_a = column.render) == null ? void 0 : _a.call(column, row[column.key], row);
266
+ }
267
+ })))
268
+ })))
269
+ })));
270
+ }
271
+ });
272
+ }
273
+ });
274
+ }
275
+ function Pagination(props) {
276
+ const totalPages = () => Math.max(1, Math.ceil(props.total / Math.max(1, props.limit)));
277
+ return createComponent(Show, {
278
+ get when() {
279
+ return totalPages() > 1;
280
+ },
281
+ get children() {
282
+ return ssr(_tmpl$21, ssrHydrationKey(), ssrAttribute("disabled", props.page <= 1, true), escape(props.page), escape(totalPages()), ssrAttribute("disabled", props.page >= totalPages(), true));
283
+ }
284
+ });
285
+ }
286
+ //#endregion
287
+ //#region src/ext/slots.tsx
288
+ var _tmpl$$9 = [
289
+ "<a",
290
+ " href=\"",
291
+ "\" class=\"sidebar__link\"><!--$-->",
292
+ "<!--/--> <!--$-->",
293
+ "<!--/--></a>"
294
+ ];
295
+ var _tmpl$2$8 = [
296
+ "<span",
297
+ " aria-hidden=\"true\">",
298
+ "</span>"
299
+ ];
300
+ /**
301
+ * Slots nomeados consumidos pelo shell do admin.
302
+ * Plugins registram extensões via SDK; o admin apenas renderiza
303
+ * os dados declarativos — sem injeção de DOM direta (DECI-027).
304
+ */
305
+ function AdminSidebarSlot(props) {
306
+ const allowedPages = () => props.extensions.menuPages.filter((page) => props.can(page.capability ?? "read"));
307
+ return createComponent(For, {
308
+ get each() {
309
+ return allowedPages();
310
+ },
311
+ children: (page) => ssr(_tmpl$$9, ssrHydrationKey(), `/plugins/${escape(page.slug, true)}`, page.icon ? ssr(_tmpl$2$8, ssrHydrationKey(), escape(page.icon)) : escape(null), escape(page.label))
312
+ });
313
+ }
314
+ //#endregion
315
+ //#region src/ext/extensions.tsx
316
+ var _tmpl$$8 = [
317
+ "<div",
318
+ " class=\"sidebar-plugins\" data-extensions=\"sidebar\"><!--$-->",
319
+ "<!--/--><!--$-->",
320
+ "<!--/--></div>"
321
+ ];
322
+ var _tmpl$2$7 = [
323
+ "<div",
324
+ " class=\"",
325
+ "\"",
326
+ "><span>",
327
+ "</span></div>"
328
+ ];
329
+ function emptyExtensionsState() {
330
+ return {
331
+ menuPages: [],
332
+ submenuPages: [],
333
+ dashboardWidgets: [],
334
+ metaBoxes: [],
335
+ notices: [],
336
+ columns: {},
337
+ columnRenderers: {},
338
+ actionLinks: []
339
+ };
340
+ }
341
+ /** Converte as rows de plugins (API) no estado declarativo dos slots. */
342
+ function extensionsFromPlugins(plugins) {
343
+ const state = emptyExtensionsState();
344
+ for (const plugin of plugins) {
345
+ if (plugin.status !== "ACTIVE") continue;
346
+ const admin = plugin.manifest?.admin;
347
+ if (!admin) continue;
348
+ const pluginSlug = plugin.slug ?? plugin.name;
349
+ state.menuPages.push(...admin.menuPages?.map((page) => ({
350
+ ...page,
351
+ slug: page.slug.startsWith(`${pluginSlug}/`) ? page.slug : `${pluginSlug}/${page.slug}`
352
+ })) ?? []);
353
+ state.dashboardWidgets.push(...admin.dashboardWidgets?.map((widget) => ({
354
+ ...widget,
355
+ id: widget.id.includes(":") ? widget.id : `${pluginSlug}:${widget.id}`,
356
+ componentId: widget.componentId.includes(":") ? widget.componentId : `${pluginSlug}:${widget.componentId}`
357
+ })) ?? []);
358
+ state.notices.push(...admin.notices?.map((notice) => ({
359
+ ...notice,
360
+ id: notice.id.includes(":") ? notice.id : `${pluginSlug}:${notice.id}`
361
+ })) ?? []);
362
+ }
363
+ return state;
364
+ }
365
+ /** Ilha client-side: busca plugins → AdminExtensionsState → slots. */
366
+ function PluginExtensionsSlot() {
367
+ const [extensions, setExtensions] = createSignal$1(emptyExtensionsState());
368
+ onMount$1(async () => {
369
+ try {
370
+ const response = await fetch("/api/v1/plugins", { credentials: "include" });
371
+ if (!response.ok) return;
372
+ const plugins = await response.json();
373
+ setExtensions(extensionsFromPlugins(plugins));
374
+ } catch {}
375
+ });
376
+ const can = () => true;
377
+ return createComponent(Show2, {
378
+ get when() {
379
+ return extensions().menuPages.length > 0;
380
+ },
381
+ get children() {
382
+ return ssr(_tmpl$$8, ssrHydrationKey(), escape(createComponent(For2, {
383
+ get each() {
384
+ return extensions().notices;
385
+ },
386
+ children: (notice) => ssr(_tmpl$2$7, ssrHydrationKey(), `notice notice--${escape(notice.level, true)}`, ssrAttribute("data-plugin", escape(notice.id.split(":")[0], true), false), escape(notice.message))
387
+ })), escape(createComponent(AdminSidebarSlot, {
388
+ get extensions() {
389
+ return extensions();
390
+ },
391
+ can
392
+ })));
393
+ }
394
+ });
395
+ }
396
+ //#endregion
397
+ //#region src/i18n/config.ts
398
+ var SUPPORTED_LOCALES = [
399
+ "pt-BR",
400
+ "en",
401
+ "es-ES",
402
+ "ru",
403
+ "uk",
404
+ "tr",
405
+ "he",
406
+ "it",
407
+ "pl",
408
+ "zh-CN",
409
+ "ja",
410
+ "ar",
411
+ "sw",
412
+ "yo",
413
+ "zu",
414
+ "am",
415
+ "ha",
416
+ "ig"
417
+ ];
418
+ var DEFAULT_LOCALE = "pt-BR";
419
+ var LOCALE_LABELS = {
420
+ "pt-BR": "Português (Brasil)",
421
+ "en": "English",
422
+ "es-ES": "Español",
423
+ "ru": "Русский",
424
+ "uk": "Українська",
425
+ "tr": "Türkçe",
426
+ "he": "עברית",
427
+ "it": "Italiano",
428
+ "pl": "Polski",
429
+ "zh-CN": "中文 (简体)",
430
+ "ja": "日本語",
431
+ "ar": "العربية",
432
+ "sw": "Kiswahili",
433
+ "yo": "Yorùbá",
434
+ "zu": "isiZulu",
435
+ "am": "አማርኛ",
436
+ "ha": "Hausa",
437
+ "ig": "Igbo"
438
+ };
439
+ var LOCALE_FLAGS = {
440
+ "pt-BR": "🇧🇷",
441
+ "en": "🇺🇸",
442
+ "es-ES": "🇪🇸",
443
+ "ru": "🇷🇺",
444
+ "uk": "🇺🇦",
445
+ "tr": "🇹🇷",
446
+ "he": "🇮🇱",
447
+ "it": "🇮🇹",
448
+ "pl": "🇵🇱",
449
+ "zh-CN": "🇨🇳",
450
+ "ja": "🇯🇵",
451
+ "ar": "🇸🇦",
452
+ "sw": "🇹🇿",
453
+ "yo": "🇳🇬",
454
+ "zu": "🇿🇦",
455
+ "am": "🇪🇹",
456
+ "ha": "🇳🇬",
457
+ "ig": "🇳🇬"
458
+ };
459
+ //#endregion
460
+ //#region \0rolldown_dynamic_import_helper.js
461
+ var _rolldown_dynamic_import_helper_default = (glob, path, segments) => {
462
+ const query = path.lastIndexOf("?");
463
+ const v = glob[query === -1 || query < path.lastIndexOf("/") ? path : path.slice(0, query)];
464
+ if (v) return typeof v === "function" ? v() : Promise.resolve(v);
465
+ return new Promise((_, reject) => {
466
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, /* @__PURE__ */ new Error("Unknown variable dynamic import: " + path + (path.split("/").length !== segments ? ". Note that variables only represent file names one level deep." : ""))));
467
+ });
468
+ };
469
+ //#endregion
470
+ //#region src/i18n/loaders.ts
471
+ var localeCache = /* @__PURE__ */ new Map();
472
+ /** Carrega arquivo JSON de locale */
473
+ async function loadLocale(locale) {
474
+ if (localeCache.has(locale)) return localeCache.get(locale);
475
+ try {
476
+ const module = await _rolldown_dynamic_import_helper_default(/* #__PURE__ */ Object.assign({
477
+ "./locales/ar.json": () => import("./ar_DBjdWIJ0.mjs"),
478
+ "./locales/en.json": () => import("./en_C750mYKk.mjs"),
479
+ "./locales/es-ES.json": () => import("./es-ES_TJ4oK1yi.mjs"),
480
+ "./locales/he.json": () => import("./he_TWsuTphz.mjs"),
481
+ "./locales/it.json": () => import("./it_CEVFVWh1.mjs"),
482
+ "./locales/ja.json": () => import("./ja_CqDirMqf.mjs"),
483
+ "./locales/pl.json": () => import("./pl_ChIKxfZG.mjs"),
484
+ "./locales/pt-BR.json": () => import("./pt-BR_4d4jZWL0.mjs"),
485
+ "./locales/ru.json": () => import("./ru_CIc6O5Q7.mjs"),
486
+ "./locales/sw.json": () => import("./sw_Bs3iYVDM.mjs"),
487
+ "./locales/tr.json": () => import("./tr_C7JbXuoQ.mjs"),
488
+ "./locales/uk.json": () => import("./uk_Dibs8Wkc.mjs"),
489
+ "./locales/yo.json": () => import("./yo_B6MPvz_U.mjs"),
490
+ "./locales/zh-CN.json": () => import("./zh-CN_G1Dc2b28.mjs")
491
+ }), `./locales/${locale}.json`, 3);
492
+ const translations = module.default ?? module;
493
+ localeCache.set(locale, translations);
494
+ return translations;
495
+ } catch {
496
+ if (locale !== "en") return loadLocale("en");
497
+ return {};
498
+ }
499
+ }
500
+ //#endregion
501
+ //#region src/lib/api.ts
502
+ var API_BASE = "http://localhost:3000";
503
+ var ApiClient = class {
504
+ baseUrl;
505
+ csrfToken = null;
506
+ isRefreshing = false;
507
+ constructor(baseUrl = API_BASE) {
508
+ this.baseUrl = baseUrl;
509
+ }
510
+ /** Inicializa lendo CSRF do cookie (chamado no boot da app) */
511
+ async init() {
512
+ try {
513
+ await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" });
514
+ } catch {}
515
+ }
516
+ /** Sessão válida — verifica via /me (usa cookies HttpOnly automaticamente) */
517
+ async isLoggedIn() {
518
+ try {
519
+ return (await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" })).ok;
520
+ } catch {
521
+ return false;
522
+ }
523
+ }
524
+ /** Obtém tenantId do backend via /me */
525
+ async getTenantId() {
526
+ try {
527
+ const res = await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" });
528
+ if (!res.ok) return null;
529
+ return (await res.json()).tenantId ?? null;
530
+ } catch {
531
+ return null;
532
+ }
533
+ }
534
+ /** Obtém locale do usuário logado via /me/locale */
535
+ async getUserLocale() {
536
+ try {
537
+ const res = await fetch(`${this.baseUrl}/api/v1/users/me/locale`, { credentials: "include" });
538
+ if (!res.ok) return "pt-BR";
539
+ return (await res.json()).locale ?? "pt-BR";
540
+ } catch {
541
+ return "pt-BR";
542
+ }
543
+ }
544
+ /** Salva locale do usuário via /me/locale */
545
+ async setUserLocale(locale) {
546
+ await this.request("PUT", "/api/v1/users/me/locale", { locale });
547
+ }
548
+ /** Sessão atual (/auth/me) — usuário + tenant + papéis (alimenta o admin bar) */
549
+ async getMe() {
550
+ return this.request("GET", "/api/v1/auth/me");
551
+ }
552
+ /** Auditoria recente — notificações reais do sino no admin bar */
553
+ async getAuditLogs(limit = 8) {
554
+ return this.request("GET", `/api/v1/audit-logs?limit=${limit}`);
555
+ }
556
+ /** Login — o backend seta cookies HttpOnly e CSRF; retorna user + tenantId */
557
+ async login(input) {
558
+ return await this.request("POST", "/api/v1/auth/login", input);
559
+ }
560
+ /** Logout — limpa cookies no backend */
561
+ async logout() {
562
+ await this.request("POST", "/api/v1/auth/logout", {});
563
+ this.csrfToken = null;
564
+ }
565
+ /** Refresh de access token via cookie refresh_token */
566
+ async refreshTokens() {
567
+ if (this.isRefreshing) return;
568
+ this.isRefreshing = true;
569
+ try {
570
+ await this.request("POST", "/api/v1/auth/refresh", {});
571
+ } finally {
572
+ this.isRefreshing = false;
573
+ }
574
+ }
575
+ /** Requisição genérica com:
576
+ * - credentials: 'include' (envia cookies HttpOnly)
577
+ * - auto-refresh em 401
578
+ * - CSRF header para mutações
579
+ */
580
+ async request(method, path, body, headers) {
581
+ const url = `${this.baseUrl}${path}`;
582
+ const requestHeaders = {
583
+ "Content-Type": "application/json",
584
+ ...headers
585
+ };
586
+ if (![
587
+ "GET",
588
+ "HEAD",
589
+ "OPTIONS"
590
+ ].includes(method.toUpperCase())) {
591
+ const csrf = this.getCsrfToken();
592
+ if (csrf) requestHeaders["x-csrf-token"] = csrf;
593
+ }
594
+ let response = await fetch(url, {
595
+ method,
596
+ headers: requestHeaders,
597
+ credentials: "include",
598
+ body: body ? JSON.stringify(body) : void 0
599
+ });
600
+ if (response.status === 401 && !path.includes("/auth/refresh") && !path.includes("/auth/logout")) {
601
+ await this.refreshTokens();
602
+ response = await fetch(url, {
603
+ method,
604
+ headers: requestHeaders,
605
+ credentials: "include",
606
+ body: body ? JSON.stringify(body) : void 0
607
+ });
608
+ }
609
+ if (!response.ok) {
610
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
611
+ throw new Error(error.error ?? `Request failed: ${response.status}`);
612
+ }
613
+ const setCookie = response.headers.get("set-cookie");
614
+ if (setCookie) {
615
+ const csrfMatch = setCookie.match(/csrf_token=([^;]+)/);
616
+ if (csrfMatch?.[1]) this.csrfToken = csrfMatch[1];
617
+ }
618
+ return response.json();
619
+ }
620
+ /** Lê CSRF token do cookie (document.cookie) */
621
+ getCsrfToken() {
622
+ if (this.csrfToken) return this.csrfToken;
623
+ if (typeof document !== "undefined") {
624
+ const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/);
625
+ if (match?.[1]) return match[1];
626
+ }
627
+ return null;
628
+ }
629
+ async getContent(options) {
630
+ const params = new URLSearchParams();
631
+ if (options?.page) params.set("page", String(options.page));
632
+ if (options?.limit) params.set("limit", String(options.limit));
633
+ if (options?.type) params.set("type", options.type);
634
+ if (options?.status) params.set("status", options.status);
635
+ if (options?.search) params.set("search", options.search);
636
+ return this.request("GET", `/api/v1/content?${params.toString()}`);
637
+ }
638
+ async getContentById(id) {
639
+ return this.request("GET", `/api/v1/content/${id}`);
640
+ }
641
+ async createContent(data) {
642
+ return this.request("POST", `/api/v1/content`, data);
643
+ }
644
+ async updateContent(id, data) {
645
+ return this.request("PUT", `/api/v1/content/${id}`, data);
646
+ }
647
+ async deleteContent(id) {
648
+ await this.request("DELETE", `/api/v1/content/${id}`);
649
+ }
650
+ /** A2: publica via rota real do publisher (eventBus + cache + revisions). */
651
+ async publishContent(id) {
652
+ return this.request("POST", `/api/v1/content/${id}/publish`);
653
+ }
654
+ /** A2: despublica via rota real do publisher. */
655
+ async unpublishContent(id) {
656
+ return this.request("POST", `/api/v1/content/${id}/unpublish`);
657
+ }
658
+ /** Atalho usado pela ContentList: publish/unpublish conforme status atual. */
659
+ async publishToggle(id, isPublished) {
660
+ return isPublished ? this.unpublishContent(id) : this.publishContent(id);
661
+ }
662
+ async getContentTypes() {
663
+ return this.request("GET", "/api/v1/content-types");
664
+ }
665
+ async createContentType(data) {
666
+ return this.request("POST", "/api/v1/content-types", data);
667
+ }
668
+ async updateContentType(slug, data) {
669
+ return this.request("PUT", `/api/v1/content-types/${slug}`, data);
670
+ }
671
+ async deleteContentType(slug) {
672
+ await this.request("DELETE", `/api/v1/content-types/${slug}`);
673
+ }
674
+ async getTaxonomies() {
675
+ return this.request("GET", "/api/v1/taxonomies");
676
+ }
677
+ async createTaxonomy(data) {
678
+ return this.request("POST", "/api/v1/taxonomies", data);
679
+ }
680
+ async attachTaxonomy(slug, contentType) {
681
+ await this.request("POST", `/api/v1/taxonomies/${slug}/attach`, { contentType });
682
+ }
683
+ async detachTaxonomy(slug, contentType) {
684
+ await this.request("POST", `/api/v1/taxonomies/${slug}/detach`, { contentType });
685
+ }
686
+ async deleteTaxonomy(slug) {
687
+ await this.request("DELETE", `/api/v1/taxonomies/${slug}`);
688
+ }
689
+ async getFieldGroups(context) {
690
+ if (context?.type) {
691
+ const qs = new URLSearchParams({ type: context.type });
692
+ for (const [key, value] of Object.entries(context)) if (key !== "type" && value) qs.set(key, value);
693
+ return this.request("GET", `/api/v1/field-groups?${qs.toString()}`);
694
+ }
695
+ return this.request("GET", "/api/v1/field-groups");
696
+ }
697
+ async getFieldGroup(id) {
698
+ return this.request("GET", `/api/v1/field-groups/${id}`);
699
+ }
700
+ async createFieldGroup(data) {
701
+ return this.request("POST", "/api/v1/field-groups", data);
702
+ }
703
+ async getFieldTypes(category) {
704
+ const query = category ? `?category=${encodeURIComponent(category)}` : "";
705
+ return this.request("GET", `/api/v1/field-types${query}`);
706
+ }
707
+ async listMedia(options) {
708
+ const params = new URLSearchParams();
709
+ if (options?.page) params.set("page", String(options.page));
710
+ if (options?.limit) params.set("limit", String(options.limit));
711
+ if (options?.mimeType) params.set("mimeType", options.mimeType);
712
+ if (options?.search) params.set("search", options.search);
713
+ return this.request("GET", `/api/v1/media?${params.toString()}`);
714
+ }
715
+ async getMedia(id) {
716
+ return this.request("GET", `/api/v1/media/${id}`);
717
+ }
718
+ /** Upload multipart — NÃO seta Content-Type (o fetch precisa do boundary). */
719
+ async uploadMedia(file, options) {
720
+ const formData = new FormData();
721
+ formData.append("file", file);
722
+ if (options?.alt) formData.append("alt", options.alt);
723
+ if (options?.caption) formData.append("caption", options.caption);
724
+ const url = `${this.baseUrl}/api/v1/media/upload`;
725
+ const requestHeaders = {};
726
+ const csrf = this.getCsrfToken();
727
+ if (csrf) requestHeaders["x-csrf-token"] = csrf;
728
+ const response = await fetch(url, {
729
+ method: "POST",
730
+ headers: requestHeaders,
731
+ credentials: "include",
732
+ body: formData
733
+ });
734
+ if (!response.ok) {
735
+ const error = await response.json().catch(() => ({ error: `Upload failed: ${response.status}` }));
736
+ throw new Error(error.error ?? `Upload failed: ${response.status}`);
737
+ }
738
+ return response.json();
739
+ }
740
+ async updateMedia(id, data) {
741
+ return this.request("PUT", `/api/v1/media/${id}`, data);
742
+ }
743
+ async deleteMedia(id) {
744
+ await this.request("DELETE", `/api/v1/media/${id}`);
745
+ }
746
+ async listUsers(options) {
747
+ const params = new URLSearchParams();
748
+ if (options?.page) params.set("page", String(options.page));
749
+ if (options?.limit) params.set("limit", String(options.limit));
750
+ if (options?.search) params.set("search", options.search);
751
+ if (options?.status) params.set("status", options.status);
752
+ return this.request("GET", `/api/v1/users?${params.toString()}`);
753
+ }
754
+ async getUser(id) {
755
+ return this.request("GET", `/api/v1/users/${id}`);
756
+ }
757
+ async createUser(data) {
758
+ return this.request("POST", "/api/v1/users", data);
759
+ }
760
+ async updateUser(id, data) {
761
+ return this.request("PUT", `/api/v1/users/${id}`, data);
762
+ }
763
+ async deleteUser(id) {
764
+ await this.request("DELETE", `/api/v1/users/${id}`);
765
+ }
766
+ async setUserPassword(id, password) {
767
+ await this.request("PUT", `/api/v1/users/${id}/password`, { password });
768
+ }
769
+ async assignRole(userId, roleId) {
770
+ return this.request("POST", `/api/v1/users/${userId}/roles`, { roleId });
771
+ }
772
+ async removeRole(userId, roleId) {
773
+ return this.request("DELETE", `/api/v1/users/${userId}/roles/${roleId}`);
774
+ }
775
+ async listRoles() {
776
+ return this.request("GET", "/api/v1/roles");
777
+ }
778
+ async getSettings(group) {
779
+ const query = group ? `?group=${encodeURIComponent(group)}` : "";
780
+ return this.request("GET", `/api/v1/settings${query}`);
781
+ }
782
+ async updateSettings(items) {
783
+ await this.request("PUT", "/api/v1/settings", items);
784
+ }
785
+ async healthCheck() {
786
+ return this.request("GET", "/health");
787
+ }
788
+ async getThemes() {
789
+ return (await this.request("GET", "/api/v1/themes")).map((theme) => ({
790
+ id: String(theme["id"] ?? ""),
791
+ name: String(theme["name"] ?? ""),
792
+ version: theme["version"] ? String(theme["version"]) : void 0,
793
+ status: String(theme["status"] ?? "INSTALLED"),
794
+ manifest: theme["manifest"] ?? null
795
+ }));
796
+ }
797
+ };
798
+ var apiClient = new ApiClient();
799
+ //#endregion
800
+ //#region src/i18n/locale.ts
801
+ var LOCALE_COOKIE = "admin_locale";
802
+ /** Obtém locale do cookie */
803
+ function getCookieLocale() {
804
+ if (typeof document === "undefined") return null;
805
+ const match = document.cookie.match(new RegExp(`(?:^|; )${LOCALE_COOKIE}=([^;]+)`));
806
+ if (match?.[1] && SUPPORTED_LOCALES.includes(match[1])) return match[1];
807
+ return null;
808
+ }
809
+ /** Define locale no cookie (1 ano) */
810
+ function setCookieLocale(locale) {
811
+ if (typeof document === "undefined") return;
812
+ document.cookie = `${LOCALE_COOKIE}=${locale}; path=/; max-age=31536000; SameSite=Lax`;
813
+ }
814
+ /** Obtém locale do Accept-Language header */
815
+ function getBrowserLocale() {
816
+ if (typeof navigator === "undefined") return DEFAULT_LOCALE;
817
+ const lang = navigator.language?.split("-")[0]?.toLowerCase();
818
+ const fullLang = navigator.language?.toLowerCase();
819
+ for (const locale of SUPPORTED_LOCALES) if (locale.toLowerCase() === fullLang || locale.split("-")[0] === lang) return locale;
820
+ return DEFAULT_LOCALE;
821
+ }
822
+ /** Obtém locale do usuário logado via API */
823
+ async function getUserLocaleFromAPI() {
824
+ try {
825
+ const locale = await apiClient.getUserLocale();
826
+ if (locale && SUPPORTED_LOCALES.includes(locale)) return locale;
827
+ } catch {}
828
+ return null;
829
+ }
830
+ /** Salva locale do usuário via API */
831
+ async function setUserLocaleInAPI(locale) {
832
+ await apiClient.setUserLocale(locale);
833
+ }
834
+ /** Resolve locale final com prioridade: cookie → user API → browser → default */
835
+ async function resolveLocale() {
836
+ const cookie = getCookieLocale();
837
+ if (cookie) return cookie;
838
+ const user = await getUserLocaleFromAPI();
839
+ if (user) return user;
840
+ const browser = getBrowserLocale();
841
+ if (browser) return browser;
842
+ return DEFAULT_LOCALE;
843
+ }
844
+ /** Muda locale (salva no cookie + API se logado) */
845
+ async function changeLocale(locale) {
846
+ setCookieLocale(locale);
847
+ try {
848
+ await setUserLocaleInAPI(locale);
849
+ } catch {}
850
+ }
851
+ //#endregion
852
+ //#region src/i18n/index.ts
853
+ var tFunctionCache = /* @__PURE__ */ new Map();
854
+ /** Cria função de tradução para um locale */
855
+ function createTFunction(translations, fallback) {
856
+ return function t(key, params) {
857
+ const keys = key.split(".");
858
+ let value = translations;
859
+ for (const k of keys) if (value && typeof value === "object" && k in value) value = value[k];
860
+ else {
861
+ value = fallback;
862
+ for (const k of keys) if (value && typeof value === "object" && k in value) value = value[k];
863
+ else return key;
864
+ break;
865
+ }
866
+ if (typeof value !== "string") return key;
867
+ if (params) return value.replace(/\{(\w+)\}/g, (_, param) => String(params[param] ?? ""));
868
+ return value;
869
+ };
870
+ }
871
+ /** Obtém ou cria função de tradução para locale */
872
+ async function getTFunction(locale) {
873
+ if (tFunctionCache.has(locale)) return tFunctionCache.get(locale);
874
+ const [translations, fallback] = await Promise.all([loadLocale(locale), loadLocale("en")]);
875
+ const fn = createTFunction(translations, fallback);
876
+ tFunctionCache.set(locale, fn);
877
+ return fn;
878
+ }
879
+ var currentTFunction = (key) => key;
880
+ var currentLocale = DEFAULT_LOCALE;
881
+ var isLoading = true;
882
+ /** Hook Solid para usar traduções em componentes */
883
+ function useTranslation(initialLocale) {
884
+ const [, forceUpdate] = createSignal(0);
885
+ onMount(async () => {
886
+ if (isLoading) {
887
+ const resolvedLocale = initialLocale ?? await resolveLocale();
888
+ currentLocale = resolvedLocale;
889
+ currentTFunction = await getTFunction(resolvedLocale);
890
+ isLoading = false;
891
+ forceUpdate((n) => n + 1);
892
+ }
893
+ });
894
+ const changeLocaleFn = async (newLocale) => {
895
+ isLoading = true;
896
+ await changeLocale(newLocale);
897
+ currentLocale = newLocale;
898
+ currentTFunction = await getTFunction(newLocale);
899
+ isLoading = false;
900
+ forceUpdate((n) => n + 1);
901
+ };
902
+ const translate = (key, params) => currentTFunction(key, params);
903
+ return {
904
+ t: translate,
905
+ get locale() {
906
+ return currentLocale;
907
+ },
908
+ changeLocale: changeLocaleFn,
909
+ get loading() {
910
+ return isLoading;
911
+ }
912
+ };
913
+ }
914
+ //#endregion
915
+ //#region src/components/LanguageSelector.tsx
916
+ var _tmpl$$7 = [
917
+ "<ul",
918
+ " class=\"language-dropdown\" role=\"menu\"",
919
+ ">",
920
+ "</ul>"
921
+ ];
922
+ var _tmpl$2$6 = [
923
+ "<div",
924
+ " class=\"language-selector\"><button class=\"btn btn-secondary btn-sm language-trigger\"",
925
+ " type=\"button\"><span class=\"flag\">",
926
+ "</span><span>",
927
+ "</span><svg class=\"chevron\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M6 9l6 6 6-6\"></path></svg></button><!--$-->",
928
+ "<!--/--><style>\n .language-selector { position: relative; }\n .language-trigger { display: flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0.75rem; min-width: 140px; justify-content: space-between; }\n .language-trigger .flag { font-size: 1rem; }\n .language-trigger .chevron { flex-shrink: 0; transition: transform 0.15s; }\n .language-trigger[aria-expanded=\"true\"] .chevron { transform: rotate(180deg); }\n .language-dropdown { position: absolute; top: calc(100% + 0.25rem); right: 0; z-index: 100; background: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); min-width: 160px; overflow: hidden; animation: dropdown-in 0.1s ease-out; }\n @keyframes dropdown-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }\n .language-dropdown li { list-style: none; }\n .language-dropdown button { width: 100%; display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; background: none; border: none; text-align: left; color: var(--color-text); cursor: pointer; }\n .language-dropdown button:hover { background: var(--color-bg-tertiary); }\n .language-dropdown button.active { background: var(--color-primary); color: var(--color-primary-contrast); font-weight: 500; }\n .language-dropdown .flag { font-size: 1rem; }\n </style></div>"
929
+ ];
930
+ var _tmpl$3$6 = [
931
+ "<li",
932
+ " role=\"menuitem\"><button",
933
+ " type=\"button\"><span class=\"flag\">",
934
+ "</span><!--$-->",
935
+ "<!--/--></button></li>"
936
+ ];
937
+ function LanguageSelector() {
938
+ const { locale, changeLocale, t } = useTranslation();
939
+ const [open, setOpen] = createSignal(false);
940
+ const handleClickOutside = (e) => {
941
+ if (!e.target.closest(".language-selector")) setOpen(false);
942
+ };
943
+ onCleanup(() => {
944
+ document.removeEventListener("click", handleClickOutside);
945
+ });
946
+ setTimeout(() => document.addEventListener("click", handleClickOutside), 0);
947
+ const currentLocale = locale;
948
+ const translate = t;
949
+ return ssr(_tmpl$2$6, ssrHydrationKey(), ssrAttribute("aria-expanded", escape(open(), true), false) + ssrAttribute("aria-label", escape(translate("common.language") ?? "Language", true), false), escape(LOCALE_FLAGS[currentLocale] ?? "🌐"), escape(LOCALE_LABELS[currentLocale] ?? currentLocale), escape(createComponent(Show, {
950
+ get when() {
951
+ return open();
952
+ },
953
+ get children() {
954
+ return ssr(_tmpl$$7, ssrHydrationKey(), ssrAttribute("aria-label", escape(translate("common.language") ?? "Language", true), false), escape(SUPPORTED_LOCALES.map((loc) => ssr(_tmpl$3$6, ssrHydrationKey(), ssrAttribute("class", currentLocale === loc ? "active" : "", false), escape(LOCALE_FLAGS[loc] ?? "🌐"), escape(LOCALE_LABELS[loc] ?? loc)))));
955
+ }
956
+ })));
957
+ }
958
+ //#endregion
959
+ //#region src/components/admin-bar/AdminBar.tsx
960
+ var _tmpl$$6 = ["<style", ">\n #admin-bar {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 46px;\n background: #0A0A0A;\n border-bottom: 1px solid #333;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 1rem;\n z-index: 2000;\n font-family: inherit;\n }\n #admin-bar * { box-sizing: border-box; }\n .admin-bar-left, .admin-bar-right {\n display: flex;\n align-items: center;\n gap: 1rem;\n }\n .admin-bar-brand {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #FAF5E8;\n font-weight: 600;\n font-size: 1.125rem;\n text-decoration: none;\n padding: 0.375rem 0.75rem;\n border-radius: 0.375rem;\n transition: background 0.15s;\n }\n .admin-bar-brand:hover {\n background: rgba(255,255,255,0.08);\n }\n .admin-bar-brand svg { width: 28px; height: 28px; }\n .admin-bar-separator { width: 1px; height: 24px; background: #333; }\n .admin-bar-menu { display: flex; gap: 0.25rem; }\n .admin-bar-menu-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0.75rem;\n color: rgba(255,255,255,0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border-radius: 0.375rem;\n text-decoration: none;\n transition: all 0.15s;\n }\n .admin-bar-menu-item:hover {\n background: rgba(255,255,255,0.1);\n color: #fff;\n }\n .admin-bar-menu-item svg { width: 18px; height: 18px; }\n .admin-bar-right { gap: 0.75rem; }\n .notifications-btn {\n position: relative;\n background: none;\n border: none;\n color: rgba(255,255,255,0.7);\n padding: 0.375rem;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n }\n .notifications-btn:hover { background: rgba(255,255,255,0.1); color: #fff; }\n .notifications-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n background: #EF4444;\n color: #fff;\n font-size: 0.625rem;\n font-weight: 600;\n border-radius: 9999px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n }\n .notifications-dropdown { position: relative; }\n .notifications-panel {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 280px;\n max-width: 90vw;\n background: #FFFFFF;\n border: 1px solid #DCDCDE;\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);\n z-index: 2100;\n overflow: hidden;\n animation: slideIn 0.15s ease-out;\n }\n .notifications-header {\n padding: 0.75rem 1rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: #646970;\n border-bottom: 1px solid #DCDCDE;\n }\n .notifications-item {\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n padding: 0.625rem 1rem;\n border-bottom: 1px solid #F6F7F7;\n }\n .notifications-item:last-child { border-bottom: none; }\n .notifications-action {\n font-size: 0.8125rem;\n font-weight: 600;\n color: #2C3338;\n font-family: ui-monospace, SFMono-Regular, monospace;\n word-break: break-word;\n }\n .notifications-meta {\n display: flex;\n justify-content: space-between;\n gap: 0.75rem;\n font-size: 0.6875rem;\n color: #646970;\n }\n .notifications-empty { padding: 1rem; margin: 0; font-size: 0.8125rem; color: #646970; }\n .user-menu-trigger {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n background: none;\n border: none;\n color: #fff;\n padding: 0.375rem 0.75rem;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 0.8125rem;\n font-weight: 500;\n transition: background 0.15s;\n }\n .user-menu-trigger:hover { background: rgba(255,255,255,0.1); }\n .user-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: linear-gradient(135deg, #D8B45E 0%, #B99542 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 0.875rem;\n color: #0A0A0A;\n }\n .user-menu-dropdown {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 200px;\n background: #FFFFFF;\n border: 1px solid #DCDCDE;\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);\n z-index: 2100;\n overflow: hidden;\n animation: slideIn 0.15s ease-out;\n }\n @keyframes slideIn { from { opacity: 0; transform: translateY(-0.5rem); } to { opacity: 1; transform: translateY(0); } }\n .user-menu-header {\n padding: 1rem;\n border-bottom: 1px solid #DCDCDE;\n }\n .user-menu-name { font-weight: 600; color: #0A0A0A; font-size: 0.875rem; }\n .user-menu-email { color: #646970; font-size: 0.75rem; margin-top: 0.125rem; }\n .user-menu-divider { height: 1px; background: #DCDCDE; }\n .user-menu-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.625rem 1rem;\n background: none;\n border: none;\n color: #2C3338;\n font-size: 0.8125rem;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: background 0.15s;\n }\n .user-menu-item:hover { background: #F6F7F7; }\n .user-menu-item svg { width: 18px; height: 18px; color: #646970; }\n .user-menu-item.danger { color: #EF4444; }\n .user-menu-item.danger:hover { background: #FEF2F2; }\n .lang-menu-dropdown {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 180px;\n background: #FFFFFF;\n border: 1px solid #DCDCDE;\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);\n z-index: 2100;\n overflow: hidden;\n animation: slideIn 0.15s ease-out;\n }\n @keyframes slideIn { from { opacity: 0; transform: translateY(-0.5rem); } to { opacity: 1; transform: translateY(0); } }\n .lang-menu-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.625rem 1rem;\n background: none;\n border: none;\n color: #2C3338;\n font-size: 0.8125rem;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n }\n .lang-menu-item:hover { background: #F6F7F7; }\n .lang-menu-item.active { background: #FAF5E8; color: #B99542; font-weight: 600; }\n .lang-menu-item .flag { font-size: 1rem; }\n @media (max-width: 782px) {\n .admin-bar-menu { display: none; }\n }\n </style>"];
961
+ var _tmpl$2$5 = [
962
+ "<span",
963
+ " class=\"notifications-badge\">",
964
+ "</span>"
965
+ ];
966
+ var _tmpl$3$5 = [
967
+ "<div",
968
+ " class=\"notifications-panel\" role=\"menu\"",
969
+ "><div class=\"notifications-header\">",
970
+ "</div><!--$-->",
971
+ "<!--/--></div>"
972
+ ];
973
+ var _tmpl$4$5 = [
974
+ "<div",
975
+ " class=\"lang-menu-dropdown\" role=\"menu\"",
976
+ ">",
977
+ "</div>"
978
+ ];
979
+ var _tmpl$5$2 = [
980
+ "<div",
981
+ " class=\"user-menu-dropdown\" role=\"menu\"",
982
+ "><div class=\"user-menu-header\"><div class=\"user-menu-name\">",
983
+ "</div><div class=\"user-menu-email\">",
984
+ "</div></div><div class=\"user-menu-divider\"></div><button class=\"user-menu-item\" type=\"button\" role=\"menuitem\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg><!--$-->",
985
+ "<!--/--></button><div class=\"user-menu-divider\"></div><button class=\"user-menu-item danger\" type=\"button\" role=\"menuitem\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"></path><polyline points=\"16 17 21 12 16 7\"></polyline><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"></line></svg><!--$-->",
986
+ "<!--/--></button></div>"
987
+ ];
988
+ var _tmpl$6$2 = [
989
+ "<div",
990
+ " class=\"user-menu-dropdown-wrapper\"><button class=\"user-menu-trigger\"",
991
+ " type=\"button\"><span class=\"user-avatar\">",
992
+ "</span><span>",
993
+ "</span><svg class=\"chevron\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"></path></svg></button><!--$-->",
994
+ "<!--/--></div>"
995
+ ];
996
+ var _tmpl$7$1 = [
997
+ "<a",
998
+ " href=\"/login\" class=\"btn btn-primary\" style=\"padding:0.375rem 1rem;font-size:0.8125rem;\">",
999
+ "</a>"
1000
+ ];
1001
+ var _tmpl$8$1 = [
1002
+ "<header",
1003
+ " id=\"admin-bar\" role=\"banner\"><div class=\"admin-bar-left\"><a href=\"/\" class=\"admin-bar-brand\"",
1004
+ "><svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\"><rect width=\"32\" height=\"32\" rx=\"8\" fill=\"url(#grad)\"></rect><path d=\"M8 10h16M8 16h12M8 22h8\" stroke=\"#0A0A0A\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path><defs><linearGradient id=\"grad\" x1=\"0\" y1=\"0\" x2=\"32\" y2=\"32\" gradientUnits=\"userSpaceOnUse\"><stop offset=\"0%\" stop-color=\"#D8B45E\"></stop><stop offset=\"100%\" stop-color=\"#B99542\"></stop></linearGradient></defs></svg><span>OkCMS</span></a><div class=\"admin-bar-separator\"></div><nav class=\"admin-bar-menu\"",
1005
+ "><a href=\"/content\" class=\"admin-bar-menu-item\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"></path><polyline points=\"14 2 14 8 20 8\"></polyline><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"></line><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"></line></svg><!--$-->",
1006
+ "<!--/--></a><a href=\"/media\" class=\"admin-bar-menu-item\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"></rect><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"></circle><polyline points=\"21 15 16 10 5 21\"></polyline></svg><!--$-->",
1007
+ "<!--/--></a><a href=\"/settings\" class=\"admin-bar-menu-item\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg><!--$-->",
1008
+ "<!--/--></a></nav></div><div class=\"admin-bar-right\"><div class=\"notifications-dropdown\"><button class=\"notifications-btn\"",
1009
+ " type=\"button\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"></path><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"></path></svg><!--$-->",
1010
+ "<!--/--></button><!--$-->",
1011
+ "<!--/--></div><div class=\"lang-dropdown\"><button class=\"notifications-btn\"",
1012
+ "><span class=\"flag\">",
1013
+ "</span><span>",
1014
+ "</span><svg class=\"chevron\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"></path></svg></button><!--$-->",
1015
+ "<!--/--></div><!--$-->",
1016
+ "<!--/--><!--$-->",
1017
+ "<!--/--><button class=\"sidebar-toggle\"",
1018
+ " type=\"button\" style=\"background:none;border:none;color:rgba(255,255,255,0.7);padding:0.375rem;border-radius:0.375rem;cursor:pointer;display:flex;align-items:center;justify-content:center;\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\"></line><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"></line><line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\"></line></svg></button></div></header>"
1019
+ ];
1020
+ var _tmpl$9 = [
1021
+ "<p",
1022
+ " class=\"notifications-empty\">",
1023
+ "</p>"
1024
+ ];
1025
+ var _tmpl$0 = [
1026
+ "<div",
1027
+ " class=\"notifications-item\" role=\"menuitem\"><span class=\"notifications-action\">",
1028
+ "</span><span class=\"notifications-meta\"><span class=\"notifications-resource\">",
1029
+ "</span><span class=\"notifications-time\">",
1030
+ "</span></span></div>"
1031
+ ];
1032
+ var _tmpl$1 = [
1033
+ "<button",
1034
+ " type=\"button\" role=\"menuitem\"><span class=\"flag\">",
1035
+ "</span><!--$-->",
1036
+ "<!--/--></button>"
1037
+ ];
1038
+ function AdminBar(props) {
1039
+ const { locale, changeLocale, t } = useTranslation();
1040
+ const [user, setUser] = createSignal(props.user ?? null);
1041
+ const [showUserMenu, setShowUserMenu] = createSignal(false);
1042
+ const [showLangMenu, setShowLangMenu] = createSignal(false);
1043
+ const [showNotifications, setShowNotifications] = createSignal(false);
1044
+ const [notifications, setNotifications] = createSignal([]);
1045
+ const currentLocale = locale;
1046
+ const translate = t;
1047
+ const handleClickOutside = (e) => {
1048
+ if (!e.target.closest("#admin-bar")) {
1049
+ setShowUserMenu(false);
1050
+ setShowLangMenu(false);
1051
+ setShowNotifications(false);
1052
+ }
1053
+ };
1054
+ onMount(() => {
1055
+ document.addEventListener("click", handleClickOutside);
1056
+ (async () => {
1057
+ if (props.user) return;
1058
+ try {
1059
+ const me = await apiClient.getMe();
1060
+ setUser(me.user);
1061
+ } catch {}
1062
+ })();
1063
+ (async () => {
1064
+ try {
1065
+ const logs = await apiClient.getAuditLogs(8);
1066
+ setNotifications(logs.data ?? []);
1067
+ } catch {
1068
+ setNotifications([]);
1069
+ }
1070
+ })();
1071
+ return () => document.removeEventListener("click", handleClickOutside);
1072
+ });
1073
+ const formatTime = (timestamp) => {
1074
+ if (!timestamp) return "";
1075
+ const date = new Date(timestamp);
1076
+ if (Number.isNaN(date.getTime())) return "";
1077
+ const diff = Date.now() - date.getTime();
1078
+ const minutes = Math.floor(diff / 6e4);
1079
+ if (minutes < 1) return translate("activity.justNow");
1080
+ if (minutes < 60) return `${minutes} ${translate("activity.minAgo")}`;
1081
+ const hours = Math.floor(diff / 36e5);
1082
+ if (hours < 24) return `${hours}h ${translate("activity.ago")}`;
1083
+ const days = Math.floor(diff / 864e5);
1084
+ if (days < 7) return `${days}d ${translate("activity.ago")}`;
1085
+ return date.toLocaleDateString("pt-BR", {
1086
+ day: "2-digit",
1087
+ month: "2-digit",
1088
+ year: "numeric"
1089
+ });
1090
+ };
1091
+ return [ssr(_tmpl$$6, ssrHydrationKey()), ssr(_tmpl$8$1, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("layout.appName"), true), false), ssrAttribute("aria-label", escape(t("adminBar.mainMenu"), true), false), escape(t("layout.nav.content")), escape(t("layout.nav.media")), escape(t("layout.nav.settings")), ssrAttribute("aria-label", escape(t("adminBar.notifications"), true), false) + ssrAttribute("aria-expanded", escape(showNotifications(), true), false), escape(createComponent(Show, {
1092
+ get when() {
1093
+ return notifications().length > 0;
1094
+ },
1095
+ get children() {
1096
+ return ssr(_tmpl$2$5, ssrHydrationKey(), escape(notifications().length));
1097
+ }
1098
+ })), escape(createComponent(Show, {
1099
+ get when() {
1100
+ return showNotifications();
1101
+ },
1102
+ get children() {
1103
+ return ssr(_tmpl$3$5, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("adminBar.notifications"), true), false), escape(t("adminBar.notifications")), escape(createComponent(Show, {
1104
+ get when() {
1105
+ return notifications().length > 0;
1106
+ },
1107
+ get fallback() {
1108
+ return ssr(_tmpl$9, ssrHydrationKey(), escape(t("adminBar.notificationsEmpty")));
1109
+ },
1110
+ get children() {
1111
+ return notifications().map((entry) => ssr(_tmpl$0, ssrHydrationKey(), escape(entry.action), escape(entry.resourceType), escape(formatTime(entry.created_at))));
1112
+ }
1113
+ })));
1114
+ }
1115
+ })), ssrAttribute("aria-label", escape(t("common.language"), true), false) + ssrAttribute("aria-expanded", escape(showLangMenu(), true), false), escape(LOCALE_FLAGS[currentLocale] ?? "🌐"), escape(LOCALE_LABELS[currentLocale] ?? currentLocale), escape(createComponent(Show, {
1116
+ get when() {
1117
+ return showLangMenu();
1118
+ },
1119
+ get children() {
1120
+ return ssr(_tmpl$4$5, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("common.language"), true), false), escape(SUPPORTED_LOCALES.map((loc) => ssr(_tmpl$1, ssrHydrationKey() + ssrAttribute("class", currentLocale === loc ? "lang-menu-item active" : "lang-menu-item", false), escape(LOCALE_FLAGS[loc] ?? "🌐"), escape(LOCALE_LABELS[loc] ?? loc)))));
1121
+ }
1122
+ })), escape(createComponent(Show, {
1123
+ get when() {
1124
+ return user();
1125
+ },
1126
+ get children() {
1127
+ return ssr(_tmpl$6$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("adminBar.userMenu"), true), false) + ssrAttribute("aria-expanded", escape(showUserMenu(), true), false), escape(user()?.name?.charAt(0).toUpperCase() ?? "U"), escape(user()?.name), escape(createComponent(Show, {
1128
+ get when() {
1129
+ return showUserMenu();
1130
+ },
1131
+ get children() {
1132
+ return ssr(_tmpl$5$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("adminBar.userMenu"), true), false), escape(user()?.name), escape(user()?.email), escape(t("adminBar.settings")), escape(t("layout.actions.logout")));
1133
+ }
1134
+ })));
1135
+ }
1136
+ })), escape(createComponent(Show, {
1137
+ get when() {
1138
+ return !user();
1139
+ },
1140
+ get children() {
1141
+ return ssr(_tmpl$7$1, ssrHydrationKey(), escape(t("login.submit")));
1142
+ }
1143
+ })), ssrAttribute("aria-label", escape(t("adminBar.toggleSidebar"), true), false))];
1144
+ }
1145
+ //#endregion
1146
+ //#region src/components/screen-options/ScreenOptions.tsx
1147
+ var _tmpl$$5 = [
1148
+ "<div",
1149
+ " class=\"screen-options-panel\" role=\"region\"",
1150
+ "><div class=\"screen-options-header\"><h3>",
1151
+ "</h3><button class=\"screen-options-close\"",
1152
+ " type=\"button\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg></button></div><div class=\"screen-options-content\"><fieldset><legend>",
1153
+ "</legend><div class=\"screen-options-checkboxes\">",
1154
+ "</div></fieldset><div class=\"screen-options-footer\"><button class=\"btn btn-primary\">",
1155
+ "</button></div></div></div>"
1156
+ ];
1157
+ var _tmpl$2$4 = [
1158
+ "<div",
1159
+ " class=\"screen-options\"><button class=\"screen-options-trigger\"",
1160
+ " type=\"button\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"></path></svg><span>",
1161
+ "</span><svg class=\"chevron\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"></path></svg></button><!--$-->",
1162
+ "<!--/--></div>"
1163
+ ];
1164
+ var _tmpl$3$4 = ["<style", ">\n .screen-options { position: relative; }\n .screen-options-trigger {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0.75rem;\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n color: var(--color-text);\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n }\n .screen-options-trigger:hover {\n background: var(--color-surface-hover);\n border-color: var(--color-primary);\n }\n .screen-options-trigger .chevron {\n transition: transform 0.15s;\n flex-shrink: 0;\n }\n .screen-options-trigger[aria-expanded=\"true\"] .chevron {\n transform: rotate(180deg);\n }\n .screen-options-panel {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 280px;\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-xl);\n z-index: 1000;\n animation: slideIn 0.15s ease-out;\n }\n @keyframes slideIn { from { opacity: 0; transform: translateY(-0.5rem); } to { opacity: 1; transform: translateY(0); } }\n .screen-options-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem;\n border-bottom: 1px solid var(--color-border);\n }\n .screen-options-header h3 { font-size: 0.875rem; font-weight: 600; }\n .screen-options-close {\n background: none; border: none; padding: 0.25rem;\n color: var(--color-muted); cursor: pointer; border-radius: var(--radius-sm);\n }\n .screen-options-close:hover { background: var(--color-background); color: var(--color-text); }\n .screen-options-content { padding: 1rem; }\n .screen-options-content fieldset { border: none; margin: 0; padding: 0; }\n .screen-options-content legend {\n font-size: 0.75rem; font-weight: 600; text-transform: uppercase;\n color: var(--color-muted); letter-spacing: 0.04em; margin-bottom: 0.75rem;\n }\n .screen-options-checkboxes { display: flex; flex-direction: column; gap: 0.5rem; }\n .screen-options-checkbox {\n display: flex; align-items: center; gap: 0.5rem;\n padding: 0.5rem; border-radius: var(--radius-md);\n cursor: pointer; transition: background 0.15s;\n }\n .screen-options-checkbox:hover { background: var(--color-background); }\n .screen-options-checkbox input { width: 16px; height: 16px; accent-color: var(--color-primary); }\n .screen-options-checkbox span { font-size: 0.8125rem; color: var(--color-text); }\n .screen-options-footer { display: flex; justify-content: flex-end; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--color-border); }\n </style>"];
1165
+ var _tmpl$4$4 = [
1166
+ "<label",
1167
+ " class=\"screen-options-checkbox\"><input type=\"checkbox\"",
1168
+ "><span>",
1169
+ "</span></label>"
1170
+ ];
1171
+ var STORAGE_KEY = "screen-options";
1172
+ /** Preferências salvas (localStorage) — precedem o default do painel. */
1173
+ function loadPrefs() {
1174
+ try {
1175
+ return JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "{}");
1176
+ } catch {
1177
+ return {};
1178
+ }
1179
+ }
1180
+ function ScreenOptions(props) {
1181
+ const { t } = useTranslation();
1182
+ const [open, setOpen] = createSignal(false);
1183
+ const [enabled, setEnabled] = createSignal({
1184
+ ...Object.fromEntries(props.panels.map((p) => [p.id, p.defaultOpen !== false])),
1185
+ ...loadPrefs()
1186
+ });
1187
+ const handleClickOutside = (e) => {
1188
+ if (!e.target.closest(".screen-options")) setOpen(false);
1189
+ };
1190
+ onMount(() => {
1191
+ document.addEventListener("click", handleClickOutside);
1192
+ });
1193
+ onCleanup(() => {
1194
+ document.removeEventListener("click", handleClickOutside);
1195
+ });
1196
+ return [ssr(_tmpl$2$4, ssrHydrationKey(), ssrAttribute("aria-expanded", escape(open(), true), false) + ssrAttribute("aria-label", escape(t("screenOptions.label"), true), false), escape(t("screenOptions.title")), escape(createComponent(Show, {
1197
+ get when() {
1198
+ return open();
1199
+ },
1200
+ get children() {
1201
+ return ssr(_tmpl$$5, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("screenOptions.title"), true), false), escape(t("screenOptions.title")), ssrAttribute("aria-label", escape(t("common.close"), true), false), escape(t("screenOptions.showOnScreen")), escape(props.panels.map((panel) => ssr(_tmpl$4$4, ssrHydrationKey(), ssrAttribute("checked", enabled()[panel.id] ?? panel.defaultOpen !== false, true), escape(panel.label)))), escape(t("common.close")));
1202
+ }
1203
+ }))), ssr(_tmpl$3$4, ssrHydrationKey())];
1204
+ }
1205
+ //#endregion
1206
+ //#region src/lib/sanitize.ts
1207
+ /**
1208
+ * Sanitizador de HTML em allowlist para pontos de injeção (innerHTML).
1209
+ *
1210
+ * O admin injeta HTML apenas no conteúdo das abas de ajuda (HelpTabs), que
1211
+ * vem do i18n — mas todo innerHTML passa por aqui por defesa em profundidade.
1212
+ *
1213
+ * Garantias:
1214
+ * - Allowlist de tags e atributos (script/style/svg/iframe/form são removidos,
1215
+ * incluindo o conteúdo de tags de texto bruto como <script> e <style>).
1216
+ * - Atributos de evento (on*), style e demais fora da allowlist são descartados.
1217
+ * - href/src têm o protocolo validado DEPOIS de decodificar entidades e remover
1218
+ * tab/newline — o valor emitido é re-escapado a partir do valor decodificado,
1219
+ * de modo que o que o navegador decodifica é exatamente o que foi validado
1220
+ * (bloqueia `javascript:`, `&#106;avascript:`, `javascript&colon;`, etc).
1221
+ * - Texto é escapado (& < >), preservando entidades já válidas.
1222
+ * - Tags de fechamento sem âncora são ignoradas: conteúdo malicioso não consegue
1223
+ * "escapar" do container nem desbalancear a árvore (o quebra-cabeça de abas
1224
+ * e widgets continua íntegro).
1225
+ *
1226
+ * Puro JavaScript, sem APIs de DOM: roda igual no SSR (Node) e no navegador.
1227
+ */
1228
+ /** Tags permitidas (conteúdo rico simples: ajuda, títulos, listas, links). */
1229
+ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
1230
+ "a",
1231
+ "abbr",
1232
+ "b",
1233
+ "blockquote",
1234
+ "br",
1235
+ "code",
1236
+ "dd",
1237
+ "div",
1238
+ "dl",
1239
+ "dt",
1240
+ "em",
1241
+ "figcaption",
1242
+ "figure",
1243
+ "h1",
1244
+ "h2",
1245
+ "h3",
1246
+ "h4",
1247
+ "h5",
1248
+ "h6",
1249
+ "hr",
1250
+ "i",
1251
+ "img",
1252
+ "li",
1253
+ "ol",
1254
+ "p",
1255
+ "pre",
1256
+ "q",
1257
+ "s",
1258
+ "span",
1259
+ "strong",
1260
+ "sub",
1261
+ "sup",
1262
+ "u",
1263
+ "ul"
1264
+ ]);
1265
+ /** Tags vazias (emitidas com fechamento próprio, nunca empilhadas). */
1266
+ var VOID_TAGS = /* @__PURE__ */ new Set([
1267
+ "br",
1268
+ "hr",
1269
+ "img"
1270
+ ]);
1271
+ /**
1272
+ * Tags cujo conteúdo é texto bruto no HTML. Ao encontrá-las abertas, todo o
1273
+ * miolo é descartado até o fechamento correspondente (senão, o conteúdo do
1274
+ * <script> viraria texto visível ou vetor de parse).
1275
+ */
1276
+ var RAW_TEXT_TAGS = /* @__PURE__ */ new Set([
1277
+ "script",
1278
+ "style",
1279
+ "iframe",
1280
+ "object",
1281
+ "embed",
1282
+ "svg",
1283
+ "math",
1284
+ "textarea",
1285
+ "title",
1286
+ "noscript",
1287
+ "template"
1288
+ ]);
1289
+ /** Atributos permitidos (globais; validação extra por atributo abaixo). */
1290
+ var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
1291
+ "class",
1292
+ "title",
1293
+ "alt",
1294
+ "width",
1295
+ "height",
1296
+ "href",
1297
+ "src",
1298
+ "target",
1299
+ "rel"
1300
+ ]);
1301
+ /** Esquemas aceitos em href (links externos, e-mail, telefone). */
1302
+ var HREF_SCHEMES = /* @__PURE__ */ new Set([
1303
+ "http",
1304
+ "https",
1305
+ "mailto",
1306
+ "tel"
1307
+ ]);
1308
+ /** Esquemas aceitos em src (somente rede). */
1309
+ var SRC_SCHEMES = /* @__PURE__ */ new Set(["http", "https"]);
1310
+ /** Entidades nomeadas relevantes (as que poderiam alterar a validação de URL). */
1311
+ var NAMED_ENTITIES = {
1312
+ amp: "&",
1313
+ lt: "<",
1314
+ gt: ">",
1315
+ quot: "\"",
1316
+ apos: "'",
1317
+ colon: ":",
1318
+ tab: " ",
1319
+ newline: "\n",
1320
+ sol: "/",
1321
+ lpar: "(",
1322
+ rpar: ")",
1323
+ num: "#",
1324
+ period: ".",
1325
+ excl: "!",
1326
+ comma: ","
1327
+ };
1328
+ /** Decodifica referências numéricas e nomeadas (uma passada, como o navegador). */
1329
+ function decodeEntities(value) {
1330
+ return value.replace(/&#x([0-9a-fA-F]+);?/g, (_m, hex) => fromCodePoint(parseInt(hex, 16))).replace(/&#(\d+);?/g, (_m, dec) => fromCodePoint(parseInt(dec, 10))).replace(/&([a-zA-Z][a-zA-Z0-9]{1,30});?/g, (m, name) => {
1331
+ return NAMED_ENTITIES[name in NAMED_ENTITIES ? name : name.toLowerCase()] ?? m;
1332
+ });
1333
+ }
1334
+ function fromCodePoint(cp) {
1335
+ if (!Number.isFinite(cp) || cp < 0 || cp > 1114111) return "";
1336
+ try {
1337
+ return String.fromCodePoint(cp);
1338
+ } catch {
1339
+ return "";
1340
+ }
1341
+ }
1342
+ /** Escapa valor para uso dentro de atributo entre aspas duplas. */
1343
+ function escapeAttr(value) {
1344
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1345
+ }
1346
+ /**
1347
+ * Escapa texto preservando entidades já válidas (evita exibir `&amp;`
1348
+ * literalmente quando a tradução usa `&amp;` de propósito).
1349
+ */
1350
+ function escapeText(text) {
1351
+ return text.replace(/&(?![a-zA-Z][a-zA-Z0-9]{1,30};|#[0-9]{1,7};|#[xX][0-9a-fA-F]{1,6};)|[<>]/g, (m) => m === "&" ? "&amp;" : m === "<" ? "&lt;" : "&gt;");
1352
+ }
1353
+ /**
1354
+ * Valida URL decodificando entidades e removendo tab/newline (mesmo tratamento
1355
+ * do parser de URL do navegador) antes de inspecionar o esquema.
1356
+ */
1357
+ function isSafeUrl(raw, allowedSchemes) {
1358
+ const decoded = decodeEntities(raw).replace(/[\t\n\r]/g, "").trim();
1359
+ const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(decoded);
1360
+ if (!scheme) return true;
1361
+ return allowedSchemes.has(scheme[1].toLowerCase());
1362
+ }
1363
+ /** Normaliza valor de atributo: decodifica (como o navegador faria) e re-escapa. */
1364
+ function normalizeAttrValue(raw) {
1365
+ return escapeAttr(decodeEntities(raw));
1366
+ }
1367
+ /**
1368
+ * Extrai pares nome/valor de uma tag, respeitando aspas (um `>` dentro de
1369
+ * aspas não termina a tag) e valores não-aspados do HTML.
1370
+ */
1371
+ function parseAttrs(body) {
1372
+ const pairs = [];
1373
+ const n = body.length;
1374
+ let i = 0;
1375
+ const isWs = (c) => c === " " || c === " " || c === "\n" || c === "\r" || c === "\f";
1376
+ while (i < n) {
1377
+ while (i < n && (isWs(body.charAt(i)) || body.charAt(i) === "/")) i++;
1378
+ if (i >= n) break;
1379
+ let name = "";
1380
+ while (i < n && !isWs(body.charAt(i)) && body.charAt(i) !== "=" && body.charAt(i) !== ">" && body.charAt(i) !== "/" && body.charAt(i) !== "<") {
1381
+ name += body.charAt(i);
1382
+ i++;
1383
+ }
1384
+ if (!name) {
1385
+ i++;
1386
+ continue;
1387
+ }
1388
+ let value = "";
1389
+ let j = i;
1390
+ while (j < n && isWs(body.charAt(j))) j++;
1391
+ if (j < n && body.charAt(j) === "=") {
1392
+ j++;
1393
+ while (j < n && isWs(body.charAt(j))) j++;
1394
+ if (j < n && (body.charAt(j) === "\"" || body.charAt(j) === "'")) {
1395
+ const quote = body.charAt(j);
1396
+ j++;
1397
+ const start = j;
1398
+ while (j < n && body.charAt(j) !== quote) j++;
1399
+ value = body.slice(start, j);
1400
+ j++;
1401
+ } else {
1402
+ const start = j;
1403
+ while (j < n && !isWs(body.charAt(j)) && body.charAt(j) !== ">") j++;
1404
+ value = body.slice(start, j);
1405
+ }
1406
+ i = j;
1407
+ }
1408
+ pairs.push([name.toLowerCase(), value]);
1409
+ }
1410
+ return pairs;
1411
+ }
1412
+ /** Filtra atributos: allowlist + validação de protocolo; força rel seguro. */
1413
+ function filterAttrs(tag, pairs) {
1414
+ const kept = [];
1415
+ const seen = /* @__PURE__ */ new Set();
1416
+ let targetBlank = false;
1417
+ for (const [name, raw] of pairs) {
1418
+ if (!ALLOWED_ATTRS.has(name) || seen.has(name)) continue;
1419
+ if (name === "href" && !isSafeUrl(raw, HREF_SCHEMES)) continue;
1420
+ if (name === "src" && !isSafeUrl(raw, SRC_SCHEMES)) continue;
1421
+ if (name === "target") {
1422
+ if (normalizeAttrValue(raw) !== "_blank") continue;
1423
+ targetBlank = true;
1424
+ continue;
1425
+ }
1426
+ if (name === "rel") continue;
1427
+ seen.add(name);
1428
+ kept.push(`${name}="${normalizeAttrValue(raw)}"`);
1429
+ }
1430
+ if (tag === "a" && targetBlank) {
1431
+ kept.push("target=\"_blank\"");
1432
+ kept.push("rel=\"noopener noreferrer\"");
1433
+ }
1434
+ return kept.length > 0 ? ` ${kept.join(" ")}` : "";
1435
+ }
1436
+ /**
1437
+ * Sanitiza uma string de HTML. Retorna apenas marcação da allowlist.
1438
+ * Idempotente e sem dependências de DOM (seguro no SSR e no cliente).
1439
+ */
1440
+ function sanitizeHtml(input) {
1441
+ if (typeof input !== "string" || input.length === 0) return "";
1442
+ const lower = input.toLowerCase();
1443
+ const n = input.length;
1444
+ const stack = [];
1445
+ let out = "";
1446
+ let i = 0;
1447
+ while (i < n) {
1448
+ const lt = input.indexOf("<", i);
1449
+ if (lt === -1) {
1450
+ out += escapeText(input.slice(i));
1451
+ break;
1452
+ }
1453
+ if (lt > i) out += escapeText(input.slice(i, lt));
1454
+ if (input.startsWith("<!--", lt)) {
1455
+ const end = input.indexOf("-->", lt + 4);
1456
+ i = end === -1 ? n : end + 3;
1457
+ continue;
1458
+ }
1459
+ if (input.charAt(lt + 1) === "!" || input.charAt(lt + 1) === "?") {
1460
+ const end = input.indexOf(">", lt + 2);
1461
+ i = end === -1 ? n : end + 1;
1462
+ continue;
1463
+ }
1464
+ const tagMatch = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)(?=[\s/>])/.exec(input.slice(lt, Math.min(lt + 64, n)));
1465
+ if (!tagMatch) {
1466
+ out += "&lt;";
1467
+ i = lt + 1;
1468
+ continue;
1469
+ }
1470
+ const isClosing = tagMatch[1] === "/";
1471
+ const tag = tagMatch[2].toLowerCase();
1472
+ let j = lt + tagMatch[0].length;
1473
+ let quote = "";
1474
+ while (j < n) {
1475
+ const ch = input[j];
1476
+ if (quote) {
1477
+ if (ch === quote) quote = "";
1478
+ } else if (ch === "\"" || ch === "'") quote = ch;
1479
+ else if (ch === ">") break;
1480
+ j++;
1481
+ }
1482
+ if (j >= n) break;
1483
+ const body = input.slice(lt + tagMatch[0].length, j);
1484
+ i = j + 1;
1485
+ if (!isClosing && RAW_TEXT_TAGS.has(tag)) {
1486
+ const closeAt = lower.indexOf(`</${tag}`, i);
1487
+ if (closeAt === -1) break;
1488
+ const closeEnd = input.indexOf(">", closeAt);
1489
+ i = closeEnd === -1 ? n : closeEnd + 1;
1490
+ continue;
1491
+ }
1492
+ if (isClosing) {
1493
+ const anchor = stack.lastIndexOf(tag);
1494
+ if (anchor !== -1) {
1495
+ for (let k = stack.length - 1; k >= anchor; k--) out += `</${stack[k]}>`;
1496
+ stack.length = anchor;
1497
+ }
1498
+ continue;
1499
+ }
1500
+ if (!ALLOWED_TAGS.has(tag)) continue;
1501
+ const attrs = filterAttrs(tag, parseAttrs(body));
1502
+ if (VOID_TAGS.has(tag)) out += `<${tag}${attrs} />`;
1503
+ else {
1504
+ out += `<${tag}${attrs}>`;
1505
+ stack.push(tag);
1506
+ }
1507
+ }
1508
+ for (let k = stack.length - 1; k >= 0; k--) out += `</${stack[k]}>`;
1509
+ return out;
1510
+ }
1511
+ //#endregion
1512
+ //#region src/components/screen-options/HelpTabs.tsx
1513
+ var _tmpl$$4 = [
1514
+ "<div",
1515
+ " class=\"help-tabs-panel\" role=\"dialog\"",
1516
+ "><div class=\"help-tabs-header\"><h3>",
1517
+ "</h3><button class=\"help-tabs-close\"",
1518
+ " type=\"button\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg></button></div><div class=\"help-tabs-nav\" role=\"tablist\"",
1519
+ ">",
1520
+ "</div><div class=\"help-tabs-panels\">",
1521
+ "</div><div class=\"help-tabs-footer\"><button class=\"btn btn-primary\">",
1522
+ "</button></div></div>"
1523
+ ];
1524
+ var _tmpl$2$3 = [
1525
+ "<div",
1526
+ " class=\"help-tabs-wrapper\"><div class=\"help-tabs\"><button class=\"help-tabs-trigger\"",
1527
+ " type=\"button\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><path d=\"M12 16v-4M12 8h.01\"></path></svg><span>",
1528
+ "</span><svg class=\"chevron\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"></path></svg></button><!--$-->",
1529
+ "<!--/--></div><style>\n .help-tabs-wrapper { position: relative; }\n .help-tabs { position: relative; }\n .help-tabs-trigger {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0.75rem;\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n color: var(--color-text);\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n }\n .help-tabs-trigger:hover {\n background: var(--color-surface-hover);\n border-color: var(--color-primary);\n }\n .help-tabs-trigger .chevron {\n transition: transform 0.15s;\n flex-shrink: 0;\n }\n .help-tabs-trigger[aria-expanded=\"true\"] .chevron {\n transform: rotate(180deg);\n }\n .help-tabs-panel {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n width: 480px;\n max-width: 90vw;\n max-height: 70vh;\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-xl);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.15s ease-out;\n overflow: hidden;\n }\n @keyframes slideIn { from { opacity: 0; transform: translateY(-0.5rem); } to { opacity: 1; transform: translateY(0); } }\n .help-tabs-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem;\n border-bottom: 1px solid var(--color-border);\n }\n .help-tabs-header h3 { font-size: 0.875rem; font-weight: 600; }\n .help-tabs-close {\n background: none; border: none; padding: 0.25rem;\n color: var(--color-muted); cursor: pointer; border-radius: var(--radius-sm);\n }\n .help-tabs-close:hover { background: var(--color-background); color: var(--color-text); }\n .help-tabs-nav {\n display: flex;\n border-bottom: 1px solid var(--color-border);\n overflow-x: auto;\n }\n .help-tabs-tab {\n padding: 0.75rem 1rem;\n background: none; border: none;\n color: var(--color-muted); font-size: 0.8125rem; font-weight: 500;\n cursor: pointer; white-space: nowrap;\n border-bottom: 2px solid transparent;\n transition: all 0.15s;\n }\n .help-tabs-tab:hover { color: var(--color-text); background: var(--color-background); }\n .help-tabs-tab.active {\n color: var(--color-primary);\n border-bottom-color: var(--color-primary);\n font-weight: 600;\n }\n .help-tabs-panels {\n flex: 1; overflow-y: auto; padding: 1.5rem;\n }\n .help-tabs-panel { display: none; }\n .help-tabs-panel.active { display: block; animation: fadeIn 0.15s ease-out; }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n .help-tabs-content { line-height: 1.6; color: var(--color-text); }\n .help-tabs-content h4 { font-size: 0.9375rem; font-weight: 600; margin: 1rem 0 0.5rem; color: var(--color-text); }\n .help-tabs-content h4:first-child { margin-top: 0; }\n .help-tabs-content p { margin: 0 0 0.75rem; color: var(--color-muted); }\n .help-tabs-content ul { margin: 0 0 0.75rem 1.25rem; color: var(--color-text); }\n .help-tabs-content li { margin-bottom: 0.375rem; }\n .help-tabs-content code {\n background: var(--color-background); padding: 0.125rem 0.375rem;\n border-radius: var(--radius-sm); font-size: 0.8125rem;\n font-family: ui-monospace, SFMono-Regular, monospace;\n }\n .help-tabs-content a { color: var(--color-primary); text-decoration: underline; }\n .help-tabs-footer {\n display: flex; justify-content: flex-end;\n padding: 1rem; border-top: 1px solid var(--color-border);\n }\n </style></div>"
1530
+ ];
1531
+ var _tmpl$3$3 = [
1532
+ "<button",
1533
+ " role=\"tab\"",
1534
+ " aria-controls=\"",
1535
+ "\" id=\"",
1536
+ "\" type=\"button\">",
1537
+ "</button>"
1538
+ ];
1539
+ var _tmpl$4$3 = [
1540
+ "<div",
1541
+ " role=\"tabpanel\" id=\"",
1542
+ "\" aria-labelledby=\"",
1543
+ "\"><div class=\"help-tabs-content\">",
1544
+ "</div></div>"
1545
+ ];
1546
+ function HelpTabs(props) {
1547
+ const { t } = useTranslation();
1548
+ const [open, setOpen] = createSignal(false);
1549
+ const [activeTab, setActiveTab] = createSignal(props.tabs[0]?.id ?? "");
1550
+ const handleClickOutside = (e) => {
1551
+ if (!e.target.closest(".help-tabs")) setOpen(false);
1552
+ };
1553
+ onMount(() => {
1554
+ document.addEventListener("click", handleClickOutside);
1555
+ });
1556
+ onCleanup(() => {
1557
+ document.removeEventListener("click", handleClickOutside);
1558
+ });
1559
+ return ssr(_tmpl$2$3, ssrHydrationKey(), ssrAttribute("aria-expanded", escape(open(), true), false) + ssrAttribute("aria-label", escape(t("helpTabs.label"), true), false), escape(t("helpTabs.title")), escape(createComponent(Show, {
1560
+ get when() {
1561
+ return open();
1562
+ },
1563
+ get children() {
1564
+ return ssr(_tmpl$$4, ssrHydrationKey(), ssrAttribute("aria-label", escape(t("helpTabs.title"), true), false), escape(t("helpTabs.title")), ssrAttribute("aria-label", escape(t("common.close"), true), false), ssrAttribute("aria-label", escape(t("helpTabs.tabs"), true), false), escape(props.tabs.map((tab) => ssr(_tmpl$3$3, ssrHydrationKey() + ssrAttribute("class", activeTab() === tab.id ? "help-tabs-tab active" : "help-tabs-tab", false), ssrAttribute("aria-selected", escape(activeTab(), true) === escape(tab.id, true), false), `help-panel-${escape(tab.id, true)}`, `help-tab-${escape(tab.id, true)}`, escape(tab.label)))), escape(props.tabs.map((tab) => ssr(_tmpl$4$3, ssrHydrationKey() + ssrAttribute("class", activeTab() === tab.id ? "help-tabs-panel active" : "help-tabs-panel", false), `help-panel-${escape(tab.id, true)}`, `help-tab-${escape(tab.id, true)}`, sanitizeHtml(tab.content)))), escape(t("common.close")));
1565
+ }
1566
+ })));
1567
+ }
1568
+ //#endregion
1569
+ //#region src/lib/version.ts
1570
+ /** Versão do release atual (ex.: "0.4.0"). */
1571
+ var APP_VERSION = {
1572
+ name: "okcms",
1573
+ version: "0.4.0",
1574
+ "private": true,
1575
+ description: "Hybrid, modular, API-first CMS",
1576
+ engines: {
1577
+ "node": ">=20.0.0",
1578
+ "bun": ">=1.3.0"
1579
+ },
1580
+ workspaces: [
1581
+ "apps/*",
1582
+ "packages/*",
1583
+ "plugins/*",
1584
+ "themes/*"
1585
+ ],
1586
+ overrides: { "ioredis": "5.3.0" },
1587
+ scripts: {
1588
+ "dev": "bun run --filter '@oktis-works/*' dev",
1589
+ "build": "bun run --filter '@oktis-works/*' build",
1590
+ "test": "vitest",
1591
+ "test:run": "vitest run",
1592
+ "lint": "eslint .",
1593
+ "typecheck": "tsc --noEmit",
1594
+ "clean": "rm -rf node_modules apps/*/node_modules packages/*/node_modules",
1595
+ "changeset": "changeset",
1596
+ "version-packages": "changeset version",
1597
+ "publish:all": "node scripts/prepare-publish.mjs && for pkg in packages/* apps/api apps/admin apps/web apps/worker; do [ -f \"$pkg/package.json\" ] || continue; echo \"→ publishing $pkg\"; (cd \"$pkg\" && npm publish --access public) || exit 1; done"
1598
+ },
1599
+ devDependencies: {
1600
+ "@changesets/changelog-github": "^1.0.1",
1601
+ "@changesets/cli": "^3.0.3",
1602
+ "@types/node": "22.0.0",
1603
+ "@types/semver": "7.7.0",
1604
+ "@typescript-eslint/eslint-plugin": "^8.71.0",
1605
+ "@typescript-eslint/parser": "8.0.0",
1606
+ "autoprefixer": "^10.6.1",
1607
+ "eslint": "9.0.0",
1608
+ "playwright": "1.59.1",
1609
+ "playwright-core": "1.59.1",
1610
+ "postcss": "^8.5.28",
1611
+ "sass": "^1.105.1",
1612
+ "tailwindcss": "^4.3.3",
1613
+ "typescript": "5.7.3",
1614
+ "typescript-eslint": "8.31.0",
1615
+ "vitest": "3.0.0"
1616
+ },
1617
+ packageManager: "bun@1.3.14"
1618
+ }.version;
1619
+ //#endregion
1620
+ //#region src/components/dashboard-widgets/AtGlanceWidget.tsx
1621
+ var _tmpl$$3 = [
1622
+ "<div",
1623
+ " class=\"",
1624
+ "\"",
1625
+ " style=\"",
1626
+ "\"><div class=\"dashboard-widget-header\"><h3 class=\"dashboard-widget-title\">",
1627
+ "</h3></div><div class=\"dashboard-widget-content\">",
1628
+ "</div><style>\n .dashboard-widget {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n display: flex;\n flex-direction: column;\n min-height: 200px;\n transition: all 0.15s ease;\n }\n .dashboard-widget:hover { border-color: var(--color-primary); box-shadow: var(--shadow-md); }\n .dashboard-widget-header {\n padding: 1rem 1.25rem;\n border-bottom: 1px solid var(--color-border);\n display: flex; align-items: center; justify-content: space-between;\n }\n .dashboard-widget-title { font-size: 0.875rem; font-weight: 600; color: var(--color-text); }\n .dashboard-widget-content { padding: 1.25rem; flex: 1; }\n </style></div>"
1629
+ ];
1630
+ var _tmpl$2$2 = [
1631
+ "<div",
1632
+ " class=\"stat-grid\"><div class=\"stat-item\"><span class=\"stat-label\">",
1633
+ "</span><div class=\"stat-values\"><span class=\"stat-value published\">",
1634
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value draft\">",
1635
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value trash\">",
1636
+ "</span></div><span class=\"stat-desc\">",
1637
+ "</span></div><div class=\"stat-item\"><span class=\"stat-label\">",
1638
+ "</span><div class=\"stat-values\"><span class=\"stat-value published\">",
1639
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value draft\">",
1640
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value trash\">",
1641
+ "</span></div><span class=\"stat-desc\">",
1642
+ "</span></div><div class=\"stat-item\"><span class=\"stat-label\">",
1643
+ "</span><div class=\"stat-values\"><span class=\"stat-value total\">",
1644
+ "</span></div><span class=\"stat-desc\">",
1645
+ "</span></div><div class=\"stat-item\"><span class=\"stat-label\">",
1646
+ "</span><div class=\"stat-values\"><span class=\"stat-value total\">",
1647
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value active\">",
1648
+ "</span><span class=\"stat-separator\">/</span><span class=\"stat-value inactive\">",
1649
+ "</span></div><span class=\"stat-desc\">",
1650
+ "</span></div><div class=\"stat-item full-width\"><span class=\"stat-label\">",
1651
+ "</span><div class=\"version-info\"><span class=\"version-label\">OkCMS</span><span class=\"version-number\">",
1652
+ "</span><span class=\"version-separator\">|</span><span class=\"storage-label\">",
1653
+ "</span><span class=\"storage-value\">",
1654
+ "</span></div></div></div>"
1655
+ ];
1656
+ var _tmpl$3$2 = ["<style", ">\n .stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }\n .stat-item { display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem; background: var(--color-background); border: 1px solid var(--color-border); border-radius: var(--radius-md); }\n .stat-item.full-width { grid-column: 1 / -1; }\n .stat-label { font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-muted); }\n .stat-values { display: flex; align-items: baseline; gap: 0.375rem; flex-wrap: wrap; }\n .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--color-text); }\n .stat-value.published { color: var(--color-success); }\n .stat-value.draft { color: var(--color-warning); }\n .stat-value.trash { color: var(--color-muted); }\n .stat-value.pending { color: var(--color-warning); }\n .stat-value.approved { color: var(--color-success); }\n .stat-value.spam { color: var(--color-danger); }\n .stat-value.total { color: var(--color-primary); }\n .stat-value.active { color: var(--color-success); }\n .stat-value.inactive { color: var(--color-danger); }\n .stat-separator { color: var(--color-muted); }\n .stat-desc { font-size: 0.6875rem; color: var(--color-muted); }\n .version-info { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }\n .version-label { font-weight: 500; color: var(--color-text); }\n .version-number { background: var(--color-primary-soft); color: var(--color-primary-hover); padding: 0.125rem 0.5rem; border-radius: var(--radius-sm); font-size: 0.8125rem; font-weight: 600; }\n .version-separator { color: var(--color-muted); }\n .storage-label { font-size: 0.8125rem; color: var(--color-muted); }\n .storage-value { font-weight: 600; color: var(--color-text); }\n </style>"];
1657
+ var _tmpl$4$2 = ["<div", " class=\"stat-grid skeleton\">Loading...</div>"];
1658
+ function DashboardWidget(props) {
1659
+ return ssr(_tmpl$$3, ssrHydrationKey(), `dashboard-widget ${escape(props.className || "", true)}`, ssrAttribute("data-widget-panel", escape(props.panelId, true), false), ssrStyle(`grid-column: span ${props.columns || 1}`), escape(props.title), escape(props.children));
1660
+ }
1661
+ function formatBytes(bytes) {
1662
+ if (bytes <= 0) return "0 B";
1663
+ const units = [
1664
+ "B",
1665
+ "KB",
1666
+ "MB",
1667
+ "GB",
1668
+ "TB"
1669
+ ];
1670
+ const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
1671
+ const value = bytes / 1024 ** i;
1672
+ return `${value >= 100 || i === 0 ? Math.round(value) : value.toFixed(1)} ${units[i]}`;
1673
+ }
1674
+ function AtGlanceWidget() {
1675
+ const { t } = useTranslation();
1676
+ const [stats, setStats] = createSignal(null);
1677
+ const [loading, setLoading] = createSignal(true);
1678
+ onMount(async () => {
1679
+ try {
1680
+ const [content, media, users] = await Promise.all([
1681
+ apiClient.getContent({ limit: 1e3 }),
1682
+ apiClient.listMedia({ limit: 1e3 }),
1683
+ apiClient.listUsers({ limit: 1e3 })
1684
+ ]);
1685
+ const contentData = content.data ?? [];
1686
+ const mediaData = media.data ?? [];
1687
+ const usersData = users.data ?? [];
1688
+ const storageBytes = mediaData.reduce((sum, file) => sum + (Number(file.size) || 0), 0);
1689
+ setStats({
1690
+ posts: {
1691
+ published: contentData.filter((c) => c.type === "post" && c.status === "PUBLISHED").length,
1692
+ drafts: contentData.filter((c) => c.type === "post" && c.status === "DRAFT").length,
1693
+ trash: contentData.filter((c) => c.type === "post" && c.status === "TRASHED").length
1694
+ },
1695
+ pages: {
1696
+ published: contentData.filter((c) => c.type === "page" && c.status === "PUBLISHED").length,
1697
+ drafts: contentData.filter((c) => c.type === "page" && c.status === "DRAFT").length,
1698
+ trash: contentData.filter((c) => c.type === "page" && c.status === "TRASHED").length
1699
+ },
1700
+ media: { total: media.total ?? mediaData.length },
1701
+ users: {
1702
+ total: usersData.length,
1703
+ active: usersData.filter((u) => u.status === "ACTIVE").length,
1704
+ inactive: usersData.filter((u) => u.status === "INACTIVE").length
1705
+ },
1706
+ storage: { used: formatBytes(storageBytes) },
1707
+ version: APP_VERSION
1708
+ });
1709
+ } catch (e) {
1710
+ console.error("Failed to load At Glance stats:", e);
1711
+ } finally {
1712
+ setLoading(false);
1713
+ }
1714
+ });
1715
+ return createComponent(DashboardWidget, {
1716
+ get title() {
1717
+ return t("dashboard.widgets.atGlance");
1718
+ },
1719
+ panelId: "at-glance",
1720
+ get children() {
1721
+ return [createComponent(Show, {
1722
+ get when() {
1723
+ return loading();
1724
+ },
1725
+ get fallback() {
1726
+ return ssr(_tmpl$4$2, ssrHydrationKey());
1727
+ },
1728
+ get children() {
1729
+ return ssr(_tmpl$2$2, ssrHydrationKey(), escape(t("dashboard.widgets.posts")), escape(stats()?.posts.published ?? 0), escape(stats()?.posts.drafts ?? 0), escape(stats()?.posts.trash ?? 0), escape(t("dashboard.widgets.postsDesc")), escape(t("dashboard.widgets.pages")), escape(stats()?.pages.published ?? 0), escape(stats()?.pages.drafts ?? 0), escape(stats()?.pages.trash ?? 0), escape(t("dashboard.widgets.pagesDesc")), escape(t("dashboard.widgets.media")), escape(stats()?.media.total ?? 0), escape(t("dashboard.widgets.mediaDesc")), escape(t("dashboard.widgets.users")), escape(stats()?.users.total ?? 0), escape(stats()?.users.active ?? 0), escape(stats()?.users.inactive ?? 0), escape(t("dashboard.widgets.usersDesc")), escape(t("dashboard.widgets.version")), escape(stats()?.version), escape(t("dashboard.widgets.storage")), escape(stats()?.storage.used));
1730
+ }
1731
+ }), ssr(_tmpl$3$2, ssrHydrationKey())];
1732
+ }
1733
+ });
1734
+ }
1735
+ //#endregion
1736
+ //#region src/components/dashboard-widgets/QuickDraftWidget.tsx
1737
+ var _tmpl$$2 = [
1738
+ "<div",
1739
+ " class=\"quick-draft-wrapper\"><div class=\"quick-draft-content-wrapper\">",
1740
+ "</div></div>"
1741
+ ];
1742
+ var _tmpl$2$1 = ["<style", ">\n .quick-draft-form { display: flex; flex-direction: column; gap: 1rem; }\n .form-group textarea { min-height: 100px; resize: vertical; font-family: inherit; }\n .drafts-list h4 { margin-bottom: 1rem; }\n .draft-item {\n display: flex; flex-direction: column; gap: 0.5rem;\n padding: 0.75rem; background: var(--color-surface);\n border: 1px solid var(--color-border); border-radius: var(--radius-md);\n text-decoration: none; color: inherit; transition: all 0.15s ease;\n }\n .draft-item:hover { border-color: var(--color-primary); background: var(--color-surface-hover); }\n .draft-info { display: flex; flex-direction: column; gap: 0.25rem; }\n .draft-title { font-weight: 600; color: var(--color-text); }\n .draft-meta { display: flex; gap: 0.5rem; font-size: 0.8125rem; color: var(--color-muted); }\n .status-draft { color: var(--color-warning); font-weight: 500; }\n .draft-date { font-size: 0.75rem; }\n </style>"];
1743
+ var _tmpl$3$1 = ["<div", " class=\"skeleton\">Loading...</div>"];
1744
+ var _tmpl$4$1 = [
1745
+ "<div",
1746
+ " class=\"quick-draft-content\"><form class=\"quick-draft-form\"><div class=\"form-group\"><label for=\"quick-draft-title\">",
1747
+ "</label><input type=\"text\" id=\"quick-draft-title\" class=\"input\"",
1748
+ " required></div><div class=\"form-group\"><label for=\"quick-draft-content\">",
1749
+ "</label><textarea id=\"quick-draft-content\" class=\"input\" rows=\"4\"",
1750
+ "></textarea></div><div class=\"form-actions\"><button type=\"submit\" class=\"btn btn-primary\"",
1751
+ ">",
1752
+ "</button><button type=\"button\" class=\"btn btn-secondary\">",
1753
+ "</button></div></form><div class=\"drafts-section\">",
1754
+ "</div></div>"
1755
+ ];
1756
+ var _tmpl$5$1 = ["<span", " class=\"spinner\"></span>"];
1757
+ var _tmpl$6$1 = [
1758
+ "<div",
1759
+ " class=\"drafts-list\"><h4>",
1760
+ "</h4><!--$-->",
1761
+ "<!--/--></div>"
1762
+ ];
1763
+ var _tmpl$7 = [
1764
+ "<a",
1765
+ " href=\"",
1766
+ "\" class=\"draft-item\"><div class=\"draft-info\"><span class=\"draft-title\">",
1767
+ "</span><span class=\"draft-meta\"><span class=\"status-draft\">",
1768
+ "</span><span class=\"draft-date\">",
1769
+ "</span></span></div></a>"
1770
+ ];
1771
+ var _tmpl$8 = [
1772
+ "<p",
1773
+ " class=\"empty-state\">",
1774
+ "</p>"
1775
+ ];
1776
+ function QuickDraftWidget() {
1777
+ const { t } = useTranslation();
1778
+ const [drafts, setDrafts] = createSignal([]);
1779
+ const [loading, setLoading] = createSignal(true);
1780
+ const [saving, setSaving] = createSignal(false);
1781
+ const [newTitle, setNewTitle] = createSignal("");
1782
+ const [newContent, setNewContent] = createSignal("");
1783
+ onMount(async () => {
1784
+ try {
1785
+ const result = await apiClient.getContent({
1786
+ type: "post",
1787
+ status: "DRAFT",
1788
+ limit: 5
1789
+ });
1790
+ setDrafts(result.data ?? []);
1791
+ } catch (e) {
1792
+ console.error("Failed to load drafts:", e);
1793
+ } finally {
1794
+ setLoading(false);
1795
+ }
1796
+ });
1797
+ const formatDate = (dateStr) => {
1798
+ if (!dateStr) return "";
1799
+ return new Date(dateStr).toLocaleDateString("pt-BR", {
1800
+ day: "2-digit",
1801
+ month: "2-digit",
1802
+ year: "numeric",
1803
+ hour: "2-digit",
1804
+ minute: "2-digit"
1805
+ });
1806
+ };
1807
+ return createComponent(DashboardWidget, {
1808
+ get title() {
1809
+ return t("dashboard.widgets.quickDraft.title");
1810
+ },
1811
+ panelId: "quick-draft",
1812
+ get children() {
1813
+ return [ssr(_tmpl$$2, ssrHydrationKey(), loading() ? _tmpl$3$1[0] + ssrHydrationKey() + _tmpl$3$1[1] : ssr(_tmpl$4$1, ssrHydrationKey(), escape(t("dashboard.widgets.quickDraft.heading")), ssrAttribute("value", escape(newTitle(), true), false) + ssrAttribute("placeholder", escape(t("dashboard.widgets.quickDraft.headingPlaceholder"), true), false), escape(t("dashboard.widgets.quickDraft.content")), ssrAttribute("value", escape(newContent(), true), false) + ssrAttribute("placeholder", escape(t("dashboard.widgets.quickDraft.contentPlaceholder"), true), false), ssrAttribute("disabled", saving(), true), saving() ? _tmpl$5$1[0] + ssrHydrationKey() + _tmpl$5$1[1] : escape(t("dashboard.widgets.quickDraft.save")), escape(t("common.cancel")), drafts().length > 0 ? ssr(_tmpl$6$1, ssrHydrationKey(), escape(t("dashboard.widgets.quickDraft.yourDrafts")), escape(createComponent(For, {
1814
+ get each() {
1815
+ return drafts();
1816
+ },
1817
+ children: (draft) => ssr(_tmpl$7, ssrHydrationKey(), `/content/edit?id=${escape(draft.id, true)}`, escape(draft.title), escape(t("content.list.statuses.draft")), escape(formatDate(draft.updated_at)))
1818
+ }))) : ssr(_tmpl$8, ssrHydrationKey(), escape(t("dashboard.widgets.quickDraft.noDrafts"))))), ssr(_tmpl$2$1, ssrHydrationKey())];
1819
+ }
1820
+ });
1821
+ }
1822
+ //#endregion
1823
+ //#region src/components/dashboard-widgets/ActivityWidget.tsx
1824
+ var _tmpl$$1 = [
1825
+ "<div",
1826
+ " class=\"activity-widget\" data-widget-panel=\"activity\" style=\"grid-column:span 2\"><div class=\"dashboard-widget-header\"><h3 class=\"dashboard-widget-title\">",
1827
+ "</h3></div><div class=\"dashboard-widget-content\">",
1828
+ "</div><div class=\"styles-container\"><style>\n .activity-list { display: flex; flex-direction: column; gap: 0.5rem; }\n .activity-item {\n display: flex; gap: 0.75rem; padding: 0.75rem;\n background: var(--color-background); border: 1px solid var(--color-border);\n border-radius: var(--radius-md); transition: all 0.15s;\n text-decoration: none; color: inherit;\n }\n .activity-item:hover { border-color: var(--color-primary); background: var(--color-surface); }\n .activity-icon { font-size: 1.25rem; flex-shrink: 0; }\n .activity-content { flex: 1; min-width: 0; }\n .activity-description { font-size: 0.875rem; color: var(--color-text); margin: 0 0 0.25rem; word-break: break-word; }\n .activity-meta { display: flex; gap: 0.75rem; font-size: 0.6875rem; }\n .activity-user { font-weight: 500; color: var(--color-text); }\n .activity-time { color: var(--color-muted); }\n </style></div></div>"
1829
+ ];
1830
+ var _tmpl$2 = ["<div", " class=\"skeleton\">Loading...</div>"];
1831
+ var _tmpl$3 = [
1832
+ "<div",
1833
+ ">",
1834
+ "</div>"
1835
+ ];
1836
+ var _tmpl$4 = [
1837
+ "<div",
1838
+ " class=\"activity-list\">",
1839
+ "</div>"
1840
+ ];
1841
+ var _tmpl$5 = [
1842
+ "<a",
1843
+ " class=\"activity-item\"",
1844
+ "><div class=\"activity-icon\">",
1845
+ "</div><div class=\"activity-content\"><p class=\"activity-description\">",
1846
+ "</p><p class=\"activity-meta\"><span class=\"activity-user\">",
1847
+ "</span><span class=\"activity-time\">",
1848
+ "</span></p></div></a>"
1849
+ ];
1850
+ var _tmpl$6 = [
1851
+ "<p",
1852
+ " class=\"empty-state\">",
1853
+ "</p>"
1854
+ ];
1855
+ function ActivityWidget() {
1856
+ const { t } = useTranslation();
1857
+ const [activities, setActivities] = createSignal([]);
1858
+ const [loading, setLoading] = createSignal(true);
1859
+ onMount(async () => {
1860
+ try {
1861
+ const [contentRes, usersRes] = await Promise.all([apiClient.getContent({ limit: 20 }), apiClient.listUsers({ limit: 5 })]);
1862
+ const activities = [];
1863
+ const recentContent = (contentRes.data ?? []).slice(0, 10);
1864
+ const details = await Promise.all(recentContent.map((item) => apiClient.getContentById(item.id).catch(() => null)));
1865
+ recentContent.forEach((item, index) => {
1866
+ const raw = item;
1867
+ const updatedAt = raw["updated_at"] ?? raw["updatedAt"] ?? raw["created_at"];
1868
+ const author = details[index]?.author;
1869
+ activities.push({
1870
+ id: `content-${item.id}`,
1871
+ type: item.status === "PUBLISHED" ? "post_published" : "post_updated",
1872
+ user: {
1873
+ name: author?.name ?? "—",
1874
+ email: author?.email ?? ""
1875
+ },
1876
+ description: `${item.status === "PUBLISHED" ? t("activity.published") : t("activity.updated")} "${item.title}"`,
1877
+ timestamp: updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1878
+ url: `/content/edit?id=${item.id}`
1879
+ });
1880
+ });
1881
+ for (const user of usersRes.data ?? []) activities.push({
1882
+ id: `user-${user.id}`,
1883
+ type: "user_registered",
1884
+ user: {
1885
+ name: user.name,
1886
+ email: user.email
1887
+ },
1888
+ description: t("activity.newUser", { name: user.name }),
1889
+ timestamp: user.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
1890
+ });
1891
+ activities.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
1892
+ setActivities(activities.slice(0, 15));
1893
+ } catch (e) {
1894
+ console.error("Failed to load activity:", e);
1895
+ } finally {
1896
+ setLoading(false);
1897
+ }
1898
+ });
1899
+ const formatTime = (timestamp) => {
1900
+ const date = new Date(timestamp);
1901
+ const diff = (/* @__PURE__ */ new Date()).getTime() - date.getTime();
1902
+ const minutes = Math.floor(diff / 6e4);
1903
+ const hours = Math.floor(diff / 36e5);
1904
+ const days = Math.floor(diff / 864e5);
1905
+ if (minutes < 1) return t("activity.justNow");
1906
+ if (minutes < 60) return `${minutes} ${t("activity.minAgo")}`;
1907
+ if (hours < 24) return `${hours}h ${t("activity.ago")}`;
1908
+ if (days < 7) return `${days}d ${t("activity.ago")}`;
1909
+ return date.toLocaleDateString("pt-BR", {
1910
+ day: "2-digit",
1911
+ month: "2-digit",
1912
+ year: "numeric"
1913
+ });
1914
+ };
1915
+ const getIcon = (type) => {
1916
+ switch (type) {
1917
+ case "post_created": return "📝";
1918
+ case "post_updated": return "✏️";
1919
+ case "post_published": return "🚀";
1920
+ case "media_uploaded": return "📎";
1921
+ case "user_registered": return "👤";
1922
+ case "comment_added": return "💬";
1923
+ default: return "📌";
1924
+ }
1925
+ };
1926
+ return ssr(_tmpl$$1, ssrHydrationKey(), escape(t("dashboard.widgets.activity.title")), loading() ? _tmpl$2[0] + ssrHydrationKey() + _tmpl$2[1] : ssr(_tmpl$3, ssrHydrationKey(), activities().length > 0 ? ssr(_tmpl$4, ssrHydrationKey(), escape(createComponent(For, {
1927
+ get each() {
1928
+ return activities();
1929
+ },
1930
+ children: (activity) => ssr(_tmpl$5, ssrHydrationKey() + ssrAttribute("href", escape(activity.url || "#", true), false), ssrAttribute("target", activity.url ? "_blank" : "", false), escape(getIcon(activity.type)), escape(activity.description), escape(activity.user.name), escape(formatTime(activity.timestamp)))
1931
+ }))) : ssr(_tmpl$6, ssrHydrationKey(), escape(t("dashboard.widgets.activity.empty")))));
1932
+ }
1933
+ //#endregion
1934
+ //#region src/components/Footer.tsx
1935
+ var _tmpl$ = [
1936
+ "<footer",
1937
+ " class=\"admin-footer\" role=\"contentinfo\"><div class=\"footer-content\"><div class=\"footer-left\"><p class=\"footer-version\"><span class=\"product-name\">OkCMS</span><span class=\"version-badge\">v<!--$-->",
1938
+ "<!--/--></span></p><p class=\"footer-copyright\">",
1939
+ "</p></div><nav class=\"footer-links\"",
1940
+ "><a href=\"https://oktisworks.com\" target=\"_blank\" rel=\"noopener noreferrer\">",
1941
+ "</a><a href=\"https://github.com/oktis-works/cms\" target=\"_blank\" rel=\"noopener noreferrer\">",
1942
+ "</a><a href=\"https://docs.oktisworks.com\" target=\"_blank\" rel=\"noopener noreferrer\">",
1943
+ "</a><a href=\"https://oktisworks.com/community\" target=\"_blank\" rel=\"noopener noreferrer\">",
1944
+ "</a></nav><div class=\"footer-right\"><p class=\"footer-powered\">",
1945
+ "</p></div></div><style>\n .admin-footer {\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n height: 48px;\n background: var(--color-surface);\n border-top: 1px solid var(--color-border);\n padding: 0 1.5rem;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 0.75rem;\n color: var(--color-muted);\n }\n\n .footer-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n max-width: 1400px;\n margin: 0 auto;\n gap: 1.5rem;\n }\n\n .footer-left { display: flex; flex-direction: column; gap: 0.125rem; }\n\n .footer-version {\n display: flex; align-items: center; gap: 0.5rem;\n font-weight: 600; color: var(--color-text); font-size: 0.8125rem;\n }\n\n .version-badge {\n background: var(--color-primary-soft);\n color: var(--color-primary-hover);\n padding: 0.125rem 0.375rem;\n border-radius: var(--radius-sm);\n font-size: 0.6875rem;\n font-weight: 700;\n }\n\n .footer-copyright { font-size: 0.6875rem; color: var(--color-muted); }\n\n .footer-links {\n display: flex; gap: 1.5rem;\n }\n\n .footer-links a {\n color: var(--color-muted);\n font-size: 0.75rem;\n font-weight: 500;\n text-decoration: none;\n transition: color 0.15s;\n }\n\n .footer-links a:hover { color: var(--color-primary); }\n\n .footer-right { text-align: right; }\n .footer-powered { font-size: 0.6875rem; color: var(--color-muted); }\n\n @media (max-width: 768px) {\n .admin-footer { flex-direction: column; height: auto; padding: 0.75rem 1rem; gap: 0.5rem; }\n .footer-content { flex-direction: column; gap: 0.5rem; }\n .footer-links { flex-wrap: wrap; justify-content: center; }\n }\n\n /* RTL adjustments */\n [dir=\"rtl\"] .footer-links { flex-direction: row-reverse; }\n [dir=\"rtl\"] .footer-right { text-align: left; }\n [dir=\"rtl\"] .footer-left { align-items: flex-end; }\n </style></footer>"
1946
+ ];
1947
+ function Footer() {
1948
+ const { t } = useTranslation();
1949
+ const version = APP_VERSION;
1950
+ return ssr(_tmpl$, ssrHydrationKey(), escape(version), escape(t("footer.copyright")), ssrAttribute("aria-label", escape(t("footer.links"), true), false), escape(t("footer.website")), escape(t("footer.github")), escape(t("footer.docs")), escape(t("footer.community")), escape(t("footer.poweredBy")));
1951
+ }
1952
+ //#endregion
1953
+ //#region src/layouts/DashboardLayout.astro
1954
+ createAstro("https://astro.build");
1955
+ var $$DashboardLayout = createComponent$1(($$result, $$props, $$slots) => {
1956
+ const Astro = $$result.createAstro($$props, $$slots);
1957
+ Astro.self = $$DashboardLayout;
1958
+ const { title, description } = Astro.props;
1959
+ const { t, locale } = Astro.locals;
1960
+ const pathname = Astro.url.pathname;
1961
+ const isActive = (href) => href === "/" ? pathname === "/" : pathname === href || pathname.startsWith(`${href}/`);
1962
+ const navActive = {
1963
+ dashboard: isActive("/"),
1964
+ content: isActive("/content"),
1965
+ media: isActive("/media"),
1966
+ users: isActive("/users"),
1967
+ settings: isActive("/settings")
1968
+ };
1969
+ const settingsChildren = [
1970
+ {
1971
+ href: "/settings/general",
1972
+ label: t("settings.general.title"),
1973
+ active: isActive("/settings/general")
1974
+ },
1975
+ {
1976
+ href: "/settings/post-types",
1977
+ label: t("settings.postTypes.title"),
1978
+ active: isActive("/settings/post-types")
1979
+ },
1980
+ {
1981
+ href: "/settings/taxonomies",
1982
+ label: t("settings.taxonomies.title"),
1983
+ active: isActive("/settings/taxonomies")
1984
+ }
1985
+ ];
1986
+ const screenOptionsPanels = [
1987
+ {
1988
+ id: "at-glance",
1989
+ label: t("dashboard.widgets.atGlance"),
1990
+ defaultOpen: true
1991
+ },
1992
+ {
1993
+ id: "activity",
1994
+ label: t("dashboard.widgets.activity.title"),
1995
+ defaultOpen: true
1996
+ },
1997
+ {
1998
+ id: "quick-draft",
1999
+ label: t("dashboard.widgets.quickDraft.title"),
2000
+ defaultOpen: true
2001
+ }
2002
+ ];
2003
+ const helpTabs = [
2004
+ {
2005
+ id: "overview",
2006
+ label: t("helpTabs.topics.overview.label"),
2007
+ content: t("helpTabs.topics.overview.content")
2008
+ },
2009
+ {
2010
+ id: "content",
2011
+ label: t("helpTabs.topics.content.label"),
2012
+ content: t("helpTabs.topics.content.content")
2013
+ },
2014
+ {
2015
+ id: "media",
2016
+ label: t("helpTabs.topics.media.label"),
2017
+ content: t("helpTabs.topics.media.content")
2018
+ }
2019
+ ];
2020
+ return renderTemplate`${renderComponent($$result, "BaseLayout", $$BaseLayout, {
2021
+ "title": title,
2022
+ "description": description,
2023
+ "data-astro-cid-ynf3rr4n": true
2024
+ }, { "default": ($$result) => renderTemplate`${renderComponent($$result, "AdminBar", AdminBar, {
2025
+ "client:load": true,
2026
+ "data-astro-cid-ynf3rr4n": true,
2027
+ "client:component-hydration": "load",
2028
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/admin-bar/AdminBar.tsx",
2029
+ "client:component-export": "AdminBar"
2030
+ })}${maybeRenderHead($$result)}<div class="layout" data-astro-cid-ynf3rr4n><!-- Sidebar colapsável — o estado (body.sidebar-collapsed) é aplicado pelo script abaixo --><aside class="sidebar" data-astro-cid-ynf3rr4n><div class="sidebar-header" data-astro-cid-ynf3rr4n><h2 class="text-lg font-bold" data-astro-cid-ynf3rr4n>${t("layout.appName")}</h2><span class="badge badge-secondary" data-astro-cid-ynf3rr4n>${t("layout.admin")}</span><span class="sidebar-collapsed-brand"${addAttribute(t("layout.appName"), "title")} data-astro-cid-ynf3rr4n><svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="28" height="28" data-astro-cid-ynf3rr4n><rect width="32" height="32" rx="8" fill="url(#grad)" data-astro-cid-ynf3rr4n></rect><path d="M8 10h16M8 16h12M8 22h8" stroke="#0A0A0A" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n></path><defs data-astro-cid-ynf3rr4n><linearGradient id="grad" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse" data-astro-cid-ynf3rr4n><stop offset="0%" stop-color="#D8B45E" data-astro-cid-ynf3rr4n></stop><stop offset="100%" stop-color="#B99542" data-astro-cid-ynf3rr4n></stop></linearGradient></defs></svg></span></div><nav class="sidebar-nav" data-astro-cid-ynf3rr4n><a href="/"${addAttribute(["nav-item", { active: navActive.dashboard }], "class:list")} data-astro-cid-ynf3rr4n><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n><rect x="3" y="3" width="7" height="7" data-astro-cid-ynf3rr4n></rect><rect x="14" y="3" width="7" height="7" data-astro-cid-ynf3rr4n></rect><rect x="14" y="14" width="7" height="7" data-astro-cid-ynf3rr4n></rect><rect x="3" y="14" width="7" height="7" data-astro-cid-ynf3rr4n></rect></svg><span class="nav-label" data-astro-cid-ynf3rr4n>${t("layout.nav.dashboard")}</span></a><a href="/content"${addAttribute(["nav-item", { active: navActive.content }], "class:list")} data-astro-cid-ynf3rr4n><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" data-astro-cid-ynf3rr4n></path><polyline points="14 2 14 8 20 8" data-astro-cid-ynf3rr4n></polyline><line x1="16" y1="13" x2="8" y2="13" data-astro-cid-ynf3rr4n></line><line x1="16" y1="17" x2="8" y2="17" data-astro-cid-ynf3rr4n></line><polyline points="10 9 9 9 8 9" data-astro-cid-ynf3rr4n></polyline></svg><span class="nav-label" data-astro-cid-ynf3rr4n>${t("layout.nav.content")}</span></a><a href="/media"${addAttribute(["nav-item", { active: navActive.media }], "class:list")} data-astro-cid-ynf3rr4n><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n><rect x="3" y="3" width="18" height="18" rx="2" ry="2" data-astro-cid-ynf3rr4n></rect><circle cx="8.5" cy="8.5" r="1.5" data-astro-cid-ynf3rr4n></circle><polyline points="21 15 16 10 5 21" data-astro-cid-ynf3rr4n></polyline></svg><span class="nav-label" data-astro-cid-ynf3rr4n>${t("layout.nav.media")}</span></a><a href="/users"${addAttribute(["nav-item", { active: navActive.users }], "class:list")} data-astro-cid-ynf3rr4n><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" data-astro-cid-ynf3rr4n></path><circle cx="9" cy="7" r="4" data-astro-cid-ynf3rr4n></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87" data-astro-cid-ynf3rr4n></path><path d="M16 3.13a4 4 0 0 1 0 7.75" data-astro-cid-ynf3rr4n></path></svg><span class="nav-label" data-astro-cid-ynf3rr4n>${t("layout.nav.users")}</span></a><a href="/settings"${addAttribute(["nav-item", { active: navActive.settings }], "class:list")} data-astro-cid-ynf3rr4n><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-ynf3rr4n><circle cx="12" cy="12" r="3" data-astro-cid-ynf3rr4n></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" data-astro-cid-ynf3rr4n></path></svg><span class="nav-label" data-astro-cid-ynf3rr4n>${t("layout.nav.settings")}</span></a><!-- Submenu de configurações (CSS esconde quando a sidebar está colapsada) --><div class="nav-submenu" data-astro-cid-ynf3rr4n>${settingsChildren.map((child) => renderTemplate`<a${addAttribute(child.href, "href")}${addAttribute(["nav-subitem", { active: child.active }], "class:list")} data-astro-cid-ynf3rr4n>${child.label}</a>`)}</div><!-- D1: slots de extensão — páginas de menu declaradas por plugins ativos -->${renderComponent($$result, "PluginExtensionsSlot", PluginExtensionsSlot, {
2031
+ "client:load": true,
2032
+ "data-astro-cid-ynf3rr4n": true,
2033
+ "client:component-hydration": "load",
2034
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/ext/extensions.tsx",
2035
+ "client:component-export": "PluginExtensionsSlot"
2036
+ })}</nav></aside><main class="main-content" data-astro-cid-ynf3rr4n><!-- Screen Options & Help Tabs --><div class="screen-options-bar" data-astro-cid-ynf3rr4n>${renderComponent($$result, "ScreenOptions", ScreenOptions, {
2037
+ "client:load": true,
2038
+ "panels": screenOptionsPanels,
2039
+ "data-astro-cid-ynf3rr4n": true,
2040
+ "client:component-hydration": "load",
2041
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/screen-options/ScreenOptions.tsx",
2042
+ "client:component-export": "ScreenOptions"
2043
+ })}${renderComponent($$result, "HelpTabs", HelpTabs, {
2044
+ "client:load": true,
2045
+ "tabs": helpTabs,
2046
+ "data-astro-cid-ynf3rr4n": true,
2047
+ "client:component-hydration": "load",
2048
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/screen-options/HelpTabs.tsx",
2049
+ "client:component-export": "HelpTabs"
2050
+ })}</div><div class="content-wrapper" data-astro-cid-ynf3rr4n><header class="main-header" data-astro-cid-ynf3rr4n><h1 class="text-lg font-bold" data-astro-cid-ynf3rr4n>${title}</h1><div class="header-actions" data-astro-cid-ynf3rr4n>${renderComponent($$result, "LanguageSelector", LanguageSelector, {
2051
+ "client:load": true,
2052
+ "locale": locale,
2053
+ "data-astro-cid-ynf3rr4n": true,
2054
+ "client:component-hydration": "load",
2055
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/LanguageSelector.tsx",
2056
+ "client:component-export": "LanguageSelector"
2057
+ })}<button class="btn btn-secondary btn-sm" id="logout-btn" data-astro-cid-ynf3rr4n>${t("layout.actions.logout")}</button></div></header><div class="content" data-astro-cid-ynf3rr4n>${renderSlot($$result, $$slots["default"])}</div><!-- Dashboard Widgets (only on dashboard page) -->${pathname === "/" && renderTemplate`<div class="dashboard-widgets-area" data-astro-cid-ynf3rr4n><div class="dashboard-widgets-grid" data-astro-cid-ynf3rr4n>${renderComponent($$result, "AtGlanceWidget", AtGlanceWidget, {
2058
+ "client:load": true,
2059
+ "data-astro-cid-ynf3rr4n": true,
2060
+ "client:component-hydration": "load",
2061
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/dashboard-widgets/AtGlanceWidget.tsx",
2062
+ "client:component-export": "AtGlanceWidget"
2063
+ })}${renderComponent($$result, "QuickDraftWidget", QuickDraftWidget, {
2064
+ "client:load": true,
2065
+ "data-astro-cid-ynf3rr4n": true,
2066
+ "client:component-hydration": "load",
2067
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/dashboard-widgets/QuickDraftWidget.tsx",
2068
+ "client:component-export": "QuickDraftWidget"
2069
+ })}${renderComponent($$result, "ActivityWidget", ActivityWidget, {
2070
+ "client:load": true,
2071
+ "data-astro-cid-ynf3rr4n": true,
2072
+ "client:component-hydration": "load",
2073
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/dashboard-widgets/ActivityWidget.tsx",
2074
+ "client:component-export": "ActivityWidget"
2075
+ })}</div></div>`}<!-- Footer -->${renderComponent($$result, "Footer", Footer, {
2076
+ "client:load": true,
2077
+ "data-astro-cid-ynf3rr4n": true,
2078
+ "client:component-hydration": "load",
2079
+ "client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/Footer.tsx",
2080
+ "client:component-export": "Footer"
2081
+ })}</div></main></div>` })}${renderScript($$result, "/home/runner/work/cms/cms/apps/admin/src/layouts/DashboardLayout.astro?astro&type=script&index=0&lang.ts")}`;
2082
+ }, "/home/runner/work/cms/cms/apps/admin/src/layouts/DashboardLayout.astro", void 0);
2083
+ //#endregion
2084
+ export { Button as a, Input as c, Show2 as d, Table as f, onMount$1 as h, Badge as i, Pagination as l, createSignal$1 as m, useTranslation as n, Card as o, createMemo$1 as p, apiClient as r, For2 as s, $$DashboardLayout as t, Select as u };