Files
2026-05-02 23:06:32 -03:00

459 lines
14 KiB
Django/Jinja

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ tenant_name }}</title>
<style>
:root {
--primary: {{ tenant_primary_color }};
--accent: {{ tenant_accent_color }};
--bg: #0f172a;
--surface: #1e293b;
--surface2: #273449;
--border: #334155;
--text: #f1f5f9;
--text-muted: #94a3b8;
--radius: 10px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
}
/* ── Header ── */
header {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 0 2rem;
display: flex;
align-items: center;
justify-content: space-between;
height: 64px;
}
.brand {
display: flex;
align-items: center;
gap: 0.75rem;
text-decoration: none;
color: var(--text);
}
{% if tenant_logo_local_path %}
.brand-logo {
height: 36px;
width: auto;
}
{% else %}
.brand-icon {
width: 36px;
height: 36px;
background: var(--primary);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
font-weight: 700;
color: #fff;
flex-shrink: 0;
}
{% endif %}
.brand-name {
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -0.02em;
}
.domain-badge {
font-size: 0.75rem;
color: var(--text-muted);
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 6px;
padding: 0.25rem 0.6rem;
font-family: 'SF Mono', 'Fira Code', monospace;
}
/* ── Hero ── */
.hero {
text-align: center;
padding: 3.5rem 2rem 2.5rem;
}
.hero h1 {
font-size: clamp(1.75rem, 4vw, 2.5rem);
font-weight: 700;
letter-spacing: -0.03em;
margin-bottom: 0.75rem;
}
.hero h1 span {
background: linear-gradient(135deg, var(--primary), var(--accent));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
color: var(--text-muted);
font-size: 1.05rem;
max-width: 520px;
margin: 0 auto;
line-height: 1.6;
}
/* ── Category sections ── */
main {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem 4rem;
}
.category {
margin-bottom: 2.5rem;
}
.category-title {
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
/* ── Service card ── */
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.25rem 1.5rem;
display: flex;
align-items: flex-start;
gap: 1rem;
text-decoration: none;
color: var(--text);
transition: border-color 0.15s, background 0.15s, transform 0.15s;
position: relative;
overflow: hidden;
}
.card::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--radius);
background: linear-gradient(135deg, var(--primary), var(--accent));
opacity: 0;
transition: opacity 0.15s;
z-index: 0;
}
.card:hover {
border-color: var(--primary);
background: var(--surface2);
transform: translateY(-2px);
}
.card:hover::after { opacity: 0.04; }
.card > * { position: relative; z-index: 1; }
.card-icon {
width: 42px;
height: 42px;
border-radius: 8px;
background: var(--surface2);
border: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-size: 1.3rem;
}
.card:hover .card-icon {
background: var(--primary);
border-color: var(--primary);
}
.card-body { flex: 1; min-width: 0; }
.card-name {
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.25rem;
}
.card-desc {
font-size: 0.82rem;
color: var(--text-muted);
line-height: 1.5;
margin-bottom: 0.5rem;
}
.card-url {
font-size: 0.72rem;
font-family: 'SF Mono', 'Fira Code', monospace;
color: var(--primary);
opacity: 0.8;
}
/* ── Footer ── */
footer {
border-top: 1px solid var(--border);
text-align: center;
padding: 1.5rem 2rem;
color: var(--text-muted);
font-size: 0.8rem;
}
footer a { color: var(--primary); text-decoration: none; }
footer a:hover { text-decoration: underline; }
@media (max-width: 600px) {
header { padding: 0 1rem; }
.hero { padding: 2rem 1rem 1.5rem; }
main { padding: 0 1rem 3rem; }
.grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<header>
<a class="brand" href="https://{{ base_domain }}">
{% if tenant_logo_local_path %}
<img class="brand-logo" src="/logo" alt="{{ tenant_name }} logo">
{% else %}
<div class="brand-icon">{{ tenant_name[0] | upper }}</div>
{% endif %}
<span class="brand-name">{{ tenant_name }}</span>
</a>
<span class="domain-badge">{{ base_domain }}</span>
</header>
<div class="hero">
<h1>Your <span>self-hosted</span> workspace</h1>
<p>All {{ tenant_name }} services in one place — private, secure, and fully under your control.</p>
</div>
<main>
<!-- ── Collaboration ── -->
<section class="category">
<div class="category-title">Collaboration</div>
<div class="grid">
<a class="card" href="https://cloud.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#9729;</div>
<div class="card-body">
<div class="card-name">Nextcloud</div>
<div class="card-desc">File storage, sharing, and collaboration suite. Sync files across devices and share with teammates.</div>
<div class="card-url">cloud.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://chat.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128172;</div>
<div class="card-body">
<div class="card-name">Element / Matrix</div>
<div class="card-desc">Encrypted team messaging and channels. Federated communication via the Matrix protocol.</div>
<div class="card-url">chat.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://meet.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#127910;</div>
<div class="card-body">
<div class="card-name">Jitsi Meet</div>
<div class="card-desc">Browser-based video conferencing. No account required — share a link to start a meeting instantly.</div>
<div class="card-url">meet.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
<!-- ── Email ── -->
<section class="category">
<div class="category-title">Email</div>
<div class="grid">
<a class="card" href="https://webmail.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#9993;</div>
<div class="card-body">
<div class="card-name">Roundcube Webmail</div>
<div class="card-desc">Browser-based email client. Read, compose, and manage your @{{ base_domain }} inbox.</div>
<div class="card-url">webmail.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://mail.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128231;</div>
<div class="card-body">
<div class="card-name">Stalwart Mail</div>
<div class="card-desc">Mail server administration. Manage domains, mailboxes, aliases, and anti-spam settings.</div>
<div class="card-url">mail.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
<!-- ── Development ── -->
<section class="category">
<div class="category-title">Development</div>
<div class="grid">
<a class="card" href="https://git.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#127807;</div>
<div class="card-body">
<div class="card-name">Forgejo</div>
<div class="card-desc">Self-hosted Git platform. Manage repositories, review code, track issues, and run CI pipelines.</div>
<div class="card-url">git.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://s3.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128191;</div>
<div class="card-body">
<div class="card-name">MinIO</div>
<div class="card-desc">S3-compatible object storage. Store and serve large files, backups, and application assets.</div>
<div class="card-url">s3.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
<!-- ── Security & Access ── -->
<section class="category">
<div class="category-title">Security &amp; Access</div>
<div class="grid">
<a class="card" href="https://auth.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128274;</div>
<div class="card-body">
<div class="card-name">Authentik</div>
<div class="card-desc">Identity provider and SSO. Manage users, groups, and single sign-on across all services.</div>
<div class="card-url">auth.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://vault.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128272;</div>
<div class="card-body">
<div class="card-name">Vaultwarden</div>
<div class="card-desc">Password manager compatible with Bitwarden clients. Store and autofill credentials securely.</div>
<div class="card-url">vault.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://headscale.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128225;</div>
<div class="card-body">
<div class="card-name">Headscale</div>
<div class="card-desc">WireGuard mesh VPN coordinator. Connect all your devices on a private, encrypted network.</div>
<div class="card-url">headscale.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
<!-- ── Operations ── -->
<section class="category">
<div class="category-title">Operations</div>
<div class="grid">
<a class="card" href="https://logs.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128202;</div>
<div class="card-body">
<div class="card-name">Graylog</div>
<div class="card-desc">Centralized log management. Search, analyze, and alert on logs from every service.</div>
<div class="card-url">logs.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://wazuh.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128737;</div>
<div class="card-body">
<div class="card-name">Wazuh</div>
<div class="card-desc">Security information and event management (SIEM). Threat detection, compliance, and incident response.</div>
<div class="card-url">wazuh.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://traefik.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128260;</div>
<div class="card-body">
<div class="card-name">Traefik</div>
<div class="card-desc">Reverse proxy and TLS dashboard. Monitor active routes, certificates, and service health.</div>
<div class="card-url">traefik.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://status.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128994;</div>
<div class="card-body">
<div class="card-name">Uptime Kuma</div>
<div class="card-desc">Uptime monitoring dashboard. Track availability and response times for all your services.</div>
<div class="card-url">status.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
<!-- ── Business ── -->
<section class="category">
<div class="category-title">Business</div>
<div class="grid">
<a class="card" href="https://crm.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#128101;</div>
<div class="card-body">
<div class="card-name">Twenty CRM</div>
<div class="card-desc">Customer relationship management. Track contacts, deals, and sales pipelines for your business.</div>
<div class="card-url">crm.{{ base_domain }}</div>
</div>
</a>
<a class="card" href="https://automate.{{ base_domain }}" target="_blank" rel="noopener">
<div class="card-icon">&#9889;</div>
<div class="card-body">
<div class="card-name">Automatisch</div>
<div class="card-desc">Workflow automation. Connect services and automate repetitive tasks without writing code.</div>
<div class="card-url">automate.{{ base_domain }}</div>
</div>
</a>
</div>
</section>
</main>
<footer>
<p>Powered by <a href="https://git.{{ base_domain }}" target="_blank" rel="noopener">Sovereign</a> &mdash; {{ tenant_name }}</p>
</footer>
</body>
</html>