@oktis-works/admin 0.1.4 → 0.1.7
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/bin/admin.js +14 -0
- package/bin/listen-log.d.ts +8 -0
- package/bin/listen-log.js +66 -0
- package/dist/client/_astro/{BaseLayout.COf3Eran.css → BaseLayout.BPkaFsmK.css} +1 -1
- package/dist/client/_astro/{ContentEditor.COyD6bGV.js → ContentEditor.DOcUnkMP.js} +1 -1
- package/dist/client/_astro/ContentList.KzxsMMxH.js +1 -0
- package/dist/client/_astro/DashboardHome.DFRZ_yyM.js +1 -0
- package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.B663y3aY.js +1 -0
- package/dist/client/_astro/GeneralSettings.gbcKHf_p.js +1 -0
- package/dist/client/_astro/MediaLibrary.BtCjwNlR.js +1 -0
- package/dist/client/_astro/{PostTypesManager.APvO7Cs9.js → PostTypesManager.DsxV-sF3.js} +1 -1
- package/dist/client/_astro/{TaxonomiesManager.CVFdfaUR.js → TaxonomiesManager.DqnwUCtt.js} +1 -1
- package/dist/client/_astro/UserCreateForm.BLaiQTzI.js +1 -0
- package/dist/client/_astro/UsersManager.BPRG8tjn.js +1 -0
- package/dist/client/_astro/api.BegLcOlq.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.ozrnjgkA.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_DwBpNq-K.mjs} +21 -30
- package/dist/server/chunks/DashboardLayout_DO66tdeZ.mjs +43 -0
- package/dist/server/chunks/MediaLibrary_DEi9k6ms.mjs +179 -0
- package/dist/server/chunks/api_BWOj0bUJ.mjs +274 -0
- package/dist/server/chunks/edit_DNavSwFw.mjs +30 -0
- package/dist/server/chunks/general_r50g45qE.mjs +173 -0
- package/dist/server/chunks/index_6G7rXrus.mjs +133 -0
- package/dist/server/chunks/index_B50u2M3P.mjs +23 -0
- package/dist/server/chunks/index_DUzUgyr4.mjs +155 -0
- package/dist/server/chunks/index_qxSk7_hO.mjs +30 -0
- package/dist/server/chunks/index_yiAU3Mfy.mjs +204 -0
- package/dist/server/chunks/{login_B7vbWIed.mjs → login_BH67N4b1.mjs} +2 -19
- package/dist/server/chunks/new_BWcSqoqV.mjs +86 -0
- package/dist/server/chunks/new_h8TItZZ9.mjs +30 -0
- package/dist/server/chunks/{post-types_BtNyF2Iv.mjs → post-types_BSobAovm.mjs} +2 -2
- package/dist/server/chunks/{taxonomies_DSgstawN.mjs → taxonomies_Ij7CReDF.mjs} +2 -2
- package/dist/server/chunks/upload_16xg6koU.mjs +31 -0
- package/dist/server/entry.mjs +259 -13
- package/package.json +5 -5
- package/dist/client/_astro/api.DSP61PKM.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
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { t as createComponent$1 } from "./compiler_CYjwXhLT.mjs";
|
|
4
|
-
import { t as $$DashboardLayout } from "./DashboardLayout_CP5ag-_P.mjs";
|
|
5
|
-
import { t as apiClient } from "./api_Cy8sbUHf.mjs";
|
|
1
|
+
import "./rolldown-runtime_BMI-E3GI.mjs";
|
|
2
|
+
import { t as apiClient } from "./api_BWOj0bUJ.mjs";
|
|
6
3
|
import { t as require_semver } from "./semver_WbqCUY_o.mjs";
|
|
7
4
|
import { createComponent, escape, memo, ssr, ssrAttribute, ssrHydrationKey } from "solid-js/web";
|
|
8
5
|
import { For, For as For$1, Show, Show as Show$1, createMemo, createMemo as createMemo$1, createSignal, createSignal as createSignal$1, onMount } from "solid-js";
|
|
@@ -710,6 +707,24 @@ function ContentEditor() {
|
|
|
710
707
|
} catch (err) {
|
|
711
708
|
setErrors([err instanceof Error ? err.message : String(err)]);
|
|
712
709
|
}
|
|
710
|
+
const editId = new URLSearchParams(window.location.search).get("id");
|
|
711
|
+
if (editId) try {
|
|
712
|
+
const existing = await apiClient.getContentById(editId);
|
|
713
|
+
const rawRow = existing;
|
|
714
|
+
setDraft({
|
|
715
|
+
id: existing.id,
|
|
716
|
+
type: existing.type,
|
|
717
|
+
title: existing.title,
|
|
718
|
+
slug: existing.slug,
|
|
719
|
+
excerpt: existing.excerpt,
|
|
720
|
+
featuredImageId: rawRow["featuredImageId"] ?? rawRow["featured_image_id"],
|
|
721
|
+
status: existing.status,
|
|
722
|
+
layout: existing.layout
|
|
723
|
+
});
|
|
724
|
+
setData(existing.body ?? {});
|
|
725
|
+
} catch (err) {
|
|
726
|
+
setErrors([err instanceof Error ? err.message : String(err)]);
|
|
727
|
+
}
|
|
713
728
|
await loadGroups(draft().type);
|
|
714
729
|
});
|
|
715
730
|
const availableLayouts = () => {
|
|
@@ -818,28 +833,4 @@ function ContentEditor() {
|
|
|
818
833
|
})), ssrAttribute("disabled", saving(), true));
|
|
819
834
|
}
|
|
820
835
|
//#endregion
|
|
821
|
-
|
|
822
|
-
var edit_exports = /* @__PURE__ */ __exportAll({
|
|
823
|
-
default: () => $$Edit,
|
|
824
|
-
file: () => $$file,
|
|
825
|
-
url: () => $$url
|
|
826
|
-
});
|
|
827
|
-
var $$Edit = createComponent$1(($$result, $$props, $$slots) => {
|
|
828
|
-
return renderTemplate`${renderComponent($$result, "DashboardLayout", $$DashboardLayout, {
|
|
829
|
-
"title": "Editor de Conteúdo",
|
|
830
|
-
"data-astro-cid-4zhgedtj": true
|
|
831
|
-
}, { "default": ($$result) => renderTemplate`${maybeRenderHead($$result)}<div class="editor-page" data-astro-cid-4zhgedtj>${renderComponent($$result, "ContentEditor", ContentEditor, {
|
|
832
|
-
"client:load": true,
|
|
833
|
-
"data-astro-cid-4zhgedtj": true,
|
|
834
|
-
"client:component-hydration": "load",
|
|
835
|
-
"client:component-path": "/home/runner/work/cms/cms/apps/admin/src/components/content/ContentEditor.tsx",
|
|
836
|
-
"client:component-export": "ContentEditor"
|
|
837
|
-
})}</div>` })}`;
|
|
838
|
-
}, "/home/runner/work/cms/cms/apps/admin/src/pages/content/edit.astro", void 0);
|
|
839
|
-
var $$file = "/home/runner/work/cms/cms/apps/admin/src/pages/content/edit.astro";
|
|
840
|
-
var $$url = "/content/edit";
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region \0virtual:astro:page:src/pages/content/edit@_@astro
|
|
843
|
-
var page = () => edit_exports;
|
|
844
|
-
//#endregion
|
|
845
|
-
export { page };
|
|
836
|
+
export { ContentEditor as t };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { S as createAstro, d as maybeRenderHead, i as renderComponent, p as addAttribute, s as renderSlot, u as renderTemplate } from "./server_CnzC2Y0K.mjs";
|
|
2
|
+
import { t as createComponent } from "./compiler_CYjwXhLT.mjs";
|
|
3
|
+
import { n as renderScript, t as $$BaseLayout } from "./BaseLayout_C41_wW4F.mjs";
|
|
4
|
+
//#region src/layouts/DashboardLayout.astro
|
|
5
|
+
createAstro("https://astro.build");
|
|
6
|
+
var $$DashboardLayout = createComponent(($$result, $$props, $$slots) => {
|
|
7
|
+
const Astro = $$result.createAstro($$props, $$slots);
|
|
8
|
+
Astro.self = $$DashboardLayout;
|
|
9
|
+
const { title, description } = Astro.props;
|
|
10
|
+
const pathname = Astro.url.pathname;
|
|
11
|
+
const isActive = (href) => href === "/" ? pathname === "/" : pathname === href || pathname.startsWith(`${href}/`);
|
|
12
|
+
const navActive = {
|
|
13
|
+
dashboard: isActive("/"),
|
|
14
|
+
content: isActive("/content"),
|
|
15
|
+
media: isActive("/media"),
|
|
16
|
+
users: isActive("/users"),
|
|
17
|
+
settings: isActive("/settings")
|
|
18
|
+
};
|
|
19
|
+
const settingsChildren = [
|
|
20
|
+
{
|
|
21
|
+
href: "/settings/general",
|
|
22
|
+
label: "General",
|
|
23
|
+
active: isActive("/settings/general")
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
href: "/settings/post-types",
|
|
27
|
+
label: "Content Types",
|
|
28
|
+
active: isActive("/settings/post-types")
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
href: "/settings/taxonomies",
|
|
32
|
+
label: "Taxonomies",
|
|
33
|
+
active: isActive("/settings/taxonomies")
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
return renderTemplate`${renderComponent($$result, "BaseLayout", $$BaseLayout, {
|
|
37
|
+
"title": title,
|
|
38
|
+
"description": description,
|
|
39
|
+
"data-astro-cid-ynf3rr4n": true
|
|
40
|
+
}, { "default": ($$result) => renderTemplate`${maybeRenderHead($$result)}<div class="layout" data-astro-cid-ynf3rr4n><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>OkCMS</h2><span class="badge badge-secondary" data-astro-cid-ynf3rr4n>Admin</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>Dashboard</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>Content</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>Media</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>Users</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 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" data-astro-cid-ynf3rr4n></path></svg>Settings</a><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></nav></aside><main class="main-content" 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><button class="btn btn-secondary btn-sm" id="logout-btn" data-astro-cid-ynf3rr4n>Logout</button></div></header><div class="content" data-astro-cid-ynf3rr4n>${renderSlot($$result, $$slots["default"])}</div></main></div>` })}${renderScript($$result, "/home/runner/work/cms/cms/apps/admin/src/layouts/DashboardLayout.astro?astro&type=script&index=0&lang.ts")}`;
|
|
41
|
+
}, "/home/runner/work/cms/cms/apps/admin/src/layouts/DashboardLayout.astro", void 0);
|
|
42
|
+
//#endregion
|
|
43
|
+
export { $$DashboardLayout as t };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { t as apiClient } from "./api_BWOj0bUJ.mjs";
|
|
2
|
+
import { createComponent, escape, ssr, ssrAttribute, ssrHydrationKey, ssrStyleProperty } from "solid-js/web";
|
|
3
|
+
import { For, Show, createSignal, onMount } from "solid-js";
|
|
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=\"pagination\"><button class=\"btn btn-secondary btn-sm\" type=\"button\"",
|
|
23
|
+
">← Anterior</button><span class=\"muted\">Página <!--$-->",
|
|
24
|
+
"<!--/--> de <!--$-->",
|
|
25
|
+
"<!--/--></span><button class=\"btn btn-secondary btn-sm\" type=\"button\"",
|
|
26
|
+
">Próxima →</button></div>"
|
|
27
|
+
];
|
|
28
|
+
var _tmpl$5 = [
|
|
29
|
+
"<div",
|
|
30
|
+
" class=\"media-library\"><!--$-->",
|
|
31
|
+
"<!--/--><!--$-->",
|
|
32
|
+
"<!--/--><div class=\"",
|
|
33
|
+
"\"><p><strong>Arraste arquivos aqui</strong> ou</p><label class=\"btn btn-primary\" style=\"",
|
|
34
|
+
"\"><!--$-->",
|
|
35
|
+
"<!--/--><input type=\"file\" multiple style=\"",
|
|
36
|
+
"\"",
|
|
37
|
+
"></label><p class=\"muted\">Imagens, vídeos, áudios e documentos · até 25MB por arquivo</p></div><div class=\"toolbar\"><input class=\"input\" placeholder=\"Buscar por nome ou alt…\"",
|
|
38
|
+
"><select class=\"input\"",
|
|
39
|
+
"><option value>Todos os tipos</option><option value=\"image/png\">PNG</option><option value=\"image/jpeg\">JPEG</option><option value=\"image/gif\">GIF</option><option value=\"image/webp\">WebP</option><option value=\"image/svg+xml\">SVG</option><option value=\"application/pdf\">PDF</option><option value=\"video/mp4\">MP4</option><option value=\"audio/mpeg\">MP3</option></select><button class=\"btn btn-secondary\" type=\"button\">Buscar</button></div><!--$-->",
|
|
40
|
+
"<!--/--><!--$-->",
|
|
41
|
+
"<!--/--><!--$-->",
|
|
42
|
+
"<!--/--></div>"
|
|
43
|
+
];
|
|
44
|
+
var _tmpl$6 = ["<p", " class=\"muted\">Nenhum arquivo ainda. Envie o primeiro!</p>"];
|
|
45
|
+
var _tmpl$7 = ["<img", " loading=\"lazy\">"];
|
|
46
|
+
var _tmpl$8 = [
|
|
47
|
+
"<button",
|
|
48
|
+
" type=\"button\" class=\"",
|
|
49
|
+
"\"><div class=\"media-card__preview\">",
|
|
50
|
+
"</div><div class=\"media-card__meta\"><span class=\"media-card__name\"",
|
|
51
|
+
">",
|
|
52
|
+
"</span><span class=\"muted\">",
|
|
53
|
+
"</span></div></button>"
|
|
54
|
+
];
|
|
55
|
+
var _tmpl$9 = [
|
|
56
|
+
"<span",
|
|
57
|
+
" class=\"media-card__ext\">",
|
|
58
|
+
"</span>"
|
|
59
|
+
];
|
|
60
|
+
var _tmpl$0 = ["<img", ">"];
|
|
61
|
+
var _tmpl$1 = [
|
|
62
|
+
"<div",
|
|
63
|
+
" class=\"card media-details\"><h3>Detalhes</h3><div class=\"media-details__preview\">",
|
|
64
|
+
"</div><dl class=\"media-details__list\"><dt>Arquivo</dt><dd>",
|
|
65
|
+
"</dd><dt>Tipo</dt><dd>",
|
|
66
|
+
"</dd><dt>Tamanho</dt><dd>",
|
|
67
|
+
"</dd><dt>URL</dt><dd class=\"media-details__url\"><code>",
|
|
68
|
+
"</code><button class=\"btn btn-secondary btn-sm\" type=\"button\">Copiar</button></dd></dl><label>Texto alternativo (alt)<input class=\"input\"",
|
|
69
|
+
"></label><label>Legenda<input class=\"input\"",
|
|
70
|
+
"></label><div class=\"media-details__actions\"><button class=\"btn btn-primary\" type=\"button\"",
|
|
71
|
+
">",
|
|
72
|
+
"</button><button class=\"btn btn-danger\" type=\"button\">Excluir</button><button class=\"btn btn-secondary\" type=\"button\">Fechar</button></div></div>"
|
|
73
|
+
];
|
|
74
|
+
var _tmpl$10 = [
|
|
75
|
+
"<p",
|
|
76
|
+
" class=\"muted\">",
|
|
77
|
+
"</p>"
|
|
78
|
+
];
|
|
79
|
+
function formatSize(bytes) {
|
|
80
|
+
if (!Number.isFinite(bytes)) return "—";
|
|
81
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
82
|
+
if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
83
|
+
return `${(bytes / 1048576).toFixed(1)} MB`;
|
|
84
|
+
}
|
|
85
|
+
var isImage = (media) => media.mime_type.startsWith("image/");
|
|
86
|
+
function MediaLibrary(props) {
|
|
87
|
+
const [items, setItems] = createSignal([]);
|
|
88
|
+
const [total, setTotal] = createSignal(0);
|
|
89
|
+
const [page, setPage] = createSignal(1);
|
|
90
|
+
const [search, setSearch] = createSignal("");
|
|
91
|
+
const [mimeType, setMimeType] = createSignal("");
|
|
92
|
+
const [error, setError] = createSignal("");
|
|
93
|
+
const [info, setInfo] = createSignal("");
|
|
94
|
+
const [uploading, setUploading] = createSignal(false);
|
|
95
|
+
const [selected, setSelected] = createSignal(null);
|
|
96
|
+
const [dragOver, setDragOver] = createSignal(false);
|
|
97
|
+
const [savingDetails, setSavingDetails] = createSignal(false);
|
|
98
|
+
const limit = 24;
|
|
99
|
+
const load = async () => {
|
|
100
|
+
try {
|
|
101
|
+
const result = await apiClient.listMedia({
|
|
102
|
+
page: page(),
|
|
103
|
+
limit,
|
|
104
|
+
search: search() || void 0,
|
|
105
|
+
mimeType: mimeType() || void 0
|
|
106
|
+
});
|
|
107
|
+
setItems(result.data ?? []);
|
|
108
|
+
setTotal(result.total ?? 0);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
onMount(load);
|
|
114
|
+
const totalPages = () => Math.max(1, Math.ceil(total() / limit));
|
|
115
|
+
return ssr(_tmpl$5, ssrHydrationKey(), escape(createComponent(Show, {
|
|
116
|
+
get when() {
|
|
117
|
+
return error();
|
|
118
|
+
},
|
|
119
|
+
get children() {
|
|
120
|
+
return ssr(_tmpl$, ssrHydrationKey(), escape(error()));
|
|
121
|
+
}
|
|
122
|
+
})), escape(createComponent(Show, {
|
|
123
|
+
get when() {
|
|
124
|
+
return info();
|
|
125
|
+
},
|
|
126
|
+
get children() {
|
|
127
|
+
return ssr(_tmpl$2, ssrHydrationKey(), escape(info()));
|
|
128
|
+
}
|
|
129
|
+
})), `upload-zone ${dragOver() || props.focusUpload ? "upload-zone--active" : ""}`, ssrStyleProperty("cursor:", "pointer"), uploading() ? "Enviando…" : "Selecionar arquivos", ssrStyleProperty("display:", "none"), ssrAttribute("disabled", uploading(), true), ssrAttribute("value", escape(search(), true), false), ssrAttribute("value", escape(mimeType(), true), false), escape(createComponent(Show, {
|
|
130
|
+
get when() {
|
|
131
|
+
return items().length > 0;
|
|
132
|
+
},
|
|
133
|
+
get fallback() {
|
|
134
|
+
return ssr(_tmpl$6, ssrHydrationKey());
|
|
135
|
+
},
|
|
136
|
+
get children() {
|
|
137
|
+
return ssr(_tmpl$3, ssrHydrationKey(), escape(createComponent(For, {
|
|
138
|
+
get each() {
|
|
139
|
+
return items();
|
|
140
|
+
},
|
|
141
|
+
children: (media) => ssr(_tmpl$8, ssrHydrationKey(), `media-card ${selected()?.id === media.id ? "media-card--selected" : ""}`, escape(createComponent(Show, {
|
|
142
|
+
get when() {
|
|
143
|
+
return isImage(media);
|
|
144
|
+
},
|
|
145
|
+
get fallback() {
|
|
146
|
+
return ssr(_tmpl$9, ssrHydrationKey(), escape(media.mime_type.split("/")[1]?.toUpperCase() ?? "FILE"));
|
|
147
|
+
},
|
|
148
|
+
get children() {
|
|
149
|
+
return ssr(_tmpl$7, ssrHydrationKey() + ssrAttribute("src", escape(media.url, true), false) + ssrAttribute("alt", escape(media.alt ?? media.filename, true), false));
|
|
150
|
+
}
|
|
151
|
+
})), ssrAttribute("title", escape(media.filename, true), false), escape(media.filename), escape(formatSize(media.size)))
|
|
152
|
+
})));
|
|
153
|
+
}
|
|
154
|
+
})), escape(createComponent(Show, {
|
|
155
|
+
get when() {
|
|
156
|
+
return totalPages() > 1;
|
|
157
|
+
},
|
|
158
|
+
get children() {
|
|
159
|
+
return ssr(_tmpl$4, ssrHydrationKey(), ssrAttribute("disabled", page() <= 1, true), escape(page()), escape(totalPages()), ssrAttribute("disabled", page() >= totalPages(), true));
|
|
160
|
+
}
|
|
161
|
+
})), escape(createComponent(Show, {
|
|
162
|
+
get when() {
|
|
163
|
+
return selected();
|
|
164
|
+
},
|
|
165
|
+
children: (media) => ssr(_tmpl$1, ssrHydrationKey(), escape(createComponent(Show, {
|
|
166
|
+
get when() {
|
|
167
|
+
return isImage(media());
|
|
168
|
+
},
|
|
169
|
+
get fallback() {
|
|
170
|
+
return ssr(_tmpl$10, ssrHydrationKey(), escape(media().mime_type));
|
|
171
|
+
},
|
|
172
|
+
get children() {
|
|
173
|
+
return ssr(_tmpl$0, ssrHydrationKey() + ssrAttribute("src", escape(media().url, true), false) + ssrAttribute("alt", escape(media().alt ?? "", true), false));
|
|
174
|
+
}
|
|
175
|
+
})), escape(media().filename), escape(media().mime_type), escape(formatSize(media().size)), escape(media().url), ssrAttribute("value", escape(media().alt ?? "", true), false), ssrAttribute("value", escape(media().caption ?? "", true), false), ssrAttribute("disabled", savingDetails(), true), savingDetails() ? "Salvando…" : "Salvar detalhes")
|
|
176
|
+
})));
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { MediaLibrary as t };
|
|
@@ -0,0 +1,274 @@
|
|
|
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
|
+
async getContentTypes() {
|
|
137
|
+
return this.request("GET", "/api/v1/content-types");
|
|
138
|
+
}
|
|
139
|
+
async createContentType(data) {
|
|
140
|
+
return this.request("POST", "/api/v1/content-types", data);
|
|
141
|
+
}
|
|
142
|
+
async updateContentType(slug, data) {
|
|
143
|
+
return this.request("PUT", `/api/v1/content-types/${slug}`, data);
|
|
144
|
+
}
|
|
145
|
+
async deleteContentType(slug) {
|
|
146
|
+
await this.request("DELETE", `/api/v1/content-types/${slug}`);
|
|
147
|
+
}
|
|
148
|
+
async getTaxonomies() {
|
|
149
|
+
return this.request("GET", "/api/v1/taxonomies");
|
|
150
|
+
}
|
|
151
|
+
async createTaxonomy(data) {
|
|
152
|
+
return this.request("POST", "/api/v1/taxonomies", data);
|
|
153
|
+
}
|
|
154
|
+
async attachTaxonomy(slug, contentType) {
|
|
155
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/attach`, { contentType });
|
|
156
|
+
}
|
|
157
|
+
async detachTaxonomy(slug, contentType) {
|
|
158
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/detach`, { contentType });
|
|
159
|
+
}
|
|
160
|
+
async deleteTaxonomy(slug) {
|
|
161
|
+
await this.request("DELETE", `/api/v1/taxonomies/${slug}`);
|
|
162
|
+
}
|
|
163
|
+
async getFieldGroups(context) {
|
|
164
|
+
if (context?.type) {
|
|
165
|
+
const qs = new URLSearchParams({ type: context.type });
|
|
166
|
+
for (const [key, value] of Object.entries(context)) if (key !== "type" && value) qs.set(key, value);
|
|
167
|
+
return this.request("GET", `/api/v1/field-groups?${qs.toString()}`);
|
|
168
|
+
}
|
|
169
|
+
return this.request("GET", "/api/v1/field-groups");
|
|
170
|
+
}
|
|
171
|
+
async getFieldGroup(id) {
|
|
172
|
+
return this.request("GET", `/api/v1/field-groups/${id}`);
|
|
173
|
+
}
|
|
174
|
+
async createFieldGroup(data) {
|
|
175
|
+
return this.request("POST", "/api/v1/field-groups", data);
|
|
176
|
+
}
|
|
177
|
+
async getFieldTypes(category) {
|
|
178
|
+
const query = category ? `?category=${encodeURIComponent(category)}` : "";
|
|
179
|
+
return this.request("GET", `/api/v1/field-types${query}`);
|
|
180
|
+
}
|
|
181
|
+
async listMedia(options) {
|
|
182
|
+
const params = new URLSearchParams();
|
|
183
|
+
if (options?.page) params.set("page", String(options.page));
|
|
184
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
185
|
+
if (options?.mimeType) params.set("mimeType", options.mimeType);
|
|
186
|
+
if (options?.search) params.set("search", options.search);
|
|
187
|
+
return this.request("GET", `/api/v1/media?${params.toString()}`);
|
|
188
|
+
}
|
|
189
|
+
async getMedia(id) {
|
|
190
|
+
return this.request("GET", `/api/v1/media/${id}`);
|
|
191
|
+
}
|
|
192
|
+
/** Upload multipart — NÃO seta Content-Type (o fetch precisa do boundary). */
|
|
193
|
+
async uploadMedia(file, options) {
|
|
194
|
+
const formData = new FormData();
|
|
195
|
+
formData.append("file", file);
|
|
196
|
+
if (options?.alt) formData.append("alt", options.alt);
|
|
197
|
+
if (options?.caption) formData.append("caption", options.caption);
|
|
198
|
+
const url = `${this.baseUrl}/api/v1/media/upload`;
|
|
199
|
+
const requestHeaders = {};
|
|
200
|
+
const csrf = this.getCsrfToken();
|
|
201
|
+
if (csrf) requestHeaders["x-csrf-token"] = csrf;
|
|
202
|
+
const response = await fetch(url, {
|
|
203
|
+
method: "POST",
|
|
204
|
+
headers: requestHeaders,
|
|
205
|
+
credentials: "include",
|
|
206
|
+
body: formData
|
|
207
|
+
});
|
|
208
|
+
if (!response.ok) {
|
|
209
|
+
const error = await response.json().catch(() => ({ error: `Upload failed: ${response.status}` }));
|
|
210
|
+
throw new Error(error.error ?? `Upload failed: ${response.status}`);
|
|
211
|
+
}
|
|
212
|
+
return response.json();
|
|
213
|
+
}
|
|
214
|
+
async updateMedia(id, data) {
|
|
215
|
+
return this.request("PUT", `/api/v1/media/${id}`, data);
|
|
216
|
+
}
|
|
217
|
+
async deleteMedia(id) {
|
|
218
|
+
await this.request("DELETE", `/api/v1/media/${id}`);
|
|
219
|
+
}
|
|
220
|
+
async listUsers(options) {
|
|
221
|
+
const params = new URLSearchParams();
|
|
222
|
+
if (options?.page) params.set("page", String(options.page));
|
|
223
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
224
|
+
if (options?.search) params.set("search", options.search);
|
|
225
|
+
if (options?.status) params.set("status", options.status);
|
|
226
|
+
return this.request("GET", `/api/v1/users?${params.toString()}`);
|
|
227
|
+
}
|
|
228
|
+
async getUser(id) {
|
|
229
|
+
return this.request("GET", `/api/v1/users/${id}`);
|
|
230
|
+
}
|
|
231
|
+
async createUser(data) {
|
|
232
|
+
return this.request("POST", "/api/v1/users", data);
|
|
233
|
+
}
|
|
234
|
+
async updateUser(id, data) {
|
|
235
|
+
return this.request("PUT", `/api/v1/users/${id}`, data);
|
|
236
|
+
}
|
|
237
|
+
async deleteUser(id) {
|
|
238
|
+
await this.request("DELETE", `/api/v1/users/${id}`);
|
|
239
|
+
}
|
|
240
|
+
async setUserPassword(id, password) {
|
|
241
|
+
await this.request("PUT", `/api/v1/users/${id}/password`, { password });
|
|
242
|
+
}
|
|
243
|
+
async assignRole(userId, roleId) {
|
|
244
|
+
return this.request("POST", `/api/v1/users/${userId}/roles`, { roleId });
|
|
245
|
+
}
|
|
246
|
+
async removeRole(userId, roleId) {
|
|
247
|
+
return this.request("DELETE", `/api/v1/users/${userId}/roles/${roleId}`);
|
|
248
|
+
}
|
|
249
|
+
async listRoles() {
|
|
250
|
+
return this.request("GET", "/api/v1/roles");
|
|
251
|
+
}
|
|
252
|
+
async getSettings(group) {
|
|
253
|
+
const query = group ? `?group=${encodeURIComponent(group)}` : "";
|
|
254
|
+
return this.request("GET", `/api/v1/settings${query}`);
|
|
255
|
+
}
|
|
256
|
+
async updateSettings(items) {
|
|
257
|
+
await this.request("PUT", "/api/v1/settings", items);
|
|
258
|
+
}
|
|
259
|
+
async healthCheck() {
|
|
260
|
+
return this.request("GET", "/health");
|
|
261
|
+
}
|
|
262
|
+
async getThemes() {
|
|
263
|
+
return (await this.request("GET", "/api/v1/themes")).map((theme) => ({
|
|
264
|
+
id: String(theme["id"] ?? ""),
|
|
265
|
+
name: String(theme["name"] ?? ""),
|
|
266
|
+
version: theme["version"] ? String(theme["version"]) : void 0,
|
|
267
|
+
status: String(theme["status"] ?? "INSTALLED"),
|
|
268
|
+
manifest: theme["manifest"] ?? null
|
|
269
|
+
}));
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
var apiClient = new ApiClient();
|
|
273
|
+
//#endregion
|
|
274
|
+
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_DO66tdeZ.mjs";
|
|
5
|
+
import { t as ContentEditor } from "./ContentEditor_DwBpNq-K.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 };
|