@kaikybrofc/omnizap-system 2.2.10 → 2.3.1
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/README.md +13 -13
- package/app/config/adminIdentity.js +1 -3
- package/app/connection/socketController.js +10 -20
- package/app/controllers/messageController.js +7 -28
- package/app/modules/aiModule/catCommand.js +29 -192
- package/app/modules/broadcastModule/noticeCommand.js +28 -97
- package/app/modules/gameModule/diceCommand.js +6 -32
- package/app/modules/playModule/playCommand.js +57 -258
- package/app/modules/quoteModule/quoteCommand.js +2 -4
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1 -13
- package/app/modules/statsModule/noMessageCommand.js +16 -84
- package/app/modules/statsModule/rankingCommand.js +5 -25
- package/app/modules/statsModule/rankingCommon.js +1 -9
- package/app/modules/stickerModule/convertToWebp.js +4 -27
- package/app/modules/stickerModule/stickerCommand.js +13 -24
- package/app/modules/stickerModule/stickerTextCommand.js +13 -25
- package/app/modules/stickerPackModule/autoPackCollectorService.js +16 -7
- package/app/modules/stickerPackModule/domainEventOutboxRepository.js +20 -36
- package/app/modules/stickerPackModule/domainEvents.js +2 -11
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +13 -50
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +2 -15
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +14 -41
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +25 -95
- package/app/modules/stickerPackModule/stickerAssetRepository.js +12 -31
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +13 -18
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +284 -709
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +27 -106
- package/app/modules/stickerPackModule/stickerClassificationService.js +46 -77
- package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +13 -53
- package/app/modules/stickerPackModule/stickerDomainEventBus.js +10 -16
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +40 -39
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +1 -4
- package/app/modules/stickerPackModule/stickerObjectStorageService.js +26 -26
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +32 -187
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +6 -15
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +6 -32
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +12 -36
- package/app/modules/stickerPackModule/stickerPackMessageService.js +12 -40
- package/app/modules/stickerPackModule/stickerPackRepository.js +23 -66
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +9 -21
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +10 -40
- package/app/modules/stickerPackModule/stickerPackService.js +50 -115
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +2 -21
- package/app/modules/stickerPackModule/stickerPackUtils.js +13 -3
- package/app/modules/stickerPackModule/stickerStorageService.js +16 -65
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +4 -22
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +14 -29
- package/app/modules/systemMetricsModule/pingCommand.js +9 -39
- package/app/modules/tiktokModule/tiktokCommand.js +17 -109
- package/app/modules/userModule/userCommand.js +2 -88
- package/app/observability/metrics.js +5 -16
- package/app/services/captchaService.js +1 -6
- package/app/services/dbWriteQueue.js +3 -18
- package/app/services/featureFlagService.js +2 -8
- package/app/services/newsBroadcastService.js +0 -1
- package/app/services/queueUtils.js +2 -4
- package/app/services/whatsappLoginLinkService.js +7 -9
- package/app/store/premiumUserStore.js +1 -2
- package/app/utils/antiLink/antiLinkModule.js +3 -233
- package/app/utils/logger/loggerModule.js +9 -34
- package/app/utils/systemMetrics/systemMetricsModule.js +1 -4
- package/database/index.js +1 -0
- package/database/init.js +1 -8
- package/database/migrations/20260228_0027_web_visit_event.sql +15 -0
- package/docker-compose.yml +27 -27
- package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +26 -0
- package/docs/seo/satellite-page-template.md +2 -0
- package/docs/seo/satellite-pages-phase1.json +40 -177
- package/eslint.config.js +2 -15
- package/index.js +8 -36
- package/ml/clip_classifier/README.md +4 -6
- package/observability/alert-rules.yml +12 -12
- package/observability/grafana/provisioning/dashboards/dashboards.yml +1 -1
- package/package.json +6 -3
- package/public/api-docs/index.html +220 -193
- package/public/bot-whatsapp-para-grupo/index.html +291 -261
- package/public/bot-whatsapp-sem-programar/index.html +291 -261
- package/public/comandos/index.html +421 -406
- package/public/como-automatizar-avisos-no-whatsapp/index.html +291 -261
- package/public/como-criar-comandos-whatsapp/index.html +291 -261
- package/public/como-evitar-spam-no-whatsapp/index.html +291 -261
- package/public/como-moderar-grupo-whatsapp/index.html +291 -261
- package/public/como-organizar-comunidade-whatsapp/index.html +291 -261
- package/public/css/github-project-panel.css +13 -8
- package/public/css/stickers-admin.css +25 -9
- package/public/css/styles.css +23 -16
- package/public/index.html +1106 -993
- package/public/js/apps/apiDocsApp.js +17 -167
- package/public/js/apps/createPackApp.js +69 -332
- package/public/js/apps/homeApp.js +274 -101
- package/public/js/apps/loginApp.js +3 -12
- package/public/js/apps/stickersAdminApp.js +190 -181
- package/public/js/apps/stickersApp.js +482 -1411
- package/public/js/apps/userApp.js +217 -1
- package/public/js/catalog.js +11 -74
- package/public/js/github-panel/components/ErrorState.js +1 -8
- package/public/js/github-panel/components/GithubProjectPanel.js +2 -9
- package/public/js/github-panel/components/SkeletonPanel.js +1 -11
- package/public/js/github-panel/components/StatCard.js +1 -7
- package/public/js/github-panel/vendor/react.js +1 -9
- package/public/js/runtime/react-runtime.js +1 -9
- package/public/licenca/index.html +200 -86
- package/public/login/index.html +315 -325
- package/public/melhor-bot-whatsapp-para-grupos/index.html +291 -261
- package/public/stickers/admin/index.html +14 -19
- package/public/stickers/create/index.html +39 -44
- package/public/stickers/index.html +96 -107
- package/public/termos-de-uso/index.html +369 -122
- package/public/user/index.html +527 -350
- package/scripts/cache-bust.mjs +5 -24
- package/scripts/generate-seo-satellite-pages.mjs +10 -13
- package/scripts/run-prettier-all.mjs +25 -0
- package/scripts/sticker-catalog-loadtest.mjs +13 -11
- package/scripts/sticker-worker-task.mjs +1 -4
- package/scripts/sync-readme-snapshot.mjs +3 -2
- package/server/auth/googleWebAuth/googleWebAuthService.js +614 -0
- package/server/controllers/stickerCatalogController.js +297 -632
- package/server/http/httpServer.js +2 -10
- package/server/routes/stickerCatalog/catalogHandlers/catalogAdminHttp.js +1 -8
- package/server/routes/stickerCatalog/catalogHandlers/catalogAuthHttp.js +1 -9
- package/server/routes/stickerCatalog/catalogHandlers/catalogPublicHttp.js +10 -11
- package/server/routes/stickerCatalog/catalogHandlers/catalogUploadHttp.js +1 -10
- package/server/routes/stickerCatalog/catalogRouter.js +11 -13
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* global document, window, fetch, URLSearchParams */
|
|
1
|
+
/* global document, window, fetch, URL, URLSearchParams */
|
|
2
2
|
|
|
3
3
|
const DEFAULT_API_BASE_PATH = '/api/sticker-packs';
|
|
4
4
|
const DEFAULT_STICKERS_PATH = '/stickers';
|
|
@@ -31,6 +31,24 @@ if (root) {
|
|
|
31
31
|
manageHeadLink: document.getElementById('user-manage-head-link'),
|
|
32
32
|
manageMainLink: document.getElementById('user-manage-main-link'),
|
|
33
33
|
currentYear: document.getElementById('user-current-year'),
|
|
34
|
+
adminPanel: document.getElementById('user-admin-panel'),
|
|
35
|
+
adminRole: document.getElementById('user-admin-role'),
|
|
36
|
+
adminStatus: document.getElementById('user-admin-status'),
|
|
37
|
+
adminError: document.getElementById('user-admin-error'),
|
|
38
|
+
adminUnlockForm: document.getElementById('user-admin-unlock-form'),
|
|
39
|
+
adminPassword: document.getElementById('user-admin-password'),
|
|
40
|
+
adminUnlockBtn: document.getElementById('user-admin-unlock-btn'),
|
|
41
|
+
adminOverview: document.getElementById('user-admin-overview'),
|
|
42
|
+
adminRefreshBtn: document.getElementById('user-admin-refresh-btn'),
|
|
43
|
+
adminLogoutBtn: document.getElementById('user-admin-logout-btn'),
|
|
44
|
+
adminTotalPacks: document.getElementById('user-admin-total-packs'),
|
|
45
|
+
adminTotalStickers: document.getElementById('user-admin-total-stickers'),
|
|
46
|
+
adminActiveBans: document.getElementById('user-admin-active-bans'),
|
|
47
|
+
adminKnownUsers: document.getElementById('user-admin-known-users'),
|
|
48
|
+
adminActiveSessions: document.getElementById('user-admin-active-sessions'),
|
|
49
|
+
adminVisits24h: document.getElementById('user-admin-visits-24h'),
|
|
50
|
+
adminVisits7d: document.getElementById('user-admin-visits-7d'),
|
|
51
|
+
adminUniqueVisitors7d: document.getElementById('user-admin-unique-visitors-7d'),
|
|
34
52
|
};
|
|
35
53
|
|
|
36
54
|
const state = {
|
|
@@ -38,11 +56,16 @@ if (root) {
|
|
|
38
56
|
stickersPath: String(root.dataset.stickersPath || DEFAULT_STICKERS_PATH).trim() || DEFAULT_STICKERS_PATH,
|
|
39
57
|
loginPath: String(root.dataset.loginPath || DEFAULT_LOGIN_PATH).trim() || DEFAULT_LOGIN_PATH,
|
|
40
58
|
botPhone: '',
|
|
59
|
+
adminBusy: false,
|
|
60
|
+
adminStatusPayload: null,
|
|
61
|
+
adminOverviewPayload: null,
|
|
41
62
|
};
|
|
42
63
|
|
|
43
64
|
const sessionApiPath = `${state.apiBasePath}/auth/google/session`;
|
|
44
65
|
const myProfileApiPath = `${state.apiBasePath}/me`;
|
|
45
66
|
const botContactApiPath = `${state.apiBasePath}/bot-contact`;
|
|
67
|
+
const adminSessionApiPath = `${state.apiBasePath}/admin/session`;
|
|
68
|
+
const adminOverviewApiPath = `${state.apiBasePath}/admin/overview`;
|
|
46
69
|
|
|
47
70
|
const setText = (el, value) => {
|
|
48
71
|
if (!el) return;
|
|
@@ -56,6 +79,13 @@ if (root) {
|
|
|
56
79
|
if (safeMessage) ui.error.textContent = safeMessage;
|
|
57
80
|
};
|
|
58
81
|
|
|
82
|
+
const showAdminError = (message) => {
|
|
83
|
+
if (!ui.adminError) return;
|
|
84
|
+
const safeMessage = String(message || '').trim();
|
|
85
|
+
ui.adminError.hidden = !safeMessage;
|
|
86
|
+
if (safeMessage) ui.adminError.textContent = safeMessage;
|
|
87
|
+
};
|
|
88
|
+
|
|
59
89
|
const normalizeDigits = (value) => String(value || '').replace(/\D+/g, '');
|
|
60
90
|
|
|
61
91
|
const formatPhone = (digits) => {
|
|
@@ -181,6 +211,172 @@ if (root) {
|
|
|
181
211
|
if (ui.grid) ui.grid.hidden = false;
|
|
182
212
|
};
|
|
183
213
|
|
|
214
|
+
const getAdminSession = () => state.adminStatusPayload?.session || null;
|
|
215
|
+
const isAdminAuthenticated = () => Boolean(getAdminSession()?.authenticated);
|
|
216
|
+
const isAdminEligible = () => Boolean(state.adminStatusPayload?.eligible_google_login || isAdminAuthenticated());
|
|
217
|
+
|
|
218
|
+
const resolveAdminRole = () =>
|
|
219
|
+
String(getAdminSession()?.role || state.adminStatusPayload?.eligible_role || '')
|
|
220
|
+
.trim()
|
|
221
|
+
.toLowerCase();
|
|
222
|
+
|
|
223
|
+
const formatAdminRole = (role) => {
|
|
224
|
+
if (role === 'owner') return 'dono';
|
|
225
|
+
if (role === 'moderator') return 'moderador';
|
|
226
|
+
return 'admin';
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const setAdminBusy = (value) => {
|
|
230
|
+
const busy = Boolean(value);
|
|
231
|
+
state.adminBusy = busy;
|
|
232
|
+
|
|
233
|
+
if (ui.adminPassword) ui.adminPassword.disabled = busy || isAdminAuthenticated();
|
|
234
|
+
if (ui.adminUnlockBtn) ui.adminUnlockBtn.disabled = busy || !isAdminEligible() || isAdminAuthenticated();
|
|
235
|
+
if (ui.adminRefreshBtn) ui.adminRefreshBtn.disabled = busy || !isAdminAuthenticated();
|
|
236
|
+
if (ui.adminLogoutBtn) ui.adminLogoutBtn.disabled = busy || !isAdminAuthenticated();
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const resetAdminMetrics = () => {
|
|
240
|
+
setText(ui.adminTotalPacks, '0');
|
|
241
|
+
setText(ui.adminTotalStickers, '0');
|
|
242
|
+
setText(ui.adminActiveBans, '0');
|
|
243
|
+
setText(ui.adminKnownUsers, '0');
|
|
244
|
+
setText(ui.adminActiveSessions, '0');
|
|
245
|
+
setText(ui.adminVisits24h, '0');
|
|
246
|
+
setText(ui.adminVisits7d, '0');
|
|
247
|
+
setText(ui.adminUniqueVisitors7d, '0');
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const renderAdminOverview = () => {
|
|
251
|
+
const counters = state.adminOverviewPayload?.counters || {};
|
|
252
|
+
setText(ui.adminTotalPacks, formatNumber(counters.total_packs_any_status || 0));
|
|
253
|
+
setText(ui.adminTotalStickers, formatNumber(counters.total_stickers_any_status || 0));
|
|
254
|
+
setText(ui.adminActiveBans, formatNumber(counters.active_bans || 0));
|
|
255
|
+
setText(ui.adminKnownUsers, formatNumber(counters.known_google_users || 0));
|
|
256
|
+
setText(ui.adminActiveSessions, formatNumber(counters.active_google_sessions || 0));
|
|
257
|
+
setText(ui.adminVisits24h, formatNumber(counters.visit_events_24h || 0));
|
|
258
|
+
setText(ui.adminVisits7d, formatNumber(counters.visit_events_7d || 0));
|
|
259
|
+
setText(ui.adminUniqueVisitors7d, formatNumber(counters.unique_visitors_7d || 0));
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const renderAdminPanel = () => {
|
|
263
|
+
if (!ui.adminPanel) return;
|
|
264
|
+
|
|
265
|
+
const enabled = state.adminStatusPayload?.enabled !== false;
|
|
266
|
+
const authenticated = isAdminAuthenticated();
|
|
267
|
+
const eligible = isAdminEligible();
|
|
268
|
+
|
|
269
|
+
if (!enabled || (!eligible && !authenticated)) {
|
|
270
|
+
ui.adminPanel.hidden = true;
|
|
271
|
+
if (ui.adminUnlockForm) ui.adminUnlockForm.hidden = true;
|
|
272
|
+
if (ui.adminOverview) ui.adminOverview.hidden = true;
|
|
273
|
+
showAdminError('');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
ui.adminPanel.hidden = false;
|
|
278
|
+
const role = resolveAdminRole();
|
|
279
|
+
setText(ui.adminRole, formatAdminRole(role));
|
|
280
|
+
|
|
281
|
+
if (authenticated) {
|
|
282
|
+
setText(ui.adminStatus, `Sessão admin ativa como ${formatAdminRole(role)}.`);
|
|
283
|
+
if (ui.adminUnlockForm) ui.adminUnlockForm.hidden = true;
|
|
284
|
+
if (ui.adminOverview) ui.adminOverview.hidden = false;
|
|
285
|
+
renderAdminOverview();
|
|
286
|
+
} else {
|
|
287
|
+
setText(ui.adminStatus, `Conta elegível para admin (${formatAdminRole(role)}). Informe a senha para liberar os dados.`);
|
|
288
|
+
if (ui.adminUnlockForm) ui.adminUnlockForm.hidden = false;
|
|
289
|
+
if (ui.adminOverview) ui.adminOverview.hidden = true;
|
|
290
|
+
resetAdminMetrics();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
setAdminBusy(state.adminBusy);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const loadAdminStatus = async () => {
|
|
297
|
+
const payload = await fetchJson(adminSessionApiPath, { method: 'GET' });
|
|
298
|
+
state.adminStatusPayload = payload?.data || null;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const loadAdminOverview = async () => {
|
|
302
|
+
if (!isAdminAuthenticated()) {
|
|
303
|
+
state.adminOverviewPayload = null;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const payload = await fetchJson(adminOverviewApiPath, { method: 'GET' });
|
|
307
|
+
state.adminOverviewPayload = payload?.data || null;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const refreshAdminArea = async ({ keepCurrentError = false } = {}) => {
|
|
311
|
+
if (!keepCurrentError) showAdminError('');
|
|
312
|
+
try {
|
|
313
|
+
await loadAdminStatus();
|
|
314
|
+
await loadAdminOverview();
|
|
315
|
+
} catch (error) {
|
|
316
|
+
if (error?.statusCode === 404) {
|
|
317
|
+
state.adminStatusPayload = { enabled: false };
|
|
318
|
+
state.adminOverviewPayload = null;
|
|
319
|
+
} else {
|
|
320
|
+
showAdminError(error?.message || 'Falha ao carregar área admin.');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
renderAdminPanel();
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const handleAdminUnlock = async () => {
|
|
327
|
+
const password = String(ui.adminPassword?.value || '').trim();
|
|
328
|
+
if (!password) {
|
|
329
|
+
showAdminError('Informe a senha do painel admin.');
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (state.adminBusy) return;
|
|
333
|
+
|
|
334
|
+
showAdminError('');
|
|
335
|
+
setAdminBusy(true);
|
|
336
|
+
try {
|
|
337
|
+
const payload = await fetchJson(adminSessionApiPath, {
|
|
338
|
+
method: 'POST',
|
|
339
|
+
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
|
340
|
+
body: JSON.stringify({ password }),
|
|
341
|
+
});
|
|
342
|
+
state.adminStatusPayload = payload?.data || null;
|
|
343
|
+
if (ui.adminPassword) ui.adminPassword.value = '';
|
|
344
|
+
await loadAdminOverview();
|
|
345
|
+
} catch (error) {
|
|
346
|
+
showAdminError(error?.message || 'Falha ao desbloquear área admin.');
|
|
347
|
+
await loadAdminStatus().catch(() => {});
|
|
348
|
+
state.adminOverviewPayload = null;
|
|
349
|
+
} finally {
|
|
350
|
+
setAdminBusy(false);
|
|
351
|
+
renderAdminPanel();
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const handleAdminLogout = async () => {
|
|
356
|
+
if (state.adminBusy) return;
|
|
357
|
+
showAdminError('');
|
|
358
|
+
setAdminBusy(true);
|
|
359
|
+
try {
|
|
360
|
+
await fetchJson(adminSessionApiPath, { method: 'DELETE' });
|
|
361
|
+
} catch {
|
|
362
|
+
// no-op: we still revalidate status below
|
|
363
|
+
}
|
|
364
|
+
state.adminOverviewPayload = null;
|
|
365
|
+
await loadAdminStatus().catch(() => {
|
|
366
|
+
state.adminStatusPayload = null;
|
|
367
|
+
});
|
|
368
|
+
setAdminBusy(false);
|
|
369
|
+
renderAdminPanel();
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const handleAdminRefresh = async () => {
|
|
373
|
+
if (state.adminBusy) return;
|
|
374
|
+
setAdminBusy(true);
|
|
375
|
+
await refreshAdminArea({ keepCurrentError: false });
|
|
376
|
+
setAdminBusy(false);
|
|
377
|
+
renderAdminPanel();
|
|
378
|
+
};
|
|
379
|
+
|
|
184
380
|
const handleLogout = async () => {
|
|
185
381
|
if (!ui.logoutBtn) return;
|
|
186
382
|
ui.logoutBtn.disabled = true;
|
|
@@ -218,6 +414,7 @@ if (root) {
|
|
|
218
414
|
|
|
219
415
|
renderSession(sessionData);
|
|
220
416
|
await loadBotPhone();
|
|
417
|
+
await refreshAdminArea();
|
|
221
418
|
|
|
222
419
|
try {
|
|
223
420
|
const myProfilePayload = await fetchJson(myProfileApiPath, { method: 'GET' });
|
|
@@ -240,5 +437,24 @@ if (root) {
|
|
|
240
437
|
});
|
|
241
438
|
}
|
|
242
439
|
|
|
440
|
+
if (ui.adminUnlockForm) {
|
|
441
|
+
ui.adminUnlockForm.addEventListener('submit', (event) => {
|
|
442
|
+
event.preventDefault();
|
|
443
|
+
void handleAdminUnlock();
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (ui.adminLogoutBtn) {
|
|
448
|
+
ui.adminLogoutBtn.addEventListener('click', () => {
|
|
449
|
+
void handleAdminLogout();
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (ui.adminRefreshBtn) {
|
|
454
|
+
ui.adminRefreshBtn.addEventListener('click', () => {
|
|
455
|
+
void handleAdminRefresh();
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
243
459
|
void init();
|
|
244
460
|
}
|
package/public/js/catalog.js
CHANGED
|
@@ -90,51 +90,11 @@
|
|
|
90
90
|
packPageWhatsApp: document.getElementById('pack-page-whatsapp'),
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
if (
|
|
94
|
-
!els.hero ||
|
|
95
|
-
!els.form ||
|
|
96
|
-
!els.search ||
|
|
97
|
-
!els.visibility ||
|
|
98
|
-
!els.categories ||
|
|
99
|
-
!els.categoriesPicker ||
|
|
100
|
-
!els.categoriesSearch ||
|
|
101
|
-
!els.categoriesChips ||
|
|
102
|
-
!els.categoriesOptions ||
|
|
103
|
-
!els.status ||
|
|
104
|
-
!els.grid ||
|
|
105
|
-
!els.more ||
|
|
106
|
-
!els.orphanStatus ||
|
|
107
|
-
!els.orphanGrid ||
|
|
108
|
-
!els.orphanPrev ||
|
|
109
|
-
!els.orphanNext ||
|
|
110
|
-
!els.orphanPageInfo ||
|
|
111
|
-
!els.panel ||
|
|
112
|
-
!els.panelTitle ||
|
|
113
|
-
!els.panelSub ||
|
|
114
|
-
!els.panelChip ||
|
|
115
|
-
!els.panelError ||
|
|
116
|
-
!els.panelPrev ||
|
|
117
|
-
!els.panelNext ||
|
|
118
|
-
!els.panelPageInfo ||
|
|
119
|
-
!els.copy ||
|
|
120
|
-
!els.useWhatsAppLink ||
|
|
121
|
-
!els.stickers ||
|
|
122
|
-
!els.packPage ||
|
|
123
|
-
!els.packPageTitle ||
|
|
124
|
-
!els.packPageSub ||
|
|
125
|
-
!els.packPageChip ||
|
|
126
|
-
!els.packPageStatus ||
|
|
127
|
-
!els.packPageGrid ||
|
|
128
|
-
!els.packPageBack ||
|
|
129
|
-
!els.packPageCopy ||
|
|
130
|
-
!els.packPageWhatsApp
|
|
131
|
-
) {
|
|
93
|
+
if (!els.hero || !els.form || !els.search || !els.visibility || !els.categories || !els.categoriesPicker || !els.categoriesSearch || !els.categoriesChips || !els.categoriesOptions || !els.status || !els.grid || !els.more || !els.orphanStatus || !els.orphanGrid || !els.orphanPrev || !els.orphanNext || !els.orphanPageInfo || !els.panel || !els.panelTitle || !els.panelSub || !els.panelChip || !els.panelError || !els.panelPrev || !els.panelNext || !els.panelPageInfo || !els.copy || !els.useWhatsAppLink || !els.stickers || !els.packPage || !els.packPageTitle || !els.packPageSub || !els.packPageChip || !els.packPageStatus || !els.packPageGrid || !els.packPageBack || !els.packPageCopy || !els.packPageWhatsApp) {
|
|
132
94
|
return;
|
|
133
95
|
}
|
|
134
96
|
|
|
135
|
-
const panelModal = window.bootstrap?.Modal
|
|
136
|
-
? window.bootstrap.Modal.getOrCreateInstance(els.panel)
|
|
137
|
-
: null;
|
|
97
|
+
const panelModal = window.bootstrap?.Modal ? window.bootstrap.Modal.getOrCreateInstance(els.panel) : null;
|
|
138
98
|
|
|
139
99
|
let shouldReplaceStateOnHide = false;
|
|
140
100
|
|
|
@@ -208,10 +168,7 @@
|
|
|
208
168
|
chip.className = 'category-chip';
|
|
209
169
|
chip.dataset.value = value;
|
|
210
170
|
chip.setAttribute('aria-label', 'Remover categoria ' + (entry?.label || value));
|
|
211
|
-
chip.innerHTML =
|
|
212
|
-
'<span class="category-chip-label">' +
|
|
213
|
-
(entry?.label || value) +
|
|
214
|
-
'</span><i class="fa-solid fa-xmark category-chip-remove" aria-hidden="true"></i>';
|
|
171
|
+
chip.innerHTML = '<span class="category-chip-label">' + (entry?.label || value) + '</span><i class="fa-solid fa-xmark category-chip-remove" aria-hidden="true"></i>';
|
|
215
172
|
els.categoriesChips.appendChild(chip);
|
|
216
173
|
});
|
|
217
174
|
};
|
|
@@ -240,10 +197,7 @@
|
|
|
240
197
|
button.type = 'button';
|
|
241
198
|
button.className = 'category-option' + (selected.has(entry.value) ? ' selected' : '');
|
|
242
199
|
button.dataset.value = entry.value;
|
|
243
|
-
button.innerHTML =
|
|
244
|
-
'<span class="category-option-label">' +
|
|
245
|
-
entry.label +
|
|
246
|
-
'</span><i class="fa-solid fa-check category-option-check" aria-hidden="true"></i>';
|
|
200
|
+
button.innerHTML = '<span class="category-option-label">' + entry.label + '</span><i class="fa-solid fa-check category-option-check" aria-hidden="true"></i>';
|
|
247
201
|
els.categoriesOptions.appendChild(button);
|
|
248
202
|
});
|
|
249
203
|
};
|
|
@@ -401,9 +355,7 @@
|
|
|
401
355
|
.map(([label]) => toTagToken(label))
|
|
402
356
|
.filter(Boolean);
|
|
403
357
|
|
|
404
|
-
const merged = [...rankedFromScores, ...classificationTags, ...explicitTags]
|
|
405
|
-
.map((tag) => toTagToken(tag))
|
|
406
|
-
.filter(Boolean);
|
|
358
|
+
const merged = [...rankedFromScores, ...classificationTags, ...explicitTags].map((tag) => toTagToken(tag)).filter(Boolean);
|
|
407
359
|
|
|
408
360
|
return Array.from(new Set(merged)).slice(0, 3);
|
|
409
361
|
};
|
|
@@ -430,9 +382,7 @@
|
|
|
430
382
|
const explicitTags = Array.isArray(pack?.tags) ? pack.tags : [];
|
|
431
383
|
const classificationTags = Array.isArray(pack?.classification?.tags) ? pack.classification.tags : [];
|
|
432
384
|
|
|
433
|
-
const merged = [...classificationTags, ...explicitTags]
|
|
434
|
-
.map((tag) => toTagToken(tag))
|
|
435
|
-
.filter(Boolean);
|
|
385
|
+
const merged = [...classificationTags, ...explicitTags].map((tag) => toTagToken(tag)).filter(Boolean);
|
|
436
386
|
|
|
437
387
|
return Array.from(new Set(merged)).slice(0, 3);
|
|
438
388
|
};
|
|
@@ -473,8 +423,7 @@
|
|
|
473
423
|
const visibilityBadge = document.createElement('span');
|
|
474
424
|
visibilityBadge.className = 'pack-visibility-badge';
|
|
475
425
|
const visibility = String(pack.visibility || '').toLowerCase();
|
|
476
|
-
visibilityBadge.textContent =
|
|
477
|
-
visibility === 'public' ? 'Público' : visibility === 'unlisted' ? 'Não listado' : 'Privado';
|
|
426
|
+
visibilityBadge.textContent = visibility === 'public' ? 'Público' : visibility === 'unlisted' ? 'Não listado' : 'Privado';
|
|
478
427
|
|
|
479
428
|
const countBadge = document.createElement('span');
|
|
480
429
|
countBadge.className = 'pack-count-badge';
|
|
@@ -546,13 +495,7 @@
|
|
|
546
495
|
for (let index = 0; index < count; index += 1) {
|
|
547
496
|
const col = document.createElement('div');
|
|
548
497
|
col.className = 'col-4 col-sm-6 col-md-4 col-lg-3';
|
|
549
|
-
col.innerHTML =
|
|
550
|
-
'<div class="card h-100 bg-dark text-light shadow-sm pack-card">' +
|
|
551
|
-
'<div class="card-body d-flex flex-column gap-2">' +
|
|
552
|
-
'<div class="skeleton skeleton-thumb"></div>' +
|
|
553
|
-
'<div class="skeleton skeleton-line"></div>' +
|
|
554
|
-
'<div class="skeleton skeleton-line short"></div>' +
|
|
555
|
-
'</div></div>';
|
|
498
|
+
col.innerHTML = '<div class="card h-100 bg-dark text-light shadow-sm pack-card">' + '<div class="card-body d-flex flex-column gap-2">' + '<div class="skeleton skeleton-thumb"></div>' + '<div class="skeleton skeleton-line"></div>' + '<div class="skeleton skeleton-line short"></div>' + '</div></div>';
|
|
556
499
|
els.grid.appendChild(col);
|
|
557
500
|
}
|
|
558
501
|
};
|
|
@@ -607,8 +550,7 @@
|
|
|
607
550
|
|
|
608
551
|
els.packPageTitle.textContent = pack?.name || 'Pack';
|
|
609
552
|
els.packPageSub.textContent = (pack?.publisher || '-') + ' | ' + (pack?.description || 'Sem descrição');
|
|
610
|
-
els.packPageChip.textContent =
|
|
611
|
-
String(pack?.sticker_count || items.length || 0) + ' itens | ' + (pack?.visibility || '-') + ' | ' + (pack?.pack_key || '-');
|
|
553
|
+
els.packPageChip.textContent = String(pack?.sticker_count || items.length || 0) + ' itens | ' + (pack?.visibility || '-') + ' | ' + (pack?.pack_key || '-');
|
|
612
554
|
applyWhatsAppLink(els.packPageWhatsApp, pack?.whatsapp?.url);
|
|
613
555
|
|
|
614
556
|
els.packPageGrid.innerHTML = '';
|
|
@@ -643,11 +585,7 @@
|
|
|
643
585
|
for (let index = 0; index < count; index += 1) {
|
|
644
586
|
const col = document.createElement('div');
|
|
645
587
|
col.className = 'col-6 col-md-3 col-lg-2';
|
|
646
|
-
col.innerHTML =
|
|
647
|
-
'<article class="orphan-card card h-100"><div class="card-body p-2">' +
|
|
648
|
-
'<div class="skeleton skeleton-orphan"></div>' +
|
|
649
|
-
'<div class="skeleton skeleton-line short mt-2"></div>' +
|
|
650
|
-
'</div></article>';
|
|
588
|
+
col.innerHTML = '<article class="orphan-card card h-100"><div class="card-body p-2">' + '<div class="skeleton skeleton-orphan"></div>' + '<div class="skeleton skeleton-line short mt-2"></div>' + '</div></article>';
|
|
651
589
|
els.orphanGrid.appendChild(col);
|
|
652
590
|
}
|
|
653
591
|
};
|
|
@@ -779,8 +717,7 @@
|
|
|
779
717
|
|
|
780
718
|
els.panelPrev.disabled = state.panelPagination.page <= 1;
|
|
781
719
|
els.panelNext.disabled = state.panelPagination.page >= totalPages;
|
|
782
|
-
els.panelPageInfo.textContent =
|
|
783
|
-
'Página ' + state.panelPagination.page + ' de ' + totalPages + ' - ' + safeTotal + ' stickers';
|
|
720
|
+
els.panelPageInfo.textContent = 'Página ' + state.panelPagination.page + ' de ' + totalPages + ' - ' + safeTotal + ' stickers';
|
|
784
721
|
};
|
|
785
722
|
|
|
786
723
|
const renderPanelStickersPage = () => {
|
|
@@ -3,14 +3,7 @@ import { React, memo } from '../vendor/react.js';
|
|
|
3
3
|
const h = React.createElement;
|
|
4
4
|
|
|
5
5
|
function ErrorStateComponent({ message, onRetry, isRateLimited }) {
|
|
6
|
-
return h(
|
|
7
|
-
'section',
|
|
8
|
-
{ className: 'ghp-error', role: 'alert' },
|
|
9
|
-
h('h3', null, 'Não foi possível carregar os dados do GitHub'),
|
|
10
|
-
h('p', null, message || 'Tente novamente em alguns instantes.'),
|
|
11
|
-
isRateLimited ? h('p', { className: 'ghp-rate-limit' }, 'Limite de requisições do GitHub atingido. Tente novamente em breve.') : null,
|
|
12
|
-
h('button', { type: 'button', className: 'ghp-retry', onClick: onRetry }, 'Tentar novamente'),
|
|
13
|
-
);
|
|
6
|
+
return h('section', { className: 'ghp-error', role: 'alert' }, h('h3', null, 'Não foi possível carregar os dados do GitHub'), h('p', null, message || 'Tente novamente em alguns instantes.'), isRateLimited ? h('p', { className: 'ghp-rate-limit' }, 'Limite de requisições do GitHub atingido. Tente novamente em breve.') : null, h('button', { type: 'button', className: 'ghp-retry', onClick: onRetry }, 'Tentar novamente'));
|
|
14
7
|
}
|
|
15
8
|
|
|
16
9
|
export const ErrorState = memo(ErrorStateComponent);
|
|
@@ -92,15 +92,8 @@ export function GithubProjectPanel({ owner, repo, endpoint }) {
|
|
|
92
92
|
),
|
|
93
93
|
),
|
|
94
94
|
),
|
|
95
|
-
error
|
|
96
|
-
? h('p', { className: 'ghp-inline-warning', role: 'status' }, error.rateLimited ? 'Limite da API do GitHub atingido; exibindo cache local.' : 'Exibindo último snapshot disponível.')
|
|
97
|
-
: null,
|
|
95
|
+
error ? h('p', { className: 'ghp-inline-warning', role: 'status' }, error.rateLimited ? 'Limite da API do GitHub atingido; exibindo cache local.' : 'Exibindo último snapshot disponível.') : null,
|
|
98
96
|
h('div', { className: 'ghp-stat-grid' }, ...statCards.map((card) => h(StatCard, { key: card.label, ...card }))),
|
|
99
|
-
h(
|
|
100
|
-
'div',
|
|
101
|
-
{ className: 'ghp-list-grid' },
|
|
102
|
-
h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimos Commits'), h(CommitList, { items: data?.latest_commits || [], formatDate: fmtDate })),
|
|
103
|
-
h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimas Releases'), h(ReleaseList, { items: data?.latest_releases || [], formatDate: fmtDate })),
|
|
104
|
-
),
|
|
97
|
+
h('div', { className: 'ghp-list-grid' }, h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimos Commits'), h(CommitList, { items: data?.latest_commits || [], formatDate: fmtDate })), h('section', { className: 'ghp-list-card' }, h('h4', { className: 'ghp-list-title' }, 'Últimas Releases'), h(ReleaseList, { items: data?.latest_releases || [], formatDate: fmtDate }))),
|
|
105
98
|
);
|
|
106
99
|
}
|
|
@@ -6,17 +6,7 @@ function SkeletonPanelComponent() {
|
|
|
6
6
|
const statNodes = Array.from({ length: 10 }).map((_, index) => h('div', { key: `s-${index}`, className: 'ghp-skeleton-card' }));
|
|
7
7
|
const listNodes = Array.from({ length: 4 }).map((_, index) => h('li', { key: `l-${index}`, className: 'ghp-skeleton-line' }));
|
|
8
8
|
|
|
9
|
-
return h(
|
|
10
|
-
'section',
|
|
11
|
-
{ className: 'ghp-panel', 'aria-busy': 'true', 'aria-live': 'polite' },
|
|
12
|
-
h('div', { className: 'ghp-stat-grid' }, ...statNodes),
|
|
13
|
-
h(
|
|
14
|
-
'div',
|
|
15
|
-
{ className: 'ghp-list-grid' },
|
|
16
|
-
h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes)),
|
|
17
|
-
h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes)),
|
|
18
|
-
),
|
|
19
|
-
);
|
|
9
|
+
return h('section', { className: 'ghp-panel', 'aria-busy': 'true', 'aria-live': 'polite' }, h('div', { className: 'ghp-stat-grid' }, ...statNodes), h('div', { className: 'ghp-list-grid' }, h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes)), h('div', { className: 'ghp-list-card' }, h('div', { className: 'ghp-skeleton-title' }), h('ul', { className: 'ghp-list' }, ...listNodes))));
|
|
20
10
|
}
|
|
21
11
|
|
|
22
12
|
export const SkeletonPanel = memo(SkeletonPanelComponent);
|
|
@@ -3,13 +3,7 @@ import { React, memo } from '../vendor/react.js';
|
|
|
3
3
|
const h = React.createElement;
|
|
4
4
|
|
|
5
5
|
function StatCardComponent({ label, value, detail, iconClass }) {
|
|
6
|
-
return h(
|
|
7
|
-
'article',
|
|
8
|
-
{ className: 'ghp-stat-card' },
|
|
9
|
-
h('header', { className: 'ghp-stat-head' }, h('span', { className: 'ghp-stat-label' }, label), iconClass ? h('i', { className: iconClass, 'aria-hidden': 'true' }) : null),
|
|
10
|
-
h('p', { className: 'ghp-stat-value' }, value),
|
|
11
|
-
h('p', { className: 'ghp-stat-detail', title: detail || '' }, detail || ' '),
|
|
12
|
-
);
|
|
6
|
+
return h('article', { className: 'ghp-stat-card' }, h('header', { className: 'ghp-stat-head' }, h('span', { className: 'ghp-stat-label' }, label), iconClass ? h('i', { className: iconClass, 'aria-hidden': 'true' }) : null), h('p', { className: 'ghp-stat-value' }, value), h('p', { className: 'ghp-stat-detail', title: detail || '' }, detail || ' '));
|
|
13
7
|
}
|
|
14
8
|
|
|
15
9
|
export const StatCard = memo(StatCardComponent);
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
default as React,
|
|
3
|
-
memo,
|
|
4
|
-
useMemo,
|
|
5
|
-
useCallback,
|
|
6
|
-
useEffect,
|
|
7
|
-
useRef,
|
|
8
|
-
useState,
|
|
9
|
-
} from 'https://esm.sh/react@18.3.1';
|
|
1
|
+
export { default as React, memo, useMemo, useCallback, useEffect, useRef, useState } from 'https://esm.sh/react@18.3.1';
|
|
10
2
|
|
|
11
3
|
export { createRoot } from 'https://esm.sh/react-dom@18.3.1/client';
|
|
@@ -7,14 +7,6 @@ if (typeof document !== 'undefined' && !window.__omnizapTwindReady) {
|
|
|
7
7
|
window.__omnizapTwindReady = true;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export {
|
|
11
|
-
default as React,
|
|
12
|
-
useCallback,
|
|
13
|
-
useEffect,
|
|
14
|
-
useMemo,
|
|
15
|
-
useRef,
|
|
16
|
-
useState,
|
|
17
|
-
memo,
|
|
18
|
-
} from 'https://esm.sh/react@18.3.1';
|
|
10
|
+
export { default as React, useCallback, useEffect, useMemo, useRef, useState, memo } from 'https://esm.sh/react@18.3.1';
|
|
19
11
|
|
|
20
12
|
export { createRoot } from 'https://esm.sh/react-dom@18.3.1/client';
|