@oktis-works/admin 0.1.5 → 0.1.8
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.
- package/dist/client/_astro/{BaseLayout.COf3Eran.css → BaseLayout.BPkaFsmK.css} +1 -1
- package/dist/client/_astro/ContentEditor.C9TSxsGW.js +1 -0
- package/dist/client/_astro/ContentList.e1datweV.js +1 -0
- package/dist/client/_astro/DashboardHome.CqnldWlv.js +1 -0
- package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.sNve10RH.js +1 -0
- package/dist/client/_astro/GeneralSettings.D-ALN9_r.js +1 -0
- package/dist/client/_astro/MediaLibrary.NQ1lF95i.js +1 -0
- package/dist/client/_astro/PostTypesManager.CdMx_Nxn.js +1 -0
- package/dist/client/_astro/TaxonomiesManager.BU7A02Ay.js +1 -0
- package/dist/client/_astro/UserCreateForm.BvDn97aZ.js +1 -0
- package/dist/client/_astro/UsersManager.CFBCKO-t.js +1 -0
- package/dist/client/_astro/api.DCaprPaL.js +1 -0
- package/dist/client/_astro/client.BY0Z100j.js +1 -0
- package/dist/client/_astro/dist.B3u752Tx.js +1 -0
- package/dist/client/_astro/extensions.PfWqwyUU.js +1 -0
- package/dist/client/_astro/{login.astro_astro_type_script_index_0_lang.BLhqPWk8.js → login.astro_astro_type_script_index_0_lang.BZaUVRCc.js} +1 -1
- package/dist/client/_astro/{web.BRlgYXBp.js → web.D_vCtCLj.js} +1 -1
- package/dist/server/chunks/{BaseLayout_Mvr1_6Ng.mjs → BaseLayout_C41_wW4F.mjs} +19 -2
- package/dist/server/chunks/{edit_D14rRl_p.mjs → ContentEditor_CrO12IkK.mjs} +535 -48
- package/dist/server/chunks/DashboardLayout_h9iqOf7E.mjs +524 -0
- package/dist/server/chunks/MediaLibrary_Ctc5H6Od.mjs +309 -0
- package/dist/server/chunks/_slug__FVgVdi48.mjs +30 -0
- package/dist/server/chunks/api_C1VC3OiH.mjs +286 -0
- package/dist/server/chunks/edit_Dau0tASP.mjs +30 -0
- package/dist/server/chunks/general_DOXmhv-h.mjs +180 -0
- package/dist/server/chunks/index_B26K6w42.mjs +316 -0
- package/dist/server/chunks/index_BYBvZsat.mjs +23 -0
- package/dist/server/chunks/index_D9OGVvPs.mjs +275 -0
- package/dist/server/chunks/index_Owj31XBA.mjs +133 -0
- package/dist/server/chunks/index_oZK1qJym.mjs +30 -0
- package/dist/server/chunks/{login_B7vbWIed.mjs → login_BH67N4b1.mjs} +2 -19
- package/dist/server/chunks/new_2mb-n_fU.mjs +86 -0
- package/dist/server/chunks/new_BhA9pTES.mjs +30 -0
- package/dist/server/chunks/{post-types_BtNyF2Iv.mjs → post-types_B4rrV0WI.mjs} +2 -2
- package/dist/server/chunks/{taxonomies_DSgstawN.mjs → taxonomies_Bdxv94jK.mjs} +2 -2
- package/dist/server/chunks/upload_RgdwSWbY.mjs +31 -0
- package/dist/server/entry.mjs +291 -15
- package/package.json +5 -5
- package/dist/client/_astro/ContentEditor.COyD6bGV.js +0 -1
- package/dist/client/_astro/PostTypesManager.APvO7Cs9.js +0 -1
- package/dist/client/_astro/TaxonomiesManager.CVFdfaUR.js +0 -1
- package/dist/client/_astro/api.DSP61PKM.js +0 -1
- package/dist/client/_astro/client.D7G9q8lk.js +0 -1
- package/dist/server/chunks/DashboardLayout_CP5ag-_P.mjs +0 -17
- package/dist/server/chunks/api_Cy8sbUHf.mjs +0 -153
- package/dist/server/chunks/index_BgbHlcwr.mjs +0 -23
- package/dist/server/chunks/index_c3b5hMDp.mjs +0 -22
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { a as For2, c as Select, f as createSignal, l as Show2, o as Input, p as onMount, r as Button, s as Pagination } from "./DashboardLayout_h9iqOf7E.mjs";
|
|
2
|
+
import { t as apiClient } from "./api_C1VC3OiH.mjs";
|
|
3
|
+
import { createComponent, escape, ssr, ssrAttribute, ssrHydrationKey, ssrStyleProperty } from "solid-js/web";
|
|
4
|
+
//#region src/components/media/MediaLibrary.tsx
|
|
5
|
+
var _tmpl$ = [
|
|
6
|
+
"<div",
|
|
7
|
+
" class=\"notice notice--error\">",
|
|
8
|
+
"</div>"
|
|
9
|
+
];
|
|
10
|
+
var _tmpl$2 = [
|
|
11
|
+
"<div",
|
|
12
|
+
" class=\"notice\">",
|
|
13
|
+
"</div>"
|
|
14
|
+
];
|
|
15
|
+
var _tmpl$3 = [
|
|
16
|
+
"<div",
|
|
17
|
+
" class=\"media-grid\">",
|
|
18
|
+
"</div>"
|
|
19
|
+
];
|
|
20
|
+
var _tmpl$4 = [
|
|
21
|
+
"<div",
|
|
22
|
+
" class=\"media-library\"><!--$-->",
|
|
23
|
+
"<!--/--><!--$-->",
|
|
24
|
+
"<!--/--><div class=\"",
|
|
25
|
+
"\"><p><strong>Arraste arquivos aqui</strong> ou</p><label class=\"btn btn-primary\" style=\"",
|
|
26
|
+
"\"><!--$-->",
|
|
27
|
+
"<!--/--><input type=\"file\" multiple style=\"",
|
|
28
|
+
"\"",
|
|
29
|
+
"></label><p class=\"muted\">Imagens, vídeos, áudios e documentos · até 25MB por arquivo</p></div><div class=\"toolbar\"><!--$-->",
|
|
30
|
+
"<!--/--><!--$-->",
|
|
31
|
+
"<!--/--><!--$-->",
|
|
32
|
+
"<!--/--></div><!--$-->",
|
|
33
|
+
"<!--/--><!--$-->",
|
|
34
|
+
"<!--/--><!--$-->",
|
|
35
|
+
"<!--/--></div>"
|
|
36
|
+
];
|
|
37
|
+
var _tmpl$5 = ["<p", " class=\"muted\">Nenhum arquivo ainda. Envie o primeiro!</p>"];
|
|
38
|
+
var _tmpl$6 = ["<img", " loading=\"lazy\">"];
|
|
39
|
+
var _tmpl$7 = [
|
|
40
|
+
"<button",
|
|
41
|
+
" type=\"button\" class=\"",
|
|
42
|
+
"\"><div class=\"media-card__preview\">",
|
|
43
|
+
"</div><div class=\"media-card__meta\"><span class=\"media-card__name\"",
|
|
44
|
+
">",
|
|
45
|
+
"</span><span class=\"muted\">",
|
|
46
|
+
"</span></div></button>"
|
|
47
|
+
];
|
|
48
|
+
var _tmpl$8 = [
|
|
49
|
+
"<span",
|
|
50
|
+
" class=\"media-card__ext\">",
|
|
51
|
+
"</span>"
|
|
52
|
+
];
|
|
53
|
+
var _tmpl$9 = ["<img", ">"];
|
|
54
|
+
var _tmpl$0 = [
|
|
55
|
+
"<div",
|
|
56
|
+
" class=\"card media-details\"><h3>Detalhes</h3><div class=\"media-details__preview\">",
|
|
57
|
+
"</div><dl class=\"media-details__list\"><dt>Arquivo</dt><dd>",
|
|
58
|
+
"</dd><dt>Tipo</dt><dd>",
|
|
59
|
+
"</dd><dt>Tamanho</dt><dd>",
|
|
60
|
+
"</dd><dt>URL</dt><dd class=\"media-details__url\"><code>",
|
|
61
|
+
"</code><button class=\"btn btn-secondary btn-sm\" type=\"button\">Copiar</button></dd></dl><!--$-->",
|
|
62
|
+
"<!--/--><!--$-->",
|
|
63
|
+
"<!--/--><div class=\"media-details__actions\"><!--$-->",
|
|
64
|
+
"<!--/--><!--$-->",
|
|
65
|
+
"<!--/--><!--$-->",
|
|
66
|
+
"<!--/--></div></div>"
|
|
67
|
+
];
|
|
68
|
+
var _tmpl$1 = [
|
|
69
|
+
"<p",
|
|
70
|
+
" class=\"muted\">",
|
|
71
|
+
"</p>"
|
|
72
|
+
];
|
|
73
|
+
function formatSize(bytes) {
|
|
74
|
+
if (!Number.isFinite(bytes)) return "—";
|
|
75
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
76
|
+
if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
77
|
+
return `${(bytes / 1048576).toFixed(1)} MB`;
|
|
78
|
+
}
|
|
79
|
+
var isImage = (media) => media.mime_type.startsWith("image/");
|
|
80
|
+
function MediaLibrary(props) {
|
|
81
|
+
const [items, setItems] = createSignal([]);
|
|
82
|
+
const [total, setTotal] = createSignal(0);
|
|
83
|
+
const [page, setPage] = createSignal(1);
|
|
84
|
+
const [search, setSearch] = createSignal("");
|
|
85
|
+
const [mimeType, setMimeType] = createSignal("");
|
|
86
|
+
const [error, setError] = createSignal("");
|
|
87
|
+
const [info, setInfo] = createSignal("");
|
|
88
|
+
const [uploading, setUploading] = createSignal(false);
|
|
89
|
+
const [selected, setSelected] = createSignal(null);
|
|
90
|
+
const [dragOver, setDragOver] = createSignal(false);
|
|
91
|
+
const [savingDetails, setSavingDetails] = createSignal(false);
|
|
92
|
+
const limit = 24;
|
|
93
|
+
const load = async () => {
|
|
94
|
+
try {
|
|
95
|
+
const result = await apiClient.listMedia({
|
|
96
|
+
page: page(),
|
|
97
|
+
limit,
|
|
98
|
+
search: search() || void 0,
|
|
99
|
+
mimeType: mimeType() || void 0
|
|
100
|
+
});
|
|
101
|
+
setItems(result.data ?? []);
|
|
102
|
+
setTotal(result.total ?? 0);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
onMount(load);
|
|
108
|
+
const searchNow = async () => {
|
|
109
|
+
setPage(1);
|
|
110
|
+
await load();
|
|
111
|
+
};
|
|
112
|
+
const remove = async (media) => {
|
|
113
|
+
if (!confirm(`Excluir "${media.filename}"? O arquivo será removido do disco.`)) return;
|
|
114
|
+
try {
|
|
115
|
+
await apiClient.deleteMedia(media.id);
|
|
116
|
+
if (selected()?.id === media.id) setSelected(null);
|
|
117
|
+
await load();
|
|
118
|
+
} catch (err) {
|
|
119
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const saveDetails = async () => {
|
|
123
|
+
const media = selected();
|
|
124
|
+
if (!media) return;
|
|
125
|
+
setSavingDetails(true);
|
|
126
|
+
setError("");
|
|
127
|
+
try {
|
|
128
|
+
const updated = await apiClient.updateMedia(media.id, {
|
|
129
|
+
alt: media.alt ?? "",
|
|
130
|
+
caption: media.caption ?? ""
|
|
131
|
+
});
|
|
132
|
+
setSelected({
|
|
133
|
+
...media,
|
|
134
|
+
...updated
|
|
135
|
+
});
|
|
136
|
+
setInfo("Detalhes salvos ✓");
|
|
137
|
+
await load();
|
|
138
|
+
} catch (err) {
|
|
139
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
140
|
+
} finally {
|
|
141
|
+
setSavingDetails(false);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
return ssr(_tmpl$4, ssrHydrationKey(), escape(createComponent(Show2, {
|
|
145
|
+
get when() {
|
|
146
|
+
return error();
|
|
147
|
+
},
|
|
148
|
+
get children() {
|
|
149
|
+
return ssr(_tmpl$, ssrHydrationKey(), escape(error()));
|
|
150
|
+
}
|
|
151
|
+
})), escape(createComponent(Show2, {
|
|
152
|
+
get when() {
|
|
153
|
+
return info();
|
|
154
|
+
},
|
|
155
|
+
get children() {
|
|
156
|
+
return ssr(_tmpl$2, ssrHydrationKey(), escape(info()));
|
|
157
|
+
}
|
|
158
|
+
})), `upload-zone ${dragOver() || props.focusUpload ? "upload-zone--active" : ""}`, ssrStyleProperty("cursor:", "pointer"), uploading() ? "Enviando…" : "Selecionar arquivos", ssrStyleProperty("display:", "none"), ssrAttribute("disabled", uploading(), true), escape(createComponent(Input, {
|
|
159
|
+
name: "media-search",
|
|
160
|
+
placeholder: "Buscar por nome ou alt…",
|
|
161
|
+
get value() {
|
|
162
|
+
return search();
|
|
163
|
+
},
|
|
164
|
+
onInput: (value) => {
|
|
165
|
+
setSearch(value);
|
|
166
|
+
searchNow();
|
|
167
|
+
}
|
|
168
|
+
})), escape(createComponent(Select, {
|
|
169
|
+
name: "media-mime",
|
|
170
|
+
placeholder: "Todos os tipos",
|
|
171
|
+
get value() {
|
|
172
|
+
return mimeType();
|
|
173
|
+
},
|
|
174
|
+
options: [
|
|
175
|
+
{
|
|
176
|
+
value: "image/png",
|
|
177
|
+
label: "PNG"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
value: "image/jpeg",
|
|
181
|
+
label: "JPEG"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
value: "image/gif",
|
|
185
|
+
label: "GIF"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
value: "image/webp",
|
|
189
|
+
label: "WebP"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
value: "image/svg+xml",
|
|
193
|
+
label: "SVG"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
value: "application/pdf",
|
|
197
|
+
label: "PDF"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
value: "video/mp4",
|
|
201
|
+
label: "MP4"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
value: "audio/mpeg",
|
|
205
|
+
label: "MP3"
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
onChange: (value) => {
|
|
209
|
+
setMimeType(value);
|
|
210
|
+
searchNow();
|
|
211
|
+
}
|
|
212
|
+
})), escape(createComponent(Button, {
|
|
213
|
+
variant: "secondary",
|
|
214
|
+
onClick: () => void searchNow(),
|
|
215
|
+
children: "Buscar"
|
|
216
|
+
})), escape(createComponent(Show2, {
|
|
217
|
+
get when() {
|
|
218
|
+
return items().length > 0;
|
|
219
|
+
},
|
|
220
|
+
get fallback() {
|
|
221
|
+
return ssr(_tmpl$5, ssrHydrationKey());
|
|
222
|
+
},
|
|
223
|
+
get children() {
|
|
224
|
+
return ssr(_tmpl$3, ssrHydrationKey(), escape(createComponent(For2, {
|
|
225
|
+
get each() {
|
|
226
|
+
return items();
|
|
227
|
+
},
|
|
228
|
+
children: (media) => ssr(_tmpl$7, ssrHydrationKey(), `media-card ${selected()?.id === media.id ? "media-card--selected" : ""}`, escape(createComponent(Show2, {
|
|
229
|
+
get when() {
|
|
230
|
+
return isImage(media);
|
|
231
|
+
},
|
|
232
|
+
get fallback() {
|
|
233
|
+
return ssr(_tmpl$8, ssrHydrationKey(), escape(media.mime_type.split("/")[1]?.toUpperCase() ?? "FILE"));
|
|
234
|
+
},
|
|
235
|
+
get children() {
|
|
236
|
+
return ssr(_tmpl$6, ssrHydrationKey() + ssrAttribute("src", escape(media.url, true), false) + ssrAttribute("alt", escape(media.alt ?? media.filename, true), false));
|
|
237
|
+
}
|
|
238
|
+
})), ssrAttribute("title", escape(media.filename, true), false), escape(media.filename), escape(formatSize(media.size)))
|
|
239
|
+
})));
|
|
240
|
+
}
|
|
241
|
+
})), escape(createComponent(Pagination, {
|
|
242
|
+
get page() {
|
|
243
|
+
return page();
|
|
244
|
+
},
|
|
245
|
+
limit,
|
|
246
|
+
get total() {
|
|
247
|
+
return total();
|
|
248
|
+
},
|
|
249
|
+
onPageChange: (next) => {
|
|
250
|
+
setPage(next);
|
|
251
|
+
load();
|
|
252
|
+
}
|
|
253
|
+
})), escape(createComponent(Show2, {
|
|
254
|
+
get when() {
|
|
255
|
+
return selected();
|
|
256
|
+
},
|
|
257
|
+
children: (media) => ssr(_tmpl$0, ssrHydrationKey(), escape(createComponent(Show2, {
|
|
258
|
+
get when() {
|
|
259
|
+
return isImage(media());
|
|
260
|
+
},
|
|
261
|
+
get fallback() {
|
|
262
|
+
return ssr(_tmpl$1, ssrHydrationKey(), escape(media().mime_type));
|
|
263
|
+
},
|
|
264
|
+
get children() {
|
|
265
|
+
return ssr(_tmpl$9, ssrHydrationKey() + ssrAttribute("src", escape(media().url, true), false) + ssrAttribute("alt", escape(media().alt ?? "", true), false));
|
|
266
|
+
}
|
|
267
|
+
})), escape(media().filename), escape(media().mime_type), escape(formatSize(media().size)), escape(media().url), escape(createComponent(Input, {
|
|
268
|
+
name: "media-alt",
|
|
269
|
+
label: "Texto alternativo (alt)",
|
|
270
|
+
get value() {
|
|
271
|
+
return media().alt ?? "";
|
|
272
|
+
},
|
|
273
|
+
onInput: (value) => setSelected({
|
|
274
|
+
...media(),
|
|
275
|
+
alt: value
|
|
276
|
+
})
|
|
277
|
+
})), escape(createComponent(Input, {
|
|
278
|
+
name: "media-caption",
|
|
279
|
+
label: "Legenda",
|
|
280
|
+
get value() {
|
|
281
|
+
return media().caption ?? "";
|
|
282
|
+
},
|
|
283
|
+
onInput: (value) => setSelected({
|
|
284
|
+
...media(),
|
|
285
|
+
caption: value
|
|
286
|
+
})
|
|
287
|
+
})), escape(createComponent(Button, {
|
|
288
|
+
variant: "primary",
|
|
289
|
+
get disabled() {
|
|
290
|
+
return savingDetails();
|
|
291
|
+
},
|
|
292
|
+
get loading() {
|
|
293
|
+
return savingDetails();
|
|
294
|
+
},
|
|
295
|
+
onClick: () => void saveDetails(),
|
|
296
|
+
children: "Salvar detalhes"
|
|
297
|
+
})), escape(createComponent(Button, {
|
|
298
|
+
variant: "danger",
|
|
299
|
+
onClick: () => void remove(media()),
|
|
300
|
+
children: "Excluir"
|
|
301
|
+
})), escape(createComponent(Button, {
|
|
302
|
+
variant: "secondary",
|
|
303
|
+
onClick: () => setSelected(null),
|
|
304
|
+
children: "Fechar"
|
|
305
|
+
})))
|
|
306
|
+
})));
|
|
307
|
+
}
|
|
308
|
+
//#endregion
|
|
309
|
+
export { MediaLibrary as t };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { r as __exportAll } from "./rolldown-runtime_BMI-E3GI.mjs";
|
|
2
|
+
import { S as createAstro, d as maybeRenderHead, i as renderComponent, p as addAttribute, u as renderTemplate } from "./server_CnzC2Y0K.mjs";
|
|
3
|
+
import { t as createComponent } from "./compiler_CYjwXhLT.mjs";
|
|
4
|
+
import { t as $$DashboardLayout } from "./DashboardLayout_h9iqOf7E.mjs";
|
|
5
|
+
//#region src/pages/plugins/[slug].astro
|
|
6
|
+
var _slug__exports = /* @__PURE__ */ __exportAll({
|
|
7
|
+
default: () => $$Slug,
|
|
8
|
+
file: () => $$file,
|
|
9
|
+
url: () => $$url
|
|
10
|
+
});
|
|
11
|
+
createAstro("https://astro.build");
|
|
12
|
+
var $$Slug = createComponent(($$result, $$props, $$slots) => {
|
|
13
|
+
const Astro = $$result.createAstro($$props, $$slots);
|
|
14
|
+
Astro.self = $$Slug;
|
|
15
|
+
const { slug } = Astro.props;
|
|
16
|
+
const pluginSlug = String(slug ?? "").split("/")[0] ?? "";
|
|
17
|
+
const pageTitle = String(slug ?? "Plugin");
|
|
18
|
+
return renderTemplate`${renderComponent($$result, "DashboardLayout", $$DashboardLayout, {
|
|
19
|
+
"title": pageTitle,
|
|
20
|
+
"description": `Página de extensão do plugin ${pluginSlug}`,
|
|
21
|
+
"data-astro-cid-q2qjpybz": true
|
|
22
|
+
}, { "default": ($$result) => renderTemplate`${maybeRenderHead($$result)}<div class="plugin-page"${addAttribute(pluginSlug, "data-plugin")}${addAttribute(slug, "data-plugin-page")} data-astro-cid-q2qjpybz><div class="card plugin-page__container" data-astro-cid-q2qjpybz><h2 data-astro-cid-q2qjpybz>${pageTitle}</h2><p class="muted" data-astro-cid-q2qjpybz>Conteúdo renderizado pelo runtime de componentes do plugin — isolado via<code data-astro-cid-q2qjpybz>data-plugin="${pluginSlug}"</code>.</p><div class="plugin-page__mount"${addAttribute(`page:${slug}`, "data-plugin-component")}${addAttribute(pluginSlug, "data-plugin")} data-astro-cid-q2qjpybz><!-- Componente do plugin (declarativo, sem injeção de DOM direta — DECI-027) --></div></div></div>` })}`;
|
|
23
|
+
}, "/home/runner/work/cms/cms/apps/admin/src/pages/plugins/[slug].astro", void 0);
|
|
24
|
+
var $$file = "/home/runner/work/cms/cms/apps/admin/src/pages/plugins/[slug].astro";
|
|
25
|
+
var $$url = "/plugins/[slug]";
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region \0virtual:astro:page:src/pages/plugins/[slug]@_@astro
|
|
28
|
+
var page = () => _slug__exports;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { page };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//#region src/lib/api.ts
|
|
2
|
+
var API_BASE = Object.assign({
|
|
3
|
+
"ASSETS_PREFIX": void 0,
|
|
4
|
+
"BASE_URL": "/",
|
|
5
|
+
"DEV": false,
|
|
6
|
+
"MODE": "production",
|
|
7
|
+
"PROD": true,
|
|
8
|
+
"SITE": void 0,
|
|
9
|
+
"SSR": true
|
|
10
|
+
}, { _: "/home/runner/work/cms/cms/apps/admin/node_modules/.bin/astro" })["PUBLIC_API_URL"] ?? "http://localhost:3000";
|
|
11
|
+
var ApiClient = class {
|
|
12
|
+
baseUrl;
|
|
13
|
+
csrfToken = null;
|
|
14
|
+
isRefreshing = false;
|
|
15
|
+
constructor(baseUrl = API_BASE) {
|
|
16
|
+
this.baseUrl = baseUrl;
|
|
17
|
+
}
|
|
18
|
+
/** Inicializa lendo CSRF do cookie (chamado no boot da app) */
|
|
19
|
+
async init() {
|
|
20
|
+
try {
|
|
21
|
+
await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" });
|
|
22
|
+
} catch {}
|
|
23
|
+
}
|
|
24
|
+
/** Sessão válida — verifica via /me (usa cookies HttpOnly automaticamente) */
|
|
25
|
+
async isLoggedIn() {
|
|
26
|
+
try {
|
|
27
|
+
return (await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" })).ok;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Obtém tenantId do backend via /me */
|
|
33
|
+
async getTenantId() {
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(`${this.baseUrl}/api/v1/auth/me`, { credentials: "include" });
|
|
36
|
+
if (!res.ok) return null;
|
|
37
|
+
return (await res.json()).tenantId ?? null;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Login — o backend seta cookies HttpOnly e CSRF; retorna user + tenantId */
|
|
43
|
+
async login(input) {
|
|
44
|
+
return await this.request("POST", "/api/v1/auth/login", input);
|
|
45
|
+
}
|
|
46
|
+
/** Logout — limpa cookies no backend */
|
|
47
|
+
async logout() {
|
|
48
|
+
await this.request("POST", "/api/v1/auth/logout", {});
|
|
49
|
+
this.csrfToken = null;
|
|
50
|
+
}
|
|
51
|
+
/** Refresh de access token via cookie refresh_token */
|
|
52
|
+
async refreshTokens() {
|
|
53
|
+
if (this.isRefreshing) return;
|
|
54
|
+
this.isRefreshing = true;
|
|
55
|
+
try {
|
|
56
|
+
await this.request("POST", "/api/v1/auth/refresh", {});
|
|
57
|
+
} finally {
|
|
58
|
+
this.isRefreshing = false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Requisição genérica com:
|
|
62
|
+
* - credentials: 'include' (envia cookies HttpOnly)
|
|
63
|
+
* - auto-refresh em 401
|
|
64
|
+
* - CSRF header para mutações
|
|
65
|
+
*/
|
|
66
|
+
async request(method, path, body, headers) {
|
|
67
|
+
const url = `${this.baseUrl}${path}`;
|
|
68
|
+
const requestHeaders = {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
...headers
|
|
71
|
+
};
|
|
72
|
+
if (![
|
|
73
|
+
"GET",
|
|
74
|
+
"HEAD",
|
|
75
|
+
"OPTIONS"
|
|
76
|
+
].includes(method.toUpperCase())) {
|
|
77
|
+
const csrf = this.getCsrfToken();
|
|
78
|
+
if (csrf) requestHeaders["x-csrf-token"] = csrf;
|
|
79
|
+
}
|
|
80
|
+
let response = await fetch(url, {
|
|
81
|
+
method,
|
|
82
|
+
headers: requestHeaders,
|
|
83
|
+
credentials: "include",
|
|
84
|
+
body: body ? JSON.stringify(body) : void 0
|
|
85
|
+
});
|
|
86
|
+
if (response.status === 401 && !path.includes("/auth/refresh") && !path.includes("/auth/logout")) {
|
|
87
|
+
await this.refreshTokens();
|
|
88
|
+
response = await fetch(url, {
|
|
89
|
+
method,
|
|
90
|
+
headers: requestHeaders,
|
|
91
|
+
credentials: "include",
|
|
92
|
+
body: body ? JSON.stringify(body) : void 0
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
97
|
+
throw new Error(error.error ?? `Request failed: ${response.status}`);
|
|
98
|
+
}
|
|
99
|
+
const setCookie = response.headers.get("set-cookie");
|
|
100
|
+
if (setCookie) {
|
|
101
|
+
const csrfMatch = setCookie.match(/csrf_token=([^;]+)/);
|
|
102
|
+
if (csrfMatch?.[1]) this.csrfToken = csrfMatch[1];
|
|
103
|
+
}
|
|
104
|
+
return response.json();
|
|
105
|
+
}
|
|
106
|
+
/** Lê CSRF token do cookie (document.cookie) */
|
|
107
|
+
getCsrfToken() {
|
|
108
|
+
if (this.csrfToken) return this.csrfToken;
|
|
109
|
+
if (typeof document !== "undefined") {
|
|
110
|
+
const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/);
|
|
111
|
+
if (match?.[1]) return match[1];
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
async getContent(options) {
|
|
116
|
+
const params = new URLSearchParams();
|
|
117
|
+
if (options?.page) params.set("page", String(options.page));
|
|
118
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
119
|
+
if (options?.type) params.set("type", options.type);
|
|
120
|
+
if (options?.status) params.set("status", options.status);
|
|
121
|
+
if (options?.search) params.set("search", options.search);
|
|
122
|
+
return this.request("GET", `/api/v1/content?${params.toString()}`);
|
|
123
|
+
}
|
|
124
|
+
async getContentById(id) {
|
|
125
|
+
return this.request("GET", `/api/v1/content/${id}`);
|
|
126
|
+
}
|
|
127
|
+
async createContent(data) {
|
|
128
|
+
return this.request("POST", `/api/v1/content`, data);
|
|
129
|
+
}
|
|
130
|
+
async updateContent(id, data) {
|
|
131
|
+
return this.request("PUT", `/api/v1/content/${id}`, data);
|
|
132
|
+
}
|
|
133
|
+
async deleteContent(id) {
|
|
134
|
+
await this.request("DELETE", `/api/v1/content/${id}`);
|
|
135
|
+
}
|
|
136
|
+
/** A2: publica via rota real do publisher (eventBus + cache + revisions). */
|
|
137
|
+
async publishContent(id) {
|
|
138
|
+
return this.request("POST", `/api/v1/content/${id}/publish`);
|
|
139
|
+
}
|
|
140
|
+
/** A2: despublica via rota real do publisher. */
|
|
141
|
+
async unpublishContent(id) {
|
|
142
|
+
return this.request("POST", `/api/v1/content/${id}/unpublish`);
|
|
143
|
+
}
|
|
144
|
+
/** Atalho usado pela ContentList: publish/unpublish conforme status atual. */
|
|
145
|
+
async publishToggle(id, isPublished) {
|
|
146
|
+
return isPublished ? this.unpublishContent(id) : this.publishContent(id);
|
|
147
|
+
}
|
|
148
|
+
async getContentTypes() {
|
|
149
|
+
return this.request("GET", "/api/v1/content-types");
|
|
150
|
+
}
|
|
151
|
+
async createContentType(data) {
|
|
152
|
+
return this.request("POST", "/api/v1/content-types", data);
|
|
153
|
+
}
|
|
154
|
+
async updateContentType(slug, data) {
|
|
155
|
+
return this.request("PUT", `/api/v1/content-types/${slug}`, data);
|
|
156
|
+
}
|
|
157
|
+
async deleteContentType(slug) {
|
|
158
|
+
await this.request("DELETE", `/api/v1/content-types/${slug}`);
|
|
159
|
+
}
|
|
160
|
+
async getTaxonomies() {
|
|
161
|
+
return this.request("GET", "/api/v1/taxonomies");
|
|
162
|
+
}
|
|
163
|
+
async createTaxonomy(data) {
|
|
164
|
+
return this.request("POST", "/api/v1/taxonomies", data);
|
|
165
|
+
}
|
|
166
|
+
async attachTaxonomy(slug, contentType) {
|
|
167
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/attach`, { contentType });
|
|
168
|
+
}
|
|
169
|
+
async detachTaxonomy(slug, contentType) {
|
|
170
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/detach`, { contentType });
|
|
171
|
+
}
|
|
172
|
+
async deleteTaxonomy(slug) {
|
|
173
|
+
await this.request("DELETE", `/api/v1/taxonomies/${slug}`);
|
|
174
|
+
}
|
|
175
|
+
async getFieldGroups(context) {
|
|
176
|
+
if (context?.type) {
|
|
177
|
+
const qs = new URLSearchParams({ type: context.type });
|
|
178
|
+
for (const [key, value] of Object.entries(context)) if (key !== "type" && value) qs.set(key, value);
|
|
179
|
+
return this.request("GET", `/api/v1/field-groups?${qs.toString()}`);
|
|
180
|
+
}
|
|
181
|
+
return this.request("GET", "/api/v1/field-groups");
|
|
182
|
+
}
|
|
183
|
+
async getFieldGroup(id) {
|
|
184
|
+
return this.request("GET", `/api/v1/field-groups/${id}`);
|
|
185
|
+
}
|
|
186
|
+
async createFieldGroup(data) {
|
|
187
|
+
return this.request("POST", "/api/v1/field-groups", data);
|
|
188
|
+
}
|
|
189
|
+
async getFieldTypes(category) {
|
|
190
|
+
const query = category ? `?category=${encodeURIComponent(category)}` : "";
|
|
191
|
+
return this.request("GET", `/api/v1/field-types${query}`);
|
|
192
|
+
}
|
|
193
|
+
async listMedia(options) {
|
|
194
|
+
const params = new URLSearchParams();
|
|
195
|
+
if (options?.page) params.set("page", String(options.page));
|
|
196
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
197
|
+
if (options?.mimeType) params.set("mimeType", options.mimeType);
|
|
198
|
+
if (options?.search) params.set("search", options.search);
|
|
199
|
+
return this.request("GET", `/api/v1/media?${params.toString()}`);
|
|
200
|
+
}
|
|
201
|
+
async getMedia(id) {
|
|
202
|
+
return this.request("GET", `/api/v1/media/${id}`);
|
|
203
|
+
}
|
|
204
|
+
/** Upload multipart — NÃO seta Content-Type (o fetch precisa do boundary). */
|
|
205
|
+
async uploadMedia(file, options) {
|
|
206
|
+
const formData = new FormData();
|
|
207
|
+
formData.append("file", file);
|
|
208
|
+
if (options?.alt) formData.append("alt", options.alt);
|
|
209
|
+
if (options?.caption) formData.append("caption", options.caption);
|
|
210
|
+
const url = `${this.baseUrl}/api/v1/media/upload`;
|
|
211
|
+
const requestHeaders = {};
|
|
212
|
+
const csrf = this.getCsrfToken();
|
|
213
|
+
if (csrf) requestHeaders["x-csrf-token"] = csrf;
|
|
214
|
+
const response = await fetch(url, {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: requestHeaders,
|
|
217
|
+
credentials: "include",
|
|
218
|
+
body: formData
|
|
219
|
+
});
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
const error = await response.json().catch(() => ({ error: `Upload failed: ${response.status}` }));
|
|
222
|
+
throw new Error(error.error ?? `Upload failed: ${response.status}`);
|
|
223
|
+
}
|
|
224
|
+
return response.json();
|
|
225
|
+
}
|
|
226
|
+
async updateMedia(id, data) {
|
|
227
|
+
return this.request("PUT", `/api/v1/media/${id}`, data);
|
|
228
|
+
}
|
|
229
|
+
async deleteMedia(id) {
|
|
230
|
+
await this.request("DELETE", `/api/v1/media/${id}`);
|
|
231
|
+
}
|
|
232
|
+
async listUsers(options) {
|
|
233
|
+
const params = new URLSearchParams();
|
|
234
|
+
if (options?.page) params.set("page", String(options.page));
|
|
235
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
236
|
+
if (options?.search) params.set("search", options.search);
|
|
237
|
+
if (options?.status) params.set("status", options.status);
|
|
238
|
+
return this.request("GET", `/api/v1/users?${params.toString()}`);
|
|
239
|
+
}
|
|
240
|
+
async getUser(id) {
|
|
241
|
+
return this.request("GET", `/api/v1/users/${id}`);
|
|
242
|
+
}
|
|
243
|
+
async createUser(data) {
|
|
244
|
+
return this.request("POST", "/api/v1/users", data);
|
|
245
|
+
}
|
|
246
|
+
async updateUser(id, data) {
|
|
247
|
+
return this.request("PUT", `/api/v1/users/${id}`, data);
|
|
248
|
+
}
|
|
249
|
+
async deleteUser(id) {
|
|
250
|
+
await this.request("DELETE", `/api/v1/users/${id}`);
|
|
251
|
+
}
|
|
252
|
+
async setUserPassword(id, password) {
|
|
253
|
+
await this.request("PUT", `/api/v1/users/${id}/password`, { password });
|
|
254
|
+
}
|
|
255
|
+
async assignRole(userId, roleId) {
|
|
256
|
+
return this.request("POST", `/api/v1/users/${userId}/roles`, { roleId });
|
|
257
|
+
}
|
|
258
|
+
async removeRole(userId, roleId) {
|
|
259
|
+
return this.request("DELETE", `/api/v1/users/${userId}/roles/${roleId}`);
|
|
260
|
+
}
|
|
261
|
+
async listRoles() {
|
|
262
|
+
return this.request("GET", "/api/v1/roles");
|
|
263
|
+
}
|
|
264
|
+
async getSettings(group) {
|
|
265
|
+
const query = group ? `?group=${encodeURIComponent(group)}` : "";
|
|
266
|
+
return this.request("GET", `/api/v1/settings${query}`);
|
|
267
|
+
}
|
|
268
|
+
async updateSettings(items) {
|
|
269
|
+
await this.request("PUT", "/api/v1/settings", items);
|
|
270
|
+
}
|
|
271
|
+
async healthCheck() {
|
|
272
|
+
return this.request("GET", "/health");
|
|
273
|
+
}
|
|
274
|
+
async getThemes() {
|
|
275
|
+
return (await this.request("GET", "/api/v1/themes")).map((theme) => ({
|
|
276
|
+
id: String(theme["id"] ?? ""),
|
|
277
|
+
name: String(theme["name"] ?? ""),
|
|
278
|
+
version: theme["version"] ? String(theme["version"]) : void 0,
|
|
279
|
+
status: String(theme["status"] ?? "INSTALLED"),
|
|
280
|
+
manifest: theme["manifest"] ?? null
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
var apiClient = new ApiClient();
|
|
285
|
+
//#endregion
|
|
286
|
+
export { apiClient as t };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { r as __exportAll } from "./rolldown-runtime_BMI-E3GI.mjs";
|
|
2
|
+
import { d as maybeRenderHead, i as renderComponent, u as renderTemplate } from "./server_CnzC2Y0K.mjs";
|
|
3
|
+
import { t as createComponent } from "./compiler_CYjwXhLT.mjs";
|
|
4
|
+
import { t as $$DashboardLayout } from "./DashboardLayout_h9iqOf7E.mjs";
|
|
5
|
+
import { t as ContentEditor } from "./ContentEditor_CrO12IkK.mjs";
|
|
6
|
+
//#region src/pages/content/edit.astro
|
|
7
|
+
var edit_exports = /* @__PURE__ */ __exportAll({
|
|
8
|
+
default: () => $$Edit,
|
|
9
|
+
file: () => $$file,
|
|
10
|
+
url: () => $$url
|
|
11
|
+
});
|
|
12
|
+
var $$Edit = createComponent(($$result, $$props, $$slots) => {
|
|
13
|
+
return renderTemplate`${renderComponent($$result, "DashboardLayout", $$DashboardLayout, {
|
|
14
|
+
"title": "Editor de Conteúdo",
|
|
15
|
+
"data-astro-cid-4zhgedtj": true
|
|
16
|
+
}, { "default": ($$result) => renderTemplate`${maybeRenderHead($$result)}<div class="editor-page" data-astro-cid-4zhgedtj>${renderComponent($$result, "ContentEditor", ContentEditor, {
|
|
17
|
+
"client:load": true,
|
|
18
|
+
"data-astro-cid-4zhgedtj": true,
|
|
19
|
+
"client:component-hydration": "load",
|
|
20
|
+
"client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/content/ContentEditor.tsx",
|
|
21
|
+
"client:component-export": "ContentEditor"
|
|
22
|
+
})}</div>` })}`;
|
|
23
|
+
}, "/home/runner/work/cms/cms/apps/admin/src/pages/content/edit.astro", void 0);
|
|
24
|
+
var $$file = "/home/runner/work/cms/cms/apps/admin/src/pages/content/edit.astro";
|
|
25
|
+
var $$url = "/content/edit";
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region \0virtual:astro:page:src/pages/content/edit@_@astro
|
|
28
|
+
var page = () => edit_exports;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { page };
|