238 lines
6.4 KiB
Cheetah
238 lines
6.4 KiB
Cheetah
{{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}}
|