@oktis-works/admin 0.4.13 → 0.4.15
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/{ActivityWidget.DeayROhc.js → ActivityWidget.B83CLwGG.js} +2 -2
- package/dist/client/_astro/AdminBar.BNESswxs.js +253 -0
- package/dist/client/_astro/{AtGlanceWidget.CDFVi_eX.js → AtGlanceWidget.Cqbb9anJ.js} +3 -3
- package/dist/client/_astro/BaseLayout.B3A9-IS6.css +1 -0
- package/dist/client/_astro/ContentEditor.CBH227Ni.js +1 -0
- package/dist/client/_astro/ContentList.hmLCz5_S.js +1 -0
- package/dist/client/_astro/CustomFieldsManager.Dzhp_sZl.js +3 -0
- package/dist/client/_astro/DashboardHome.DawF-CZ9.js +1 -0
- package/dist/client/_astro/DashboardLayout.CEvRGr78.css +1 -0
- package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.Ckp0okyg.js +1 -0
- package/dist/client/_astro/FieldTypePicker.BEuYPzV8.js +1 -0
- package/dist/client/_astro/{Footer.KkyZkNxH.js → Footer.dcA-nmBA.js} +10 -12
- package/dist/client/_astro/GeneralSettings.DdAwp-oL.js +1 -0
- package/dist/client/_astro/MediaLibrary.B9SPVPYH.js +1 -0
- package/dist/client/_astro/PluginManager.DN5xhAsV.js +93 -0
- package/dist/client/_astro/PostTypesManager.BZH1eM3c.js +1 -0
- package/dist/client/_astro/{QuickDraftWidget.Drp_cL_D.js → QuickDraftWidget.DBvLubay.js} +2 -2
- package/dist/client/_astro/ResourceHubs.BvrE39A0.js +1 -0
- package/dist/client/_astro/TaxonomiesManager.BrjG05jb.js +1 -0
- package/dist/client/_astro/ThemeManager.CsrK3HXj.js +129 -0
- package/dist/client/_astro/UserCreateForm.Dxq80Bqx.js +1 -0
- package/dist/client/_astro/UsersManager.DmBadxWw.js +1 -0
- package/dist/client/_astro/api.BfxYC8bU.js +1 -0
- package/dist/client/_astro/ar.DsV0P0EN.js +1 -0
- package/dist/client/_astro/{client.C7p516_9.js → client.BY0Z100j.js} +1 -1
- package/dist/client/_astro/custom-fields.IjuRIdAC.css +1 -0
- package/dist/client/_astro/es-ES.etPSaiLd.js +1 -0
- package/dist/client/_astro/extensions.C6GOqTCd.js +1 -0
- package/dist/client/_astro/he.U1Vtp3zT.js +1 -0
- package/dist/client/_astro/i18n.B4BuieMb.js +1 -0
- package/dist/client/_astro/it.DJuI8oO_.js +1 -0
- package/dist/client/_astro/ja.Cw8I_NUV.js +1 -0
- package/dist/client/_astro/{login.astro_astro_type_script_index_0_lang.D6nHqYm6.js → login.astro_astro_type_script_index_0_lang.yH8kNMtD.js} +1 -1
- package/dist/client/_astro/pl.Dsz-4G_z.js +1 -0
- package/dist/client/_astro/pt-BR.CyQAHnXs.js +1 -0
- package/dist/client/_astro/ru.CwIIcTdy.js +1 -0
- package/dist/client/_astro/src.HVGUo-fm.js +1 -0
- package/dist/client/_astro/sw.DwpL3sb6.js +1 -0
- package/dist/client/_astro/tr.CY2JWJ7Y.js +1 -0
- package/dist/client/_astro/uk.BudEWIU8.js +1 -0
- package/dist/client/_astro/{version.C0f0jrCn.js → version.CilNJ_fk.js} +1 -1
- package/dist/client/_astro/{web.D1H9RxZL.js → web.D_vCtCLj.js} +1 -1
- package/dist/client/_astro/yo.BmoZs0fO.js +1 -0
- package/dist/client/_astro/zh-CN.khaXV6fv.js +1 -0
- package/dist/server/chunks/{BaseLayout_BsR68tOH.mjs → BaseLayout_BmkfK9tu.mjs} +19 -2
- package/dist/server/chunks/{ContentEditor_BtclxOqH.mjs → ContentEditor_C-kz5cS4.mjs} +31 -101
- package/dist/server/chunks/{DashboardLayout_B9pE8ZBQ.mjs → DashboardLayout_KIUq60Dv.mjs} +52 -566
- package/dist/server/chunks/FieldTypePicker_CXwpmcQ3.mjs +79 -0
- package/dist/server/chunks/{MediaLibrary_DLO2K_4d.mjs → MediaLibrary_C-lJBpPG.mjs} +2 -2
- package/dist/server/chunks/ResourceHubs_T-WuZoVF.mjs +453 -0
- package/dist/server/chunks/{_slug__yqDK_Ow8.mjs → _slug__DjcyD19w.mjs} +1 -1
- package/dist/server/chunks/access_Bjuw_Gvp.mjs +34 -0
- package/dist/server/chunks/{ar_DBjdWIJ0.mjs → ar_DMC8HaoP.mjs} +3 -1
- package/dist/server/chunks/custom-fields_CxntKU56.mjs +488 -0
- package/dist/server/chunks/{edit_0bCUPzfW.mjs → edit_CFKKfQux.mjs} +2 -2
- package/dist/server/chunks/{es-ES_TJ4oK1yi.mjs → es-ES_DZvHskAD.mjs} +3 -1
- package/dist/server/chunks/{general_D-MMl9p8.mjs → general_CVsJAP2e.mjs} +6 -6
- package/dist/server/chunks/{he_TWsuTphz.mjs → he_zy3stNhR.mjs} +3 -1
- package/dist/server/chunks/i18n_CH59YTvE.mjs +1406 -0
- package/dist/server/chunks/{index_Z7GukanS.mjs → index_2Y9ZC7Gs.mjs} +8 -6
- package/dist/server/chunks/{index_CTpEX5iK.mjs → index_Bb3w_UqS.mjs} +2 -2
- package/dist/server/chunks/{index_DB6MLU0v.mjs → index_BqyoH4bc.mjs} +3 -3
- package/dist/server/chunks/{index_CALAZTDB.mjs → index_G7lx2uke.mjs} +2 -2
- package/dist/server/chunks/{index_Bq7o-ZHF.mjs → index_TyNyWm6y.mjs} +1 -1
- package/dist/server/chunks/{it_CEVFVWh1.mjs → it_BiUDLszZ.mjs} +3 -1
- package/dist/server/chunks/{ja_CqDirMqf.mjs → ja_DjFAG7hL.mjs} +3 -1
- package/dist/server/chunks/{login_BcWk_36h.mjs → login_BCjtaOE9.mjs} +1 -2
- package/dist/server/chunks/{new_DlqbYYA1.mjs → new_BZOJIQfZ.mjs} +2 -2
- package/dist/server/chunks/{new_BbKoexYG.mjs → new_DkHY3O0r.mjs} +2 -2
- package/dist/server/chunks/operations_DYc6rwSI.mjs +34 -0
- package/dist/server/chunks/{pl_ChIKxfZG.mjs → pl_0Xe9Qom2.mjs} +3 -1
- package/dist/server/chunks/{plugins_BLJAzLX4.mjs → plugins_p805vlEb.mjs} +55 -22
- package/dist/server/chunks/{post-types_BvVl0hZs.mjs → post-types_C7YAi_V0.mjs} +6 -6
- package/dist/server/chunks/{pt-BR_4d4jZWL0.mjs → pt-BR_DIZpU2Mk.mjs} +206 -2
- package/dist/server/chunks/resources_BVP5krU_.mjs +34 -0
- package/dist/server/chunks/{ru_CIc6O5Q7.mjs → ru_DFvIxd0Y.mjs} +3 -1
- package/dist/server/chunks/{sw_Bs3iYVDM.mjs → sw_CmaPgGYa.mjs} +3 -1
- package/dist/server/chunks/{taxonomies_Dkx7d-vc.mjs → taxonomies_CWhPYZDq.mjs} +2 -2
- package/dist/server/chunks/themes_iwb1637h.mjs +155 -0
- package/dist/server/chunks/{tr_C7JbXuoQ.mjs → tr_B_acwl2e.mjs} +3 -1
- package/dist/server/chunks/{uk_Dibs8Wkc.mjs → uk_DXnk4imL.mjs} +3 -1
- package/dist/server/chunks/{upload_CpGGKDEH.mjs → upload_BE7qzxe7.mjs} +2 -2
- package/dist/server/chunks/{yo_B6MPvz_U.mjs → yo_DDQ8a-0v.mjs} +3 -1
- package/dist/server/chunks/{zh-CN_G1Dc2b28.mjs → zh-CN_763uzTMQ.mjs} +3 -1
- package/dist/server/entry.mjs +149 -25
- package/dist/server/virtual_astro_middleware.mjs +6 -3
- package/package.json +1 -1
- package/dist/client/_astro/AdminBar.DQilvzQe.js +0 -234
- package/dist/client/_astro/BaseLayout.B2MfKf6B.css +0 -1
- package/dist/client/_astro/ContentEditor.WyLHMY9o.js +0 -1
- package/dist/client/_astro/ContentList.BWtiYbDy.js +0 -1
- package/dist/client/_astro/DashboardHome.-0s3t1kG.js +0 -1
- package/dist/client/_astro/DashboardLayout.DWuCsemN.css +0 -1
- package/dist/client/_astro/DashboardLayout.astro_astro_type_script_index_0_lang.Bm7kqhGo.js +0 -1
- package/dist/client/_astro/GeneralSettings.CaEyAV2f.js +0 -1
- package/dist/client/_astro/HelpTabs.99giF0f1.js +0 -103
- package/dist/client/_astro/LanguageSelector.DPBYaSN4.js +0 -14
- package/dist/client/_astro/MediaLibrary.DBfw3BM0.js +0 -1
- package/dist/client/_astro/PluginManager.BFoAz05U.js +0 -93
- package/dist/client/_astro/PostTypesManager.y9aB2d3_.js +0 -1
- package/dist/client/_astro/ScreenOptions.C8K8Bufc.js +0 -70
- package/dist/client/_astro/TaxonomiesManager.Cj54HB7P.js +0 -1
- package/dist/client/_astro/ThemeManager.BuULAG8h.js +0 -124
- package/dist/client/_astro/UserCreateForm.BMWIRfb2.js +0 -1
- package/dist/client/_astro/UsersManager.BogkOfCQ.js +0 -1
- package/dist/client/_astro/api.PfLklAa1.js +0 -1
- package/dist/client/_astro/ar.CzsjUutD.js +0 -1
- package/dist/client/_astro/en.DmN7xy_a.js +0 -1
- package/dist/client/_astro/es-ES.p2TLEMlZ.js +0 -1
- package/dist/client/_astro/extensions.DfxrGzbo.js +0 -1
- package/dist/client/_astro/he.BnYHiYpn.js +0 -1
- package/dist/client/_astro/i18n.BMDVwjZM.js +0 -1
- package/dist/client/_astro/it.WrWKBEAD.js +0 -1
- package/dist/client/_astro/ja.DxnfhIdt.js +0 -1
- package/dist/client/_astro/pl.jUj-RfZS.js +0 -1
- package/dist/client/_astro/pt-BR.DtNwEO0i.js +0 -1
- package/dist/client/_astro/ru.KFSfdjWn.js +0 -1
- package/dist/client/_astro/src.Cgonpfb5.js +0 -1
- package/dist/client/_astro/sw.3jlAOLOv.js +0 -1
- package/dist/client/_astro/tr.tnLMnGPg.js +0 -1
- package/dist/client/_astro/uk.VquHY_xc.js +0 -1
- package/dist/client/_astro/yo.Cr8hCb5u.js +0 -1
- package/dist/client/_astro/zh-CN.E32QqP4v.js +0 -1
- package/dist/server/chunks/en_C750mYKk.mjs +0 -408
- package/dist/server/chunks/i18n_Dj2ieo-N.mjs +0 -548
- package/dist/server/chunks/script_CPGt5jAh.mjs +0 -19
- package/dist/server/chunks/themes_CCDPOhVZ.mjs +0 -127
|
@@ -0,0 +1,1406 @@
|
|
|
1
|
+
import { r as __exportAll } from "./rolldown-runtime_BMI-E3GI.mjs";
|
|
2
|
+
import { createSignal, onMount } from "solid-js";
|
|
3
|
+
//#region src/i18n/config.ts
|
|
4
|
+
var SUPPORTED_LOCALES = [
|
|
5
|
+
"pt-BR",
|
|
6
|
+
"en",
|
|
7
|
+
"es-ES",
|
|
8
|
+
"ru",
|
|
9
|
+
"uk",
|
|
10
|
+
"tr",
|
|
11
|
+
"he",
|
|
12
|
+
"it",
|
|
13
|
+
"pl",
|
|
14
|
+
"zh-CN",
|
|
15
|
+
"ja",
|
|
16
|
+
"ar",
|
|
17
|
+
"sw",
|
|
18
|
+
"yo",
|
|
19
|
+
"zu",
|
|
20
|
+
"am",
|
|
21
|
+
"ha",
|
|
22
|
+
"ig"
|
|
23
|
+
];
|
|
24
|
+
var RTL_LOCALES = ["he", "ar"];
|
|
25
|
+
var LOCALE_LABELS = {
|
|
26
|
+
"pt-BR": "Português (Brasil)",
|
|
27
|
+
"en": "English",
|
|
28
|
+
"es-ES": "Español",
|
|
29
|
+
"ru": "Русский",
|
|
30
|
+
"uk": "Українська",
|
|
31
|
+
"tr": "Türkçe",
|
|
32
|
+
"he": "עברית",
|
|
33
|
+
"it": "Italiano",
|
|
34
|
+
"pl": "Polski",
|
|
35
|
+
"zh-CN": "中文 (简体)",
|
|
36
|
+
"ja": "日本語",
|
|
37
|
+
"ar": "العربية",
|
|
38
|
+
"sw": "Kiswahili",
|
|
39
|
+
"yo": "Yorùbá",
|
|
40
|
+
"zu": "isiZulu",
|
|
41
|
+
"am": "አማርኛ",
|
|
42
|
+
"ha": "Hausa",
|
|
43
|
+
"ig": "Igbo"
|
|
44
|
+
};
|
|
45
|
+
var LOCALE_FLAGS = {
|
|
46
|
+
"pt-BR": "🇧🇷",
|
|
47
|
+
"en": "🇺🇸",
|
|
48
|
+
"es-ES": "🇪🇸",
|
|
49
|
+
"ru": "🇷🇺",
|
|
50
|
+
"uk": "🇺🇦",
|
|
51
|
+
"tr": "🇹🇷",
|
|
52
|
+
"he": "🇮🇱",
|
|
53
|
+
"it": "🇮🇹",
|
|
54
|
+
"pl": "🇵🇱",
|
|
55
|
+
"zh-CN": "🇨🇳",
|
|
56
|
+
"ja": "🇯🇵",
|
|
57
|
+
"ar": "🇸🇦",
|
|
58
|
+
"sw": "🇹🇿",
|
|
59
|
+
"yo": "🇳🇬",
|
|
60
|
+
"zu": "🇿🇦",
|
|
61
|
+
"am": "🇪🇹",
|
|
62
|
+
"ha": "🇳🇬",
|
|
63
|
+
"ig": "🇳🇬"
|
|
64
|
+
};
|
|
65
|
+
function isRTLLocale(locale) {
|
|
66
|
+
return RTL_LOCALES.includes(locale);
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region \0rolldown_dynamic_import_helper.js
|
|
70
|
+
var _rolldown_dynamic_import_helper_default = (glob, path, segments) => {
|
|
71
|
+
const query = path.lastIndexOf("?");
|
|
72
|
+
const v = glob[query === -1 || query < path.lastIndexOf("/") ? path : path.slice(0, query)];
|
|
73
|
+
if (v) return typeof v === "function" ? v() : Promise.resolve(v);
|
|
74
|
+
return new Promise((_, reject) => {
|
|
75
|
+
(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." : ""))));
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/i18n/loaders.ts
|
|
80
|
+
var localeCache = /* @__PURE__ */ new Map();
|
|
81
|
+
/** Carrega arquivo JSON de locale */
|
|
82
|
+
async function loadLocale(locale) {
|
|
83
|
+
if (localeCache.has(locale)) return localeCache.get(locale);
|
|
84
|
+
try {
|
|
85
|
+
const module = await _rolldown_dynamic_import_helper_default(/* #__PURE__ */ Object.assign({
|
|
86
|
+
"./locales/ar.json": () => import("./ar_DMC8HaoP.mjs"),
|
|
87
|
+
"./locales/en.json": () => Promise.resolve().then(() => en_exports),
|
|
88
|
+
"./locales/es-ES.json": () => import("./es-ES_DZvHskAD.mjs"),
|
|
89
|
+
"./locales/he.json": () => import("./he_zy3stNhR.mjs"),
|
|
90
|
+
"./locales/it.json": () => import("./it_BiUDLszZ.mjs"),
|
|
91
|
+
"./locales/ja.json": () => import("./ja_DjFAG7hL.mjs"),
|
|
92
|
+
"./locales/pl.json": () => import("./pl_0Xe9Qom2.mjs"),
|
|
93
|
+
"./locales/pt-BR.json": () => import("./pt-BR_DIZpU2Mk.mjs"),
|
|
94
|
+
"./locales/ru.json": () => import("./ru_DFvIxd0Y.mjs"),
|
|
95
|
+
"./locales/sw.json": () => import("./sw_CmaPgGYa.mjs"),
|
|
96
|
+
"./locales/tr.json": () => import("./tr_B_acwl2e.mjs"),
|
|
97
|
+
"./locales/uk.json": () => import("./uk_DXnk4imL.mjs"),
|
|
98
|
+
"./locales/yo.json": () => import("./yo_DDQ8a-0v.mjs"),
|
|
99
|
+
"./locales/zh-CN.json": () => import("./zh-CN_763uzTMQ.mjs")
|
|
100
|
+
}), `./locales/${locale}.json`, 3);
|
|
101
|
+
const translations = module.default ?? module;
|
|
102
|
+
localeCache.set(locale, translations);
|
|
103
|
+
return translations;
|
|
104
|
+
} catch {
|
|
105
|
+
if (locale !== "en") return loadLocale("en");
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/lib/api.ts
|
|
111
|
+
var API_BASE = "";
|
|
112
|
+
var ApiClient = class {
|
|
113
|
+
baseUrl;
|
|
114
|
+
csrfToken = null;
|
|
115
|
+
refreshPromise = null;
|
|
116
|
+
refreshOwner = typeof globalThis.crypto?.randomUUID === "function" ? globalThis.crypto.randomUUID() : Math.random().toString(36).slice(2);
|
|
117
|
+
refreshLockKey = "okcms:auth:refresh-lock";
|
|
118
|
+
constructor(baseUrl = API_BASE) {
|
|
119
|
+
this.baseUrl = baseUrl;
|
|
120
|
+
}
|
|
121
|
+
/** Inicializa lendo CSRF do cookie (chamado no boot da app) */
|
|
122
|
+
async init() {
|
|
123
|
+
try {
|
|
124
|
+
await this.ensureCsrfToken();
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
/** Sessão válida — verifica via /me (usa cookies HttpOnly automaticamente) */
|
|
128
|
+
async isLoggedIn() {
|
|
129
|
+
try {
|
|
130
|
+
await this.request("GET", "/api/v1/auth/me");
|
|
131
|
+
return true;
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Obtém tenantId do backend via /me */
|
|
137
|
+
async getTenantId() {
|
|
138
|
+
try {
|
|
139
|
+
return (await this.request("GET", "/api/v1/auth/me")).tenantId ?? null;
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Obtém locale do usuário logado via /me/locale */
|
|
145
|
+
async getUserLocale() {
|
|
146
|
+
try {
|
|
147
|
+
return (await this.request("GET", "/api/v1/users/me/locale")).locale ?? "pt-BR";
|
|
148
|
+
} catch {
|
|
149
|
+
return "pt-BR";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Salva locale do usuário via /me/locale */
|
|
153
|
+
async setUserLocale(locale) {
|
|
154
|
+
await this.request("PUT", "/api/v1/users/me/locale", { locale });
|
|
155
|
+
}
|
|
156
|
+
/** Sessão atual (/auth/me) — usuário + tenant + papéis (alimenta o admin bar) */
|
|
157
|
+
async getMe() {
|
|
158
|
+
return this.request("GET", "/api/v1/auth/me");
|
|
159
|
+
}
|
|
160
|
+
/** Auditoria recente — notificações reais do sino no admin bar */
|
|
161
|
+
async getAuditLogs(limit = 8) {
|
|
162
|
+
return this.request("GET", `/api/v1/audit-logs?limit=${limit}`);
|
|
163
|
+
}
|
|
164
|
+
/** Login — o backend seta cookies HttpOnly e CSRF; retorna user + tenantId */
|
|
165
|
+
async login(input) {
|
|
166
|
+
await this.ensureCsrfToken();
|
|
167
|
+
return await this.request("POST", "/api/v1/auth/login", input);
|
|
168
|
+
}
|
|
169
|
+
/** Logout — limpa cookies no backend */
|
|
170
|
+
async logout() {
|
|
171
|
+
await this.request("POST", "/api/v1/auth/logout", {});
|
|
172
|
+
this.csrfToken = null;
|
|
173
|
+
}
|
|
174
|
+
/** Refresh de access token via cookie refresh_token */
|
|
175
|
+
async refreshTokens() {
|
|
176
|
+
if (this.refreshPromise) return this.refreshPromise;
|
|
177
|
+
this.refreshPromise = this.refreshWithCrossTabLock().finally(() => {
|
|
178
|
+
this.refreshPromise = null;
|
|
179
|
+
});
|
|
180
|
+
return this.refreshPromise;
|
|
181
|
+
}
|
|
182
|
+
async refreshWithCrossTabLock() {
|
|
183
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
184
|
+
await this.request("POST", "/api/v1/auth/refresh", {}, void 0, { skipRefresh: true });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
let current;
|
|
189
|
+
try {
|
|
190
|
+
current = JSON.parse(localStorage.getItem(this.refreshLockKey) ?? "null");
|
|
191
|
+
} catch {
|
|
192
|
+
await this.request("POST", "/api/v1/auth/refresh", {}, void 0, { skipRefresh: true });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (current?.owner && current.owner !== this.refreshOwner && Number(current.expiresAt) > now) {
|
|
196
|
+
await this.waitForOtherTabRefresh(Number(current.expiresAt));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
localStorage.setItem(this.refreshLockKey, JSON.stringify({
|
|
201
|
+
owner: this.refreshOwner,
|
|
202
|
+
expiresAt: now + 1e4
|
|
203
|
+
}));
|
|
204
|
+
} catch {
|
|
205
|
+
await this.request("POST", "/api/v1/auth/refresh", {}, void 0, { skipRefresh: true });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
await this.request("POST", "/api/v1/auth/refresh", {}, void 0, { skipRefresh: true });
|
|
210
|
+
} finally {
|
|
211
|
+
try {
|
|
212
|
+
if (JSON.parse(localStorage.getItem(this.refreshLockKey) ?? "null")?.owner === this.refreshOwner) localStorage.removeItem(this.refreshLockKey);
|
|
213
|
+
} catch {}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async waitForOtherTabRefresh(expiresAt) {
|
|
217
|
+
while (Date.now() < Math.min(expiresAt, Date.now() + 1e4)) {
|
|
218
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
219
|
+
try {
|
|
220
|
+
const lock = JSON.parse(localStorage.getItem(this.refreshLockKey) ?? "null");
|
|
221
|
+
if (!lock || Number(lock.expiresAt) <= Date.now()) return;
|
|
222
|
+
} catch {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** Requisição genérica com:
|
|
228
|
+
* - credentials: 'include' (envia cookies HttpOnly)
|
|
229
|
+
* - auto-refresh em 401
|
|
230
|
+
* - CSRF header para mutações
|
|
231
|
+
*/
|
|
232
|
+
async request(method, path, body, headers, options) {
|
|
233
|
+
const url = `${this.baseUrl}${path}`;
|
|
234
|
+
const send = async () => {
|
|
235
|
+
const requestHeaders = {
|
|
236
|
+
"Content-Type": "application/json",
|
|
237
|
+
...headers
|
|
238
|
+
};
|
|
239
|
+
if (![
|
|
240
|
+
"GET",
|
|
241
|
+
"HEAD",
|
|
242
|
+
"OPTIONS"
|
|
243
|
+
].includes(method.toUpperCase())) {
|
|
244
|
+
const csrf = await this.ensureCsrfToken();
|
|
245
|
+
if (csrf) requestHeaders["x-csrf-token"] = csrf;
|
|
246
|
+
}
|
|
247
|
+
return fetch(url, {
|
|
248
|
+
method,
|
|
249
|
+
headers: requestHeaders,
|
|
250
|
+
credentials: "include",
|
|
251
|
+
body: body ? JSON.stringify(body) : void 0
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
let response = await send();
|
|
255
|
+
if (response.status === 401 && !options?.skipRefresh && !path.includes("/auth/refresh") && !path.includes("/auth/logout")) {
|
|
256
|
+
await this.refreshTokens();
|
|
257
|
+
response = await send();
|
|
258
|
+
}
|
|
259
|
+
if (response.status === 403 && !options?.skipCsrfRecovery) {
|
|
260
|
+
let errorCode = "";
|
|
261
|
+
try {
|
|
262
|
+
errorCode = (await (typeof response.clone === "function" ? response.clone() : response).json()).error ?? "";
|
|
263
|
+
} catch {}
|
|
264
|
+
if (errorCode === "CSRF_TOKEN_INVALID") {
|
|
265
|
+
await this.ensureCsrfToken(true);
|
|
266
|
+
response = await send();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (!response.ok) {
|
|
270
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
271
|
+
throw new Error(error.error ?? `Request failed: ${response.status}`);
|
|
272
|
+
}
|
|
273
|
+
return response.json();
|
|
274
|
+
}
|
|
275
|
+
/** Garante um token CSRF sincronizado com o cookie do browser. */
|
|
276
|
+
async ensureCsrfToken(force = false) {
|
|
277
|
+
const cookieToken = this.readCsrfCookie();
|
|
278
|
+
if (!force && cookieToken) {
|
|
279
|
+
this.csrfToken = cookieToken;
|
|
280
|
+
return cookieToken;
|
|
281
|
+
}
|
|
282
|
+
if (!force && this.csrfToken) return this.csrfToken;
|
|
283
|
+
try {
|
|
284
|
+
const response = await fetch(`${this.baseUrl}/api/v1/auth/csrf`, {
|
|
285
|
+
credentials: "include",
|
|
286
|
+
headers: { Accept: "application/json" }
|
|
287
|
+
});
|
|
288
|
+
if (!response.ok) return this.csrfToken;
|
|
289
|
+
const data = await response.json();
|
|
290
|
+
this.csrfToken = data.csrfToken ?? this.readCsrfCookie();
|
|
291
|
+
} catch {}
|
|
292
|
+
return this.csrfToken;
|
|
293
|
+
}
|
|
294
|
+
readCsrfCookie() {
|
|
295
|
+
if (typeof document !== "undefined") {
|
|
296
|
+
const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/);
|
|
297
|
+
if (match?.[1]) return match[1];
|
|
298
|
+
}
|
|
299
|
+
return this.csrfToken;
|
|
300
|
+
}
|
|
301
|
+
async getContent(options) {
|
|
302
|
+
const params = new URLSearchParams();
|
|
303
|
+
if (options?.page) params.set("page", String(options.page));
|
|
304
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
305
|
+
if (options?.type) params.set("type", options.type);
|
|
306
|
+
if (options?.status) params.set("status", options.status);
|
|
307
|
+
if (options?.search) params.set("search", options.search);
|
|
308
|
+
return this.request("GET", `/api/v1/content?${params.toString()}`);
|
|
309
|
+
}
|
|
310
|
+
async getContentById(id) {
|
|
311
|
+
return this.request("GET", `/api/v1/content/${id}`);
|
|
312
|
+
}
|
|
313
|
+
async createContent(data) {
|
|
314
|
+
return this.request("POST", `/api/v1/content`, data);
|
|
315
|
+
}
|
|
316
|
+
async updateContent(id, data) {
|
|
317
|
+
return this.request("PUT", `/api/v1/content/${id}`, data);
|
|
318
|
+
}
|
|
319
|
+
async deleteContent(id) {
|
|
320
|
+
await this.request("DELETE", `/api/v1/content/${id}`);
|
|
321
|
+
}
|
|
322
|
+
/** A2: publica via rota real do publisher (eventBus + cache + revisions). */
|
|
323
|
+
async publishContent(id) {
|
|
324
|
+
const response = await this.request("POST", `/api/v1/content/${id}/publish`);
|
|
325
|
+
return "content" in response ? response.content : response;
|
|
326
|
+
}
|
|
327
|
+
/** A2: despublica via rota real do publisher. */
|
|
328
|
+
async unpublishContent(id) {
|
|
329
|
+
const response = await this.request("POST", `/api/v1/content/${id}/unpublish`);
|
|
330
|
+
return "content" in response ? response.content : response;
|
|
331
|
+
}
|
|
332
|
+
/** Atalho usado pela ContentList: publish/unpublish conforme status atual. */
|
|
333
|
+
async publishToggle(id, isPublished) {
|
|
334
|
+
return isPublished ? this.unpublishContent(id) : this.publishContent(id);
|
|
335
|
+
}
|
|
336
|
+
async getContentTypes() {
|
|
337
|
+
return this.request("GET", "/api/v1/content-types");
|
|
338
|
+
}
|
|
339
|
+
async createContentType(data) {
|
|
340
|
+
return this.request("POST", "/api/v1/content-types", data);
|
|
341
|
+
}
|
|
342
|
+
async updateContentType(slug, data) {
|
|
343
|
+
return this.request("PUT", `/api/v1/content-types/${slug}`, data);
|
|
344
|
+
}
|
|
345
|
+
async deleteContentType(slug) {
|
|
346
|
+
await this.request("DELETE", `/api/v1/content-types/${slug}`);
|
|
347
|
+
}
|
|
348
|
+
async getTaxonomies() {
|
|
349
|
+
return this.request("GET", "/api/v1/taxonomies");
|
|
350
|
+
}
|
|
351
|
+
async createTaxonomy(data) {
|
|
352
|
+
return this.request("POST", "/api/v1/taxonomies", data);
|
|
353
|
+
}
|
|
354
|
+
async attachTaxonomy(slug, contentType) {
|
|
355
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/attach`, { contentType });
|
|
356
|
+
}
|
|
357
|
+
async detachTaxonomy(slug, contentType) {
|
|
358
|
+
await this.request("POST", `/api/v1/taxonomies/${slug}/detach`, { contentType });
|
|
359
|
+
}
|
|
360
|
+
async deleteTaxonomy(slug) {
|
|
361
|
+
await this.request("DELETE", `/api/v1/taxonomies/${slug}`);
|
|
362
|
+
}
|
|
363
|
+
async getTaxonomyTerms(slug) {
|
|
364
|
+
return this.request("GET", `/api/v1/taxonomies/${encodeURIComponent(slug)}/terms`);
|
|
365
|
+
}
|
|
366
|
+
async createTaxonomyTerm(slug, data) {
|
|
367
|
+
return this.request("POST", `/api/v1/taxonomies/${encodeURIComponent(slug)}/terms`, data);
|
|
368
|
+
}
|
|
369
|
+
async updateTaxonomyTerm(slug, id, data) {
|
|
370
|
+
return this.request("PUT", `/api/v1/taxonomies/${encodeURIComponent(slug)}/terms/${id}`, data);
|
|
371
|
+
}
|
|
372
|
+
async deleteTaxonomyTerm(slug, id) {
|
|
373
|
+
await this.request("DELETE", `/api/v1/taxonomies/${encodeURIComponent(slug)}/terms/${id}`);
|
|
374
|
+
}
|
|
375
|
+
async getCategories() {
|
|
376
|
+
return this.request("GET", "/api/v1/categories");
|
|
377
|
+
}
|
|
378
|
+
async createCategory(data) {
|
|
379
|
+
return this.request("POST", "/api/v1/categories", data);
|
|
380
|
+
}
|
|
381
|
+
async updateCategory(id, data) {
|
|
382
|
+
return this.request("PUT", `/api/v1/categories/${id}`, data);
|
|
383
|
+
}
|
|
384
|
+
async deleteCategory(id) {
|
|
385
|
+
await this.request("DELETE", `/api/v1/categories/${id}`);
|
|
386
|
+
}
|
|
387
|
+
async getTags() {
|
|
388
|
+
return this.request("GET", "/api/v1/tags");
|
|
389
|
+
}
|
|
390
|
+
async createTag(data) {
|
|
391
|
+
return this.request("POST", "/api/v1/tags", data);
|
|
392
|
+
}
|
|
393
|
+
async updateTag(id, data) {
|
|
394
|
+
return this.request("PUT", `/api/v1/tags/${id}`, data);
|
|
395
|
+
}
|
|
396
|
+
async deleteTag(id) {
|
|
397
|
+
await this.request("DELETE", `/api/v1/tags/${id}`);
|
|
398
|
+
}
|
|
399
|
+
async getMenus() {
|
|
400
|
+
return this.request("GET", "/api/v1/menus");
|
|
401
|
+
}
|
|
402
|
+
async createMenu(data) {
|
|
403
|
+
return this.request("POST", "/api/v1/menus", data);
|
|
404
|
+
}
|
|
405
|
+
async updateMenu(id, data) {
|
|
406
|
+
return this.request("PUT", `/api/v1/menus/${id}`, data);
|
|
407
|
+
}
|
|
408
|
+
async deleteMenu(id) {
|
|
409
|
+
await this.request("DELETE", `/api/v1/menus/${id}`);
|
|
410
|
+
}
|
|
411
|
+
async getFieldGroups(context) {
|
|
412
|
+
if (context?.type) {
|
|
413
|
+
const qs = new URLSearchParams({ type: context.type });
|
|
414
|
+
for (const [key, value] of Object.entries(context)) if (key !== "type" && value) qs.set(key, value);
|
|
415
|
+
return this.request("GET", `/api/v1/field-groups?${qs.toString()}`);
|
|
416
|
+
}
|
|
417
|
+
return this.request("GET", "/api/v1/field-groups");
|
|
418
|
+
}
|
|
419
|
+
async getFieldGroup(id) {
|
|
420
|
+
return this.request("GET", `/api/v1/field-groups/${id}`);
|
|
421
|
+
}
|
|
422
|
+
async createFieldGroup(data) {
|
|
423
|
+
return this.request("POST", "/api/v1/field-groups", data);
|
|
424
|
+
}
|
|
425
|
+
async updateFieldGroup(id, data) {
|
|
426
|
+
return this.request("PUT", `/api/v1/field-groups/${id}`, data);
|
|
427
|
+
}
|
|
428
|
+
async deleteFieldGroup(id) {
|
|
429
|
+
await this.request("DELETE", `/api/v1/field-groups/${id}`);
|
|
430
|
+
}
|
|
431
|
+
async getFieldTypes(category) {
|
|
432
|
+
const query = category ? `?category=${encodeURIComponent(category)}` : "";
|
|
433
|
+
return this.request("GET", `/api/v1/field-types${query}`);
|
|
434
|
+
}
|
|
435
|
+
async getWebhooks() {
|
|
436
|
+
return this.request("GET", "/api/v1/webhooks");
|
|
437
|
+
}
|
|
438
|
+
async createWebhook(data) {
|
|
439
|
+
return this.request("POST", "/api/v1/webhooks", data);
|
|
440
|
+
}
|
|
441
|
+
async updateWebhook(id, data) {
|
|
442
|
+
return this.request("PUT", `/api/v1/webhooks/${id}`, data);
|
|
443
|
+
}
|
|
444
|
+
async deleteWebhook(id) {
|
|
445
|
+
await this.request("DELETE", `/api/v1/webhooks/${id}`);
|
|
446
|
+
}
|
|
447
|
+
async getBuilds(options) {
|
|
448
|
+
const params = new URLSearchParams();
|
|
449
|
+
if (options?.page) params.set("page", String(options.page));
|
|
450
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
451
|
+
if (options?.status) params.set("status", options.status);
|
|
452
|
+
return this.request("GET", `/api/v1/builds?${params.toString()}`);
|
|
453
|
+
}
|
|
454
|
+
async createBuild(data) {
|
|
455
|
+
return this.request("POST", "/api/v1/builds", data);
|
|
456
|
+
}
|
|
457
|
+
async getDeployments(options) {
|
|
458
|
+
const params = new URLSearchParams();
|
|
459
|
+
if (options?.page) params.set("page", String(options.page));
|
|
460
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
461
|
+
if (options?.status) params.set("status", options.status);
|
|
462
|
+
return this.request("GET", `/api/v1/deployments?${params.toString()}`);
|
|
463
|
+
}
|
|
464
|
+
async createDeployment(data) {
|
|
465
|
+
return this.request("POST", "/api/v1/deployments", data);
|
|
466
|
+
}
|
|
467
|
+
async rollbackDeployment(id, rollbackToId) {
|
|
468
|
+
return this.request("POST", `/api/v1/deployments/${id}/rollback`, { rollbackToId });
|
|
469
|
+
}
|
|
470
|
+
async getEvents(options) {
|
|
471
|
+
const params = new URLSearchParams();
|
|
472
|
+
if (options?.page) params.set("page", String(options.page));
|
|
473
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
474
|
+
if (options?.type) params.set("type", options.type);
|
|
475
|
+
return this.request("GET", `/api/v1/events?${params.toString()}`);
|
|
476
|
+
}
|
|
477
|
+
async listMedia(options) {
|
|
478
|
+
const params = new URLSearchParams();
|
|
479
|
+
if (options?.page) params.set("page", String(options.page));
|
|
480
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
481
|
+
if (options?.mimeType) params.set("mimeType", options.mimeType);
|
|
482
|
+
if (options?.search) params.set("search", options.search);
|
|
483
|
+
return this.request("GET", `/api/v1/media?${params.toString()}`);
|
|
484
|
+
}
|
|
485
|
+
async getMedia(id) {
|
|
486
|
+
return this.request("GET", `/api/v1/media/${id}`);
|
|
487
|
+
}
|
|
488
|
+
/** Upload multipart — NÃO seta Content-Type (o fetch precisa do boundary). */
|
|
489
|
+
async uploadMedia(file, options) {
|
|
490
|
+
const formData = new FormData();
|
|
491
|
+
formData.append("file", file);
|
|
492
|
+
if (options?.alt) formData.append("alt", options.alt);
|
|
493
|
+
if (options?.caption) formData.append("caption", options.caption);
|
|
494
|
+
const url = `${this.baseUrl}/api/v1/media/upload`;
|
|
495
|
+
const send = async () => {
|
|
496
|
+
const csrf = await this.ensureCsrfToken();
|
|
497
|
+
const requestHeaders = {};
|
|
498
|
+
if (csrf) requestHeaders["x-csrf-token"] = csrf;
|
|
499
|
+
return fetch(url, {
|
|
500
|
+
method: "POST",
|
|
501
|
+
headers: requestHeaders,
|
|
502
|
+
credentials: "include",
|
|
503
|
+
body: formData
|
|
504
|
+
});
|
|
505
|
+
};
|
|
506
|
+
let response = await send();
|
|
507
|
+
if (response.status === 401) {
|
|
508
|
+
await this.refreshTokens();
|
|
509
|
+
response = await send();
|
|
510
|
+
}
|
|
511
|
+
if (response.status === 403) {
|
|
512
|
+
let errorCode = "";
|
|
513
|
+
try {
|
|
514
|
+
errorCode = (await response.clone().json()).error ?? "";
|
|
515
|
+
} catch {}
|
|
516
|
+
if (errorCode === "CSRF_TOKEN_INVALID") {
|
|
517
|
+
await this.ensureCsrfToken(true);
|
|
518
|
+
response = await send();
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (!response.ok) {
|
|
522
|
+
const error = await response.json().catch(() => ({ error: `Upload failed: ${response.status}` }));
|
|
523
|
+
throw new Error(error.error ?? `Upload failed: ${response.status}`);
|
|
524
|
+
}
|
|
525
|
+
return response.json();
|
|
526
|
+
}
|
|
527
|
+
async updateMedia(id, data) {
|
|
528
|
+
return this.request("PUT", `/api/v1/media/${id}`, data);
|
|
529
|
+
}
|
|
530
|
+
async deleteMedia(id) {
|
|
531
|
+
await this.request("DELETE", `/api/v1/media/${id}`);
|
|
532
|
+
}
|
|
533
|
+
async listUsers(options) {
|
|
534
|
+
const params = new URLSearchParams();
|
|
535
|
+
if (options?.page) params.set("page", String(options.page));
|
|
536
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
537
|
+
if (options?.search) params.set("search", options.search);
|
|
538
|
+
if (options?.status) params.set("status", options.status);
|
|
539
|
+
return this.request("GET", `/api/v1/users?${params.toString()}`);
|
|
540
|
+
}
|
|
541
|
+
async getUser(id) {
|
|
542
|
+
return this.request("GET", `/api/v1/users/${id}`);
|
|
543
|
+
}
|
|
544
|
+
async createUser(data) {
|
|
545
|
+
return this.request("POST", "/api/v1/users", data);
|
|
546
|
+
}
|
|
547
|
+
async updateUser(id, data) {
|
|
548
|
+
return this.request("PUT", `/api/v1/users/${id}`, data);
|
|
549
|
+
}
|
|
550
|
+
async deleteUser(id) {
|
|
551
|
+
await this.request("DELETE", `/api/v1/users/${id}`);
|
|
552
|
+
}
|
|
553
|
+
async setUserPassword(id, password) {
|
|
554
|
+
await this.request("PUT", `/api/v1/users/${id}/password`, { password });
|
|
555
|
+
}
|
|
556
|
+
async assignRole(userId, roleId) {
|
|
557
|
+
return this.request("POST", `/api/v1/users/${userId}/roles`, { roleId });
|
|
558
|
+
}
|
|
559
|
+
async removeRole(userId, roleId) {
|
|
560
|
+
return this.request("DELETE", `/api/v1/users/${userId}/roles/${roleId}`);
|
|
561
|
+
}
|
|
562
|
+
async listRoles() {
|
|
563
|
+
return this.request("GET", "/api/v1/roles");
|
|
564
|
+
}
|
|
565
|
+
async createRole(data) {
|
|
566
|
+
return this.request("POST", "/api/v1/roles", data);
|
|
567
|
+
}
|
|
568
|
+
async updateRole(id, data) {
|
|
569
|
+
return this.request("PUT", `/api/v1/roles/${id}`, data);
|
|
570
|
+
}
|
|
571
|
+
async deleteRole(id) {
|
|
572
|
+
await this.request("DELETE", `/api/v1/roles/${id}`);
|
|
573
|
+
}
|
|
574
|
+
async listTenants(options) {
|
|
575
|
+
const params = new URLSearchParams();
|
|
576
|
+
if (options?.page) params.set("page", String(options.page));
|
|
577
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
578
|
+
if (options?.search) params.set("search", options.search);
|
|
579
|
+
return this.request("GET", `/api/v1/tenants?${params.toString()}`);
|
|
580
|
+
}
|
|
581
|
+
async createTenant(data) {
|
|
582
|
+
return this.request("POST", "/api/v1/tenants", data);
|
|
583
|
+
}
|
|
584
|
+
async updateTenant(id, data) {
|
|
585
|
+
return this.request("PUT", `/api/v1/tenants/${id}`, data);
|
|
586
|
+
}
|
|
587
|
+
async deleteTenant(id) {
|
|
588
|
+
await this.request("DELETE", `/api/v1/tenants/${id}`);
|
|
589
|
+
}
|
|
590
|
+
async getSettings(group) {
|
|
591
|
+
const query = group ? `?group=${encodeURIComponent(group)}` : "";
|
|
592
|
+
return this.request("GET", `/api/v1/settings${query}`);
|
|
593
|
+
}
|
|
594
|
+
async updateSettings(items) {
|
|
595
|
+
await this.request("PUT", "/api/v1/settings", items);
|
|
596
|
+
}
|
|
597
|
+
async healthCheck() {
|
|
598
|
+
return this.request("GET", "/health");
|
|
599
|
+
}
|
|
600
|
+
async getThemes() {
|
|
601
|
+
return (await this.request("GET", "/api/v1/themes")).map((theme) => ({
|
|
602
|
+
id: String(theme["id"] ?? ""),
|
|
603
|
+
name: String(theme["name"] ?? ""),
|
|
604
|
+
version: theme["version"] ? String(theme["version"]) : void 0,
|
|
605
|
+
status: String(theme["status"] ?? "INSTALLED"),
|
|
606
|
+
manifest: theme["manifest"] ?? null
|
|
607
|
+
}));
|
|
608
|
+
}
|
|
609
|
+
async activateTheme(id) {
|
|
610
|
+
return this.request("POST", `/api/v1/themes/${id}/activate`);
|
|
611
|
+
}
|
|
612
|
+
async deactivateTheme(id) {
|
|
613
|
+
return this.request("POST", `/api/v1/themes/${id}/deactivate`);
|
|
614
|
+
}
|
|
615
|
+
async installTheme(data) {
|
|
616
|
+
return this.request("POST", "/api/v1/themes/install", data);
|
|
617
|
+
}
|
|
618
|
+
async uninstallTheme(id) {
|
|
619
|
+
await this.request("DELETE", `/api/v1/themes/${id}`);
|
|
620
|
+
}
|
|
621
|
+
async getPlugins() {
|
|
622
|
+
return (await this.request("GET", "/api/v1/plugins")).map((plugin) => ({
|
|
623
|
+
id: String(plugin["id"] ?? ""),
|
|
624
|
+
name: String(plugin["name"] ?? ""),
|
|
625
|
+
version: String(plugin["version"] ?? ""),
|
|
626
|
+
status: String(plugin["status"] ?? "INSTALLED"),
|
|
627
|
+
manifest: plugin["manifest"] ?? null
|
|
628
|
+
}));
|
|
629
|
+
}
|
|
630
|
+
async activatePlugin(id) {
|
|
631
|
+
return this.request("POST", `/api/v1/plugins/${id}/activate`);
|
|
632
|
+
}
|
|
633
|
+
async deactivatePlugin(id) {
|
|
634
|
+
return this.request("POST", `/api/v1/plugins/${id}/deactivate`);
|
|
635
|
+
}
|
|
636
|
+
async installPlugin(data) {
|
|
637
|
+
return this.request("POST", "/api/v1/plugins/install", data);
|
|
638
|
+
}
|
|
639
|
+
async uninstallPlugin(id) {
|
|
640
|
+
await this.request("DELETE", `/api/v1/plugins/${id}`);
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
var apiClient = new ApiClient();
|
|
644
|
+
//#endregion
|
|
645
|
+
//#region src/i18n/locale.ts
|
|
646
|
+
var LOCALE_COOKIE = "admin_locale";
|
|
647
|
+
/** Obtém locale do cookie */
|
|
648
|
+
function getCookieLocale() {
|
|
649
|
+
if (typeof document === "undefined") return null;
|
|
650
|
+
const match = document.cookie.match(new RegExp(`(?:^|; )${LOCALE_COOKIE}=([^;]+)`));
|
|
651
|
+
if (match?.[1] && SUPPORTED_LOCALES.includes(match[1])) return match[1];
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
/** Define locale no cookie (1 ano) */
|
|
655
|
+
function setCookieLocale(locale) {
|
|
656
|
+
if (typeof document === "undefined") return;
|
|
657
|
+
document.cookie = `${LOCALE_COOKIE}=${locale}; path=/; max-age=31536000; SameSite=Lax`;
|
|
658
|
+
}
|
|
659
|
+
/** Obtém locale do Accept-Language header */
|
|
660
|
+
function getBrowserLocale() {
|
|
661
|
+
if (typeof navigator === "undefined") return "en";
|
|
662
|
+
const lang = navigator.language?.split("-")[0]?.toLowerCase();
|
|
663
|
+
const fullLang = navigator.language?.toLowerCase();
|
|
664
|
+
for (const locale of SUPPORTED_LOCALES) if (locale.toLowerCase() === fullLang || locale.split("-")[0] === lang) return locale;
|
|
665
|
+
return "en";
|
|
666
|
+
}
|
|
667
|
+
/** Obtém locale do usuário logado via API */
|
|
668
|
+
async function getUserLocaleFromAPI() {
|
|
669
|
+
try {
|
|
670
|
+
const locale = await apiClient.getUserLocale();
|
|
671
|
+
if (locale && SUPPORTED_LOCALES.includes(locale)) return locale;
|
|
672
|
+
} catch {}
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
/** Salva locale do usuário via API */
|
|
676
|
+
async function setUserLocaleInAPI(locale) {
|
|
677
|
+
await apiClient.setUserLocale(locale);
|
|
678
|
+
}
|
|
679
|
+
/** Resolve locale final com prioridade: cookie → user API → browser → default */
|
|
680
|
+
async function resolveLocale() {
|
|
681
|
+
const cookie = getCookieLocale();
|
|
682
|
+
if (cookie) return cookie;
|
|
683
|
+
const user = await getUserLocaleFromAPI();
|
|
684
|
+
if (user) return user;
|
|
685
|
+
const browser = getBrowserLocale();
|
|
686
|
+
if (browser) return browser;
|
|
687
|
+
return "en";
|
|
688
|
+
}
|
|
689
|
+
/** Muda locale (salva no cookie + API se logado) */
|
|
690
|
+
async function changeLocale(locale) {
|
|
691
|
+
setCookieLocale(locale);
|
|
692
|
+
try {
|
|
693
|
+
await setUserLocaleInAPI(locale);
|
|
694
|
+
} catch {}
|
|
695
|
+
}
|
|
696
|
+
//#endregion
|
|
697
|
+
//#region src/i18n/locales/en.json
|
|
698
|
+
var en_exports = /* @__PURE__ */ __exportAll({
|
|
699
|
+
access: () => access,
|
|
700
|
+
activity: () => activity,
|
|
701
|
+
adminBar: () => adminBar,
|
|
702
|
+
common: () => common,
|
|
703
|
+
content: () => content,
|
|
704
|
+
dashboard: () => dashboard,
|
|
705
|
+
default: () => en_default,
|
|
706
|
+
footer: () => footer,
|
|
707
|
+
helpTabs: () => helpTabs,
|
|
708
|
+
layout: () => layout,
|
|
709
|
+
login: () => login,
|
|
710
|
+
media: () => media,
|
|
711
|
+
operations: () => operations,
|
|
712
|
+
plugins: () => plugins,
|
|
713
|
+
resources: () => resources,
|
|
714
|
+
screenOptions: () => screenOptions,
|
|
715
|
+
settings: () => settings,
|
|
716
|
+
themes: () => themes,
|
|
717
|
+
users: () => users
|
|
718
|
+
});
|
|
719
|
+
var layout = {
|
|
720
|
+
"appName": "OkCMS",
|
|
721
|
+
"admin": "Admin",
|
|
722
|
+
"nav": {
|
|
723
|
+
"dashboard": "Dashboard",
|
|
724
|
+
"content": "Content",
|
|
725
|
+
"media": "Media",
|
|
726
|
+
"users": "Users",
|
|
727
|
+
"settings": "Settings",
|
|
728
|
+
"plugins": "Plugins",
|
|
729
|
+
"themes": "Themes"
|
|
730
|
+
},
|
|
731
|
+
"actions": {
|
|
732
|
+
"logout": "Logout",
|
|
733
|
+
"newPost": "New Post",
|
|
734
|
+
"uploadMedia": "Upload Media",
|
|
735
|
+
"addUser": "Add User",
|
|
736
|
+
"openSettings": "Settings"
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
var dashboard = {
|
|
740
|
+
"title": "Dashboard",
|
|
741
|
+
"stats": {
|
|
742
|
+
"totalContent": "Total Content",
|
|
743
|
+
"published": "Published",
|
|
744
|
+
"drafts": "Drafts",
|
|
745
|
+
"mediaFiles": "Media Files",
|
|
746
|
+
"users": "Users"
|
|
747
|
+
},
|
|
748
|
+
"recent": {
|
|
749
|
+
"title": "Recent Content",
|
|
750
|
+
"viewAll": "View All",
|
|
751
|
+
"empty": "No content yet — create your first!",
|
|
752
|
+
"columns": {
|
|
753
|
+
"title": "Title",
|
|
754
|
+
"type": "Type",
|
|
755
|
+
"status": "Status",
|
|
756
|
+
"updated": "Updated"
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
"widgets": {
|
|
760
|
+
"atGlance": "At a Glance",
|
|
761
|
+
"posts": "Posts",
|
|
762
|
+
"postsDesc": "Published / Drafts / Trash",
|
|
763
|
+
"pages": "Pages",
|
|
764
|
+
"pagesDesc": "Published / Drafts / Trash",
|
|
765
|
+
"media": "Media",
|
|
766
|
+
"mediaDesc": "Files in the library",
|
|
767
|
+
"users": "Users",
|
|
768
|
+
"usersDesc": "Total / Active / Inactive",
|
|
769
|
+
"version": "Version",
|
|
770
|
+
"storage": "Storage",
|
|
771
|
+
"quickDraft": {
|
|
772
|
+
"title": "Quick Draft",
|
|
773
|
+
"heading": "Title",
|
|
774
|
+
"headingPlaceholder": "Give your draft a title",
|
|
775
|
+
"content": "Content",
|
|
776
|
+
"contentPlaceholder": "What's on your mind?",
|
|
777
|
+
"save": "Save Draft",
|
|
778
|
+
"yourDrafts": "Your Drafts",
|
|
779
|
+
"noDrafts": "No drafts yet."
|
|
780
|
+
},
|
|
781
|
+
"activity": {
|
|
782
|
+
"title": "Activity",
|
|
783
|
+
"empty": "No activity yet."
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
var content = {
|
|
788
|
+
"list": {
|
|
789
|
+
"title": "Content",
|
|
790
|
+
"description": "Search, filter, edit and publish your content.",
|
|
791
|
+
"columns": {
|
|
792
|
+
"title": "Title",
|
|
793
|
+
"type": "Type",
|
|
794
|
+
"status": "Status",
|
|
795
|
+
"updated": "Updated"
|
|
796
|
+
},
|
|
797
|
+
"actions": {
|
|
798
|
+
"edit": "Edit",
|
|
799
|
+
"publish": "Publish",
|
|
800
|
+
"unpublish": "Unpublish",
|
|
801
|
+
"delete": "Delete"
|
|
802
|
+
},
|
|
803
|
+
"filters": {
|
|
804
|
+
"search": "Search content…",
|
|
805
|
+
"allTypes": "All types",
|
|
806
|
+
"allStatus": "All status"
|
|
807
|
+
},
|
|
808
|
+
"buttons": {
|
|
809
|
+
"new": "+ New content",
|
|
810
|
+
"search": "Search"
|
|
811
|
+
},
|
|
812
|
+
"empty": "No content found.",
|
|
813
|
+
"statuses": {
|
|
814
|
+
"draft": "Draft",
|
|
815
|
+
"published": "Published",
|
|
816
|
+
"archived": "Archived"
|
|
817
|
+
},
|
|
818
|
+
"confirmDelete": "Delete \"{title}\"?",
|
|
819
|
+
"toasts": {
|
|
820
|
+
"published": "Content published ✓",
|
|
821
|
+
"unpublished": "Content unpublished ✓"
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
"editor": {
|
|
825
|
+
"type": "Type",
|
|
826
|
+
"title": "Title",
|
|
827
|
+
"slug": "Slug",
|
|
828
|
+
"excerpt": "Excerpt",
|
|
829
|
+
"featuredImage": "Featured Image (media ID)",
|
|
830
|
+
"status": "Status",
|
|
831
|
+
"statusOptions": {
|
|
832
|
+
"draft": "Draft",
|
|
833
|
+
"published": "Published",
|
|
834
|
+
"archived": "Archived"
|
|
835
|
+
},
|
|
836
|
+
"layout": "Layout",
|
|
837
|
+
"layoutAuto": "Automatic (theme hierarchy)",
|
|
838
|
+
"customFields": "Custom Fields",
|
|
839
|
+
"inspectTypes": "Inspect available types",
|
|
840
|
+
"save": "Save",
|
|
841
|
+
"saved": "Content saved successfully."
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
var media = {
|
|
845
|
+
"title": "Media Library",
|
|
846
|
+
"description": "Upload and manage images, videos and documents. Files are stored in `uploads/` and served publicly.",
|
|
847
|
+
"upload": {
|
|
848
|
+
"dropzone": "Drop files here or",
|
|
849
|
+
"select": "Select files",
|
|
850
|
+
"uploading": "Uploading…",
|
|
851
|
+
"hint": "Images, videos, audio and documents · up to 25MB per file"
|
|
852
|
+
},
|
|
853
|
+
"toolbar": {
|
|
854
|
+
"search": "Search by name or alt…",
|
|
855
|
+
"allTypes": "All types",
|
|
856
|
+
"searchBtn": "Search"
|
|
857
|
+
},
|
|
858
|
+
"mimeTypes": {
|
|
859
|
+
"png": "PNG",
|
|
860
|
+
"jpeg": "JPEG",
|
|
861
|
+
"gif": "GIF",
|
|
862
|
+
"webp": "WebP",
|
|
863
|
+
"svg": "SVG",
|
|
864
|
+
"pdf": "PDF",
|
|
865
|
+
"mp4": "MP4",
|
|
866
|
+
"mp3": "MP3"
|
|
867
|
+
},
|
|
868
|
+
"empty": "No files yet. Upload the first one!",
|
|
869
|
+
"details": {
|
|
870
|
+
"title": "Details",
|
|
871
|
+
"file": "File",
|
|
872
|
+
"type": "Type",
|
|
873
|
+
"size": "Size",
|
|
874
|
+
"url": "URL",
|
|
875
|
+
"copy": "Copy",
|
|
876
|
+
"alt": "Alt text",
|
|
877
|
+
"caption": "Caption",
|
|
878
|
+
"save": "Save details",
|
|
879
|
+
"delete": "Delete",
|
|
880
|
+
"close": "Close",
|
|
881
|
+
"confirmDelete": "Delete \"{filename}\"? The file will be removed from disk.",
|
|
882
|
+
"saved": "Details saved ✓",
|
|
883
|
+
"copied": "URL copied ✓",
|
|
884
|
+
"copyError": "Could not copy URL"
|
|
885
|
+
},
|
|
886
|
+
"toasts": { "uploaded": "{count} file(s) uploaded ✓" }
|
|
887
|
+
};
|
|
888
|
+
var users = {
|
|
889
|
+
"title": "Users",
|
|
890
|
+
"description": "Manage accounts, roles and project access.",
|
|
891
|
+
"new": "New User",
|
|
892
|
+
"toolbar": {
|
|
893
|
+
"search": "Search by name or email…",
|
|
894
|
+
"allStatus": "All status",
|
|
895
|
+
"active": "Active",
|
|
896
|
+
"inactive": "Inactive",
|
|
897
|
+
"newBtn": "+ New user",
|
|
898
|
+
"searchBtn": "Search"
|
|
899
|
+
},
|
|
900
|
+
"table": {
|
|
901
|
+
"name": "Name",
|
|
902
|
+
"email": "Email",
|
|
903
|
+
"role": "Role",
|
|
904
|
+
"status": "Status",
|
|
905
|
+
"lastAccess": "Last access",
|
|
906
|
+
"actions": {
|
|
907
|
+
"manage": "Manage",
|
|
908
|
+
"delete": "Delete"
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
"empty": "No users found.",
|
|
912
|
+
"noRole": "No role",
|
|
913
|
+
"detail": {
|
|
914
|
+
"title": "Manage user",
|
|
915
|
+
"fields": {
|
|
916
|
+
"name": "Name",
|
|
917
|
+
"email": "Email",
|
|
918
|
+
"status": "Status",
|
|
919
|
+
"role": "Role",
|
|
920
|
+
"password": "Password"
|
|
921
|
+
},
|
|
922
|
+
"statusOptions": {
|
|
923
|
+
"active": "Active",
|
|
924
|
+
"inactive": "Inactive"
|
|
925
|
+
},
|
|
926
|
+
"rolePlaceholder": "— no role —",
|
|
927
|
+
"meta": "Created on {created} · last access {lastAccess}",
|
|
928
|
+
"actions": {
|
|
929
|
+
"save": "Save",
|
|
930
|
+
"resetPassword": "Reset password",
|
|
931
|
+
"close": "Close"
|
|
932
|
+
},
|
|
933
|
+
"passwordPrompt": "New password for {email} (minimum 8 chars):",
|
|
934
|
+
"passwordError": "Password must be at least 8 characters",
|
|
935
|
+
"toasts": {
|
|
936
|
+
"roleUpdated": "Role for {name} updated ✓",
|
|
937
|
+
"passwordChanged": "Password for {name} changed ✓",
|
|
938
|
+
"saved": "User {name} saved ✓",
|
|
939
|
+
"deleted": "User {name} deleted ✓"
|
|
940
|
+
},
|
|
941
|
+
"confirmDelete": "Delete user {email}?"
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
var settings = {
|
|
945
|
+
"general": {
|
|
946
|
+
"title": "General",
|
|
947
|
+
"description": "Basic information displayed on the site.",
|
|
948
|
+
"back": "← All settings",
|
|
949
|
+
"fields": {
|
|
950
|
+
"siteTitle": "Site Title",
|
|
951
|
+
"siteTitlePlaceholder": "My Site",
|
|
952
|
+
"siteDescription": "Description",
|
|
953
|
+
"siteDescriptionPlaceholder": "A new site built with OkCMS",
|
|
954
|
+
"language": "Language",
|
|
955
|
+
"timezone": "Timezone",
|
|
956
|
+
"timezonePlaceholder": "America/Sao_Paulo"
|
|
957
|
+
},
|
|
958
|
+
"saved": "Settings saved ✓",
|
|
959
|
+
"loading": "Loading…",
|
|
960
|
+
"save": "Save"
|
|
961
|
+
},
|
|
962
|
+
"postTypes": {
|
|
963
|
+
"title": "Content Types",
|
|
964
|
+
"description": "Create custom content types (CPTs) beyond Posts and Pages.",
|
|
965
|
+
"form": {
|
|
966
|
+
"title": "Create Content Type",
|
|
967
|
+
"slug": "Slug (singular, e.g.: portfolio)",
|
|
968
|
+
"slugHint": "Only lowercase letters, numbers and underscore",
|
|
969
|
+
"singular": "Singular name",
|
|
970
|
+
"plural": "Plural name",
|
|
971
|
+
"supports": "Supports",
|
|
972
|
+
"supportsOptions": {
|
|
973
|
+
"title": "Title",
|
|
974
|
+
"editor": "Editor",
|
|
975
|
+
"thumbnail": "Featured Image",
|
|
976
|
+
"excerpt": "Excerpt",
|
|
977
|
+
"revisions": "Revisions"
|
|
978
|
+
},
|
|
979
|
+
"hasArchive": "Has public archive (/slug)",
|
|
980
|
+
"create": "Create"
|
|
981
|
+
},
|
|
982
|
+
"table": {
|
|
983
|
+
"slug": "Slug",
|
|
984
|
+
"singular": "Singular",
|
|
985
|
+
"plural": "Plural",
|
|
986
|
+
"source": "Source",
|
|
987
|
+
"supports": "Supports",
|
|
988
|
+
"archive": "Archive",
|
|
989
|
+
"actions": { "remove": "Remove" }
|
|
990
|
+
},
|
|
991
|
+
"sources": {
|
|
992
|
+
"admin": "Admin",
|
|
993
|
+
"core": "Core"
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
"taxonomies": {
|
|
997
|
+
"title": "Taxonomies",
|
|
998
|
+
"description": "Create custom taxonomies and link them to content types.",
|
|
999
|
+
"form": {
|
|
1000
|
+
"title": "Create Taxonomy",
|
|
1001
|
+
"name": "Name (e.g.: Genre)",
|
|
1002
|
+
"slug": "Slug (optional, generated from name)",
|
|
1003
|
+
"slugHint": "Only lowercase letters, numbers and underscore",
|
|
1004
|
+
"hierarchical": "Hierarchical (allows parent/child terms)",
|
|
1005
|
+
"attachTo": "Link to content types",
|
|
1006
|
+
"create": "Create"
|
|
1007
|
+
},
|
|
1008
|
+
"table": {
|
|
1009
|
+
"taxonomy": "Taxonomy",
|
|
1010
|
+
"hierarchical": "Hierarchical",
|
|
1011
|
+
"attachedTypes": "Linked content types",
|
|
1012
|
+
"actions": { "remove": "Remove" }
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
"customFields": {
|
|
1016
|
+
"title": "Custom Fields",
|
|
1017
|
+
"description": "Create field groups, arrange fields and choose which standard fields are visible for each content type.",
|
|
1018
|
+
"contentType": "Content type",
|
|
1019
|
+
"location": {
|
|
1020
|
+
"title": "Location rules",
|
|
1021
|
+
"description": "Choose where this field group appears. Rules in the same group use AND; groups use OR.",
|
|
1022
|
+
"parameter": "Location parameter",
|
|
1023
|
+
"operator": "Operator",
|
|
1024
|
+
"chooseValue": "Choose a value",
|
|
1025
|
+
"valuePlaceholder": "Enter a value or slug",
|
|
1026
|
+
"required": "Add a value to every location rule.",
|
|
1027
|
+
"addRule": "Add condition",
|
|
1028
|
+
"addGroup": "Add OR group",
|
|
1029
|
+
"remove": "Remove",
|
|
1030
|
+
"and": "AND",
|
|
1031
|
+
"or": "OR",
|
|
1032
|
+
"params": {
|
|
1033
|
+
"content_type": "Post type",
|
|
1034
|
+
"content_slug": "Post slug",
|
|
1035
|
+
"taxonomy": "Taxonomy",
|
|
1036
|
+
"term": "Term slug",
|
|
1037
|
+
"user_role": "User role",
|
|
1038
|
+
"page_template": "Page template",
|
|
1039
|
+
"post_status": "Post status"
|
|
1040
|
+
},
|
|
1041
|
+
"operators": {
|
|
1042
|
+
"eq": "is",
|
|
1043
|
+
"neq": "is not"
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
"standard": {
|
|
1047
|
+
"title": "Standard fields",
|
|
1048
|
+
"description": "Title and slug are required. The other standard fields can be enabled or disabled.",
|
|
1049
|
+
"enabled": "Enabled",
|
|
1050
|
+
"locked": "Required",
|
|
1051
|
+
"fields": {
|
|
1052
|
+
"title": "Title",
|
|
1053
|
+
"slug": "Slug",
|
|
1054
|
+
"content": "Content",
|
|
1055
|
+
"excerpt": "Excerpt",
|
|
1056
|
+
"featured_image": "Featured image",
|
|
1057
|
+
"seo_title": "SEO title",
|
|
1058
|
+
"seo_description": "SEO description",
|
|
1059
|
+
"status": "Status",
|
|
1060
|
+
"author": "Author"
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
"groups": {
|
|
1064
|
+
"title": "Field groups",
|
|
1065
|
+
"new": "New field group",
|
|
1066
|
+
"empty": "No custom field groups yet.",
|
|
1067
|
+
"fields": "fields",
|
|
1068
|
+
"edit": "Edit",
|
|
1069
|
+
"active": "Active",
|
|
1070
|
+
"inactive": "Inactive"
|
|
1071
|
+
},
|
|
1072
|
+
"form": {
|
|
1073
|
+
"createTitle": "Create field group",
|
|
1074
|
+
"editTitle": "Edit field group",
|
|
1075
|
+
"title": "Group name",
|
|
1076
|
+
"titlePlaceholder": "Example: Product details",
|
|
1077
|
+
"position": "Position",
|
|
1078
|
+
"positions": {
|
|
1079
|
+
"normal": "Normal",
|
|
1080
|
+
"side": "Sidebar",
|
|
1081
|
+
"acf_after_title": "After title"
|
|
1082
|
+
},
|
|
1083
|
+
"displayStyle": "Display style",
|
|
1084
|
+
"displayStyles": {
|
|
1085
|
+
"standard": "Standard",
|
|
1086
|
+
"seamless": "Seamless",
|
|
1087
|
+
"grouped": "Grouped"
|
|
1088
|
+
},
|
|
1089
|
+
"field": "Field",
|
|
1090
|
+
"fieldName": "Name/key",
|
|
1091
|
+
"fieldNamePlaceholder": "product_code",
|
|
1092
|
+
"fieldLabel": "Label",
|
|
1093
|
+
"fieldLabelPlaceholder": "Product code",
|
|
1094
|
+
"fieldType": "Type",
|
|
1095
|
+
"instructions": "Instructions",
|
|
1096
|
+
"instructionsPlaceholder": "Optional help text for editors",
|
|
1097
|
+
"required": "Required",
|
|
1098
|
+
"options": "Options",
|
|
1099
|
+
"optionsHint": "One option per line: value|Label",
|
|
1100
|
+
"addField": "Add field",
|
|
1101
|
+
"removeField": "Remove",
|
|
1102
|
+
"dragHint": "Drag to reorder",
|
|
1103
|
+
"save": "Save group",
|
|
1104
|
+
"cancel": "Cancel",
|
|
1105
|
+
"newFieldDefault": "New field",
|
|
1106
|
+
"saved": "Field group saved.",
|
|
1107
|
+
"deleted": "Field group deleted."
|
|
1108
|
+
},
|
|
1109
|
+
"actions": {
|
|
1110
|
+
"delete": "Delete",
|
|
1111
|
+
"confirmDelete": "Delete this field group?"
|
|
1112
|
+
},
|
|
1113
|
+
"loading": "Loading custom fields…",
|
|
1114
|
+
"loadError": "Could not load custom fields."
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
var resources = {
|
|
1118
|
+
"title": "Content Resources",
|
|
1119
|
+
"description": "Description",
|
|
1120
|
+
"tabs": {
|
|
1121
|
+
"category": "Categories",
|
|
1122
|
+
"tag": "Tags",
|
|
1123
|
+
"menu": "Menus"
|
|
1124
|
+
},
|
|
1125
|
+
"new": "New resource",
|
|
1126
|
+
"name": "Name",
|
|
1127
|
+
"slug": "Slug",
|
|
1128
|
+
"items": "Menu items (JSON)",
|
|
1129
|
+
"saved": "Resource saved.",
|
|
1130
|
+
"confirmDelete": "Delete this resource?",
|
|
1131
|
+
"form": {
|
|
1132
|
+
"new": "Create resource",
|
|
1133
|
+
"edit": "Edit resource"
|
|
1134
|
+
},
|
|
1135
|
+
"terms": {
|
|
1136
|
+
"title": "Taxonomy terms",
|
|
1137
|
+
"choose": "Choose a taxonomy",
|
|
1138
|
+
"new": "New term"
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
var access = {
|
|
1142
|
+
"title": "Access",
|
|
1143
|
+
"description": "Manage roles, permissions and tenants.",
|
|
1144
|
+
"roles": "Roles",
|
|
1145
|
+
"tenants": "Tenants",
|
|
1146
|
+
"permissions": "Permissions (comma separated)",
|
|
1147
|
+
"domain": "Domain"
|
|
1148
|
+
};
|
|
1149
|
+
var operations = {
|
|
1150
|
+
"title": "Operations",
|
|
1151
|
+
"description": "Manage webhooks, builds, deployments and events.",
|
|
1152
|
+
"webhooks": "Webhooks",
|
|
1153
|
+
"events": "Events",
|
|
1154
|
+
"secret": "Secret",
|
|
1155
|
+
"builds": "Builds",
|
|
1156
|
+
"deployments": "Deployments",
|
|
1157
|
+
"createBuild": "Create build",
|
|
1158
|
+
"deploy": "Deploy"
|
|
1159
|
+
};
|
|
1160
|
+
var plugins = {
|
|
1161
|
+
"title": "Plugins",
|
|
1162
|
+
"description": "Manage installed plugins.",
|
|
1163
|
+
"columns": {
|
|
1164
|
+
"name": "Name",
|
|
1165
|
+
"version": "Version",
|
|
1166
|
+
"status": "Status",
|
|
1167
|
+
"actions": "Actions"
|
|
1168
|
+
},
|
|
1169
|
+
"status": {
|
|
1170
|
+
"active": "Active",
|
|
1171
|
+
"installed": "Installed",
|
|
1172
|
+
"inactive": "Inactive"
|
|
1173
|
+
},
|
|
1174
|
+
"activate": "Activate",
|
|
1175
|
+
"deactivate": "Deactivate",
|
|
1176
|
+
"install": "Install plugin",
|
|
1177
|
+
"uninstall": "Uninstall",
|
|
1178
|
+
"confirmUninstall": "Uninstall {name}?",
|
|
1179
|
+
"name": "Plugin name",
|
|
1180
|
+
"version": "Version",
|
|
1181
|
+
"manifest": "Manifest (JSON)",
|
|
1182
|
+
"loadError": "Could not load plugins.",
|
|
1183
|
+
"activateError": "Could not activate the plugin.",
|
|
1184
|
+
"deactivateError": "Could not deactivate the plugin.",
|
|
1185
|
+
"installError": "Could not install the plugin.",
|
|
1186
|
+
"uninstallError": "Could not uninstall the plugin.",
|
|
1187
|
+
"empty": "No plugins installed."
|
|
1188
|
+
};
|
|
1189
|
+
var themes = {
|
|
1190
|
+
"title": "Themes",
|
|
1191
|
+
"description": "Manage installed themes.",
|
|
1192
|
+
"version": "Version",
|
|
1193
|
+
"active": "Active",
|
|
1194
|
+
"status": {
|
|
1195
|
+
"active": "Active",
|
|
1196
|
+
"installed": "Installed",
|
|
1197
|
+
"inactive": "Inactive"
|
|
1198
|
+
},
|
|
1199
|
+
"activate": "Activate",
|
|
1200
|
+
"deactivate": "Deactivate",
|
|
1201
|
+
"install": "Install theme",
|
|
1202
|
+
"uninstall": "Uninstall",
|
|
1203
|
+
"confirmUninstall": "Uninstall {name}?",
|
|
1204
|
+
"name": "Theme name",
|
|
1205
|
+
"manifest": "Manifest (JSON)",
|
|
1206
|
+
"loadError": "Could not load themes.",
|
|
1207
|
+
"activateError": "Could not activate the theme.",
|
|
1208
|
+
"deactivateError": "Could not deactivate the theme.",
|
|
1209
|
+
"installError": "Could not install the theme.",
|
|
1210
|
+
"uninstallError": "Could not uninstall the theme.",
|
|
1211
|
+
"empty": "No themes installed."
|
|
1212
|
+
};
|
|
1213
|
+
var login = {
|
|
1214
|
+
"title": "Login",
|
|
1215
|
+
"subtitle": "Sign in to your account",
|
|
1216
|
+
"email": "Email",
|
|
1217
|
+
"password": "Password",
|
|
1218
|
+
"submit": "Sign In",
|
|
1219
|
+
"failed": "Invalid email or password"
|
|
1220
|
+
};
|
|
1221
|
+
var common = {
|
|
1222
|
+
"save": "Save",
|
|
1223
|
+
"cancel": "Cancel",
|
|
1224
|
+
"delete": "Delete",
|
|
1225
|
+
"edit": "Edit",
|
|
1226
|
+
"close": "Close",
|
|
1227
|
+
"confirm": "Confirm",
|
|
1228
|
+
"loading": "Loading…",
|
|
1229
|
+
"yes": "Yes",
|
|
1230
|
+
"no": "No",
|
|
1231
|
+
"search": "Search",
|
|
1232
|
+
"filter": "Filter",
|
|
1233
|
+
"create": "Create",
|
|
1234
|
+
"update": "Update",
|
|
1235
|
+
"remove": "Remove",
|
|
1236
|
+
"viewAll": "View All",
|
|
1237
|
+
"back": "Back",
|
|
1238
|
+
"next": "Next",
|
|
1239
|
+
"previous": "Previous",
|
|
1240
|
+
"page": "Page",
|
|
1241
|
+
"of": "of",
|
|
1242
|
+
"items": "items",
|
|
1243
|
+
"item": "item",
|
|
1244
|
+
"empty": "No {items} found.",
|
|
1245
|
+
"toast": {
|
|
1246
|
+
"success": "✓",
|
|
1247
|
+
"error": "Error: {message}"
|
|
1248
|
+
},
|
|
1249
|
+
"status": {
|
|
1250
|
+
"active": "Active",
|
|
1251
|
+
"inactive": "Inactive",
|
|
1252
|
+
"draft": "Draft",
|
|
1253
|
+
"published": "Published",
|
|
1254
|
+
"archived": "Archived",
|
|
1255
|
+
"locked": "Locked"
|
|
1256
|
+
},
|
|
1257
|
+
"language": "Language"
|
|
1258
|
+
};
|
|
1259
|
+
var activity = {
|
|
1260
|
+
"justNow": "just now",
|
|
1261
|
+
"minAgo": "minutes ago",
|
|
1262
|
+
"ago": "ago",
|
|
1263
|
+
"published": "Published",
|
|
1264
|
+
"updated": "Updated",
|
|
1265
|
+
"newUser": "New user: {name}"
|
|
1266
|
+
};
|
|
1267
|
+
var adminBar = {
|
|
1268
|
+
"mainMenu": "Main menu",
|
|
1269
|
+
"notifications": "Notifications",
|
|
1270
|
+
"notificationsEmpty": "No recent activity",
|
|
1271
|
+
"settings": "Settings",
|
|
1272
|
+
"toggleSidebar": "Toggle sidebar",
|
|
1273
|
+
"userMenu": "User menu"
|
|
1274
|
+
};
|
|
1275
|
+
var footer = {
|
|
1276
|
+
"copyright": "© 2026 OkCMS. All rights reserved.",
|
|
1277
|
+
"links": "Links",
|
|
1278
|
+
"website": "Website",
|
|
1279
|
+
"github": "GitHub",
|
|
1280
|
+
"docs": "Documentation",
|
|
1281
|
+
"community": "Community",
|
|
1282
|
+
"poweredBy": "Powered by OkCMS"
|
|
1283
|
+
};
|
|
1284
|
+
var helpTabs = {
|
|
1285
|
+
"title": "Help",
|
|
1286
|
+
"label": "Help",
|
|
1287
|
+
"tabs": "Help topics",
|
|
1288
|
+
"topics": {
|
|
1289
|
+
"overview": {
|
|
1290
|
+
"label": "Overview",
|
|
1291
|
+
"content": "<h4>Welcome to the OkCMS Dashboard</h4><p>This dashboard gives you an overview of your site's content and activity.</p><h4>Available Widgets</h4><ul><li><strong>At a Glance:</strong> overview of posts, pages, media, and users</li><li><strong>Quick Draft:</strong> save drafts quickly from the dashboard</li><li><strong>Activity:</strong> recent site activity and updates</li></ul>"
|
|
1292
|
+
},
|
|
1293
|
+
"content": {
|
|
1294
|
+
"label": "Content Management",
|
|
1295
|
+
"content": "<h4>Managing Content</h4><p>Create, edit, and publish content from the Content section.</p><h4>Quick Actions</h4><ul><li>Click \"New Content\" to create a new post or page</li><li>Use filters to find specific content</li><li>Bulk actions available for multiple items</li></ul>"
|
|
1296
|
+
},
|
|
1297
|
+
"media": {
|
|
1298
|
+
"label": "Media Library",
|
|
1299
|
+
"content": "<h4>Managing Media</h4><p>Upload and manage images, videos, and documents.</p><h4>Tips</h4><ul><li>Drag and drop files to upload</li><li>Add alt text for accessibility</li><li>Organize with folders (coming soon)</li></ul>"
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
var screenOptions = {
|
|
1304
|
+
"title": "Screen Options",
|
|
1305
|
+
"label": "Screen Options",
|
|
1306
|
+
"showOnScreen": "Show on screen"
|
|
1307
|
+
};
|
|
1308
|
+
var en_default = {
|
|
1309
|
+
layout,
|
|
1310
|
+
dashboard,
|
|
1311
|
+
content,
|
|
1312
|
+
media,
|
|
1313
|
+
users,
|
|
1314
|
+
settings,
|
|
1315
|
+
resources,
|
|
1316
|
+
access,
|
|
1317
|
+
operations,
|
|
1318
|
+
plugins,
|
|
1319
|
+
themes,
|
|
1320
|
+
login,
|
|
1321
|
+
common,
|
|
1322
|
+
activity,
|
|
1323
|
+
adminBar,
|
|
1324
|
+
footer,
|
|
1325
|
+
helpTabs,
|
|
1326
|
+
screenOptions
|
|
1327
|
+
};
|
|
1328
|
+
//#endregion
|
|
1329
|
+
//#region src/i18n/index.ts
|
|
1330
|
+
var tFunctionCache = /* @__PURE__ */ new Map();
|
|
1331
|
+
var initialTranslations = en_default;
|
|
1332
|
+
var [translationVersion, notifyTranslationChange] = createSignal(0);
|
|
1333
|
+
var translationLoadPromise = null;
|
|
1334
|
+
function humanizeKey(key) {
|
|
1335
|
+
return (key.split(".").at(-1) ?? key).replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim().replace(/^\w/, (letter) => letter.toUpperCase());
|
|
1336
|
+
}
|
|
1337
|
+
/** Cria função de tradução para um locale */
|
|
1338
|
+
function createTFunction(translations, fallback) {
|
|
1339
|
+
return function t(key, params) {
|
|
1340
|
+
const keys = key.split(".");
|
|
1341
|
+
let value = translations;
|
|
1342
|
+
for (const k of keys) if (value && typeof value === "object" && k in value) value = value[k];
|
|
1343
|
+
else {
|
|
1344
|
+
value = fallback;
|
|
1345
|
+
for (const k of keys) if (value && typeof value === "object" && k in value) value = value[k];
|
|
1346
|
+
else return humanizeKey(key);
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
if (typeof value !== "string") return humanizeKey(key);
|
|
1350
|
+
if (params) return value.replace(/\{(\w+)\}/g, (_, param) => String(params[param] ?? ""));
|
|
1351
|
+
return value;
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
/** Obtém ou cria função de tradução para locale */
|
|
1355
|
+
async function getTFunction(locale) {
|
|
1356
|
+
if (tFunctionCache.has(locale)) return tFunctionCache.get(locale);
|
|
1357
|
+
const [translations, fallback] = await Promise.all([loadLocale(locale), loadLocale("en")]);
|
|
1358
|
+
const fn = createTFunction(translations, fallback);
|
|
1359
|
+
tFunctionCache.set(locale, fn);
|
|
1360
|
+
return fn;
|
|
1361
|
+
}
|
|
1362
|
+
var currentTFunction = createTFunction(initialTranslations, initialTranslations);
|
|
1363
|
+
var currentLocale = "en";
|
|
1364
|
+
var isLoading = true;
|
|
1365
|
+
/** Hook Solid para usar traduções em componentes */
|
|
1366
|
+
function useTranslation(initialLocale) {
|
|
1367
|
+
onMount(async () => {
|
|
1368
|
+
if (!isLoading) return;
|
|
1369
|
+
if (!translationLoadPromise) translationLoadPromise = (async () => {
|
|
1370
|
+
const resolvedLocale = initialLocale ?? await resolveLocale();
|
|
1371
|
+
currentLocale = resolvedLocale;
|
|
1372
|
+
currentTFunction = await getTFunction(resolvedLocale);
|
|
1373
|
+
isLoading = false;
|
|
1374
|
+
notifyTranslationChange((version) => version + 1);
|
|
1375
|
+
})();
|
|
1376
|
+
await translationLoadPromise;
|
|
1377
|
+
});
|
|
1378
|
+
const changeLocaleFn = async (newLocale) => {
|
|
1379
|
+
isLoading = true;
|
|
1380
|
+
await changeLocale(newLocale);
|
|
1381
|
+
currentLocale = newLocale;
|
|
1382
|
+
currentTFunction = await getTFunction(newLocale);
|
|
1383
|
+
isLoading = false;
|
|
1384
|
+
notifyTranslationChange((version) => version + 1);
|
|
1385
|
+
};
|
|
1386
|
+
const translate = (key, params) => {
|
|
1387
|
+
translationVersion();
|
|
1388
|
+
return currentTFunction(key, params);
|
|
1389
|
+
};
|
|
1390
|
+
return {
|
|
1391
|
+
t: translate,
|
|
1392
|
+
get locale() {
|
|
1393
|
+
return currentLocale;
|
|
1394
|
+
},
|
|
1395
|
+
changeLocale: changeLocaleFn,
|
|
1396
|
+
get loading() {
|
|
1397
|
+
return isLoading;
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
/** Carrega traduções para uso em Astro middleware/pages */
|
|
1402
|
+
async function getTranslationsForLocale(locale) {
|
|
1403
|
+
return loadLocale(locale);
|
|
1404
|
+
}
|
|
1405
|
+
//#endregion
|
|
1406
|
+
export { LOCALE_LABELS as a, LOCALE_FLAGS as i, useTranslation as n, SUPPORTED_LOCALES as o, apiClient as r, isRTLLocale as s, getTranslationsForLocale as t };
|