@omnizap-system/omnizap 2.6.1 → 2.6.2
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/.env.example +54 -9
- package/.github/workflows/ci.yml +3 -3
- package/.github/workflows/security-runner-hardening.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +1 -0
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +226 -55
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +143 -3
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +625 -124
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +88 -9
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +856 -14
- package/app/modules/adminModule/groupCommandHandlers.test.js +375 -9
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +132 -25
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +74 -16
- package/app/modules/playModule/playCommandConstants.js +13 -7
- package/app/modules/playModule/playCommandCore.js +4 -6
- package/app/modules/playModule/{playCommandYtDlpClient.js → playCommandMediaClient.js} +684 -332
- package/app/modules/playModule/playConfigRuntime.js +5 -6
- package/app/modules/playModule/playModuleCriticalFlows.test.js +44 -59
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +1 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +78 -57
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/geminiService.js +131 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/moduleAiHelpCoreService.js +33 -4
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +51 -21
- package/app/services/messaging/newsBroadcastService.js +843 -27
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/database/index.js +6 -0
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +2 -2
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/ecosystem.prod.config.cjs +31 -11
- package/index.js +52 -18
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +12 -5
- package/public/comandos/commands-catalog.json +2253 -78
- package/public/js/apps/commandsReactApp.js +267 -87
- package/public/js/apps/createPackApp.js +3 -3
- package/public/js/apps/stickersApp.js +255 -103
- package/public/js/apps/termsReactApp.js +57 -8
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +96 -47
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/politica-de-privacidade.html +1 -1
- package/public/pages/stickers.html +5 -5
- package/public/pages/termos-de-uso-texto-integral.html +1 -1
- package/public/pages/termos-de-uso.html +1 -1
- package/public/pages/user-password-reset.html +3 -4
- package/public/pages/user-systemadm.html +8 -462
- package/public/pages/user.html +1 -1
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +10 -0
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +155 -0
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/security-web-surface-check.mjs +218 -0
- package/server/controllers/admin/adminPanelHandlers.js +253 -3
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/sticker/stickerCatalogController.js +9 -23
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/stickerCatalogSystemContext.js +27 -6
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +3 -2
- package/server/http/httpServer.js +8 -4
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +2 -1
- package/app/modules/playModule/local/installYtDlp.js +0 -25
- package/app/modules/playModule/local/ytDlpInstaller.js +0 -28
|
@@ -587,14 +587,14 @@ function PackCard({ pack, index, onOpen, hasNsfwAccess = true, onRequireLogin })
|
|
|
587
587
|
};
|
|
588
588
|
|
|
589
589
|
return html`
|
|
590
|
-
<button type="button" onClick=${handleOpen} className="group w-full text-left rounded-
|
|
591
|
-
<div className="relative aspect-[
|
|
592
|
-
<${LazyCatalogImage} src=${coverUrl} alt=${`Capa de ${pack.name}`} className=${`w-full h-full object-cover transition-transform duration-300 ${lockedByNsfw ? 'blur-md scale-105' : 'md:group-hover:scale-[1.
|
|
590
|
+
<button type="button" onClick=${handleOpen} className="group w-full text-left rounded-[1rem] border border-slate-700/75 bg-slate-900/90 shadow-[0_16px_34px_rgba(2,6,23,0.34)] overflow-hidden transition-all duration-300 active:scale-[0.985] md:hover:scale-[1.02] hover:-translate-y-0.5 hover:border-cyan-400/35 hover:shadow-[0_24px_40px_rgba(2,6,23,0.5)] touch-manipulation">
|
|
591
|
+
<div className="relative aspect-[4/5] bg-slate-900 overflow-hidden">
|
|
592
|
+
<${LazyCatalogImage} src=${coverUrl} alt=${`Capa de ${pack.name}`} className=${`w-full h-full object-cover transition-transform duration-300 ${lockedByNsfw ? 'blur-md scale-105' : 'md:group-hover:scale-[1.06] group-active:scale-[1.02]'}`} />
|
|
593
593
|
<div className="absolute inset-0 bg-gradient-to-t from-slate-950 via-slate-950/60 to-transparent"></div>
|
|
594
|
-
<div className="absolute top-2 left-2 flex items-center gap-1">${lockedByNsfw ? html`<span className="rounded-full border border-amber-300/
|
|
594
|
+
<div className="absolute top-2 left-2 flex items-center gap-1">${lockedByNsfw ? html`<span className="rounded-full border border-amber-300/40 bg-amber-500/30 backdrop-blur px-1.5 py-0.5 text-[9px] font-bold text-amber-100">🔞 Login</span>` : null} ${isTrending ? html`<span className="rounded-full border border-emerald-300/35 bg-emerald-400/85 backdrop-blur px-1.5 py-0.5 text-[9px] font-bold text-slate-900">Trending</span>` : null} ${isNew ? html`<span className="rounded-full border border-white/20 bg-black/55 backdrop-blur px-1.5 py-0.5 text-[9px] font-semibold text-slate-100">Novo</span>` : null}</div>
|
|
595
595
|
|
|
596
596
|
<div className="absolute inset-x-0 bottom-0 p-2">
|
|
597
|
-
<h3 className="font-semibold text-sm leading-5 line-clamp-2">${pack.name || 'Pack sem nome'}</h3>
|
|
597
|
+
<h3 className="font-semibold text-sm leading-5 line-clamp-2 text-slate-100">${pack.name || 'Pack sem nome'}</h3>
|
|
598
598
|
<div className="mt-1 flex items-center gap-1.5 text-[10px] text-slate-300">
|
|
599
599
|
<${LazyCatalogImage} src=${getAvatarUrl(pack.publisher)} alt="Criador" className="w-4 h-4 rounded-full bg-slate-700" />
|
|
600
600
|
<span className="truncate">${pack.publisher || 'Criador não informado'}</span>
|
|
@@ -607,7 +607,7 @@ function PackCard({ pack, index, onOpen, hasNsfwAccess = true, onRequireLogin })
|
|
|
607
607
|
</div>
|
|
608
608
|
|
|
609
609
|
<div className="pointer-events-none absolute inset-x-2 bottom-2 hidden md:flex justify-center opacity-0 transition-opacity duration-200 group-hover:opacity-100">
|
|
610
|
-
<span className="inline-flex h-8 w-full items-center justify-center rounded-xl border border-
|
|
610
|
+
<span className="inline-flex h-8 w-full items-center justify-center rounded-xl border border-cyan-400/35 bg-cyan-500/15 px-3 text-xs font-semibold text-cyan-100 backdrop-blur"> ${lockedByNsfw ? 'Entrar para desbloquear' : 'Ver pack'} </span>
|
|
611
611
|
</div>
|
|
612
612
|
${lockedByNsfw
|
|
613
613
|
? html`
|
|
@@ -618,8 +618,8 @@ function PackCard({ pack, index, onOpen, hasNsfwAccess = true, onRequireLogin })
|
|
|
618
618
|
: null}
|
|
619
619
|
</div>
|
|
620
620
|
|
|
621
|
-
<div className="px-2 pb-2 pt-1 bg-slate-
|
|
622
|
-
<span className="inline-flex h-[34px] w-full items-center justify-center rounded-xl border border-
|
|
621
|
+
<div className="px-2 pb-2 pt-1 bg-slate-950/88 md:hidden">
|
|
622
|
+
<span className="inline-flex h-[34px] w-full items-center justify-center rounded-xl border border-cyan-400/35 bg-cyan-500/15 text-xs font-semibold text-cyan-100 transition group-active:brightness-110"> ${lockedByNsfw ? 'Entrar para desbloquear' : 'Ver pack'} </span>
|
|
623
623
|
</div>
|
|
624
624
|
</button>
|
|
625
625
|
`;
|
|
@@ -1397,7 +1397,7 @@ function CreatorProfileDashboard({ googleAuthConfig, googleAuth, googleAuthBusy,
|
|
|
1397
1397
|
|
|
1398
1398
|
function SkeletonGrid({ count = 10 }) {
|
|
1399
1399
|
return html`
|
|
1400
|
-
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-
|
|
1400
|
+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-3">
|
|
1401
1401
|
${Array.from({ length: count }).map(
|
|
1402
1402
|
(_, index) => html`
|
|
1403
1403
|
<div key=${index} className="rounded-2xl border border-slate-700 bg-slate-800 overflow-hidden animate-pulse">
|
|
@@ -1416,11 +1416,14 @@ function SkeletonGrid({ count = 10 }) {
|
|
|
1416
1416
|
|
|
1417
1417
|
function EmptyState({ onClear }) {
|
|
1418
1418
|
return html`
|
|
1419
|
-
<div className="
|
|
1420
|
-
<div className="
|
|
1421
|
-
<p className="text-slate-100 font-semibold">Nenhum pack encontrado</p>
|
|
1422
|
-
<p className="text-slate-400 text-sm mt-1">Tente outra busca ou
|
|
1423
|
-
<
|
|
1419
|
+
<div className="market-glass rounded-3xl p-8 text-center sm:p-10">
|
|
1420
|
+
<div className="mx-auto mb-3 flex h-14 w-14 items-center justify-center rounded-2xl border border-cyan-400/35 bg-cyan-500/12 text-2xl">🧩</div>
|
|
1421
|
+
<p className="text-slate-100 font-semibold text-lg">Nenhum pack encontrado</p>
|
|
1422
|
+
<p className="text-slate-400 text-sm mt-1">Tente outra busca, categoria ou limpe os filtros para descobrir novos packs.</p>
|
|
1423
|
+
<div className="mt-4 flex flex-wrap items-center justify-center gap-2">
|
|
1424
|
+
<button type="button" onClick=${onClear} className="inline-flex items-center justify-center rounded-xl border border-slate-600 px-4 py-2 text-sm text-slate-200 hover:bg-slate-800 transition">Limpar filtros</button>
|
|
1425
|
+
<a href="/stickers/create/" className="inline-flex items-center justify-center rounded-xl border border-emerald-400/35 bg-emerald-500/12 px-4 py-2 text-sm font-semibold text-emerald-100 hover:bg-emerald-500/22 transition">Criar pack</a>
|
|
1426
|
+
</div>
|
|
1424
1427
|
</div>
|
|
1425
1428
|
`;
|
|
1426
1429
|
}
|
|
@@ -2089,6 +2092,28 @@ function StickersApp() {
|
|
|
2089
2092
|
.slice(0, MOBILE_DISCOVER_CAROUSEL_LIMIT),
|
|
2090
2093
|
[packs],
|
|
2091
2094
|
);
|
|
2095
|
+
const catalogTotals = useMemo(() => {
|
|
2096
|
+
let stickers = 0;
|
|
2097
|
+
let likes = 0;
|
|
2098
|
+
let downloads = 0;
|
|
2099
|
+
const creators = new Set();
|
|
2100
|
+
for (const pack of packs) {
|
|
2101
|
+
stickers += Math.max(0, Number(pack?.sticker_count || 0));
|
|
2102
|
+
const engagement = getPackEngagement(pack);
|
|
2103
|
+
likes += Math.max(0, Number(engagement.likeCount || 0));
|
|
2104
|
+
downloads += Math.max(0, Number(engagement.openCount || 0));
|
|
2105
|
+
const publisher = String(pack?.publisher || '').trim();
|
|
2106
|
+
if (publisher) creators.add(publisher);
|
|
2107
|
+
}
|
|
2108
|
+
return {
|
|
2109
|
+
packs: packs.length,
|
|
2110
|
+
stickers,
|
|
2111
|
+
likes,
|
|
2112
|
+
downloads,
|
|
2113
|
+
creators: creators.size,
|
|
2114
|
+
};
|
|
2115
|
+
}, [packs]);
|
|
2116
|
+
const highlightCreator = String(featuredCreators?.[0]?.publisher || '').trim();
|
|
2092
2117
|
|
|
2093
2118
|
const hasAnyResult = packs.length > 0;
|
|
2094
2119
|
const canGoCatalogPrev = catalogPage > FIRST_CATALOG_PAGE && !packsLoading;
|
|
@@ -3449,11 +3474,74 @@ function StickersApp() {
|
|
|
3449
3474
|
};
|
|
3450
3475
|
|
|
3451
3476
|
return html`
|
|
3452
|
-
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
3477
|
+
<div className="min-h-screen bg-slate-950 text-slate-100 stickers-market-shell">
|
|
3453
3478
|
<style>
|
|
3454
3479
|
${`@keyframes fadeInCard { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
|
3480
|
+
@keyframes pulseGlow { 0%, 100% { opacity: 0.58; } 50% { opacity: 0.94; } }
|
|
3455
3481
|
.fade-card { animation: fadeInCard 260ms ease both; }
|
|
3456
3482
|
.line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
3483
|
+
.stickers-market-shell { --market-blue: #0f172a; --market-cyan: #22d3ee; --market-green: #34d399; scroll-behavior: smooth; }
|
|
3484
|
+
.market-shell-glow {
|
|
3485
|
+
pointer-events: none;
|
|
3486
|
+
position: fixed;
|
|
3487
|
+
inset: 0;
|
|
3488
|
+
z-index: 0;
|
|
3489
|
+
background:
|
|
3490
|
+
radial-gradient(48rem 28rem at 4% -10%, rgba(52, 211, 153, 0.14), transparent 62%),
|
|
3491
|
+
radial-gradient(40rem 24rem at 96% -8%, rgba(34, 211, 238, 0.15), transparent 60%),
|
|
3492
|
+
radial-gradient(52rem 30rem at 50% 120%, rgba(15, 23, 42, 0.84), transparent 70%);
|
|
3493
|
+
}
|
|
3494
|
+
.market-glass {
|
|
3495
|
+
border: 1px solid rgba(71, 85, 105, 0.52);
|
|
3496
|
+
background: linear-gradient(180deg, rgba(15, 23, 42, 0.78), rgba(2, 6, 23, 0.72));
|
|
3497
|
+
box-shadow: 0 20px 42px rgba(2, 6, 23, 0.36);
|
|
3498
|
+
backdrop-filter: blur(14px);
|
|
3499
|
+
}
|
|
3500
|
+
.market-header-glass {
|
|
3501
|
+
border-bottom: 1px solid rgba(71, 85, 105, 0.45);
|
|
3502
|
+
background: linear-gradient(180deg, rgba(2, 6, 23, 0.84), rgba(2, 6, 23, 0.68));
|
|
3503
|
+
backdrop-filter: blur(16px);
|
|
3504
|
+
}
|
|
3505
|
+
.market-search-shell {
|
|
3506
|
+
border: 1px solid rgba(71, 85, 105, 0.55);
|
|
3507
|
+
background: linear-gradient(180deg, rgba(15, 23, 42, 0.95), rgba(15, 23, 42, 0.85));
|
|
3508
|
+
box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.35);
|
|
3509
|
+
}
|
|
3510
|
+
.catalog-hero {
|
|
3511
|
+
position: relative;
|
|
3512
|
+
overflow: hidden;
|
|
3513
|
+
}
|
|
3514
|
+
.catalog-hero::before {
|
|
3515
|
+
content: '';
|
|
3516
|
+
position: absolute;
|
|
3517
|
+
inset: -24% -10% auto;
|
|
3518
|
+
height: 82%;
|
|
3519
|
+
background: radial-gradient(26rem 14rem at 22% 0%, rgba(52, 211, 153, 0.18), transparent 65%);
|
|
3520
|
+
animation: pulseGlow 6.8s ease-in-out infinite;
|
|
3521
|
+
pointer-events: none;
|
|
3522
|
+
}
|
|
3523
|
+
.catalog-hero::after {
|
|
3524
|
+
content: '';
|
|
3525
|
+
position: absolute;
|
|
3526
|
+
inset: auto -20% -38% -15%;
|
|
3527
|
+
height: 70%;
|
|
3528
|
+
background: radial-gradient(26rem 12rem at 70% 60%, rgba(34, 211, 238, 0.13), transparent 70%);
|
|
3529
|
+
pointer-events: none;
|
|
3530
|
+
}
|
|
3531
|
+
.kpi-card {
|
|
3532
|
+
border: 1px solid rgba(71, 85, 105, 0.5);
|
|
3533
|
+
background: rgba(2, 6, 23, 0.42);
|
|
3534
|
+
}
|
|
3535
|
+
.metric-card {
|
|
3536
|
+
border: 1px solid rgba(71, 85, 105, 0.5);
|
|
3537
|
+
background: linear-gradient(180deg, rgba(2, 6, 23, 0.62), rgba(2, 6, 23, 0.38));
|
|
3538
|
+
border-radius: 14px;
|
|
3539
|
+
}
|
|
3540
|
+
.market-sidebar-panel {
|
|
3541
|
+
border: 1px solid rgba(71, 85, 105, 0.54);
|
|
3542
|
+
background: linear-gradient(180deg, rgba(15, 23, 42, 0.82), rgba(2, 6, 23, 0.72));
|
|
3543
|
+
backdrop-filter: blur(10px);
|
|
3544
|
+
}
|
|
3457
3545
|
.chips-scroll {
|
|
3458
3546
|
scroll-snap-type: x mandatory;
|
|
3459
3547
|
-webkit-overflow-scrolling: touch;
|
|
@@ -3465,86 +3553,101 @@ function StickersApp() {
|
|
|
3465
3553
|
.chips-scroll::-webkit-scrollbar { display: none; }
|
|
3466
3554
|
.chip-item { scroll-snap-align: start; touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
|
|
3467
3555
|
.pack-stickers-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
3556
|
+
.market-catalog-grid { display: grid; gap: 0.8rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
3557
|
+
@media (min-width: 768px) {
|
|
3558
|
+
.market-catalog-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
3559
|
+
}
|
|
3468
3560
|
@media (min-width: 1024px) {
|
|
3469
3561
|
.pack-stickers-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
|
|
3562
|
+
.market-catalog-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
3563
|
+
}
|
|
3564
|
+
@media (min-width: 1280px) {
|
|
3565
|
+
.market-catalog-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
3566
|
+
}
|
|
3567
|
+
@media (min-width: 1536px) {
|
|
3568
|
+
.market-catalog-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
|
3569
|
+
}
|
|
3570
|
+
@media (max-width: 767px) {
|
|
3571
|
+
.market-header-action-label {
|
|
3572
|
+
display: none;
|
|
3573
|
+
}
|
|
3470
3574
|
}
|
|
3471
3575
|
@media (prefers-reduced-motion: reduce) {
|
|
3472
3576
|
.fade-card { animation: none; }
|
|
3577
|
+
.catalog-hero::before { animation: none; }
|
|
3473
3578
|
}`}
|
|
3474
3579
|
</style>
|
|
3475
3580
|
|
|
3476
|
-
<
|
|
3477
|
-
<div className="max-w-7xl mx-auto h-14 px-3 flex items-center gap-2.5">
|
|
3478
|
-
<a href="/" className="shrink-0 flex items-center gap-2">
|
|
3479
|
-
<img src=${OMNIZAP_LOGO_DATA_URL} alt="OmniZap" className="w-7 h-7 rounded-full border border-slate-700" decoding="async" />
|
|
3480
|
-
<span className="hidden sm:inline text-sm font-semibold">OmniZap</span>
|
|
3481
|
-
</a>
|
|
3482
|
-
|
|
3483
|
-
${currentView === 'catalog'
|
|
3484
|
-
? html`
|
|
3485
|
-
<form onSubmit=${onSubmit} className="flex-1 relative">
|
|
3486
|
-
<span className="absolute left-2.5 top-1/2 -translate-y-1/2 text-xs text-slate-400">🔎</span>
|
|
3487
|
-
<input
|
|
3488
|
-
type="search"
|
|
3489
|
-
value=${query}
|
|
3490
|
-
onChange=${(e) => setQuery(e.target.value)}
|
|
3491
|
-
onFocus=${() => setShowAutocomplete(true)}
|
|
3492
|
-
onBlur=${() => setTimeout(() => setShowAutocomplete(false), 120)}
|
|
3493
|
-
onKeyDown=${(event) => {
|
|
3494
|
-
if (event.key === 'Escape') {
|
|
3495
|
-
setShowAutocomplete(false);
|
|
3496
|
-
}
|
|
3497
|
-
}}
|
|
3498
|
-
placeholder="Buscar packs..."
|
|
3499
|
-
className="w-full h-9 sm:h-10 rounded-2xl border border-slate-800 bg-slate-900 pl-[34px] sm:pl-9 pr-3 text-sm text-slate-100 placeholder:text-slate-500 outline-none transition focus:border-emerald-400/50 focus:ring-2 focus:ring-emerald-400/15"
|
|
3500
|
-
/>
|
|
3501
|
-
${showAutocomplete && filteredSuggestions.length
|
|
3502
|
-
? html`
|
|
3503
|
-
<div className="absolute z-40 mt-2 w-full rounded-2xl border border-slate-800 bg-slate-900 shadow-xl overflow-hidden">
|
|
3504
|
-
${filteredSuggestions.map(
|
|
3505
|
-
(item) => html`
|
|
3506
|
-
<button key=${item.value} type="button" onClick=${() => applySuggestion(item)} className="w-full px-3 py-2.5 text-left text-sm text-slate-200 hover:bg-slate-800 flex items-center justify-between gap-2 border-b border-slate-800 last:border-b-0">
|
|
3507
|
-
<span className="inline-flex items-center gap-2">
|
|
3508
|
-
<span>${item.icon || '🏷'}</span>
|
|
3509
|
-
<span className="truncate">${item.label}</span>
|
|
3510
|
-
</span>
|
|
3511
|
-
<span className="text-xs text-slate-400 truncate">${item.value}</span>
|
|
3512
|
-
</button>
|
|
3513
|
-
`,
|
|
3514
|
-
)}
|
|
3515
|
-
</div>
|
|
3516
|
-
`
|
|
3517
|
-
: null}
|
|
3518
|
-
</form>
|
|
3519
|
-
`
|
|
3520
|
-
: html`<div className="flex-1"></div>`}
|
|
3581
|
+
<div className="market-shell-glow"></div>
|
|
3521
3582
|
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
<span className="sm:hidden">➕</span>
|
|
3529
|
-
<span className="hidden sm:inline">✨ Criar pack agora</span>
|
|
3583
|
+
<header className=${`sticky top-0 z-30 market-header-glass transition-shadow ${isScrolled ? 'shadow-[0_16px_44px_rgba(2,6,23,0.52)]' : ''}`}>
|
|
3584
|
+
<div className="mx-auto w-full max-w-[1400px] px-3 sm:px-4 lg:px-6">
|
|
3585
|
+
<div className="flex h-[74px] items-center gap-2.5 md:gap-3.5">
|
|
3586
|
+
<a href="/" className="shrink-0 flex items-center gap-2.5">
|
|
3587
|
+
<img src=${OMNIZAP_LOGO_DATA_URL} alt="OmniZap" className="h-9 w-9 rounded-full border border-slate-700/90 ring-2 ring-slate-800/70" decoding="async" />
|
|
3588
|
+
<span className="hidden md:inline text-sm font-semibold tracking-wide text-slate-100">OmniZap Marketplace</span>
|
|
3530
3589
|
</a>
|
|
3531
|
-
|
|
3590
|
+
|
|
3591
|
+
${currentView === 'catalog'
|
|
3532
3592
|
? html`
|
|
3533
|
-
<
|
|
3534
|
-
<
|
|
3535
|
-
|
|
3536
|
-
|
|
3593
|
+
<form onSubmit=${onSubmit} className="relative mx-auto w-full max-w-[760px]">
|
|
3594
|
+
<div className="market-search-shell h-11 rounded-2xl">
|
|
3595
|
+
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-[13px] text-slate-400">🔎</span>
|
|
3596
|
+
<input
|
|
3597
|
+
type="search"
|
|
3598
|
+
value=${query}
|
|
3599
|
+
onChange=${(e) => setQuery(e.target.value)}
|
|
3600
|
+
onFocus=${() => setShowAutocomplete(true)}
|
|
3601
|
+
onBlur=${() => setTimeout(() => setShowAutocomplete(false), 120)}
|
|
3602
|
+
onKeyDown=${(event) => {
|
|
3603
|
+
if (event.key === 'Escape') {
|
|
3604
|
+
setShowAutocomplete(false);
|
|
3605
|
+
}
|
|
3606
|
+
}}
|
|
3607
|
+
placeholder="Buscar packs, temas e criadores"
|
|
3608
|
+
className="h-full w-full rounded-2xl bg-transparent pl-10 pr-3 text-sm text-slate-100 placeholder:text-slate-500 outline-none transition focus:ring-2 focus:ring-cyan-400/25"
|
|
3609
|
+
/>
|
|
3610
|
+
</div>
|
|
3611
|
+
${showAutocomplete && filteredSuggestions.length
|
|
3612
|
+
? html`
|
|
3613
|
+
<div className="absolute z-40 mt-2 w-full overflow-hidden rounded-2xl border border-slate-700 bg-slate-900 shadow-xl">
|
|
3614
|
+
${filteredSuggestions.map(
|
|
3615
|
+
(item) => html`
|
|
3616
|
+
<button key=${item.value} type="button" onClick=${() => applySuggestion(item)} className="w-full border-b border-slate-800 px-3 py-2.5 text-left text-sm text-slate-200 hover:bg-slate-800 last:border-b-0 flex items-center justify-between gap-2">
|
|
3617
|
+
<span className="inline-flex items-center gap-2">
|
|
3618
|
+
<span>${item.icon || '🏷'}</span>
|
|
3619
|
+
<span className="truncate">${item.label}</span>
|
|
3620
|
+
</span>
|
|
3621
|
+
<span className="truncate text-xs text-slate-400">${item.value}</span>
|
|
3622
|
+
</button>
|
|
3623
|
+
`,
|
|
3624
|
+
)}
|
|
3625
|
+
</div>
|
|
3626
|
+
`
|
|
3627
|
+
: null}
|
|
3628
|
+
</form>
|
|
3537
3629
|
`
|
|
3538
|
-
:
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
<
|
|
3630
|
+
: html`<div className="flex-1"></div>`}
|
|
3631
|
+
|
|
3632
|
+
<div className="flex shrink-0 items-center gap-1.5 sm:gap-2">
|
|
3633
|
+
<button type="button" className=${`inline-flex h-10 items-center gap-1.5 rounded-xl border px-2.5 text-xs transition ${isProfileView ? 'border-cyan-400/45 bg-cyan-500/12 text-cyan-100' : 'border-slate-700 bg-slate-900/65 text-slate-200 hover:bg-slate-800'}`} onClick=${() => openProfile(true)} title="Meus packs">
|
|
3634
|
+
<span>📦</span>
|
|
3635
|
+
<span className="market-header-action-label">Meus Packs</span>
|
|
3636
|
+
</button>
|
|
3637
|
+
<a className="inline-flex h-10 items-center gap-1.5 rounded-xl border border-emerald-400/35 bg-emerald-500/14 px-2.5 text-xs font-semibold text-emerald-100 hover:bg-emerald-500/24 transition" href="/stickers/create/" title="Criar pack">
|
|
3638
|
+
<span>✨</span>
|
|
3639
|
+
<span className="market-header-action-label">Criar Pack</span>
|
|
3640
|
+
</a>
|
|
3641
|
+
<button type="button" onClick=${() => openProfile(true)} className="inline-flex h-10 items-center gap-2 rounded-xl border border-slate-700 bg-slate-900/65 px-2 text-xs text-slate-200 hover:bg-slate-800 transition" title="Perfil">
|
|
3642
|
+
${hasGoogleLogin && googleAuth?.user?.picture ? html`<img src=${googleAuth.user.picture} alt="Perfil" className="h-6 w-6 rounded-full border border-slate-700 object-cover" />` : html`<span className="inline-flex h-6 w-6 items-center justify-center rounded-full border border-slate-700 bg-slate-800">👤</span>`}
|
|
3643
|
+
<span className="market-header-action-label">Perfil</span>
|
|
3644
|
+
</button>
|
|
3542
3645
|
</div>
|
|
3543
3646
|
</div>
|
|
3544
3647
|
</div>
|
|
3545
3648
|
</header>
|
|
3546
3649
|
|
|
3547
|
-
<main className="
|
|
3650
|
+
<main className="relative z-[1] mx-auto w-full max-w-[1400px] px-3 py-3.5 sm:px-4 sm:py-4 lg:px-6 space-y-3.5 pb-[calc(1rem+env(safe-area-inset-bottom))]">
|
|
3548
3651
|
${error ? html`<div className="rounded-2xl border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-200">${error}</div>` : null}
|
|
3549
3652
|
${isProfileView
|
|
3550
3653
|
? html` <${CreatorProfileDashboard} googleAuthConfig=${googleAuthConfig} googleAuth=${googleAuth} googleAuthBusy=${googleAuthBusy} googleAuthError=${googleAuthError} googleSessionChecked=${googleSessionChecked} myPacks=${myPacks} myPacksLoading=${myPacksLoading} myPacksError=${myPacksError} myProfileStats=${myProfileStats} onBack=${goCatalog} onRefresh=${() => refreshMyProfile()} onLogout=${handleGoogleLogout} onOpenPublicPack=${openPack} onOpenPackActions=${openPackActionsSheet} onOpenManagePack=${(pack) => openManagePackByKey(pack?.pack_key || '')} onRequestDeletePack=${requestDeletePack} packActionBusyByKey=${packActionBusyByKey} /> `
|
|
@@ -3553,28 +3656,77 @@ function StickersApp() {
|
|
|
3553
3656
|
: currentPackKey
|
|
3554
3657
|
? html` ${packLoading ? html`<${PackPageSkeleton} />` : html`<${PackPage} pack=${currentPack} relatedPacks=${relatedPacks} relatedLoading=${relatedPacksLoading} onLoadRelated=${requestRelatedPacksForCurrentPack} onBack=${goCatalog} onOpenRelated=${openPack} onLike=${handleLike} onDislike=${handleDislike} onTagClick=${openCatalogTagFilter} reactionLoading=${reactionLoading} reactionNotice=${reactionNotice} hasNsfwAccess=${hasNsfwAccess} onRequireLogin=${requestNsfwUnlock} />`} `
|
|
3555
3658
|
: html`
|
|
3556
|
-
<
|
|
3659
|
+
<section className="catalog-hero market-glass rounded-[28px] p-4 sm:p-5 lg:p-6">
|
|
3660
|
+
<div className="relative z-[1] flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
|
|
3661
|
+
<div className="max-w-3xl">
|
|
3662
|
+
<p className="text-[11px] uppercase tracking-[0.16em] text-emerald-200/85">OmniZap Marketplace</p>
|
|
3663
|
+
<h1 className="mt-1 text-xl font-semibold leading-tight text-slate-100 sm:text-2xl lg:text-3xl">Packs de stickers prontos para seu WhatsApp</h1>
|
|
3664
|
+
<p className="mt-2 text-sm leading-relaxed text-slate-300">Explore coleções curadas, descubra criadores com melhor performance e publique novos packs com mais conversão.</p>
|
|
3665
|
+
${highlightCreator ? html`<p className="mt-2 text-xs text-cyan-200/90">⭐ Criador em destaque hoje: <span className="font-semibold">${highlightCreator}</span></p>` : null}
|
|
3666
|
+
</div>
|
|
3667
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
3668
|
+
<button type="button" onClick=${openTrendingCatalog} className="inline-flex h-10 items-center gap-1.5 rounded-xl border border-cyan-400/35 bg-cyan-500/14 px-3 text-xs font-semibold text-cyan-100 hover:bg-cyan-500/24 transition">🔎 Explorar packs</button>
|
|
3669
|
+
<a href="/stickers/create/" className="inline-flex h-10 items-center gap-1.5 rounded-xl border border-emerald-400/35 bg-emerald-500/14 px-3 text-xs font-semibold text-emerald-100 hover:bg-emerald-500/24 transition">✨ Criar pack</a>
|
|
3670
|
+
<button type="button" onClick=${() => openCreatorsRanking('popular', true)} className="inline-flex h-10 items-center gap-1.5 rounded-xl border border-indigo-400/35 bg-indigo-500/10 px-3 text-xs font-semibold text-indigo-100 hover:bg-indigo-500/20 transition">⭐ Ver criadores</button>
|
|
3671
|
+
</div>
|
|
3672
|
+
</div>
|
|
3673
|
+
<div className="relative z-[1] mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3 xl:grid-cols-5">
|
|
3674
|
+
<article className="metric-card px-3 py-2.5">
|
|
3675
|
+
<p className="text-[10px] uppercase tracking-wide text-slate-400">Packs</p>
|
|
3676
|
+
<p className="mt-1 text-base font-semibold text-slate-100">${shortNum(catalogTotals.packs)}</p>
|
|
3677
|
+
</article>
|
|
3678
|
+
<article className="metric-card px-3 py-2.5">
|
|
3679
|
+
<p className="text-[10px] uppercase tracking-wide text-slate-400">Stickers</p>
|
|
3680
|
+
<p className="mt-1 text-base font-semibold text-slate-100">${shortNum(catalogTotals.stickers)}</p>
|
|
3681
|
+
</article>
|
|
3682
|
+
<article className="metric-card px-3 py-2.5">
|
|
3683
|
+
<p className="text-[10px] uppercase tracking-wide text-slate-400">Likes</p>
|
|
3684
|
+
<p className="mt-1 text-base font-semibold text-slate-100">${shortNum(catalogTotals.likes)}</p>
|
|
3685
|
+
</article>
|
|
3686
|
+
<article className="metric-card px-3 py-2.5">
|
|
3687
|
+
<p className="text-[10px] uppercase tracking-wide text-slate-400">Downloads</p>
|
|
3688
|
+
<p className="mt-1 text-base font-semibold text-slate-100">${shortNum(catalogTotals.downloads)}</p>
|
|
3689
|
+
</article>
|
|
3690
|
+
<article className="metric-card col-span-2 px-3 py-2.5 sm:col-span-1">
|
|
3691
|
+
<p className="text-[10px] uppercase tracking-wide text-slate-400">Criadores ativos</p>
|
|
3692
|
+
<p className="mt-1 text-base font-semibold text-slate-100">${shortNum(catalogTotals.creators)}</p>
|
|
3693
|
+
</article>
|
|
3694
|
+
</div>
|
|
3695
|
+
</section>
|
|
3696
|
+
<div className="lg:grid lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-5">
|
|
3557
3697
|
<aside className="hidden lg:block">
|
|
3558
|
-
<div className="sticky top-[
|
|
3559
|
-
<div className="rounded-xl border border-slate-800 bg-slate-950/
|
|
3698
|
+
<div className="market-sidebar-panel sticky top-[98px] space-y-3 rounded-2xl p-3">
|
|
3699
|
+
<div className="rounded-xl border border-slate-800 bg-slate-950/50 p-3">
|
|
3560
3700
|
<div className="flex items-center justify-between gap-2">
|
|
3561
|
-
<h3 className="text-xs font-semibold uppercase tracking-wide text-slate-
|
|
3562
|
-
<button type="button" onClick=${clearFilters} className="h-8 rounded-lg border border-slate-700 px-2 text-[11px] text-slate-200 hover:bg-slate-800">Limpar</button>
|
|
3701
|
+
<h3 className="text-xs font-semibold uppercase tracking-wide text-slate-200">Filtros</h3>
|
|
3702
|
+
<button type="button" onClick=${clearFilters} className="h-8 rounded-lg border border-slate-700 px-2.5 text-[11px] text-slate-200 hover:bg-slate-800 transition">Limpar</button>
|
|
3563
3703
|
</div>
|
|
3564
|
-
<p className="mt-1 text-[11px] text-slate-500">${
|
|
3704
|
+
<p className="mt-1 text-[11px] text-slate-500">${sortedPacks.length} packs nesta página</p>
|
|
3565
3705
|
</div>
|
|
3566
3706
|
|
|
3567
|
-
<
|
|
3568
|
-
<
|
|
3569
|
-
<div className="mt-2 space-y-1.5"
|
|
3570
|
-
|
|
3707
|
+
<div className="rounded-xl border border-slate-800 bg-slate-950/50 p-3">
|
|
3708
|
+
<p className="text-xs font-semibold text-slate-100">Ordenação rápida</p>
|
|
3709
|
+
<div className="mt-2 space-y-1.5">
|
|
3710
|
+
${[
|
|
3711
|
+
{ value: 'recent', label: 'Mais recentes', icon: '🆕' },
|
|
3712
|
+
{ value: 'likes', label: 'Mais curtidos', icon: '👍' },
|
|
3713
|
+
{ value: 'downloads', label: 'Mais baixados', icon: '⬇️' },
|
|
3714
|
+
].map((option) => html` <button key=${option.value} type="button" onClick=${() => handleCatalogSortSelection(option.value)} disabled=${sortPickerBusy} className=${`w-full h-9 rounded-xl border px-2.5 text-left text-xs transition disabled:opacity-60 ${normalizeCatalogSort(sortBy) === option.value ? 'border-cyan-400/40 bg-cyan-500/14 text-cyan-100' : 'border-slate-700 text-slate-200 hover:bg-slate-800'}`}>${option.icon} ${option.label}</button> `)}
|
|
3715
|
+
</div>
|
|
3716
|
+
</div>
|
|
3717
|
+
|
|
3718
|
+
<div className="rounded-xl border border-slate-800 bg-slate-950/50 p-3">
|
|
3719
|
+
<p className="text-xs font-semibold text-slate-100">Categorias</p>
|
|
3720
|
+
<div className="mt-2 flex flex-wrap gap-1.5">${dynamicCategoryOptions.slice(0, 12).map((item) => html` <button key=${`sidebar-${item.value || 'all'}`} type="button" onClick=${() => handleCategoryChipPress(item.value)} className=${`h-8 rounded-full border px-2.5 text-[11px] transition ${activeCategory === item.value ? 'border-emerald-300 bg-emerald-400 text-slate-900 font-semibold' : 'border-slate-700 bg-slate-900 text-slate-300 hover:bg-slate-800'}`}>${item.label}</button> `)}</div>
|
|
3721
|
+
</div>
|
|
3571
3722
|
|
|
3572
|
-
|
|
3723
|
+
<button type="button" onClick=${openTrendingCatalog} className="inline-flex h-9 w-full items-center justify-center gap-1.5 rounded-xl border border-cyan-400/35 bg-cyan-500/12 text-xs font-semibold text-cyan-100 hover:bg-cyan-500/22 transition">🔥 Em alta agora</button>
|
|
3724
|
+
${supportInfo?.url ? html` <a href=${supportInfo.url} target="_blank" rel="noreferrer noopener" className="inline-flex h-9 w-full items-center justify-center rounded-xl border border-emerald-500/35 bg-emerald-500/10 text-xs text-emerald-200 hover:bg-emerald-500/20 transition"> 💬 Suporte no WhatsApp </a> ` : null}
|
|
3573
3725
|
</div>
|
|
3574
3726
|
</aside>
|
|
3575
3727
|
|
|
3576
3728
|
<div className="space-y-3 min-w-0">
|
|
3577
|
-
<section className="space-y-2 min-w-0">
|
|
3729
|
+
<section className="space-y-2 min-w-0 rounded-2xl border border-slate-800/80 bg-slate-900/65 px-2.5 py-2 lg:hidden">
|
|
3578
3730
|
<div className="relative min-w-0">
|
|
3579
3731
|
<div className="absolute left-0 top-0 bottom-0 w-5 bg-gradient-to-r from-slate-950 to-transparent pointer-events-none z-10"></div>
|
|
3580
3732
|
<div className="absolute right-0 top-0 bottom-0 w-5 bg-gradient-to-l from-slate-950 to-transparent pointer-events-none z-10"></div>
|
|
@@ -3585,7 +3737,7 @@ function StickersApp() {
|
|
|
3585
3737
|
${packs.length
|
|
3586
3738
|
? html`
|
|
3587
3739
|
<section className="space-y-2">
|
|
3588
|
-
<div className="rounded-2xl
|
|
3740
|
+
<div className="market-glass rounded-2xl p-3">
|
|
3589
3741
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
3590
3742
|
<div>
|
|
3591
3743
|
<p className="text-[11px] uppercase tracking-wide text-slate-400">Descobrir</p>
|
|
@@ -3713,7 +3865,7 @@ function StickersApp() {
|
|
|
3713
3865
|
</div>
|
|
3714
3866
|
</div>
|
|
3715
3867
|
|
|
3716
|
-
<div className="hidden lg:block rounded-2xl border border-emerald-500/20 bg-gradient-to-r from-emerald-500/10 to-cyan-500/5 p-
|
|
3868
|
+
<div className="hidden lg:block rounded-2xl border border-emerald-500/20 bg-gradient-to-r from-emerald-500/10 to-cyan-500/5 p-3">
|
|
3717
3869
|
<div className="flex items-center justify-between gap-3">
|
|
3718
3870
|
<div>
|
|
3719
3871
|
<p className="text-xs font-semibold text-emerald-100">Quer aparecer em destaque?</p>
|
|
@@ -3727,28 +3879,28 @@ function StickersApp() {
|
|
|
3727
3879
|
: null}
|
|
3728
3880
|
${packs.length
|
|
3729
3881
|
? html`
|
|
3730
|
-
<section id="catalog-packs-section" className="space-y-3 min-w-0">
|
|
3731
|
-
<div className="flex items-end justify-between gap-3">
|
|
3882
|
+
<section id="catalog-packs-section" className="space-y-3.5 min-w-0">
|
|
3883
|
+
<div className="flex flex-wrap items-end justify-between gap-3">
|
|
3732
3884
|
<div>
|
|
3733
|
-
<h2 className="text-lg sm:text-xl font-bold">Packs</h2>
|
|
3885
|
+
<h2 className="text-lg sm:text-xl font-bold">Catálogo de Packs</h2>
|
|
3734
3886
|
<p className="text-xs text-slate-400">Página ${catalogPage} · ${sortedPacks.length} resultados · ${categoryActiveLabel}</p>
|
|
3735
3887
|
</div>
|
|
3736
3888
|
<div className="hidden md:flex items-center gap-2">
|
|
3737
3889
|
<span className="text-xs text-slate-400">Ordenar por</span>
|
|
3738
|
-
<button type="button" onClick=${openSortPicker} disabled=${sortPickerBusy} className="inline-flex h-8 items-center gap-2 rounded-xl border border-slate-700 bg-slate-900 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:opacity-60">
|
|
3890
|
+
<button type="button" onClick=${openSortPicker} disabled=${sortPickerBusy} className="inline-flex h-8 items-center gap-2 rounded-xl border border-slate-700 bg-slate-900 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:opacity-60 transition">
|
|
3739
3891
|
<span>${catalogSortLabel(sortBy)}</span>
|
|
3740
3892
|
<span className="text-[10px] text-slate-400">▾</span>
|
|
3741
3893
|
</button>
|
|
3742
3894
|
</div>
|
|
3743
3895
|
</div>
|
|
3744
|
-
<div className="flex flex-wrap items-center justify-between gap-2 rounded-xl
|
|
3896
|
+
<div className="market-glass flex flex-wrap items-center justify-between gap-2 rounded-xl px-3 py-2.5">
|
|
3745
3897
|
<span className="text-xs text-slate-400">Página ${catalogPage}${packHasMore ? ' · há mais resultados' : ' · fim da lista'}</span>
|
|
3746
3898
|
<div className="flex items-center gap-2">
|
|
3747
|
-
<button type="button" onClick=${() => goToCatalogPage(catalogPage - 1, { push: true })} disabled=${!canGoCatalogPrev} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50">Anterior</button>
|
|
3748
|
-
<button type="button" onClick=${() => goToCatalogPage(catalogPage + 1, { push: true })} disabled=${!canGoCatalogNext} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50">Próxima</button>
|
|
3899
|
+
<button type="button" onClick=${() => goToCatalogPage(catalogPage - 1, { push: true })} disabled=${!canGoCatalogPrev} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50 transition">Anterior</button>
|
|
3900
|
+
<button type="button" onClick=${() => goToCatalogPage(catalogPage + 1, { push: true })} disabled=${!canGoCatalogNext} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50 transition">Próxima</button>
|
|
3749
3901
|
</div>
|
|
3750
3902
|
</div>
|
|
3751
|
-
<div className="grid min-w-0
|
|
3903
|
+
<div className="market-catalog-grid min-w-0">
|
|
3752
3904
|
${sortedPacks.map(
|
|
3753
3905
|
(pack, index) =>
|
|
3754
3906
|
html`<div key=${pack.pack_key || pack.id} className="fade-card">
|
|
@@ -3756,11 +3908,11 @@ function StickersApp() {
|
|
|
3756
3908
|
</div>`,
|
|
3757
3909
|
)}
|
|
3758
3910
|
</div>
|
|
3759
|
-
<div className="flex flex-wrap items-center justify-between gap-2 rounded-xl
|
|
3911
|
+
<div className="market-glass flex flex-wrap items-center justify-between gap-2 rounded-xl px-3 py-2.5">
|
|
3760
3912
|
<span className="text-xs text-slate-400">Página ${catalogPage}${packHasMore ? ' · há mais resultados' : ' · fim da lista'}</span>
|
|
3761
3913
|
<div className="flex items-center gap-2">
|
|
3762
|
-
<button type="button" onClick=${() => goToCatalogPage(catalogPage - 1, { push: true })} disabled=${!canGoCatalogPrev} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50">Anterior</button>
|
|
3763
|
-
<button type="button" onClick=${() => goToCatalogPage(catalogPage + 1, { push: true })} disabled=${!canGoCatalogNext} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50">Próxima</button>
|
|
3914
|
+
<button type="button" onClick=${() => goToCatalogPage(catalogPage - 1, { push: true })} disabled=${!canGoCatalogPrev} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50 transition">Anterior</button>
|
|
3915
|
+
<button type="button" onClick=${() => goToCatalogPage(catalogPage + 1, { push: true })} disabled=${!canGoCatalogNext} className="inline-flex h-8 items-center rounded-lg border border-slate-700 px-3 text-xs text-slate-200 hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50 transition">Próxima</button>
|
|
3764
3916
|
</div>
|
|
3765
3917
|
</div>
|
|
3766
3918
|
</section>
|