feat: initpage com sync Go + auth + frontend em web/
This commit is contained in:
153
web/ads.js
Normal file
153
web/ads.js
Normal file
@@ -0,0 +1,153 @@
|
||||
window.InitPageAds = [
|
||||
{
|
||||
matchCategory: "Produtividade",
|
||||
name: "Semana Flow",
|
||||
url: "https://renderpage.weltonmoura.com.br/?page=1izF8H4Gefbw4y6YwxVFO2ituUNOCrRlK",
|
||||
desc: "Flow da semana em quadro Kanbam.",
|
||||
icon: "https://play-lh.googleusercontent.com/4fzfggNueiSzUQbpVGLQDP3CX0T4KBvt4OvxddZWz24IYx2b4H1DOKtijG5od_g7WPWOF3IV-nTrkcH8HhNf",
|
||||
cover: "https://cdn-icons-png.flaticon.com/512/645/645939.png",
|
||||
clickEndpoint: null
|
||||
},
|
||||
{
|
||||
matchCategory: "Lazer",
|
||||
name: "Raul Rock Bar",
|
||||
url: "https://raulrockbar.com.br/",
|
||||
desc: "O melhor bar alternativo do Cariri🍻",
|
||||
icon: "https://raulrockbar.com.br/assets/logo.jpeg",
|
||||
cover: "https://raulrockbar.com.br/assets/logo.jpeg",
|
||||
clickEndpoint: null
|
||||
}
|
||||
];
|
||||
|
||||
(function () {
|
||||
const ADS = window.InitPageAds || [];
|
||||
|
||||
function safeUrl(url) {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
if (u.protocol === "https:" || u.protocol === "http:") return u.href;
|
||||
} catch (err) { }
|
||||
return null;
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
return String(str == null ? "" : str)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function getIconFallback(ad) {
|
||||
return safeUrl(ad.icon) || `https://www.google.com/s2/favicons?domain=${encodeURIComponent(ad.url)}&sz=128`;
|
||||
}
|
||||
|
||||
function getCoverHtml(ad) {
|
||||
const cover = safeUrl(ad.cover);
|
||||
if (!cover) {
|
||||
return '<div class="w-full h-full bg-gradient-to-tr from-slate-800 via-indigo-950 to-slate-800 flex items-center justify-center">' +
|
||||
'<svg class="w-8 h-8 text-white/25" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.4-9A4.5 4.5 0 1112.5 8H10a5 5 0 00-5 5"/></svg>' +
|
||||
"</div>";
|
||||
}
|
||||
return `<img src="${escapeHtml(cover)}" alt="${escapeHtml(ad.name)}" loading="lazy" class="w-full h-full object-cover" onerror="this.onerror=null;this.style.display='none';">`;
|
||||
}
|
||||
|
||||
function buildCard(ad, layout, cardSize) {
|
||||
const card = document.createElement("div");
|
||||
card.className = "group relative glass-card rounded-2xl overflow-hidden cursor-pointer select-none";
|
||||
card.setAttribute("role", "link");
|
||||
card.setAttribute("tabindex", "0");
|
||||
card.setAttribute("aria-label", `Conteúdo patrocinado: ${ad.name}`);
|
||||
card.dataset.sponsored = "true";
|
||||
card.title = "Patrocinado";
|
||||
|
||||
const icon = escapeHtml(getIconFallback(ad));
|
||||
const name = escapeHtml(ad.name);
|
||||
const desc = escapeHtml(ad.desc || "");
|
||||
|
||||
if (layout === "dock") {
|
||||
card.classList.add("p-2.5", "flex", "flex-col", "items-center", "w-20");
|
||||
card.innerHTML = `
|
||||
<div class="w-11 h-11 rounded-2xl glass-panel p-2 flex items-center justify-center shadow-md relative">
|
||||
<span class="absolute -top-1.5 -right-1.5 text-[8px] font-extrabold tracking-tighter bg-amber-400 text-slate-900 rounded-full w-4 h-4 flex items-center justify-center">AD</span>
|
||||
<img src="${icon}" alt="" class="w-full h-full object-contain" onerror="this.onerror=null; this.src='https://www.google.com/s2/favicons?domain=example.com';">
|
||||
</div>
|
||||
<span class="text-[10px] font-semibold text-slate-200 mt-1.5 truncate w-full text-center">${name}</span>
|
||||
`;
|
||||
} else if (layout === "list") {
|
||||
card.classList.add("flex", "items-center", "p-3", "gap-4");
|
||||
card.innerHTML = `
|
||||
<div class="w-14 h-14 rounded-xl overflow-hidden relative flex-shrink-0 bg-slate-900 border border-white/10">
|
||||
${getCoverHtml(ad)}
|
||||
<img src="${icon}" class="w-5 h-5 absolute bottom-1.5 right-1.5 glass-panel p-0.5 rounded shadow" onerror="this.onerror=null; this.src='https://www.google.com/s2/favicons?domain=example.com';">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<h4 class="text-sm font-bold text-white truncate">${name}</h4>
|
||||
<span class="px-2 py-0.5 rounded-full bg-amber-400/90 text-[10px] font-bold text-slate-900 flex-shrink-0">Patrocinado</span>
|
||||
</div>
|
||||
<p class="text-xs text-slate-400 line-clamp-3">${desc}</p>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
const bannerHeight = cardSize === "sm"
|
||||
? "h-16 sm:h-20"
|
||||
: cardSize === "lg"
|
||||
? "h-32 sm:h-36"
|
||||
: "h-24 sm:h-28";
|
||||
card.innerHTML = `
|
||||
<div class="w-full ${bannerHeight} relative overflow-hidden bg-slate-900">
|
||||
${getCoverHtml(ad)}
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-slate-950/80 via-transparent to-black/20"></div>
|
||||
<div class="absolute top-2 left-2 px-2 py-0.5 rounded-md bg-amber-400/95 text-slate-900 text-[10px] font-bold shadow">Patrocinado</div>
|
||||
<div class="shortcut-icon-box absolute bottom-2 left-3 w-8 h-8 rounded-xl glass-panel p-1.5 flex items-center justify-center shadow-lg">
|
||||
<img src="${icon}" alt="" class="w-full h-full object-contain" onerror="this.onerror=null; this.src='https://www.google.com/s2/favicons?domain=example.com';">
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 pt-2">
|
||||
<h4 class="text-xs sm:text-sm font-bold text-white truncate group-hover:text-accent transition-colors">${name}</h4>
|
||||
<p class="text-[10px] sm:text-xs text-slate-400 line-clamp-3 mt-0.5">${desc}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const url = safeUrl(ad.url);
|
||||
const open = () => {
|
||||
if (ad.clickEndpoint && navigator.sendBeacon) {
|
||||
try {
|
||||
navigator.sendBeacon(ad.clickEndpoint, new Blob([JSON.stringify({ ad: ad.url, t: Date.now() })], { type: "application/json" }));
|
||||
} catch (err) { }
|
||||
}
|
||||
if (url) window.open(url, "_blank", "noopener,noreferrer");
|
||||
};
|
||||
card.addEventListener("click", open);
|
||||
card.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
open();
|
||||
}
|
||||
});
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
function matchingAd(categoryName) {
|
||||
if (!categoryName) return null;
|
||||
const target = String(categoryName).trim().toLowerCase();
|
||||
return ADS.find(a => target.includes(String(a.matchCategory || "").trim().toLowerCase())) || null;
|
||||
}
|
||||
|
||||
function renderSponsored(detail) {
|
||||
if (!detail || detail.activeTabId === "all") return;
|
||||
const container = document.getElementById("shortcuts-container");
|
||||
if (!container) return;
|
||||
const ad = matchingAd(detail.activeTabName);
|
||||
if (!ad) return;
|
||||
container.appendChild(buildCard(ad, detail.layout || "grid", detail.cardSize || "md"));
|
||||
}
|
||||
|
||||
window.addEventListener("initpage:shortcuts-rendered", (e) => {
|
||||
renderSponsored((e && e.detail) || {});
|
||||
});
|
||||
})();
|
||||
2392
web/app.js
Normal file
2392
web/app.js
Normal file
File diff suppressed because it is too large
Load Diff
16
web/icon.svg
Normal file
16
web/icon.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<rect width="512" height="512" rx="96" fill="#0f172a"/>
|
||||
<rect width="512" height="512" rx="96" fill="url(#g)"/>
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#2563eb"/>
|
||||
<stop offset="1" stop-color="#7c3aed"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g fill="none" stroke="#ffffff" stroke-width="28" stroke-linecap="round">
|
||||
<rect x="128" y="128" width="112" height="112" rx="24"/>
|
||||
<rect x="272" y="128" width="112" height="112" rx="24"/>
|
||||
<rect x="128" y="272" width="112" height="112" rx="24"/>
|
||||
<rect x="272" y="272" width="112" height="112" rx="24"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 702 B |
899
web/index.html
Normal file
899
web/index.html
Normal file
@@ -0,0 +1,899 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR" class="h-full">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<base href="/initpage/">
|
||||
<title>InitPage — Seu navegador, personalizado</title>
|
||||
<meta name="description" content="Pagina inicial personalizavel com atalhos, categorias, busca e plano de fundo. Tudo salvo localmente no seu navegador.">
|
||||
<meta name="theme-color" content="#0f172a">
|
||||
<link rel="icon" href="https://www.google.com/s2/favicons?domain=weltonmoura.com.br&sz=128">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<!-- Open Graph / Social -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="InitPage — Seu navegador, personalizado">
|
||||
<meta property="og:description" content="Pagina inicial personalizavel com atalhos, categorias, busca e plano de fundo.">
|
||||
<meta property="og:url" content="https://apps.weltonmoura.com.br/initpage/">
|
||||
<meta property="og:site_name" content="InitPage">
|
||||
<meta property="og:image" content="https://apps.weltonmoura.com.br/initpage/icon.svg">
|
||||
<meta name="twitter:card" content="summary">
|
||||
|
||||
<!-- Tailwind CSS CDN -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
<!-- Ícones Lucide -->
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
|
||||
<!-- Anúncios patrocinados (injeção independente, fora do estado/export) -->
|
||||
<script src="ads.js" defer></script>
|
||||
|
||||
<!-- Fonte Google Plus Jakarta Sans -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['"Plus Jakarta Sans"', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
accent: 'var(--accent-color)',
|
||||
'accent-hover': 'var(--accent-hover)',
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fadeIn 0.3s ease-out forwards',
|
||||
'slide-up': 'slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards',
|
||||
},
|
||||
keyframes: {
|
||||
fadeIn: {
|
||||
'0%': { opacity: '0' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
slideUp: {
|
||||
'0%': { opacity: '0', transform: 'translateY(12px)' },
|
||||
'100%': { opacity: '1', transform: 'translateY(0)' },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body class="h-full bg-slate-950 text-slate-100 font-sans antialiased overflow-x-hidden relative flex flex-col justify-between pb-14 sm:pb-0 sm:pr-12 sm:pl-0">
|
||||
|
||||
<!-- Fundo com Imagem e Máscara -->
|
||||
<div id="bg-cover" class="fixed inset-0 bg-cover bg-center transition-all duration-700 -z-20 transform scale-105"></div>
|
||||
<div id="bg-overlay" class="fixed inset-0 bg-black/60 transition-all duration-500 -z-10"></div>
|
||||
|
||||
<!-- Notificação Toast Flutuante -->
|
||||
<div id="toast" role="status" aria-live="polite" class="fixed bottom-6 right-6 z-[90] transform translate-y-16 opacity-0 transition-all duration-300 pointer-events-none flex items-center gap-3 px-4 py-3 rounded-2xl glass-panel text-sm text-white shadow-2xl">
|
||||
<i id="toast-icon" data-lucide="info" class="w-4 h-4 text-accent"></i>
|
||||
<span id="toast-msg">Notificação</span>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Lateral Direita (desktop) e Barra Inferior (mobile) -->
|
||||
<aside id="app-sidebar" class="fixed right-0 top-auto bottom-0 w-full h-12 z-600 flex flex-row items-center justify-center px-2 gap-2 border-t border-white/10 sm:top-0 sm:bottom-0 sm:right-0 sm:left-auto sm:w-12 sm:h-auto sm:flex-col sm:justify-start sm:pt-4 sm:pb-4 sm:border-t-0 sm:border-l sm:border-white/10 sm:border-r-0">
|
||||
<button id="clock-calendar-trigger" title="Calendário" aria-label="Abrir Calendário" class="sidebar-btn relative group">
|
||||
<i data-lucide="calendar" class="w-6 h-6"></i>
|
||||
</button>
|
||||
<button id="btn-open-tasks" title="Tarefas" aria-label="Abrir Tarefas" class="sidebar-btn relative group">
|
||||
<i data-lucide="clipboard-list" class="w-6 h-6"></i>
|
||||
<span id="tasks-dot-badge" class="hidden absolute -top-0.5 -right-0.5 w-2 h-2 rounded-full bg-amber-400 animate-pulse"></span>
|
||||
</button>
|
||||
<button id="btn-open-notes" title="Notas" aria-label="Abrir Notas" class="sidebar-btn relative group" style="color: var(--accent-color);">
|
||||
<i data-lucide="sticky-note" class="w-6 h-6"></i>
|
||||
</button>
|
||||
<div class="hidden sm:block flex-1"></div>
|
||||
<button id="btn-open-settings" title="Configurações e Customização" aria-label="Abrir Configurações" class="sidebar-btn relative group">
|
||||
<i data-lucide="settings" class="w-6 h-6 group-hover:rotate-45 transition-transform duration-300"></i>
|
||||
</button>
|
||||
</aside>
|
||||
|
||||
<!-- Barra Superior / Cabeçalho Minimalista -->
|
||||
<header class="w-full px-5 sm:px-8 py-4 flex items-center justify-end z-30 animate-fade-in">
|
||||
</header>
|
||||
|
||||
<!-- Área Central de Conteúdo -->
|
||||
<main class="w-full max-w-6xl mx-auto px-4 sm:px-8 pt-4 sm:pt-3 pb-12 sm:pb-12 flex-1 flex flex-col items-center justify-start gap-5 sm:gap-7 z-10">
|
||||
|
||||
<!-- 1. BLOCO INTEGRADO: RELÓGIO + DATA + SAUDAÇÃO (Gatilho do Calendário) -->
|
||||
<section class="w-full flex flex-col items-center justify-center animate-slide-up">
|
||||
<button id="clock-calendar-trigger" type="button" class="group flex flex-col items-center justify-center p-3 sm:p-4 rounded-3xl hover:bg-white/5 transition-all duration-300 active:scale-[0.99] cursor-pointer outline-none select-none" title="Clique para expandir o calendário">
|
||||
<h1 id="clock-display" class="text-6xl sm:text-7xl md:text-8xl font-black tracking-tight text-white drop-shadow-md group-hover:scale-[1.02] transition-transform duration-300">
|
||||
00:00
|
||||
</h1>
|
||||
|
||||
<!-- Elemento de Data e Saudação Integrados sem Borda e sem Animação -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-2 mt-2 text-sm sm:text-base font-medium text-slate-300">
|
||||
<span class="text-xs sm:text-sm text-slate-200 font-medium flex items-center gap-1.5">
|
||||
<span id="header-date">Carregando data...</span>
|
||||
<i data-lucide="calendar" class="w-3.5 h-3.5 text-accent opacity-80 ml-0.5"></i>
|
||||
</span>
|
||||
|
||||
<span class="text-slate-400 hidden sm:inline">•</span>
|
||||
|
||||
<div class="text-slate-200 font-light drop-shadow">
|
||||
<span id="greeting-text">Olá</span>,
|
||||
<span id="user-display-name" class="font-bold text-white tracking-wide underline decoration-accent decoration-2 underline-offset-4 hover:opacity-85 transition" title="Alterar nome">Visitante</span>!
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<!-- Informação de Tempo (meteorológico) -->
|
||||
<div id="weather-info" class="hidden mt-1">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs sm:text-sm text-slate-300 font-medium glass-card px-3 py-1 rounded-full">
|
||||
<span id="weather-icon">☀️</span>
|
||||
<span id="weather-temp">--°</span>
|
||||
<span class="text-slate-500">·</span>
|
||||
<span id="weather-city" class="capitalize">Cidade</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- ==================== COMPONENTE DE CALENDÁRIO INTEGRADO À PÁGINA ==================== -->
|
||||
<div id="calendar-widget" class="hidden mt-3 w-[92vw] sm:w-[26rem] md:w-[28rem] rounded-3xl glass-translucent p-4 border border-white/15 animate-fade-in">
|
||||
<!-- Topo do Widget de Calendário -->
|
||||
<div class="flex items-center justify-between pb-3 border-b border-white/10 mb-3">
|
||||
<button type="button" id="cal-prev-month" aria-label="Mês anterior" class="p-1.5 rounded-xl hover:bg-white/15 text-slate-300 hover:text-white transition active:scale-95">
|
||||
<i data-lucide="chevron-left" class="w-4 h-4"></i>
|
||||
</button>
|
||||
|
||||
<div class="text-center">
|
||||
<h4 id="cal-month-year" class="text-xs sm:text-sm font-bold text-white capitalize tracking-wide">Mês Ano</h4>
|
||||
</div>
|
||||
|
||||
<button type="button" id="cal-next-month" aria-label="Próximo mês" class="p-1.5 rounded-xl hover:bg-white/15 text-slate-300 hover:text-white transition active:scale-95">
|
||||
<i data-lucide="chevron-right" class="w-4 h-4"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Cabeçalho dos Dias da Semana -->
|
||||
<div class="grid grid-cols-7 text-center text-[10px] font-bold text-slate-400 mb-2">
|
||||
<span>DOM</span>
|
||||
<span>SEG</span>
|
||||
<span>TER</span>
|
||||
<span>QUA</span>
|
||||
<span>QUI</span>
|
||||
<span>SEX</span>
|
||||
<span>SÁB</span>
|
||||
</div>
|
||||
|
||||
<!-- Grade de Dias do Mês -->
|
||||
<div id="cal-days-grid" class="grid grid-cols-7 gap-1 text-center text-xs">
|
||||
<!-- Dias renderizados dinamicamente via JS -->
|
||||
</div>
|
||||
|
||||
<!-- Tarefas do Dia Selecionado -->
|
||||
<div id="cal-day-tasks" class="hidden mt-3 pt-2.5 border-t border-white/10 space-y-1.5 max-h-44 overflow-y-auto pr-1">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Tarefas do dia</p>
|
||||
<button id="btn-add-task-from-day" type="button" class="px-1.5 py-0.5 rounded-md bg-white/10 hover:bg-white/20 text-[9px] text-slate-300 flex items-center gap-1" title="Adicionar tarefa neste dia" aria-label="Adicionar tarefa neste dia">
|
||||
<i data-lucide="plus" class="w-2.5 h-2.5"></i> Adicionar
|
||||
</button>
|
||||
</div>
|
||||
<div id="cal-day-tasks-list" class="space-y-1.5">
|
||||
<!-- Renderizado dinamicamente via JS -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rodapé do Widget -->
|
||||
<div class="mt-3 pt-2.5 border-t border-white/10 flex items-center justify-between text-[11px] text-slate-400">
|
||||
<span id="cal-selected-info" aria-live="polite">Hoje</span>
|
||||
<button type="button" id="cal-btn-today" class="text-accent hover:underline font-semibold cursor-pointer">Ir para Hoje</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. BARRA DE PESQUISA COM O MESMO FUNDO DOS CARDS (glass-card) -->
|
||||
<section class="w-full max-w-2xl relative z-40 animate-slide-up">
|
||||
<form id="search-form" class="relative flex items-center glass-card rounded-2xl p-1.5 shadow-2xl focus-within:ring-2 focus-within:ring-accent focus-within:border-accent transition-all duration-300">
|
||||
|
||||
<!-- Dropdown Seletor de Buscador -->
|
||||
<div class="relative">
|
||||
<button type="button" id="search-engine-btn" class="flex items-center gap-1.5 sm:gap-2 px-2.5 sm:px-3.5 py-2 rounded-xl hover:bg-white/10 text-xs font-semibold text-slate-100 transition active:scale-95">
|
||||
<span id="search-engine-icon" class="text-base">🌐</span>
|
||||
<span id="search-engine-label" class="hidden sm:inline">Google</span>
|
||||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 opacity-70"></i>
|
||||
</button>
|
||||
|
||||
<div id="search-engine-menu" class="hidden absolute top-full left-0 mt-2 w-48 rounded-2xl glass-panel py-1.5 shadow-2xl border border-white/20 z-50 overflow-hidden">
|
||||
<button type="button" data-engine="google" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">🌐</span> Google
|
||||
</button>
|
||||
<button type="button" data-engine="duckduckgo" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">🦆</span> DuckDuckGo
|
||||
</button>
|
||||
<button type="button" data-engine="bing" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">🔎</span> Bing
|
||||
</button>
|
||||
<button type="button" data-engine="brave" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">🦁</span> Brave
|
||||
</button>
|
||||
<button type="button" data-engine="youtube" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">▶️</span> YouTube
|
||||
</button>
|
||||
<button type="button" data-engine="github" class="engine-opt w-full px-3.5 py-2.5 text-left text-xs text-slate-200 hover:bg-white/15 flex items-center gap-2.5 transition">
|
||||
<span class="text-base">🐙</span> GitHub
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="search-input"
|
||||
placeholder="Pesquisar ou digitar URL..."
|
||||
autocomplete="off"
|
||||
class="flex-1 bg-transparent px-3 py-2 text-sm sm:text-base text-white placeholder-slate-400 focus:outline-none min-w-0"
|
||||
>
|
||||
|
||||
<button type="submit" title="Buscar em nova aba" aria-label="Buscar em nova aba" class="p-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white transition shadow-md flex items-center justify-center flex-shrink-0 active:scale-95">
|
||||
<i data-lucide="arrow-right" class="w-4 h-4"></i>
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- 3. SEÇÃO DE ABAS DE CATEGORIAS E ATALHOS -->
|
||||
<section class="w-full relative z-10 space-y-3.5">
|
||||
|
||||
<!-- Linha de Abas com o Botão '+' ao final -->
|
||||
<div class="flex items-center justify-between gap-3 border-b border-white/10 pb-2">
|
||||
<div id="tabs-wrapper" class="flex items-center gap-2 overflow-x-auto no-scrollbar py-1 flex-1 pr-2">
|
||||
<!-- Abas renderizadas dinamicamente + botão '+' de gerenciar categorias -->
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 flex-shrink-0 text-xs text-slate-400 pl-2 border-l border-white/10">
|
||||
<span id="shortcuts-count" class="font-medium whitespace-nowrap">0 atalhos</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Grade / Lista / Dock de Atalhos (com o Card '+' ao final) -->
|
||||
<div id="shortcuts-container" class="min-h-[140px] w-full">
|
||||
<!-- Renderizado dinamicamente via JavaScript -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<!-- Rodapé -->
|
||||
<footer class="w-full px-6 py-3 pb-16 sm:pb-3 flex flex-col items-center gap-2 text-xs text-slate-400/80 z-10">
|
||||
<div class="w-full flex flex-col sm:flex-row items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 text-[11px] text-slate-500">
|
||||
<a href="https://weltonmoura.com.br/initpage/politica-privacidade/" class="hover:text-white transition">Política de Privacidade</a>
|
||||
<span class="text-slate-700">•</span>
|
||||
<a href="https://weltonmoura.com.br/initpage/termos-servico/" class="hover:text-white transition">Termos de Serviço</a>
|
||||
<span class="text-slate-700">•</span>
|
||||
<span>by <a href="https://weltonmoura.com.br/" class="hover:text-amber-400 text-white transition">Welton Moura</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- ==================== MODAL DE ADICIONAR / EDITAR ATALHO (Z-50) ==================== -->
|
||||
<div id="modal-shortcut" role="dialog" aria-modal="true" class="fixed inset-0 z-50 hidden flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl relative max-h-[92vh] overflow-y-auto">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 id="modal-shortcut-title" class="text-lg font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="bookmark-plus" class="w-5 h-5 text-accent"></i>
|
||||
Novo Atalho
|
||||
</h3>
|
||||
<button id="btn-close-shortcut-modal" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="form-shortcut" class="space-y-3.5 text-xs">
|
||||
<input type="hidden" id="input-shortcut-id">
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Nome do Atalho *</label>
|
||||
<input type="text" id="input-shortcut-name" required placeholder="Ex: GitHub, YouTube, Notícias" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Endereço Web (URL) *</label>
|
||||
<input type="text" id="input-shortcut-url" required placeholder="exemplo.com ou https://exemplo.com" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Categoria *</label>
|
||||
<div class="flex gap-2">
|
||||
<select id="input-shortcut-category" class="flex-1 bg-slate-900/80 border border-white/15 rounded-xl px-3 py-2.5 text-xs text-white focus:outline-none focus:border-accent">
|
||||
<!-- Categorias inseridas dinamicamente -->
|
||||
</select>
|
||||
<button type="button" id="btn-shortcut-new-cat" class="px-3 py-2 rounded-xl bg-white/10 hover:bg-white/20 text-white font-medium text-xs transition flex items-center gap-1" title="Gerenciar Categorias">
|
||||
<i data-lucide="settings-2" class="w-3 h-3 text-accent"></i> Gerenciar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Imagem de Capa (Edge-to-Edge)</label>
|
||||
<input type="url" id="input-shortcut-cover" placeholder="URL da imagem (ou deixe vazio para gradiente elegante)" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Descrição (opcional)</label>
|
||||
<input type="text" id="input-shortcut-desc" placeholder="Ex: Comunidade de programadores" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Ícone Personalizado (opcional)</label>
|
||||
<input type="url" id="input-shortcut-icon" placeholder="Deixe vazio para obter o favicon oficial" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-2.5 pt-4 border-t border-white/10">
|
||||
<button type="button" id="btn-cancel-shortcut" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition">Cancelar</button>
|
||||
<button type="submit" class="px-5 py-2 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold transition shadow-lg flex items-center gap-2">
|
||||
<i data-lucide="check" class="w-4 h-4"></i> Salvar Atalho
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE GERENCIAR CATEGORIAS (CRUD) (Z-[60]) ==================== -->
|
||||
<div id="modal-categories" role="dialog" aria-modal="true" class="fixed inset-0 z-[60] hidden flex items-center justify-center p-4 bg-black/80 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl relative space-y-4">
|
||||
<div class="flex items-center justify-between border-b border-white/10 pb-3">
|
||||
<h3 class="text-base font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="tags" class="w-5 h-5 text-accent"></i>
|
||||
Gerenciar Categorias
|
||||
</h3>
|
||||
<button id="btn-close-categories-modal" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Formulário de Criação/Edição de Categoria -->
|
||||
<form id="form-category" class="space-y-3">
|
||||
<input type="hidden" id="input-cat-id">
|
||||
<div class="flex gap-2">
|
||||
<input type="text" id="input-cat-name" required placeholder="Nome da categoria..." class="flex-1 bg-slate-900/90 border border-white/20 rounded-xl px-3.5 py-2 text-xs text-white focus:outline-none focus:border-accent">
|
||||
<button type="submit" id="btn-submit-cat" class="px-4 py-2 rounded-xl bg-accent hover:bg-accent-hover text-white text-xs font-semibold transition shadow flex items-center gap-1.5">
|
||||
<i data-lucide="plus" class="w-3.5 h-3.5"></i>
|
||||
<span id="btn-submit-cat-text">Adicionar</span>
|
||||
</button>
|
||||
<button type="button" id="btn-cancel-cat-edit" class="hidden px-3 py-2 rounded-xl bg-white/10 hover:bg-white/20 text-slate-300 text-xs transition">
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Lista de Categorias com Ações -->
|
||||
<div class="space-y-1.5 max-h-60 overflow-y-auto pr-1" id="categories-crud-list">
|
||||
<!-- Itens de categoria gerados dinamicamente -->
|
||||
</div>
|
||||
|
||||
<div class="pt-3 border-t border-white/10 flex justify-between items-center text-xs text-slate-400">
|
||||
<span>Arraste as abas na tela para mudar a ordem.</span>
|
||||
<button type="button" id="btn-done-categories" class="px-4 py-1.5 rounded-xl bg-white/10 hover:bg-white/20 text-white font-medium transition">
|
||||
Concluir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE CONFIRMAÇÃO DE EXCLUSÃO DE CATEGORIA (Z-[70]) ==================== -->
|
||||
<div id="modal-delete-cat-confirm" role="dialog" aria-modal="true" class="fixed inset-0 z-[70] hidden flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl border border-rose-500/30 text-center space-y-4">
|
||||
<div class="w-12 h-12 rounded-full bg-rose-500/20 text-rose-400 flex items-center justify-center mx-auto">
|
||||
<i data-lucide="folder-x" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white">Excluir categoria?</h3>
|
||||
<p id="delete-cat-confirm-text" class="text-xs text-slate-300 mt-1">Os atalhos associados a ela serão movidos para Geral.</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-3 pt-2">
|
||||
<button type="button" id="btn-cancel-cat-delete" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="button" id="btn-confirm-cat-delete" class="px-5 py-2 rounded-xl bg-rose-600 hover:bg-rose-500 text-white font-semibold transition text-xs shadow-lg">
|
||||
Excluir Categoria
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE CONFIRMAÇÃO DE EXCLUSÃO DE ATALHO ==================== -->
|
||||
<div id="modal-delete-confirm" role="dialog" aria-modal="true" class="fixed inset-0 z-50 hidden flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl border border-rose-500/20 text-center space-y-4">
|
||||
<div class="w-12 h-12 rounded-full bg-rose-500/20 text-rose-400 flex items-center justify-center mx-auto">
|
||||
<i data-lucide="alert-triangle" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white">Excluir este atalho?</h3>
|
||||
<p id="delete-confirm-text" class="text-xs text-slate-300 mt-1">Essa ação não pode ser desfeita.</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-3 pt-2">
|
||||
<button type="button" id="btn-cancel-delete" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="button" id="btn-confirm-delete" class="px-5 py-2 rounded-xl bg-rose-600 hover:bg-rose-500 text-white font-semibold transition text-xs shadow-lg">
|
||||
Sim, Excluir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE COLAR JSON ==================== -->
|
||||
<div id="modal-paste-json" role="dialog" aria-modal="true" class="fixed inset-0 z-[70] hidden flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="clipboard-paste" class="w-5 h-5 text-accent"></i>
|
||||
Colar JSON
|
||||
</h3>
|
||||
<button id="btn-close-paste" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<textarea id="input-paste-json" rows="8" placeholder="Cole aqui o conteúdo do arquivo .json..." class="w-full bg-slate-900/90 border border-white/15 rounded-xl px-3.5 py-2.5 text-xs text-white font-mono focus:outline-none focus:border-accent resize-y"></textarea>
|
||||
<div class="flex items-center justify-end gap-2.5 pt-2 border-t border-white/10">
|
||||
<button type="button" id="btn-cancel-paste" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">Cancelar</button>
|
||||
<button type="button" id="btn-confirm-paste" class="px-5 py-2 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold transition text-xs shadow-lg">Importar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== DRAWER DE CONFIGURAÇÕES ==================== -->
|
||||
<div id="modal-settings" role="dialog" aria-modal="true" class="fixed inset-0 z-50 hidden flex justify-end bg-black/60 backdrop-blur-sm animate-fade-in">
|
||||
<div class="w-full max-w-md h-full modal-panel p-6 overflow-y-auto border-l border-white/15 shadow-2xl flex flex-col justify-between">
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-between pb-4 border-b border-white/10">
|
||||
<div class="flex items-center gap-2.5">
|
||||
<i data-lucide="sliders" class="w-5 h-5 text-accent"></i>
|
||||
<h2 class="text-lg font-bold text-white">Configurações</h2>
|
||||
</div>
|
||||
<button id="btn-close-settings" aria-label="Fechar Configurações" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Perfil -->
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Identificação</label>
|
||||
<div>
|
||||
<label class="block text-xs text-slate-300 mb-1">Seu Nome / Apelido</label>
|
||||
<input type="text" id="setting-user-name" class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-slate-300 mb-1">Cidade (para o clima)</label>
|
||||
<input type="text" id="setting-city" placeholder="Ex: São Paulo, Rio de Janeiro..." class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2 text-sm text-white focus:outline-none focus:border-accent">
|
||||
<p class="text-[10px] text-slate-500 mt-1">Deixe vazio para ocultar o clima ao lado do relógio.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fundo -->
|
||||
<div class="space-y-3">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Plano de Fundo</label>
|
||||
<div>
|
||||
<label class="block text-xs text-slate-300 mb-1">URL da Imagem de Fundo</label>
|
||||
<div class="flex gap-2">
|
||||
<input type="url" id="setting-bg-url" placeholder="https://images.unsplash.com/..." class="flex-1 bg-slate-900/80 border border-white/15 rounded-xl px-3 py-2 text-xs text-white focus:outline-none focus:border-accent">
|
||||
<button id="btn-apply-bg" class="px-3 py-2 bg-white/10 hover:bg-white/20 rounded-xl text-xs font-semibold text-white transition">Aplicar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs text-slate-400 mb-1.5">Predefinições Rápidas</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<button type="button" class="preset-bg rounded-lg h-12 bg-cover bg-center border border-white/20 hover:scale-105 transition" style="background-image: url('https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=600&q=70')" data-url="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=1920&q=85"></button>
|
||||
<button type="button" class="preset-bg rounded-lg h-12 bg-cover bg-center border border-white/20 hover:scale-105 transition" style="background-image: url('https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=600&q=70')" data-url="https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=1920&q=85"></button>
|
||||
<button type="button" class="preset-bg rounded-lg h-12 bg-cover bg-center border border-white/20 hover:scale-105 transition" style="background-image: url('https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=600&q=70')" data-url="https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=1920&q=85"></button>
|
||||
<button type="button" class="preset-bg rounded-lg h-12 bg-cover bg-center border border-white/20 hover:scale-105 transition" style="background-image: url('https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=600&q=70')" data-url="https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=1920&q=85"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex justify-between text-xs text-slate-300 mb-1">
|
||||
<span>Escurecimento do Fundo</span>
|
||||
<span id="val-bg-dim">60%</span>
|
||||
</div>
|
||||
<input type="range" id="setting-bg-dim" min="10" max="95" value="60" class="w-full accent-accent cursor-pointer">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cores -->
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Cor de Destaque</label>
|
||||
<div class="flex items-center gap-3">
|
||||
<button type="button" data-accent="#3b82f6" data-hover="#2563eb" class="theme-color w-7 h-7 rounded-full bg-blue-500 ring-2 ring-white/20 hover:scale-110 transition"></button>
|
||||
<button type="button" data-accent="#10b981" data-hover="#059669" class="theme-color w-7 h-7 rounded-full bg-emerald-500 ring-2 ring-white/20 hover:scale-110 transition"></button>
|
||||
<button type="button" data-accent="#8b5cf6" data-hover="#7c3aed" class="theme-color w-7 h-7 rounded-full bg-purple-500 ring-2 ring-white/20 hover:scale-110 transition"></button>
|
||||
<button type="button" data-accent="#f43f5e" data-hover="#e11d48" class="theme-color w-7 h-7 rounded-full bg-rose-500 ring-2 ring-white/20 hover:scale-110 transition"></button>
|
||||
<button type="button" data-accent="#f59e0b" data-hover="#d97706" class="theme-color w-7 h-7 rounded-full bg-amber-500 ring-2 ring-white/20 hover:scale-110 transition"></button>
|
||||
|
||||
<div class="flex items-center ml-auto">
|
||||
<label for="setting-custom-color" class="text-[11px] text-slate-300 mr-2">Outra:</label>
|
||||
<input type="color" id="setting-custom-color" value="#3b82f6" class="w-7 h-7 rounded-full cursor-pointer bg-transparent border-0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout e Tamanho dos Cards -->
|
||||
<div class="space-y-3">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Estilo dos Atalhos</label>
|
||||
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<button type="button" data-layout="grid" class="layout-btn p-2.5 rounded-xl glass-panel text-center text-xs font-semibold text-white border border-transparent hover:border-accent transition flex flex-col items-center gap-1">
|
||||
<i data-lucide="layout-grid" class="w-4 h-4"></i>
|
||||
<span>Grade</span>
|
||||
</button>
|
||||
<button type="button" data-layout="dock" class="layout-btn p-2.5 rounded-xl glass-panel text-center text-xs font-semibold text-white border border-transparent hover:border-accent transition flex flex-col items-center gap-1">
|
||||
<i data-lucide="panel-bottom" class="w-4 h-4"></i>
|
||||
<span>Dock</span>
|
||||
</button>
|
||||
<button type="button" data-layout="list" class="layout-btn p-2.5 rounded-xl glass-panel text-center text-xs font-semibold text-white border border-transparent hover:border-accent transition flex flex-col items-center gap-1">
|
||||
<i data-lucide="list" class="w-4 h-4"></i>
|
||||
<span>Lista</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-1">
|
||||
<label class="block text-xs text-slate-300 mb-1.5">Tamanho dos Cards</label>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<button type="button" data-size="sm" class="size-btn py-2 rounded-xl glass-panel text-xs text-center text-slate-200 hover:text-white transition">Pequeno</button>
|
||||
<button type="button" data-size="md" class="size-btn py-2 rounded-xl glass-panel text-xs text-center text-slate-200 hover:text-white transition">Médio</button>
|
||||
<button type="button" data-size="lg" class="size-btn py-2 rounded-xl glass-panel text-xs text-center text-slate-200 hover:text-white transition">Grande</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sincronização na Nuvem -->
|
||||
<div class="pt-3 border-t border-white/10 space-y-3">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Sincronização na Nuvem</label>
|
||||
|
||||
<div class="rounded-2xl bg-white/5 border border-white/10 p-3 space-y-2.5">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-xl bg-accent/20 flex items-center justify-center">
|
||||
<i data-lucide="cloud" class="w-4 h-4 text-accent"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p id="sync-status-title" class="text-xs font-semibold text-white">Não conectado</p>
|
||||
<p id="sync-status-sub" class="text-[11px] text-slate-400">Faça login para sincronizar</p>
|
||||
</div>
|
||||
</div>
|
||||
<span id="sync-badge" class="hidden px-2 py-0.5 rounded-full text-[10px] bg-emerald-500/20 text-emerald-300 font-semibold">Sincronizado</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<button id="btn-sync-login" class="flex items-center justify-center gap-2 px-3 py-2 rounded-xl bg-accent/90 hover:bg-accent text-xs font-semibold text-white transition">
|
||||
<i data-lucide="log-in" class="w-3.5 h-3.5"></i> Entrar / Cadastrar
|
||||
</button>
|
||||
<button id="btn-sync-now" class="flex items-center justify-center gap-2 px-3 py-2 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold text-white transition disabled:opacity-40 disabled:pointer-events-none">
|
||||
<i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i> Sincronizar agora
|
||||
</button>
|
||||
</div>
|
||||
<button id="btn-sync-logout" class="hidden w-full flex items-center justify-center gap-2 px-3 py-2 rounded-xl bg-white/5 hover:bg-white/10 text-xs font-medium text-slate-300 transition">
|
||||
<i data-lucide="log-out" class="w-3.5 h-3.5"></i> Sair da conta
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dados -->
|
||||
<div class="pt-3 border-t border-white/10 space-y-3">
|
||||
<label class="block text-xs uppercase tracking-wider font-semibold text-slate-400">Dados</label>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2.5">
|
||||
<button id="btn-export-json" class="flex items-center justify-center gap-2 px-3 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold text-white transition">
|
||||
<i data-lucide="download" class="w-4 h-4 text-emerald-400"></i> Exportar
|
||||
</button>
|
||||
<label class="flex items-center justify-center gap-2 px-3 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold text-white transition cursor-pointer">
|
||||
<i data-lucide="upload" class="w-4 h-4 text-cyan-400"></i> Importar
|
||||
<input type="file" id="file-import-json" accept=".json" class="hidden">
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-2.5">
|
||||
<button id="btn-copy-json" class="flex items-center justify-center gap-2 px-3 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold text-white transition">
|
||||
<i data-lucide="copy" class="w-4 h-4 text-amber-400"></i> Copiar JSON
|
||||
</button>
|
||||
<button id="btn-paste-json" class="flex items-center justify-center gap-2 px-3 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold text-white transition">
|
||||
<i data-lucide="clipboard-paste" class="w-4 h-4 text-sky-400"></i> Colar JSON
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-6 mt-6 border-t border-white/10">
|
||||
<button id="btn-save-settings" class="w-full py-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold text-xs transition shadow-lg">
|
||||
Concluir e Fechar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE LOGIN/CADASTRO ==================== -->
|
||||
<div id="modal-auth" role="dialog" aria-modal="true" class="fixed inset-0 z-[80] hidden flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl space-y-4">
|
||||
<div class="flex items-center justify-between border-b border-white/10 pb-3">
|
||||
<h3 class="text-base font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="cloud" class="w-5 h-5 text-accent"></i>
|
||||
Sincronizar na nuvem
|
||||
</h3>
|
||||
<button id="btn-close-auth-modal" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Abas Auth -->
|
||||
<div class="flex items-center bg-white/5 rounded-xl p-1 text-xs">
|
||||
<button type="button" data-auth-tab="login" class="auth-tab-btn flex-1 py-1.5 rounded-lg font-semibold text-white bg-white/15 transition">Entrar</button>
|
||||
<button type="button" data-auth-tab="register" class="auth-tab-btn flex-1 py-1.5 rounded-lg font-semibold text-slate-300 hover:text-white transition">Criar conta</button>
|
||||
</div>
|
||||
|
||||
<!-- Login -->
|
||||
<form id="form-login" class="space-y-3 text-xs">
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">E-mail</label>
|
||||
<input type="email" id="login-email" required autocomplete="email" placeholder="seu@email.com" class="w-full bg-slate-900/90 border border-white/20 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Senha</label>
|
||||
<input type="password" id="login-password" required autocomplete="current-password" placeholder="••••••••" class="w-full bg-slate-900/90 border border-white/20 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<button type="submit" class="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold transition shadow-lg">
|
||||
<i data-lucide="log-in" class="w-4 h-4"></i> Entrar
|
||||
</button>
|
||||
<p id="login-error" class="text-rose-400 text-[11px] hidden"></p>
|
||||
</form>
|
||||
|
||||
<!-- Registro -->
|
||||
<form id="form-register" class="space-y-3 text-xs hidden">
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">E-mail</label>
|
||||
<input type="email" id="reg-email" required autocomplete="email" placeholder="seu@email.com" class="w-full bg-slate-900/90 border border-white/20 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Senha (mín. 6 caracteres)</label>
|
||||
<input type="password" id="reg-password" required minlength="6" autocomplete="new-password" placeholder="••••••••" class="w-full bg-slate-900/90 border border-white/20 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<input type="text" name="website" id="reg-honeypot" tabindex="-1" autocomplete="off" class="hidden">
|
||||
<button type="submit" class="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold transition shadow-lg">
|
||||
<i data-lucide="user-plus" class="w-4 h-4"></i> Criar conta
|
||||
</button>
|
||||
<p id="reg-error" class="text-rose-400 text-[11px] hidden"></p>
|
||||
</form>
|
||||
|
||||
<p class="text-[11px] text-slate-400 leading-relaxed">
|
||||
Seus atalhos, categorias, tarefas, notas e configurações são sincronizados com segurança na sua conta.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DE MERGE SYNC ==================== -->
|
||||
<div id="modal-sync-merge" role="dialog" aria-modal="true" class="fixed inset-0 z-[90] hidden flex items-center justify-center p-4 bg-black/90 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl space-y-4 text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-accent/20 text-accent flex items-center justify-center mx-auto">
|
||||
<i data-lucide="cloud-download" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white">Dados encontrados na nuvem</h3>
|
||||
<p class="text-xs text-slate-300 mt-2 leading-relaxed">
|
||||
Há configurações salvas nessa conta. O que deseja fazer?
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-2 pt-2">
|
||||
<button id="btn-sync-download" class="w-full px-4 py-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold text-xs transition shadow-lg flex items-center justify-center gap-2">
|
||||
<i data-lucide="download-cloud" class="w-4 h-4"></i> Substituir local pelos dados da nuvem
|
||||
</button>
|
||||
<button id="btn-sync-upload" class="w-full px-4 py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-white font-semibold text-xs transition flex items-center justify-center gap-2">
|
||||
<i data-lucide="upload-cloud" class="w-4 h-4"></i> Enviar dados locais para a nuvem
|
||||
</button>
|
||||
<button id="btn-sync-cancel" class="w-full px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PAINEL DE TAREFAS (slide esquerda) ==================== -->
|
||||
<div id="panel-tasks" role="dialog" aria-modal="true" class="fixed inset-0 z-[55] hidden">
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm animate-fade-in" data-close-panel="panel-tasks"></div>
|
||||
<div class="absolute left-0 top-0 h-full w-full sm:max-w-md modal-panel border-r border-white/15 flex flex-col">
|
||||
<div class="flex items-center justify-between p-5 border-b border-white/10 flex-shrink-0">
|
||||
<h2 class="text-base font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="clipboard-list" class="w-5 h-5 text-accent"></i>
|
||||
Tarefas
|
||||
</h2>
|
||||
<button id="btn-close-tasks" aria-label="Fechar Tarefas" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="px-5 py-3 flex-shrink-0">
|
||||
<button id="btn-new-task" class="w-full py-2.5 rounded-xl bg-accent hover:bg-accent-hover text-white text-xs font-semibold transition shadow flex items-center justify-center gap-2">
|
||||
<i data-lucide="plus" class="w-4 h-4"></i> Nova Tarefa
|
||||
</button>
|
||||
</div>
|
||||
<div id="tasks-list" class="flex-1 overflow-y-auto px-5 pb-5 space-y-2">
|
||||
<!-- Itens renderizados dinamicamente -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL DETALHE DA TAREFA ==================== -->
|
||||
<div id="modal-task-detail" role="dialog" aria-modal="true" class="fixed inset-0 z-[65] hidden flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl relative max-h-[90vh] overflow-y-auto">
|
||||
<button id="btn-close-task-detail" aria-label="Fechar" class="absolute top-4 right-4 p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition z-10">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
<div id="task-detail-content">
|
||||
<!-- Conteúdo renderizado dinamicamente -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL FORMULÁRIO DE TAREFA ==================== -->
|
||||
<div id="modal-task-form" role="dialog" aria-modal="true" class="fixed inset-0 z-[65] hidden flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl relative max-h-[92vh] overflow-y-auto">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 id="task-form-title" class="text-lg font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="clipboard-plus" class="w-5 h-5 text-accent"></i>
|
||||
Nova Tarefa
|
||||
</h3>
|
||||
<button id="btn-close-task-form" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="form-task" class="space-y-3.5 text-xs">
|
||||
<input type="hidden" id="input-task-id">
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Nome da Tarefa *</label>
|
||||
<input type="text" id="input-task-name" required placeholder="Ex: Reunião de projeto, Academia..." class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Descrição</label>
|
||||
<textarea id="input-task-desc" rows="2" placeholder="Detalhes sobre a tarefa..." class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-accent resize-y"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Data *</label>
|
||||
<input type="date" id="input-task-date" required class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Prioridade *</label>
|
||||
<select id="input-task-priority" required class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3 py-2.5 text-sm text-white focus:outline-none focus:border-accent">
|
||||
<option value="low">Baixa</option>
|
||||
<option value="medium" selected>Média</option>
|
||||
<option value="high">Alta</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Checklist</label>
|
||||
<div id="checklist-editor" class="space-y-2 mb-2">
|
||||
<!-- Itens do checklist renderizados dinamicamente -->
|
||||
</div>
|
||||
<button type="button" id="btn-add-check-item" class="flex items-center gap-1.5 text-accent hover:text-accent-hover text-xs font-semibold transition">
|
||||
<i data-lucide="plus" class="w-3.5 h-3.5"></i> Adicionar item
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-2.5 pt-4 border-t border-white/10">
|
||||
<button type="button" id="btn-cancel-task" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition">Cancelar</button>
|
||||
<button type="submit" class="px-5 py-2 rounded-xl bg-accent hover:bg-accent-hover text-white font-semibold transition shadow-lg flex items-center gap-2">
|
||||
<i data-lucide="check" class="w-4 h-4"></i> Salvar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL EXCLUSÃO DE TAREFA ==================== -->
|
||||
<div id="modal-task-delete" role="dialog" aria-modal="true" class="fixed inset-0 z-[70] hidden flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl border border-rose-500/30 text-center space-y-4">
|
||||
<div class="w-12 h-12 rounded-full bg-rose-500/20 text-rose-400 flex items-center justify-center mx-auto">
|
||||
<i data-lucide="alert-triangle" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white">Excluir esta tarefa?</h3>
|
||||
<p id="task-delete-text" class="text-xs text-slate-300 mt-1">Essa ação não pode ser desfeita.</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-3 pt-2">
|
||||
<button type="button" id="btn-cancel-task-delete" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">Cancelar</button>
|
||||
<button type="button" id="btn-confirm-task-delete" class="px-5 py-2 rounded-xl bg-rose-600 hover:bg-rose-500 text-white font-semibold transition text-xs shadow-lg">Excluir</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PAINEL DE NOTAS (slide esquerda) ==================== -->
|
||||
<div id="panel-notes" role="dialog" aria-modal="true" class="fixed inset-0 z-[55] hidden">
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm animate-fade-in" data-close-panel="panel-notes"></div>
|
||||
<div class="absolute left-0 top-0 h-full w-full sm:max-w-md modal-panel border-r border-white/15 flex flex-col">
|
||||
<div class="flex items-center justify-between p-5 border-b border-white/10 flex-shrink-0">
|
||||
<h2 class="text-base font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="sticky-note" class="w-5 h-5" style="color: var(--accent-color);"></i>
|
||||
Notas
|
||||
</h2>
|
||||
<button id="btn-close-notes" aria-label="Fechar Notas" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="px-5 py-3 flex-shrink-0">
|
||||
<button id="btn-new-note" class="w-full py-2.5 rounded-xl text-slate-900 text-xs font-bold transition shadow flex items-center justify-center gap-2" style="background: var(--accent-color);">
|
||||
<i data-lucide="plus" class="w-4 h-4"></i> Nova Nota
|
||||
</button>
|
||||
</div>
|
||||
<div id="notes-list" class="flex-1 overflow-y-auto px-5 pb-5 space-y-2">
|
||||
<!-- Itens renderizados dinamicamente -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL FORMULÁRIO DE NOTA ==================== -->
|
||||
<div id="modal-note-form" role="dialog" aria-modal="true" class="fixed inset-0 z-[65] hidden flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-md rounded-3xl p-6 shadow-2xl relative max-h-[92vh] overflow-y-auto">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 id="note-form-title" class="text-lg font-bold text-white flex items-center gap-2">
|
||||
<i data-lucide="sticky-note" class="w-5 h-5" style="color: var(--accent-color);"></i>
|
||||
Nova Nota
|
||||
</h3>
|
||||
<button id="btn-close-note-form" aria-label="Fechar" class="p-1.5 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition">
|
||||
<i data-lucide="x" class="w-5 h-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="form-note" class="space-y-3.5 text-xs">
|
||||
<input type="hidden" id="input-note-id">
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Título *</label>
|
||||
<input type="text" id="input-note-name" required placeholder="Ex: Ideias, Lembretes, Anotações..." class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none" style="--focus-border: var(--accent-color);">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-slate-300 font-medium mb-1">Conteúdo *</label>
|
||||
<textarea id="input-note-desc" rows="8" required placeholder="Escreva sua nota aqui..." class="w-full bg-slate-900/80 border border-white/15 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none resize-y" style="--focus-border: var(--accent-color);"></textarea>
|
||||
</div>
|
||||
|
||||
<p id="note-created-info" class="hidden text-[10px] text-slate-500"></p>
|
||||
|
||||
<div class="flex items-center justify-end gap-2.5 pt-4 border-t border-white/10">
|
||||
<button type="button" id="btn-cancel-note" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition">Cancelar</button>
|
||||
<button type="submit" class="px-5 py-2 rounded-xl text-slate-900 font-bold transition shadow-lg flex items-center gap-2" style="background: var(--accent-color);">
|
||||
<i data-lucide="check" class="w-4 h-4"></i> Salvar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== MODAL EXCLUSÃO DE NOTA ==================== -->
|
||||
<div id="modal-note-delete" role="dialog" aria-modal="true" class="fixed inset-0 z-[70] hidden flex items-center justify-center p-4 bg-black/85 backdrop-blur-md animate-fade-in">
|
||||
<div class="modal-panel w-full max-w-sm rounded-3xl p-6 shadow-2xl border border-rose-500/30 text-center space-y-4">
|
||||
<div class="w-12 h-12 rounded-full bg-rose-500/20 text-rose-400 flex items-center justify-center mx-auto">
|
||||
<i data-lucide="alert-triangle" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-white">Excluir esta nota?</h3>
|
||||
<p id="note-delete-text" class="text-xs text-slate-300 mt-1">Essa ação não pode ser desfeita.</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-3 pt-2">
|
||||
<button type="button" id="btn-cancel-note-delete" class="px-4 py-2 rounded-xl text-slate-300 hover:bg-white/10 transition text-xs font-semibold">Cancelar</button>
|
||||
<button type="button" id="btn-confirm-note-delete" class="px-5 py-2 rounded-xl bg-rose-600 hover:bg-rose-500 text-white font-semibold transition text-xs shadow-lg">Excluir</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== JAVASCRIPT E LÓGICA ==================== -->
|
||||
<script src="app.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
19
web/manifest.json
Normal file
19
web/manifest.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "InitPage — Sua página inicial",
|
||||
"short_name": "InitPage",
|
||||
"description": "Página inicial personalizável com atalhos, categorias, busca e plano de fundo.",
|
||||
"start_url": "./",
|
||||
"scope": "./",
|
||||
"display": "standalone",
|
||||
"background_color": "#0f172a",
|
||||
"theme_color": "#0f172a",
|
||||
"lang": "pt-BR",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
167
web/politica-privacidade/index.html
Normal file
167
web/politica-privacidade/index.html
Normal file
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Política de Privacidade · InitPage</title>
|
||||
<meta name="description" content="Política de Privacidade do InitPage, página inicial personalizável do navegador.">
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="icon" href="https://www.google.com/s2/favicons?domain=weltonmoura.com.br&sz=128">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
a.accent {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
a.accent:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-slate-950 text-slate-300 antialiased min-h-screen flex flex-col">
|
||||
<div class="fixed inset-0 bg-cover bg-center -z-20 opacity-20" style="background-image: url('https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=1920&q=85');"></div>
|
||||
|
||||
<header class="w-full px-6 py-6 flex items-center justify-between">
|
||||
<h1 class="text-lg font-extrabold text-white tracking-tight items-center">
|
||||
<span class="text-accent">InitPage</span> · Política de Privacidade
|
||||
</h1>
|
||||
<a href="https://weltonmoura.com.br" class="text-xs text-slate-400 hover:text-white transition">weltonmoura.com.br</a>
|
||||
</header>
|
||||
|
||||
<main class="w-full max-w-3xl mx-auto px-6 pb-14 flex-1">
|
||||
<section class="glass-panel rounded-3xl p-7 sm:p-10 space-y-8 border border-white/10">
|
||||
<div class="pb-4 border-b border-white/10">
|
||||
<p class="text-xs uppercase tracking-wider font-semibold text-slate-400 mb-2">Última atualização: 18 de outubro de 2026</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Esta Política de Privacidade descreve como o aplicativo web <strong class="text-white">InitPage</strong>
|
||||
(doravante "o aplicativo") coleta, usa e armazena informações. Ao utilizar o aplicativo, você concorda
|
||||
com as práticas descritas neste documento.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">1. Visão geral</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo é uma página inicial personalizável que roda inteiramente no navegador. Ele não possui
|
||||
servidor próprio e não envia seus dados a terceiros. Todo o processamento acontece localmente no seu dispositivo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">2. Dados armazenados localmente</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Suas configurações — como nome de exibição, atalhos, categorias, plano de fundo, cor de destaque e
|
||||
preferências de layout — são salvas exclusivamente no armazenamento local do seu navegador
|
||||
(<code class="text-slate-200 bg-white/10 rounded px-1.5 py-0.5 text-xs">localStorage</code>).
|
||||
</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Esses dados permanecem no seu dispositivo e podem ser apagados por você a qualquer momento,
|
||||
pela limpeza de dados do navegador ou pela exportação e exclusão manual do arquivo de configuração.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">3. Backup e exportação</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo oferece recursos de exportação e importação de configurações em formato JSON.
|
||||
Essa funcionalidade é totalmente local: o arquivo é gerado e baixado no seu dispositivo,
|
||||
e a importação ocorre a partir de um arquivo que você seleciona manualmente.
|
||||
Nenhum dado é enviado a servidores externos durante esse processo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">4. Conteúdo patrocinado</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Em certas categorias, o aplicativo pode exibir cards identificados como <strong class="text-white">"Patrocinado"</strong>.
|
||||
Esses cards são injetados durante a renderização da página e <em>não</em> fazem parte dos seus dados:
|
||||
eles não são salvos nem exportados junto com suas configurações.
|
||||
</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
A seleção do anúncio é feita <strong class="text-white">exclusivamente no seu navegador</strong>, com
|
||||
base no nome da categoria ativa. Nenhum dado pessoal (nome, atalhos, histórico) é enviado ou usado
|
||||
para escolher o anúncio a exibir.
|
||||
</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Ao clicar em um card patrocinado, você será direcionado ao site do anunciante. Uma vez no site do
|
||||
anunciante, aplicam-se a Política de Privacidade e os Termos de Serviço desse site.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">5. Serviços de terceiros</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo consulta a API <strong class="text-white">Open-Meteo</strong> (gratuita e sem chave de API)
|
||||
para exibir informações de clima, caso você tenha configurado uma cidade. Essa consulta envia apenas
|
||||
o nome da cidade digitada, sem qualquer identificador pessoal.
|
||||
</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
As bibliotecas externas carregadas (Tailwind CSS, Lucide Icons, Google Fonts) servem
|
||||
apenas para funcionamento técnico e não coletam dados de uso do aplicativo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">6. Cookies e rastreamento</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo não utiliza cookies de publicidade comportamental, redes de anúncios ou ferramentas de
|
||||
analytics próprias. Os cards patrocinados são selecionados localmente pelo nome da categoria ativa
|
||||
(ver item 4).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">7. Compartilhamento de dados</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Não vendemos, alugamos ou compartilhamos suas informações pessoais. O aplicativo não possui servidor
|
||||
próprio e não transmite seus dados de configuração para nenhum serviço externo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">8. Segurança</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Todo o tráfego ocorre sobre HTTPS. Seus dados são armazenados apenas no <code class="text-slate-200 bg-white/10 rounded px-1.5 py-0.5 text-xs">localStorage</code>
|
||||
do seu navegador, que é isolado por origem e inacessível a outros sites. URLs inseridas pelo usuário
|
||||
são sanitizadas para bloquear esquemas potencialmente perigosos (como <code class="text-slate-200 bg-white/10 rounded px-1.5 py-0.5 text-xs">javascript:</code>).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">9. Seus direitos (LGPD)</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Nos termos da Lei Geral de Proteção de Dados (Lei nº 13.709/2018), você pode solicitar acesso,
|
||||
correção ou exclusão dos dados associados ao seu uso. Como seus dados residem exclusivamente no seu
|
||||
próprio dispositivo, você pode exercê-los diretamente pela limpeza de dados do navegador,
|
||||
ou entrando em contato conosco.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">10. Alterações nesta política</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Esta política pode ser atualizada para refletir mudanças no funcionamento do aplicativo ou em
|
||||
requisitos legais. A data da última revisão consta no início desta página.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">11. Contato</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Dúvidas sobre esta Política de Privacidade podem ser enviadas para:
|
||||
<a class="accent" href="mailto:weltonmouradev@gmail.com">weltonmouradev@gmail.com</a>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="mt-8 text-center text-xs text-slate-500 space-x-4">
|
||||
<a class="accent" href="https://weltonmoura.com.br/initpage/termos-servico/">Termos de Serviço</a>
|
||||
<span>•</span>
|
||||
<a class="accent" href="https://weltonmoura.com.br/initpage/">Voltar ao início</a>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
5
web/robots.txt
Normal file
5
web/robots.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Disallow: /initpage/sw.js
|
||||
|
||||
Sitemap: https://weltonmoura.com.br/sitemap.xml
|
||||
265
web/styles.css
Normal file
265
web/styles.css
Normal file
@@ -0,0 +1,265 @@
|
||||
:root {
|
||||
--accent-color: #3b82f6;
|
||||
--accent-hover: #2563eb;
|
||||
--modal-panel-bg: linear-gradient(180deg, rgba(30, 27, 75, 0.94), rgba(15, 18, 38, 0.96));
|
||||
--modal-panel-border: rgba(139, 124, 219, 0.18);
|
||||
}
|
||||
|
||||
/* Modal: fundo coerente com glassmorphism do projeto */
|
||||
.modal-panel {
|
||||
background: rgba(15, 23, 42, 0.92);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
box-shadow: 0 40px 90px -20px rgba(2, 6, 23, 0.95);
|
||||
}
|
||||
|
||||
/* Limitar texto em até 2 linhas */
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Limitar texto em até 3 linhas */
|
||||
.line-clamp-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Scrollbars elegantes */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 9999px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* Estilos Glassmorphism */
|
||||
.glass-panel {
|
||||
background: rgba(15, 23, 42, 0.78);
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.glass-card:hover {
|
||||
border-color: rgba(255, 255, 255, 0.28);
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 14px 28px -8px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.glass-translucent {
|
||||
background: rgba(15, 23, 42, 0.38) !important;
|
||||
backdrop-filter: blur(16px) !important;
|
||||
-webkit-backdrop-filter: blur(16px) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14) !important;
|
||||
}
|
||||
|
||||
/* Botão de sidebar */
|
||||
.sidebar-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: rgba(226, 232, 255, 0.9);
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.sidebar-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.sidebar-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* Sidebar/barra de navegação */
|
||||
#app-sidebar {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 20px 60px -20px rgba(2, 6, 23, 0.9);
|
||||
}
|
||||
/* Checklist item */
|
||||
.check-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 8px;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.check-item input[type="checkbox"] {
|
||||
accent-color: var(--accent-color);
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.check-item.completed .check-item-text {
|
||||
text-decoration: line-through;
|
||||
color: rgba(148, 163, 184, 0.8);
|
||||
}
|
||||
|
||||
.check-item input.check-item-text-input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: white;
|
||||
font-size: 11px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
/* Linha do calendário com ponto de tarefa */
|
||||
.cal-day-cell {
|
||||
position: relative;
|
||||
padding: 5px 4px;
|
||||
}
|
||||
|
||||
.cal-task-dot {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-color);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Botão de layout selecionado */
|
||||
.layout-btn.selected {
|
||||
background: var(--accent-color) !important;
|
||||
border-color: transparent !important;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Aba ativa */
|
||||
.tab-btn.selected {
|
||||
background: var(--accent-color) !important;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* Ícone do atalho preenche toda a caixa (desktop e mobile), sem bordas */
|
||||
.shortcut-icon-box {
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
border: none !important;
|
||||
}
|
||||
.shortcut-icon-box img {
|
||||
object-fit: cover !important;
|
||||
}
|
||||
|
||||
/* Estilos do Drag and Drop */
|
||||
.card-dragging {
|
||||
opacity: 0.35 !important;
|
||||
transform: scale(0.95) !important;
|
||||
border: 2px dashed var(--accent-color) !important;
|
||||
}
|
||||
.card-drag-over {
|
||||
border: 2px solid var(--accent-color) !important;
|
||||
transform: scale(1.02) !important;
|
||||
box-shadow: 0 0 15px rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
.tab-drag-over {
|
||||
background: rgba(255, 255, 255, 0.25) !important;
|
||||
border-color: var(--accent-color) !important;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Transição suave do contêiner */
|
||||
#shortcuts-container {
|
||||
transition: opacity 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
#shortcuts-container.switching {
|
||||
opacity: 0;
|
||||
transform: scale(0.985);
|
||||
}
|
||||
|
||||
/* Otimizações Mobile */
|
||||
@media (max-width: 768px) {
|
||||
.glass-panel {
|
||||
background: rgba(15, 23, 42, 0.95) !important;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
}
|
||||
.glass-card, .glass-translucent {
|
||||
background: rgba(30, 41, 59, 0.92) !important;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.glass-card:hover {
|
||||
transform: none !important;
|
||||
}
|
||||
.animate-slide-up, .animate-fade-in {
|
||||
animation: none !important;
|
||||
opacity: 1 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
#app-sidebar {
|
||||
height: 48px;
|
||||
opacity: 0.95;
|
||||
transition: none;
|
||||
overflow: visible;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
.sidebar-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.card-actions button {
|
||||
padding: 8px;
|
||||
}
|
||||
.card-actions button i {
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
}
|
||||
}
|
||||
41
web/sw.js
Normal file
41
web/sw.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const CACHE = "initpage-v4";
|
||||
const ASSETS = [
|
||||
"./",
|
||||
"./index.html",
|
||||
"./styles.css",
|
||||
"./app.js",
|
||||
"./ads.js",
|
||||
"./manifest.json",
|
||||
"./icon.svg",
|
||||
"./robots.txt"
|
||||
];
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE).then((cache) => cache.addAll(ASSETS)).catch(() => {})
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
if (event.request.method !== "GET") return;
|
||||
event.respondWith(
|
||||
caches.match(event.request).then((cached) => {
|
||||
const fetchPromise = fetch(event.request).then((response) => {
|
||||
if (response && response.status === 200 && response.type === "basic") {
|
||||
const clone = response.clone();
|
||||
caches.open(CACHE).then((cache) => cache.put(event.request, clone));
|
||||
}
|
||||
return response;
|
||||
}).catch(() => cached);
|
||||
return cached || fetchPromise;
|
||||
})
|
||||
);
|
||||
});
|
||||
162
web/termos-servico/index.html
Normal file
162
web/termos-servico/index.html
Normal file
@@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Termos de Serviço · InitPage</title>
|
||||
<meta name="description" content="Termos de Serviço do InitPage, página inicial personalizável do navegador.">
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="icon" href="https://www.google.com/s2/favicons?domain=weltonmoura.com.br&sz=128">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="../styles.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
a.accent {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
a.accent:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-slate-950 text-slate-300 antialiased min-h-screen flex flex-col">
|
||||
<div class="fixed inset-0 bg-cover bg-center -z-20 opacity-20" style="background-image: url('https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=1920&q=85');"></div>
|
||||
|
||||
<header class="w-full px-6 py-6 flex items-center justify-between">
|
||||
<h1 class="text-lg font-extrabold text-white tracking-tight">
|
||||
<span class="text-accent">InitPage</span> · Termos de Serviço
|
||||
</h1>
|
||||
<a href="https://weltonmoura.com.br" class="text-xs text-slate-400 hover:text-white transition">weltonmoura.com.br</a>
|
||||
</header>
|
||||
|
||||
<main class="w-full max-w-3xl mx-auto px-6 pb-14 flex-1">
|
||||
<section class="glass-panel rounded-3xl p-7 sm:p-10 space-y-8 border border-white/10">
|
||||
<div class="pb-4 border-b border-white/10">
|
||||
<p class="text-xs uppercase tracking-wider font-semibold text-slate-400 mb-2">Última atualização: 18 de outubro de 2026</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Estes Termos de Serviço regem o uso do aplicativo web <strong class="text-white">InitPage</strong>
|
||||
(doravante "o aplicativo"). Ao utilizar o aplicativo, você declara ter lido, entendido e aceitado
|
||||
estes termos.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">1. Descrição do serviço</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo fornece uma página inicial personalizável do navegador, permitindo organizar atalhos,
|
||||
categorias, pesquisa e preferências visuais. Todo o processamento acontece no seu dispositivo
|
||||
(cliente), sem infraestrutura de servidor própria.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">2. Aceitação dos termos</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O acesso e o uso do aplicativo implicam na aceitação integral destes Termos. Se você não concorda,
|
||||
não utilize o aplicativo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">3. Uso permitido</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Você concorda em utilizar o aplicativo apenas para fins legais e lícitos, sem tentar interferir no
|
||||
seu funcionamento, sobrecarregar os serviços, ou burlar qualquer medida de segurança.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">4. Backup e exportação de dados</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo permite exportar suas configurações em formato JSON para backup local. A
|
||||
responsabilidade por manter cópias de segurança é inteiramente sua. O arquivo exportado
|
||||
contém suas configurações e deve ser tratado como informação sua.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">5. Responsabilidades do usuário</h2>
|
||||
<ul class="text-sm leading-relaxed list-disc pl-5 space-y-1.5">
|
||||
<li>Ser o único responsável pelas informações salvas localmente no seu navegador;</li>
|
||||
<li>Manter cópias de segurança (exportação/backup) se desejar preservar suas configurações;</li>
|
||||
<li>Não utilizar o aplicativo para armazenar ou divulgar conteúdos ilegais.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">6. Conteúdo patrocinado</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo pode exibir cards identificados como <strong class="text-white">"Patrocinado"</strong> em
|
||||
determinadas categorias. Esses cards são sempre claramente sinalizados e não fazem parte das suas
|
||||
configurações: não são armazenados nem exportados.
|
||||
</p>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Os anúncios são selecionados no seu próprio navegador, conforme o nome da categoria ativa, e não
|
||||
envolvem o envio dos seus dados. Ao clicar em um card patrocinado, você será direcionado ao site do
|
||||
anunciante, e a responsabilidade pelo conteúdo do anúncio e do destino do link é do anunciante.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">7. Propriedade intelectual</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O conteúdo que você cria no aplicativo (atalhos, categorias, preferências) pertence a você. O
|
||||
aplicativo em si, incluindo seu código-fonte, design e identidade visual, é de sua exclusiva
|
||||
propriedade enquanto mantenedor, salvo indicação em contrário.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">8. Disponibilidade e garantias</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
O aplicativo é fornecido gratuitamente e "no estado em que se encontra" ("as is"). Não garantimos
|
||||
disponibilidade ininterrupta ou ausência de erros. O funcionamento depende do navegador e de
|
||||
serviços de terceiros que não controlamos (bibliotecas externas, API de clima).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">9. Limitação de responsabilidade</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Na máxima extensão permitida por lei, não nos responsabilizamos por perdas diretas ou indiretas
|
||||
decorrentes do uso, impossibilidade de uso, ou perda de dados associada ao aplicativo. É
|
||||
recomendável manter backups frequentes das suas configurações.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">10. Alterações dos termos</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Podemos atualizar estes Termos periodicamente. A versão vigente será sempre a publicada nesta
|
||||
página, com a data de última atualização indicada no topo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">11. Lei aplicável</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Estes Termos são regidos pelas leis da República Federativa do Brasil. Eventuais controvérsias
|
||||
serão resolvidas no foro da comarca do mantenedor do aplicativo, respeitadas as disposições legais
|
||||
aplicáveis.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-base font-bold text-white">12. Contato</h2>
|
||||
<p class="text-sm leading-relaxed">
|
||||
Dúvidas sobre estes Termos podem ser enviadas para:
|
||||
<a class="accent" href="mailto:weltonmouradev@gmail.com">weltonmouradev@gmail.com</a>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="mt-8 text-center text-xs text-slate-500 space-x-4">
|
||||
<a class="accent" href="https://weltonmoura.com.br/initpage/politica-privacidade/">Política de Privacidade</a>
|
||||
<span>•</span>
|
||||
<a class="accent" href="https://weltonmoura.com.br/initpage/">Voltar ao início</a>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user