Files
core/internal/api/ui_shared.tmpl

238 lines
6.4 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "head"}}
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{.PageTitle}} · Reanimator</title>
<style>
:root {
--bg: #f6f8fb;
--card: #ffffff;
--text: #1f2937;
--muted: #6b7280;
--accent: #2563eb;
--border: #e5e7eb;
--success: #16a34a;
--warn: #ca8a04;
--danger: #dc2626;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "SF Pro Text", "Segoe UI", sans-serif;
color: var(--text);
background: var(--bg);
}
a { color: var(--accent); text-decoration: none; }
.topbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
padding: 18px 24px;
border-bottom: 1px solid var(--border);
background: var(--card);
position: sticky;
top: 0;
z-index: 10;
}
.brand {
color: var(--muted);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 6px;
}
.title { margin: 0; font-size: 22px; }
.subtitle { color: var(--muted); margin-top: 4px; }
.pill {
border-radius: 999px;
padding: 6px 12px;
font-size: 12px;
font-weight: 600;
border: 1px solid var(--border);
}
.pill-neutral { background: #f3f4f6; }
.nav {
display: flex;
gap: 8px;
padding: 10px 24px;
border-bottom: 1px solid var(--border);
background: var(--card);
position: sticky;
top: 84px;
z-index: 9;
}
.nav a {
color: var(--muted);
padding: 8px 12px;
border-radius: 8px;
font-weight: 500;
}
.nav a.active {
color: var(--accent);
background: #eef2ff;
}
.breadcrumbs {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
color: var(--muted);
font-size: 13px;
}
.breadcrumbs .current { color: var(--text); font-weight: 600; }
.container {
width: min(1200px, calc(100% - 32px));
margin: 16px auto 32px;
display: grid;
gap: 16px;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 14px;
padding: 16px;
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.card h2 { margin-top: 0; }
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
}
.stat {
border: 1px solid var(--border);
border-radius: 10px;
padding: 12px;
display: grid;
gap: 6px;
background: #fafafa;
}
.stat span { color: var(--muted); font-size: 13px; }
.stat strong { font-size: 24px; }
.table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.table th, .table td {
padding: 10px;
border-bottom: 1px solid var(--border);
text-align: left;
vertical-align: top;
}
.table th {
color: var(--muted);
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.clickable { cursor: pointer; }
.clickable:hover { background: #fafafa; }
.badge {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 3px 8px;
font-size: 12px;
font-weight: 600;
border: 1px solid transparent;
}
.status-green { color: #166534; background: #dcfce7; border-color: #bbf7d0; }
.status-yellow { color: #854d0e; background: #fef9c3; border-color: #fde68a; }
.status-red { color: #991b1b; background: #fee2e2; border-color: #fecaca; }
.status-gray { color: #374151; background: #f3f4f6; border-color: #e5e7eb; }
.meta { color: var(--muted); font-size: 13px; }
.meta-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 12px;
}
.meta-grid > div {
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px;
display: grid;
gap: 6px;
font-size: 14px;
}
.meta-grid span { color: var(--muted); font-size: 12px; text-transform: uppercase; }
.timeline { display: grid; gap: 10px; }
.event {
display: grid;
grid-template-columns: 190px 1fr;
gap: 10px;
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px;
}
.time { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.detail { font-weight: 600; margin-bottom: 4px; }
.form { display: grid; gap: 12px; }
.field { display: grid; gap: 6px; }
.input {
width: 100%;
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px;
font: inherit;
background: #fff;
}
.button {
border: 1px solid var(--accent);
background: var(--accent);
color: #fff;
border-radius: 8px;
padding: 8px 12px;
font-weight: 600;
cursor: pointer;
}
@media (max-width: 900px) {
.topbar { position: static; }
.nav { position: static; flex-wrap: wrap; }
.event { grid-template-columns: 1fr; }
}
</style>
<script>
function navigateToRow(url) {
window.location.href = url;
}
</script>
</head>
{{end}}
{{define "topbar"}}
<header class="topbar">
<div>
<div class="brand">Reanimator</div>
<h1 class="title">{{.PageTitle}}</h1>
{{if .PageSubtitle}}<div class="subtitle">{{.PageSubtitle}}</div>{{end}}
</div>
{{if .HeroTag}}<div class="pill {{if .HeroTagClass}}{{.HeroTagClass}}{{else}}pill-neutral{{end}}">{{.HeroTag}}</div>{{end}}
</header>
<nav class="nav">
<a href="/ui" class="{{if eq .ActiveNav "dashboard"}}active{{end}}">Dashboard</a>
<a href="/ui/assets" class="{{if eq .ActiveNav "assets"}}active{{end}}">Assets</a>
<a href="/ui/components" class="{{if eq .ActiveNav "components"}}active{{end}}">Components</a>
<a href="/ui/failures" class="{{if eq .ActiveNav "failures"}}active{{end}}">Failures</a>
<a href="/ui/ingest" class="{{if eq .ActiveNav "ingest"}}active{{end}}">Ingest</a>
</nav>
{{end}}
{{define "breadcrumbs"}}
{{if .Breadcrumbs}}
<nav class="breadcrumbs">
<a href="/ui">Home</a>
{{range $crumb := .Breadcrumbs}}
<span></span>
{{if $crumb.URL}}
<a href="{{$crumb.URL}}">{{$crumb.Label}}</a>
{{else}}
<span class="current">{{$crumb.Label}}</span>
{{end}}
{{end}}
</nav>
{{end}}
{{end}}