1e357244e1
Three full-fidelity dashboard mockups (Bridge/Console, Aurora/Glass, Bento/Modular) plus a chooser index and a tracker-detail page in the chosen Aurora language. Self-contained HTML, no build needed.
1460 lines
56 KiB
HTML
1460 lines
56 KiB
HTML
<!doctype html>
|
|
<html lang="en" data-theme="dark">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Aurora — Tracker · family-photos</title>
|
|
<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=Geist:wght@300..700&family=Geist+Mono:wght@300..600&family=Newsreader:ital,opsz,wght@0,6..72,300..700;1,6..72,300..700&display=swap" rel="stylesheet">
|
|
<style>
|
|
/* ============================================================
|
|
AURORA — Tracker Detail
|
|
Second view in the Aurora language. Stress-tests forms,
|
|
tabs, code preview, switches, and an event log — the four
|
|
surfaces a glass aesthetic can fail on if not carefully
|
|
handled.
|
|
============================================================ */
|
|
:root[data-theme="dark"] {
|
|
--bg: #050613;
|
|
--bg-deep: #02030a;
|
|
--fg: #f3f1ff;
|
|
--fg-dim: #b6b2d4;
|
|
--mute: #6f6c92;
|
|
--rule: rgba(255, 255, 255, 0.08);
|
|
--rule-strong: rgba(255, 255, 255, 0.16);
|
|
--glass: rgba(255, 255, 255, 0.04);
|
|
--glass-strong: rgba(255, 255, 255, 0.07);
|
|
--glass-elev: rgba(255, 255, 255, 0.10);
|
|
--highlight: rgba(255, 255, 255, 0.14);
|
|
--input-bg: rgba(255, 255, 255, 0.04);
|
|
--input-focus: rgba(184, 167, 255, 0.5);
|
|
|
|
--lavender: #b8a7ff;
|
|
--orchid: #ff9ec4;
|
|
--mint: #7ee8c4;
|
|
--citrus: #f0e16a;
|
|
--coral: #ff8a78;
|
|
--sky: #8ec9ff;
|
|
|
|
--shadow-card: 0 1px 0 rgba(255,255,255,0.07) inset, 0 30px 60px -20px rgba(0,0,0,0.6);
|
|
}
|
|
:root[data-theme="pearl"] {
|
|
--bg: #f5f3ff;
|
|
--bg-deep: #ede9fe;
|
|
--fg: #1a1530;
|
|
--fg-dim: #4a4670;
|
|
--mute: #7c789c;
|
|
--rule: rgba(20, 15, 60, 0.08);
|
|
--rule-strong: rgba(20, 15, 60, 0.16);
|
|
--glass: rgba(255, 255, 255, 0.55);
|
|
--glass-strong: rgba(255, 255, 255, 0.65);
|
|
--glass-elev: rgba(255, 255, 255, 0.80);
|
|
--highlight: rgba(255, 255, 255, 0.9);
|
|
--input-bg: rgba(255, 255, 255, 0.85);
|
|
--input-focus: rgba(109, 76, 224, 0.4);
|
|
|
|
--lavender: #6d4ce0;
|
|
--orchid: #d63384;
|
|
--mint: #008a64;
|
|
--citrus: #a07a00;
|
|
--coral: #e0512f;
|
|
--sky: #1f6fcc;
|
|
|
|
--shadow-card: 0 1px 0 rgba(255,255,255,0.5) inset, 0 20px 40px -16px rgba(80, 50, 180, 0.18);
|
|
}
|
|
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
html, body { margin: 0; padding: 0; }
|
|
body {
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font-family: 'Geist', ui-sans-serif, system-ui, sans-serif;
|
|
-webkit-font-smoothing: antialiased;
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
letter-spacing: -0.005em;
|
|
}
|
|
|
|
body::before {
|
|
content: '';
|
|
position: fixed; inset: -20vh -10vw;
|
|
background:
|
|
radial-gradient(40vw 40vw at 12% 18%, rgba(184, 167, 255, 0.55), transparent 60%),
|
|
radial-gradient(35vw 35vw at 88% 22%, rgba(255, 158, 196, 0.45), transparent 60%),
|
|
radial-gradient(50vw 35vw at 78% 88%, rgba(126, 232, 196, 0.40), transparent 60%),
|
|
radial-gradient(40vw 30vw at 6% 92%, rgba(142, 201, 255, 0.42), transparent 60%);
|
|
filter: blur(60px) saturate(140%);
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
animation: drift 28s ease-in-out infinite alternate;
|
|
}
|
|
body::after {
|
|
content: '';
|
|
position: fixed; inset: 0;
|
|
background: radial-gradient(circle at 50% 50%, transparent 30%, var(--bg-deep) 100%);
|
|
pointer-events: none; z-index: 0; opacity: 0.7;
|
|
}
|
|
@keyframes drift {
|
|
from { transform: translate(0, 0) scale(1); }
|
|
to { transform: translate(-2%, 1%) scale(1.05); }
|
|
}
|
|
.grain {
|
|
position: fixed; inset: 0; z-index: 1; pointer-events: none;
|
|
opacity: 0.05; mix-blend-mode: overlay;
|
|
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
|
|
}
|
|
|
|
::selection { background: var(--lavender); color: var(--bg-deep); }
|
|
::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: 999px; }
|
|
|
|
/* ============================================================
|
|
SHELL
|
|
============================================================ */
|
|
.shell {
|
|
position: relative; z-index: 2;
|
|
display: grid;
|
|
grid-template-columns: 240px 1fr;
|
|
min-height: 100vh;
|
|
padding: 18px;
|
|
gap: 18px;
|
|
}
|
|
|
|
/* RAIL — same as dashboard */
|
|
.rail {
|
|
background: var(--glass);
|
|
backdrop-filter: blur(28px) saturate(160%);
|
|
-webkit-backdrop-filter: blur(28px) saturate(160%);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 22px;
|
|
box-shadow: var(--shadow-card);
|
|
position: sticky; top: 18px;
|
|
height: calc(100vh - 36px);
|
|
display: flex; flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.rail::after {
|
|
content: ''; position: absolute; inset: 0;
|
|
border-radius: inherit; pointer-events: none;
|
|
background: linear-gradient(180deg, var(--highlight), transparent 30%);
|
|
opacity: 0.4;
|
|
}
|
|
.rail__brand {
|
|
padding: 22px 22px 18px;
|
|
display: flex; align-items: center; gap: 12px;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.rail__logo {
|
|
width: 36px; height: 36px;
|
|
border-radius: 12px;
|
|
background: conic-gradient(from 220deg, var(--lavender), var(--orchid), var(--mint), var(--lavender));
|
|
display: grid; place-items: center;
|
|
box-shadow: 0 4px 14px rgba(184, 167, 255, 0.35);
|
|
position: relative;
|
|
}
|
|
.rail__logo::after {
|
|
content: ''; position: absolute; inset: 4px;
|
|
border-radius: 8px;
|
|
background: radial-gradient(circle at 30% 25%, rgba(255,255,255,0.6), transparent 50%);
|
|
}
|
|
.rail__brand-text { line-height: 1.1; }
|
|
.rail__brand-text b { font-weight: 600; font-size: 16px; letter-spacing: -0.01em; }
|
|
.rail__brand-text small { color: var(--mute); font-size: 11px; font-family: 'Geist Mono', monospace; }
|
|
|
|
.rail__group { padding: 8px 12px; position: relative; z-index: 1; }
|
|
.rail__label {
|
|
font-size: 10px; text-transform: uppercase; letter-spacing: 0.13em;
|
|
color: var(--mute); padding: 12px 10px 8px; font-weight: 500;
|
|
}
|
|
.rail__nav { display: flex; flex-direction: column; gap: 2px; }
|
|
.rail__link {
|
|
display: flex; align-items: center; gap: 12px;
|
|
padding: 9px 12px;
|
|
color: var(--fg-dim); text-decoration: none;
|
|
font-size: 13.5px; border-radius: 12px;
|
|
transition: all .2s cubic-bezier(.4,.4,0,1);
|
|
position: relative; font-weight: 450;
|
|
}
|
|
.rail__link:hover { color: var(--fg); background: var(--glass-strong); }
|
|
.rail__link.is-active {
|
|
color: var(--fg);
|
|
background: var(--glass-elev);
|
|
box-shadow: inset 0 1px 0 var(--highlight), 0 4px 18px -8px rgba(184,167,255,0.35);
|
|
}
|
|
.rail__link.is-active::before {
|
|
content: ''; position: absolute; left: 6px; top: 50%; transform: translateY(-50%);
|
|
width: 3px; height: 14px; border-radius: 2px;
|
|
background: linear-gradient(var(--lavender), var(--orchid));
|
|
}
|
|
.rail__link svg { width: 17px; height: 17px; flex-shrink: 0; opacity: 0.85; }
|
|
.rail__link .count {
|
|
margin-left: auto;
|
|
font-family: 'Geist Mono', monospace; font-size: 10.5px; color: var(--mute);
|
|
background: var(--glass); padding: 2px 7px; border-radius: 999px;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.rail__link.is-active .count { color: var(--fg); background: var(--glass-elev); }
|
|
|
|
.rail__foot { margin-top: auto; padding: 16px; position: relative; z-index: 1; }
|
|
.rail__op {
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 14px;
|
|
padding: 10px 12px;
|
|
display: flex; align-items: center; gap: 12px;
|
|
}
|
|
.rail__avatar {
|
|
width: 34px; height: 34px; border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--orchid), var(--lavender));
|
|
display: grid; place-items: center;
|
|
color: white; font-weight: 600; font-size: 14px;
|
|
box-shadow: 0 0 0 2px var(--glass) inset;
|
|
}
|
|
.rail__op-name { font-size: 13px; font-weight: 500; }
|
|
.rail__op-role { font-size: 10.5px; color: var(--mute); margin-top: 1px; }
|
|
.rail__chip {
|
|
margin-left: auto; width: 8px; height: 8px; border-radius: 50%;
|
|
background: var(--mint); box-shadow: 0 0 8px var(--mint);
|
|
}
|
|
|
|
/* ============================================================
|
|
MAIN
|
|
============================================================ */
|
|
.main { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
|
|
|
|
/* TOP CRUMB BAR */
|
|
.topbar {
|
|
background: var(--glass);
|
|
backdrop-filter: blur(28px) saturate(160%);
|
|
-webkit-backdrop-filter: blur(28px) saturate(160%);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 22px;
|
|
padding: 12px 18px;
|
|
display: flex; align-items: center; gap: 14px;
|
|
position: relative;
|
|
}
|
|
.topbar::after {
|
|
content: ''; position: absolute; inset: 0;
|
|
border-radius: inherit; pointer-events: none;
|
|
background: linear-gradient(180deg, var(--highlight), transparent 30%);
|
|
opacity: 0.4;
|
|
}
|
|
.crumbs {
|
|
flex: 1;
|
|
display: flex; align-items: center; gap: 10px;
|
|
font-size: 13px; color: var(--fg-dim);
|
|
font-weight: 500;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.crumbs a { color: var(--fg-dim); text-decoration: none; transition: color .15s; }
|
|
.crumbs a:hover { color: var(--fg); }
|
|
.crumbs .sep { color: var(--mute); }
|
|
.crumbs .here { color: var(--fg); font-weight: 600; }
|
|
|
|
.icon-btn {
|
|
width: 36px; height: 36px;
|
|
border-radius: 12px;
|
|
border: 1px solid var(--rule);
|
|
background: var(--glass-strong);
|
|
color: var(--fg-dim);
|
|
display: grid; place-items: center;
|
|
cursor: pointer;
|
|
transition: all .2s;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.icon-btn:hover { background: var(--glass-elev); color: var(--fg); }
|
|
.icon-btn svg { width: 16px; height: 16px; }
|
|
|
|
/* HERO — tracker name + status + key actions */
|
|
.hero {
|
|
background: var(--glass);
|
|
backdrop-filter: blur(28px) saturate(160%);
|
|
-webkit-backdrop-filter: blur(28px) saturate(160%);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 22px;
|
|
padding: 30px 36px 32px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
.hero::after {
|
|
content: ''; position: absolute; inset: 0;
|
|
border-radius: inherit; pointer-events: none;
|
|
background: linear-gradient(180deg, var(--highlight), transparent 30%);
|
|
opacity: 0.4;
|
|
}
|
|
.hero__row {
|
|
position: relative; z-index: 1;
|
|
display: grid; grid-template-columns: 1fr auto;
|
|
align-items: center; gap: 28px;
|
|
}
|
|
.hero__chip {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
padding: 5px 12px;
|
|
border-radius: 999px;
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule);
|
|
font-size: 11.5px;
|
|
color: var(--fg-dim);
|
|
margin-bottom: 12px;
|
|
font-weight: 500;
|
|
}
|
|
.hero__chip svg { width: 14px; height: 14px; }
|
|
.hero__chip b { color: var(--fg); font-weight: 600; }
|
|
.hero__title {
|
|
font-family: 'Newsreader', serif; font-weight: 400;
|
|
font-size: 48px; line-height: 1; letter-spacing: -0.025em;
|
|
margin: 0 0 14px;
|
|
color: var(--fg);
|
|
display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
|
|
}
|
|
.hero__title em {
|
|
font-style: italic;
|
|
background: linear-gradient(135deg, var(--orchid), var(--lavender));
|
|
-webkit-background-clip: text; background-clip: text; color: transparent;
|
|
}
|
|
.hero__pill-live {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 4px 12px;
|
|
border-radius: 999px;
|
|
background: rgba(126, 232, 196, 0.15);
|
|
border: 1px solid rgba(126, 232, 196, 0.3);
|
|
color: var(--mint);
|
|
font-size: 11.5px;
|
|
font-weight: 600;
|
|
font-family: 'Geist', sans-serif;
|
|
text-transform: uppercase; letter-spacing: 0.1em;
|
|
vertical-align: middle;
|
|
}
|
|
.hero__pill-live::before {
|
|
content: ''; width: 7px; height: 7px;
|
|
border-radius: 50%;
|
|
background: var(--mint);
|
|
box-shadow: 0 0 8px var(--mint);
|
|
animation: ping 1.4s ease-in-out infinite;
|
|
}
|
|
@keyframes ping {
|
|
0%, 100% { transform: scale(1); opacity: 1; }
|
|
50% { transform: scale(1.5); opacity: 0.6; }
|
|
}
|
|
.hero__sub {
|
|
font-size: 14.5px; color: var(--fg-dim);
|
|
line-height: 1.55; max-width: 680px;
|
|
font-weight: 400;
|
|
}
|
|
.hero__sub b { color: var(--fg); font-weight: 500; }
|
|
|
|
.hero__actions { display: flex; gap: 8px; align-items: center; }
|
|
.toggle {
|
|
display: inline-flex; align-items: center; gap: 10px;
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 999px;
|
|
padding: 6px 14px 6px 6px;
|
|
cursor: pointer;
|
|
transition: all .2s;
|
|
}
|
|
.toggle:hover { border-color: var(--rule-strong); }
|
|
.toggle__sw {
|
|
width: 36px; height: 22px;
|
|
border-radius: 999px;
|
|
background: linear-gradient(135deg, var(--mint), var(--sky));
|
|
position: relative;
|
|
box-shadow: 0 0 12px -2px var(--mint);
|
|
}
|
|
.toggle__sw::after {
|
|
content: ''; position: absolute;
|
|
top: 2px; left: 16px;
|
|
width: 18px; height: 18px;
|
|
border-radius: 50%;
|
|
background: white;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
transition: left .2s;
|
|
}
|
|
.toggle.is-off .toggle__sw {
|
|
background: var(--glass-elev);
|
|
box-shadow: none;
|
|
}
|
|
.toggle.is-off .toggle__sw::after { left: 2px; background: var(--mute); }
|
|
.toggle__label {
|
|
font-size: 12px; font-weight: 600;
|
|
color: var(--fg);
|
|
}
|
|
.ghost-btn {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
padding: 0 14px; height: 36px;
|
|
border-radius: 12px;
|
|
border: 1px solid var(--rule-strong);
|
|
background: var(--glass-strong);
|
|
color: var(--fg);
|
|
font-family: inherit;
|
|
font-size: 12.5px; font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all .15s;
|
|
}
|
|
.ghost-btn:hover { background: var(--glass-elev); }
|
|
.ghost-btn svg { width: 14px; height: 14px; }
|
|
.danger-btn {
|
|
color: var(--coral);
|
|
border-color: rgba(255, 138, 120, 0.3);
|
|
}
|
|
.danger-btn:hover { background: rgba(255, 138, 120, 0.12); }
|
|
|
|
/* ROUTING TRAIL — the killer visual */
|
|
.trail {
|
|
margin-top: 28px;
|
|
position: relative; z-index: 1;
|
|
display: grid;
|
|
grid-template-columns: 1fr 60px 1fr 60px 1fr 60px 1fr;
|
|
gap: 0;
|
|
align-items: stretch;
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 18px;
|
|
padding: 4px;
|
|
}
|
|
.trail__node {
|
|
padding: 16px 18px;
|
|
border-radius: 14px;
|
|
background: transparent;
|
|
text-align: center;
|
|
transition: background .15s;
|
|
cursor: pointer;
|
|
display: flex; flex-direction: column; justify-content: center; gap: 6px;
|
|
position: relative;
|
|
}
|
|
.trail__node:hover { background: var(--glass); }
|
|
.trail__node-icon {
|
|
width: 36px; height: 36px;
|
|
margin: 0 auto;
|
|
border-radius: 12px;
|
|
display: grid; place-items: center;
|
|
background: var(--glass-elev);
|
|
border: 1px solid var(--rule);
|
|
color: var(--node-color, var(--lavender));
|
|
box-shadow: inset 0 1px 0 var(--highlight);
|
|
}
|
|
.trail__node-icon svg { width: 18px; height: 18px; }
|
|
.trail__node-label {
|
|
font-size: 10px; text-transform: uppercase; letter-spacing: 0.15em;
|
|
color: var(--mute); font-weight: 600;
|
|
margin-top: 2px;
|
|
}
|
|
.trail__node-name {
|
|
font-size: 14px; font-weight: 600; color: var(--fg);
|
|
line-height: 1.3;
|
|
}
|
|
.trail__node-name em {
|
|
font-family: 'Newsreader', serif;
|
|
font-style: italic;
|
|
color: var(--node-color, var(--lavender));
|
|
font-weight: 500;
|
|
-webkit-background-clip: text; background-clip: text;
|
|
}
|
|
.trail__node-meta {
|
|
font-family: 'Geist Mono', monospace;
|
|
font-size: 10.5px;
|
|
color: var(--mute);
|
|
}
|
|
.trail__wire {
|
|
display: flex; align-items: center; justify-content: center;
|
|
position: relative;
|
|
}
|
|
.trail__wire::before {
|
|
content: ''; position: absolute;
|
|
left: 0; right: 0; top: 50%;
|
|
height: 2px;
|
|
background: linear-gradient(90deg,
|
|
transparent,
|
|
var(--lavender) 30%,
|
|
var(--orchid) 70%,
|
|
transparent
|
|
);
|
|
border-radius: 2px;
|
|
opacity: 0.6;
|
|
}
|
|
.trail__wire::after {
|
|
content: '→';
|
|
position: relative;
|
|
background: var(--bg-deep);
|
|
color: var(--lavender);
|
|
font-size: 14px;
|
|
padding: 0 6px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* ============================================================
|
|
MAIN GRID — tabs (left) + side panels (right)
|
|
============================================================ */
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: 1.6fr 1fr;
|
|
gap: 18px;
|
|
}
|
|
|
|
.panel {
|
|
background: var(--glass);
|
|
backdrop-filter: blur(28px) saturate(160%);
|
|
-webkit-backdrop-filter: blur(28px) saturate(160%);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 22px;
|
|
box-shadow: var(--shadow-card);
|
|
overflow: hidden;
|
|
position: relative;
|
|
display: flex; flex-direction: column;
|
|
}
|
|
.panel::after {
|
|
content: ''; position: absolute; inset: 0;
|
|
border-radius: inherit; pointer-events: none;
|
|
background: linear-gradient(180deg, var(--highlight), transparent 30%);
|
|
opacity: 0.4;
|
|
}
|
|
|
|
/* TABS */
|
|
.tabs {
|
|
display: flex;
|
|
padding: 4px;
|
|
margin: 18px 18px 0;
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule);
|
|
border-radius: 14px;
|
|
gap: 2px;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.tabs button {
|
|
flex: 1;
|
|
padding: 9px 12px;
|
|
border: 0; background: transparent;
|
|
color: var(--fg-dim);
|
|
font-family: inherit;
|
|
font-size: 13px; font-weight: 600;
|
|
border-radius: 11px;
|
|
cursor: pointer;
|
|
transition: all .15s;
|
|
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
|
}
|
|
.tabs button:hover { color: var(--fg); }
|
|
.tabs button.is-active {
|
|
background: var(--glass-elev);
|
|
color: var(--fg);
|
|
box-shadow: inset 0 1px 0 var(--highlight), 0 2px 8px rgba(0,0,0,0.15);
|
|
}
|
|
.tabs button svg { width: 14px; height: 14px; }
|
|
.tabs button .badge {
|
|
background: var(--rule);
|
|
color: var(--fg);
|
|
font-size: 10px;
|
|
font-family: 'Geist Mono', monospace;
|
|
padding: 1px 6px;
|
|
border-radius: 999px;
|
|
font-weight: 500;
|
|
}
|
|
.tabs button.is-active .badge {
|
|
background: var(--lavender);
|
|
color: var(--bg-deep);
|
|
}
|
|
|
|
.tab-panel {
|
|
padding: 24px 28px 28px;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.tab-panel__head {
|
|
display: flex; justify-content: space-between; align-items: end;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 16px;
|
|
border-bottom: 1px solid var(--rule);
|
|
}
|
|
.tab-panel__title {
|
|
font-family: 'Newsreader', serif; font-weight: 400;
|
|
font-size: 22px; letter-spacing: -0.02em;
|
|
margin: 0;
|
|
}
|
|
.tab-panel__title em {
|
|
font-style: italic;
|
|
background: linear-gradient(135deg, var(--orchid), var(--lavender));
|
|
-webkit-background-clip: text; background-clip: text; color: transparent;
|
|
}
|
|
.tab-panel__hint {
|
|
font-size: 12.5px; color: var(--mute);
|
|
margin-top: 4px;
|
|
font-weight: 400;
|
|
}
|
|
|
|
/* FORM */
|
|
.field { margin-bottom: 20px; }
|
|
.field__label {
|
|
display: flex; align-items: center; gap: 8px;
|
|
font-size: 12.5px; font-weight: 600;
|
|
color: var(--fg);
|
|
margin-bottom: 8px;
|
|
}
|
|
.field__hint {
|
|
font-weight: 400; color: var(--mute);
|
|
font-size: 11px;
|
|
margin-left: auto;
|
|
}
|
|
.field__sub {
|
|
font-size: 12px; color: var(--mute);
|
|
margin-top: 6px;
|
|
line-height: 1.45;
|
|
}
|
|
.input, .select, .textarea {
|
|
width: 100%;
|
|
background: var(--input-bg);
|
|
border: 1px solid var(--rule-strong);
|
|
border-radius: 12px;
|
|
padding: 11px 14px;
|
|
color: var(--fg);
|
|
font-family: inherit;
|
|
font-size: 13.5px;
|
|
transition: all .15s;
|
|
}
|
|
.input:focus, .select:focus, .textarea:focus {
|
|
outline: none;
|
|
border-color: var(--lavender);
|
|
box-shadow: 0 0 0 3px var(--input-focus);
|
|
}
|
|
.input::placeholder, .textarea::placeholder { color: var(--mute); }
|
|
.textarea { font-family: 'Geist Mono', monospace; font-size: 12.5px; line-height: 1.5; resize: vertical; }
|
|
.field--mono .input { font-family: 'Geist Mono', monospace; font-size: 12.5px; }
|
|
|
|
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
|
.row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
|
|
|
|
/* CHECKBOXES — event types */
|
|
.checkboxes {
|
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
|
|
}
|
|
.check-item {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 12px 14px;
|
|
border-radius: 12px;
|
|
background: var(--input-bg);
|
|
border: 1px solid var(--rule-strong);
|
|
cursor: pointer;
|
|
transition: all .15s;
|
|
}
|
|
.check-item:hover { background: var(--glass-elev); }
|
|
.check-item.is-on {
|
|
border-color: var(--lavender);
|
|
background: rgba(184, 167, 255, 0.10);
|
|
}
|
|
.check-item__box {
|
|
width: 18px; height: 18px;
|
|
border-radius: 6px;
|
|
border: 1.5px solid var(--rule-strong);
|
|
display: grid; place-items: center;
|
|
flex-shrink: 0;
|
|
background: var(--input-bg);
|
|
transition: all .15s;
|
|
}
|
|
.check-item.is-on .check-item__box {
|
|
background: linear-gradient(135deg, var(--lavender), var(--orchid));
|
|
border-color: transparent;
|
|
box-shadow: 0 0 8px -2px var(--lavender);
|
|
}
|
|
.check-item__box svg { width: 12px; height: 12px; color: white; opacity: 0; transition: opacity .15s; }
|
|
.check-item.is-on .check-item__box svg { opacity: 1; }
|
|
.check-item__icon {
|
|
width: 28px; height: 28px;
|
|
border-radius: 8px;
|
|
background: var(--glass-elev);
|
|
display: grid; place-items: center;
|
|
flex-shrink: 0;
|
|
color: var(--ev-color, var(--fg-dim));
|
|
}
|
|
.check-item__icon svg { width: 16px; height: 16px; }
|
|
.check-item__main { flex: 1; min-width: 0; }
|
|
.check-item__name { font-size: 13px; font-weight: 600; color: var(--fg); }
|
|
.check-item__sub { font-size: 11px; color: var(--mute); margin-top: 1px; }
|
|
|
|
/* TARGET ASSIGNMENTS — pill row */
|
|
.targets-pills {
|
|
display: flex; flex-wrap: wrap; gap: 8px;
|
|
}
|
|
.tgt-pill {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
padding: 8px 12px 8px 8px;
|
|
border-radius: 999px;
|
|
background: var(--glass-strong);
|
|
border: 1px solid var(--rule-strong);
|
|
font-size: 12.5px;
|
|
color: var(--fg);
|
|
font-weight: 500;
|
|
transition: all .15s;
|
|
cursor: pointer;
|
|
}
|
|
.tgt-pill:hover { background: var(--glass-elev); }
|
|
.tgt-pill__icon {
|
|
width: 22px; height: 22px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--pill-from, var(--lavender)), var(--pill-to, var(--orchid)));
|
|
display: grid; place-items: center;
|
|
color: white;
|
|
flex-shrink: 0;
|
|
}
|
|
.tgt-pill__icon svg { width: 12px; height: 12px; }
|
|
.tgt-pill__remove {
|
|
color: var(--mute);
|
|
cursor: pointer;
|
|
width: 16px; height: 16px;
|
|
display: grid; place-items: center;
|
|
border-radius: 50%;
|
|
transition: all .15s;
|
|
}
|
|
.tgt-pill__remove:hover { background: rgba(255,138,120,0.2); color: var(--coral); }
|
|
.tgt-pill--add {
|
|
background: transparent;
|
|
border-style: dashed;
|
|
color: var(--fg-dim);
|
|
}
|
|
|
|
/* SAVE BAR */
|
|
.savebar {
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
padding: 18px 28px;
|
|
background: var(--glass-strong);
|
|
border-top: 1px solid var(--rule);
|
|
margin-top: auto;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.savebar__status {
|
|
display: flex; align-items: center; gap: 8px;
|
|
font-size: 12.5px; color: var(--fg-dim);
|
|
}
|
|
.savebar__status .dot {
|
|
width: 8px; height: 8px; border-radius: 50%;
|
|
background: var(--citrus);
|
|
box-shadow: 0 0 6px var(--citrus);
|
|
}
|
|
.savebar__actions { display: flex; gap: 8px; }
|
|
.primary-btn {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
padding: 0 18px; height: 38px;
|
|
border-radius: 12px;
|
|
border: 0;
|
|
background: linear-gradient(135deg, var(--lavender), var(--orchid));
|
|
color: white;
|
|
font-family: inherit;
|
|
font-size: 13px; font-weight: 600;
|
|
cursor: pointer;
|
|
box-shadow: 0 6px 20px -8px rgba(184,167,255,0.6), inset 0 1px 0 rgba(255,255,255,0.4);
|
|
transition: transform .15s;
|
|
}
|
|
.primary-btn:hover { transform: translateY(-1px); }
|
|
.primary-btn svg { width: 14px; height: 14px; }
|
|
|
|
/* ============================================================
|
|
RIGHT COLUMN — preview + recent events
|
|
============================================================ */
|
|
.side { display: flex; flex-direction: column; gap: 18px; }
|
|
|
|
.panel__head {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 22px 24px 14px;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.panel__title {
|
|
font-family: 'Newsreader', serif; font-weight: 400;
|
|
font-size: 20px; letter-spacing: -0.02em;
|
|
margin: 0;
|
|
}
|
|
.panel__title em {
|
|
font-style: italic;
|
|
background: linear-gradient(135deg, var(--mint), var(--sky));
|
|
-webkit-background-clip: text; background-clip: text; color: transparent;
|
|
}
|
|
.panel__title.acc-orchid em {
|
|
background: linear-gradient(135deg, var(--orchid), var(--lavender));
|
|
-webkit-background-clip: text; background-clip: text;
|
|
}
|
|
.panel__meta { font-size: 11.5px; color: var(--mute); display: flex; gap: 12px; align-items: center; }
|
|
.panel__meta b { color: var(--fg); font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
|
|
/* PREVIEW pane — chat-style mock */
|
|
.preview {
|
|
padding: 6px 24px 22px;
|
|
position: relative; z-index: 1;
|
|
}
|
|
.preview__device {
|
|
background: var(--glass-elev);
|
|
border: 1px solid var(--rule-strong);
|
|
border-radius: 18px;
|
|
padding: 14px;
|
|
box-shadow: 0 1px 0 var(--highlight) inset, 0 12px 30px -16px rgba(0,0,0,0.4);
|
|
}
|
|
.preview__head {
|
|
display: flex; align-items: center; gap: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.preview__head-icon {
|
|
width: 28px; height: 28px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, #29b6f6, #0288d1);
|
|
display: grid; place-items: center;
|
|
color: white;
|
|
}
|
|
.preview__head-icon svg { width: 14px; height: 14px; }
|
|
.preview__head-name { font-size: 13px; font-weight: 600; }
|
|
.preview__head-sub { font-size: 11px; color: var(--mute); margin-top: 1px; }
|
|
.preview__head-time {
|
|
margin-left: auto;
|
|
font-family: 'Geist Mono', monospace;
|
|
font-size: 10.5px; color: var(--mute);
|
|
}
|
|
.preview__bubble {
|
|
background: rgba(135, 206, 250, 0.08);
|
|
border: 1px solid rgba(135, 206, 250, 0.2);
|
|
border-radius: 16px 16px 16px 4px;
|
|
padding: 12px 14px;
|
|
font-size: 13.5px;
|
|
line-height: 1.55;
|
|
}
|
|
.preview__bubble b { font-weight: 700; }
|
|
.preview__bubble a { color: var(--sky); text-decoration: none; }
|
|
.preview__bubble a:hover { text-decoration: underline; }
|
|
.preview__bubble .muted { color: var(--mute); }
|
|
.preview__media {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 4px;
|
|
margin-top: 10px;
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
}
|
|
.preview__media-cell {
|
|
aspect-ratio: 1; border-radius: 6px;
|
|
background-size: cover; background-position: center;
|
|
}
|
|
/* Six cells, varied palette gradients to fake images */
|
|
.pmc-1 { background: linear-gradient(135deg, #ffb56a, #ff8a78); }
|
|
.pmc-2 { background: linear-gradient(135deg, #a0e8c4, #6db5fa); }
|
|
.pmc-3 { background: linear-gradient(135deg, #b8a7ff, #ff9ec4); }
|
|
.pmc-4 { background: linear-gradient(135deg, #f0e16a, #e8a050); }
|
|
.pmc-5 { background: linear-gradient(135deg, #8ec9ff, #b8a7ff); }
|
|
.pmc-6 { background: linear-gradient(135deg, #ff9ec4, #ffb56a); }
|
|
.preview__footer {
|
|
margin-top: 12px;
|
|
padding-top: 10px;
|
|
border-top: 1px solid var(--rule);
|
|
font-size: 11px; color: var(--mute);
|
|
display: flex; justify-content: space-between;
|
|
}
|
|
.preview__refresh {
|
|
cursor: pointer; color: var(--fg-dim);
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
transition: color .15s;
|
|
}
|
|
.preview__refresh:hover { color: var(--lavender); }
|
|
.preview__refresh svg { width: 12px; height: 12px; }
|
|
|
|
/* EVENT LOG */
|
|
.events { padding: 6px 0 14px; position: relative; z-index: 1; }
|
|
.event {
|
|
display: grid;
|
|
grid-template-columns: 38px 1fr auto;
|
|
gap: 14px;
|
|
padding: 12px 24px;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
transition: background .15s;
|
|
}
|
|
.event + .event { border-top: 1px solid var(--rule); }
|
|
.event:hover { background: var(--glass-strong); }
|
|
.event__avatar {
|
|
width: 38px; height: 38px;
|
|
border-radius: 12px;
|
|
display: grid; place-items: center;
|
|
background: linear-gradient(135deg, var(--ev-from, var(--lavender)), var(--ev-to, var(--orchid)));
|
|
color: white;
|
|
box-shadow: 0 4px 14px -4px var(--ev-from, rgba(184,167,255,0.4)), inset 0 1px 0 rgba(255,255,255,0.3);
|
|
}
|
|
.event__avatar svg { width: 17px; height: 17px; }
|
|
.event__head {
|
|
font-size: 13.5px; line-height: 1.4;
|
|
}
|
|
.event__head b { font-weight: 600; color: var(--fg); }
|
|
.event__head .v { color: var(--fg-dim); font-weight: 400; }
|
|
.event__sub {
|
|
margin-top: 3px;
|
|
font-size: 11.5px; color: var(--mute);
|
|
}
|
|
.event__sub .ch {
|
|
color: var(--fg-dim); font-family: 'Geist Mono', monospace;
|
|
font-size: 10.5px;
|
|
background: var(--glass-strong); padding: 1px 6px; border-radius: 5px;
|
|
}
|
|
.event__when {
|
|
text-align: right;
|
|
font-family: 'Geist Mono', monospace;
|
|
font-size: 10.5px; color: var(--mute);
|
|
}
|
|
.event__when b { display: block; color: var(--fg-dim); font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
|
|
/* SCHEDULE preview (mini calendar bars) */
|
|
.sched-row {
|
|
display: grid;
|
|
grid-template-columns: 38px repeat(24, 1fr);
|
|
gap: 2px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.sched-day {
|
|
font-family: 'Geist Mono', monospace;
|
|
font-size: 9.5px; color: var(--mute);
|
|
text-align: right; padding-right: 6px;
|
|
line-height: 12px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
}
|
|
.sched-cell {
|
|
height: 12px; border-radius: 3px;
|
|
background: var(--glass-strong);
|
|
}
|
|
.sched-cell.on {
|
|
background: linear-gradient(180deg, var(--lavender), var(--orchid));
|
|
box-shadow: 0 0 6px -2px var(--lavender);
|
|
}
|
|
|
|
/* THEME TOGGLE */
|
|
.theme-toggle {
|
|
position: fixed; right: 22px; top: 22px; z-index: 50;
|
|
background: var(--glass);
|
|
backdrop-filter: blur(28px) saturate(160%);
|
|
border: 1px solid var(--rule-strong);
|
|
border-radius: 999px;
|
|
padding: 4px;
|
|
display: inline-flex;
|
|
box-shadow: var(--shadow-card);
|
|
}
|
|
.theme-toggle button {
|
|
padding: 7px 14px;
|
|
border: 0; background: transparent;
|
|
color: var(--fg-dim);
|
|
font-family: inherit;
|
|
font-size: 11.5px; font-weight: 500;
|
|
border-radius: 999px; cursor: pointer;
|
|
}
|
|
.theme-toggle button.is-active { background: var(--fg); color: var(--bg); }
|
|
|
|
@keyframes rise {
|
|
from { opacity: 0; transform: translateY(14px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.stagger > * { animation: rise .6s cubic-bezier(.2,.7,.2,1) both; }
|
|
.stagger > *:nth-child(1){animation-delay:.05s}
|
|
.stagger > *:nth-child(2){animation-delay:.13s}
|
|
.stagger > *:nth-child(3){animation-delay:.21s}
|
|
.stagger > *:nth-child(4){animation-delay:.29s}
|
|
.stagger > *:nth-child(5){animation-delay:.37s}
|
|
|
|
@media (max-width: 1100px) {
|
|
.grid { grid-template-columns: 1fr; }
|
|
.trail { grid-template-columns: 1fr 1fr; }
|
|
.trail__wire { display: none; }
|
|
}
|
|
@media (max-width: 820px) {
|
|
.shell { grid-template-columns: 1fr; padding: 12px; }
|
|
.rail { position: static; height: auto; }
|
|
.hero { padding: 22px 20px; }
|
|
.hero__row { grid-template-columns: 1fr; }
|
|
.hero__title { font-size: 32px; }
|
|
.checkboxes { grid-template-columns: 1fr; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="grain"></div>
|
|
|
|
<div class="theme-toggle">
|
|
<button id="t-dark" class="is-active" onclick="setTheme('dark')">Aurora</button>
|
|
<button id="t-pearl" onclick="setTheme('pearl')">Pearl</button>
|
|
</div>
|
|
|
|
<div class="shell">
|
|
|
|
<!-- RAIL -->
|
|
<aside class="rail">
|
|
<div class="rail__brand">
|
|
<div class="rail__logo"></div>
|
|
<div class="rail__brand-text">
|
|
<b>Notify Bridge</b><br>
|
|
<small>v0.5.2</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rail__group">
|
|
<div class="rail__label">Overview</div>
|
|
<nav class="rail__nav">
|
|
<a href="dashboard-aurora.html" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 12h4l3-9 4 18 3-9h4"/></svg>
|
|
Signal
|
|
<span class="count">live</span>
|
|
</a>
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>
|
|
Providers
|
|
<span class="count">04</span>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="rail__group">
|
|
<div class="rail__label">Routing</div>
|
|
<nav class="rail__nav">
|
|
<a href="#" class="rail__link is-active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="3"/><circle cx="12" cy="12" r="8"/><path d="M12 4v3M12 17v3M4 12h3M17 12h3"/></svg>
|
|
Trackers <span class="count">12</span>
|
|
</a>
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
|
Templates <span class="count">28</span>
|
|
</a>
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
|
|
Targets <span class="count">19</span>
|
|
</a>
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M5 12l3 3 6-6 6 6"/></svg>
|
|
Actions <span class="count">07</span>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="rail__group">
|
|
<div class="rail__label">Operators</div>
|
|
<nav class="rail__nav">
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="9" cy="10" r="1.2"/><circle cx="15" cy="10" r="1.2"/><path d="M8 16c1.5 1 6.5 1 8 0"/></svg>
|
|
Bots <span class="count">06</span>
|
|
</a>
|
|
<a href="#" class="rail__link">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 18l5-5 5 5 5-9"/></svg>
|
|
Commands <span class="count">14</span>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="rail__foot">
|
|
<div class="rail__op">
|
|
<div class="rail__avatar">A</div>
|
|
<div>
|
|
<div class="rail__op-name">alexei</div>
|
|
<div class="rail__op-role">administrator</div>
|
|
</div>
|
|
<div class="rail__chip"></div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- MAIN -->
|
|
<main class="main stagger">
|
|
|
|
<!-- TOP BAR -->
|
|
<div class="topbar">
|
|
<div class="crumbs">
|
|
<a href="dashboard-aurora.html">Signal</a>
|
|
<span class="sep">/</span>
|
|
<a href="#">Trackers</a>
|
|
<span class="sep">/</span>
|
|
<span class="here">family-photos</span>
|
|
</div>
|
|
<button class="icon-btn" title="Duplicate">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
</button>
|
|
<button class="icon-btn" title="Notifications">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- HERO -->
|
|
<section class="hero">
|
|
<div class="hero__row">
|
|
<div>
|
|
<div class="hero__chip">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2.5"/><circle cx="9" cy="11" r="2"/><path d="M3 17l5-5 4 4 3-3 6 6"/></svg>
|
|
<b>Immich</b> · photos.dolgolyov.dev
|
|
</div>
|
|
<h1 class="hero__title">family<em>-photos</em><span class="hero__pill-live">live</span></h1>
|
|
<p class="hero__sub">
|
|
Watches three albums (<b>«Семейный 2025»</b>, <b>«Прага 24»</b>, <b>«Лето на даче»</b>) for added or removed assets,
|
|
collection renames, and shared-link changes. Currently routing <b>1 942 events</b> across the last 24 hours
|
|
into <b>three targets</b>.
|
|
</p>
|
|
</div>
|
|
<div class="hero__actions">
|
|
<div class="toggle">
|
|
<div class="toggle__sw"></div>
|
|
<span class="toggle__label">Armed</span>
|
|
</div>
|
|
<button class="ghost-btn">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.1 2.1 0 1 1 3 3L12 15l-4 1 1-4z"/></svg>
|
|
Edit
|
|
</button>
|
|
<button class="ghost-btn danger-btn" title="Delete tracker">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ROUTING TRAIL -->
|
|
<div class="trail">
|
|
<div class="trail__node" style="--node-color: var(--lavender)">
|
|
<div class="trail__node-icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M3 17l5-5 4 4 3-3 6 6"/></svg>
|
|
</div>
|
|
<div class="trail__node-label">Provider</div>
|
|
<div class="trail__node-name">Immich</div>
|
|
<div class="trail__node-meta">8 trackers</div>
|
|
</div>
|
|
<div class="trail__wire"></div>
|
|
|
|
<div class="trail__node" style="--node-color: var(--orchid)">
|
|
<div class="trail__node-icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="3"/><circle cx="12" cy="12" r="8"/></svg>
|
|
</div>
|
|
<div class="trail__node-label">Tracker</div>
|
|
<div class="trail__node-name"><em>family-photos</em></div>
|
|
<div class="trail__node-meta">5 events armed</div>
|
|
</div>
|
|
<div class="trail__wire"></div>
|
|
|
|
<div class="trail__node" style="--node-color: var(--mint)">
|
|
<div class="trail__node-icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
|
</div>
|
|
<div class="trail__node-label">Templates</div>
|
|
<div class="trail__node-name">5 Jinja2</div>
|
|
<div class="trail__node-meta">en + ru</div>
|
|
</div>
|
|
<div class="trail__wire"></div>
|
|
|
|
<div class="trail__node" style="--node-color: var(--sky)">
|
|
<div class="trail__node-icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/></svg>
|
|
</div>
|
|
<div class="trail__node-label">Targets</div>
|
|
<div class="trail__node-name">3 channels</div>
|
|
<div class="trail__node-meta">tg · matrix · email</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- GRID — config (left) + preview & events (right) -->
|
|
<section class="grid">
|
|
|
|
<!-- LEFT: tabs + form -->
|
|
<div class="panel">
|
|
<div class="tabs">
|
|
<button class="is-active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8M4.3 8a1.7 1.7 0 0 0 .3 1.8"/></svg>
|
|
Configuration
|
|
</button>
|
|
<button>
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
|
Templates <span class="badge">5</span>
|
|
</button>
|
|
<button>
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/></svg>
|
|
Targets <span class="badge">3</span>
|
|
</button>
|
|
<button>
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
|
|
Schedule
|
|
</button>
|
|
</div>
|
|
|
|
<div class="tab-panel">
|
|
<div class="tab-panel__head">
|
|
<div>
|
|
<h2 class="tab-panel__title">Watch <em>configuration</em></h2>
|
|
<div class="tab-panel__hint">What this tracker listens for, and where to find it</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="field__label">Tracker name</label>
|
|
<input class="input" type="text" value="family-photos" />
|
|
<div class="field__sub">Used internally for routing and event logs.</div>
|
|
</div>
|
|
|
|
<div class="row-2">
|
|
<div class="field">
|
|
<label class="field__label">Provider</label>
|
|
<select class="select">
|
|
<option>Immich · photos.dolgolyov.dev</option>
|
|
<option>Gitea · git.dolgolyov-family.by</option>
|
|
<option>GitHub · anthropics/claude-code</option>
|
|
</select>
|
|
</div>
|
|
<div class="field">
|
|
<label class="field__label">Poll interval <span class="field__hint">seconds</span></label>
|
|
<input class="input" type="text" value="30" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="field__label">Albums to watch <span class="field__hint">3 selected</span></label>
|
|
<div class="targets-pills">
|
|
<span class="tgt-pill" style="--pill-from: var(--lavender); --pill-to: var(--orchid)">
|
|
<span class="tgt-pill__icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="2"/></svg>
|
|
</span>
|
|
Семейный 2025
|
|
<span class="tgt-pill__remove"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 6l12 12M6 18L18 6"/></svg></span>
|
|
</span>
|
|
<span class="tgt-pill" style="--pill-from: var(--mint); --pill-to: var(--sky)">
|
|
<span class="tgt-pill__icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="2"/></svg>
|
|
</span>
|
|
Прага 24
|
|
<span class="tgt-pill__remove"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 6l12 12M6 18L18 6"/></svg></span>
|
|
</span>
|
|
<span class="tgt-pill" style="--pill-from: var(--citrus); --pill-to: var(--coral)">
|
|
<span class="tgt-pill__icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="2"/></svg>
|
|
</span>
|
|
Лето на даче
|
|
<span class="tgt-pill__remove"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 6l12 12M6 18L18 6"/></svg></span>
|
|
</span>
|
|
<span class="tgt-pill tgt-pill--add">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><path d="M12 5v14M5 12h14"/></svg>
|
|
Add album
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="field__label">Event types to dispatch <span class="field__hint">choose any</span></label>
|
|
<div class="checkboxes">
|
|
<label class="check-item is-on" style="--ev-color: var(--mint)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M9 11h6M12 8v6"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Assets added</div>
|
|
<div class="check-item__sub">When new photos appear in album</div>
|
|
</span>
|
|
</label>
|
|
|
|
<label class="check-item is-on" style="--ev-color: var(--coral)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M9 12h6"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Assets removed</div>
|
|
<div class="check-item__sub">When photos disappear</div>
|
|
</span>
|
|
</label>
|
|
|
|
<label class="check-item is-on" style="--ev-color: var(--lavender)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.1 2.1 0 1 1 3 3L12 15l-4 1 1-4z"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Album renamed</div>
|
|
<div class="check-item__sub">When the title changes</div>
|
|
</span>
|
|
</label>
|
|
|
|
<label class="check-item" style="--ev-color: var(--citrus)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.5 13.5l7 4M8.5 10.5l7-4"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Sharing changed</div>
|
|
<div class="check-item__sub">Link created, expired, removed</div>
|
|
</span>
|
|
</label>
|
|
|
|
<label class="check-item is-on" style="--ev-color: var(--sky)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Memory dispatch</div>
|
|
<div class="check-item__sub">«One year ago today» weekly</div>
|
|
</span>
|
|
</label>
|
|
|
|
<label class="check-item" style="--ev-color: var(--orchid)">
|
|
<span class="check-item__box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M4 12l5 5 11-12"/></svg></span>
|
|
<span class="check-item__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 12c2-5 6-7 9-7s7 2 9 7c-2 5-6 7-9 7s-7-2-9-7z"/><circle cx="12" cy="12" r="3"/></svg></span>
|
|
<span class="check-item__main">
|
|
<div class="check-item__name">Favorited</div>
|
|
<div class="check-item__sub">When an asset is starred</div>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row-2">
|
|
<div class="field field--mono">
|
|
<label class="field__label">Min batch size</label>
|
|
<input class="input" type="text" value="1" />
|
|
<div class="field__sub">Hold notifications until N items collected.</div>
|
|
</div>
|
|
<div class="field field--mono">
|
|
<label class="field__label">Coalesce window</label>
|
|
<input class="input" type="text" value="120s" />
|
|
<div class="field__sub">Group events within this window into one message.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="savebar">
|
|
<div class="savebar__status">
|
|
<span class="dot"></span>
|
|
<span>Unsaved changes — <b style="color:var(--fg)">2 fields</b> modified</span>
|
|
</div>
|
|
<div class="savebar__actions">
|
|
<button class="ghost-btn">Discard</button>
|
|
<button class="primary-btn">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M5 13l4 4L19 7"/></svg>
|
|
Save changes
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RIGHT: preview + events -->
|
|
<div class="side">
|
|
|
|
<!-- LIVE PREVIEW -->
|
|
<div class="panel">
|
|
<div class="panel__head">
|
|
<div>
|
|
<h2 class="panel__title acc-orchid">Live <em>preview</em></h2>
|
|
<div class="tab-panel__hint">Rendered with sample data — assets_added.ru</div>
|
|
</div>
|
|
<button class="icon-btn" title="Refresh">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 4v5h-5"/></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="preview">
|
|
<div class="preview__device">
|
|
<div class="preview__head">
|
|
<div class="preview__head-icon">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4z"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="preview__head-name">Notify Bridge</div>
|
|
<div class="preview__head-sub">@notifybridge_bot · @family</div>
|
|
</div>
|
|
<div class="preview__head-time">02:14</div>
|
|
</div>
|
|
<div class="preview__bubble">
|
|
📸 <b>14 новых фото в «Семейный 2025»</b><br>
|
|
<span class="muted">Прага · 13 апреля · добавил <b>alexei</b></span><br>
|
|
<a href="#">Смотреть в Immich →</a>
|
|
<div class="preview__media">
|
|
<div class="preview__media-cell pmc-1"></div>
|
|
<div class="preview__media-cell pmc-2"></div>
|
|
<div class="preview__media-cell pmc-3"></div>
|
|
<div class="preview__media-cell pmc-4"></div>
|
|
<div class="preview__media-cell pmc-5"></div>
|
|
<div class="preview__media-cell pmc-6"></div>
|
|
</div>
|
|
</div>
|
|
<div class="preview__footer">
|
|
<span>Length · 184 chars · 6 attachments</span>
|
|
<a class="preview__refresh" href="#">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 4v5h-5"/></svg>
|
|
Re-render
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RECENT EVENTS for THIS tracker -->
|
|
<div class="panel">
|
|
<div class="panel__head">
|
|
<div>
|
|
<h2 class="panel__title">Recent <em>events</em></h2>
|
|
<div class="tab-panel__hint">For this tracker only · last 24h</div>
|
|
</div>
|
|
<div class="panel__meta"><b>14</b>events</div>
|
|
</div>
|
|
|
|
<div class="events">
|
|
<div class="event" style="--ev-from: var(--mint); --ev-to: var(--sky)">
|
|
<div class="event__avatar">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M9 11h6M12 8v6"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="event__head"><span class="v">Added</span> <b>14 assets</b></div>
|
|
<div class="event__sub">to <span class="ch">Семейный 2025</span></div>
|
|
</div>
|
|
<div class="event__when"><b>02:14</b>just now</div>
|
|
</div>
|
|
|
|
<div class="event" style="--ev-from: var(--mint); --ev-to: var(--lavender)">
|
|
<div class="event__avatar">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M9 11h6M12 8v6"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="event__head"><span class="v">Added</span> <b>3 assets</b></div>
|
|
<div class="event__sub">to <span class="ch">Лето на даче</span></div>
|
|
</div>
|
|
<div class="event__when"><b>01:48</b>26m ago</div>
|
|
</div>
|
|
|
|
<div class="event" style="--ev-from: var(--citrus); --ev-to: var(--coral)">
|
|
<div class="event__avatar">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.5 13.5l7 4M8.5 10.5l7-4"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="event__head"><span class="v">Shared link</span> <b>expired</b></div>
|
|
<div class="event__sub">for <span class="ch">Прага 24</span></div>
|
|
</div>
|
|
<div class="event__when"><b>00:22</b>2h ago</div>
|
|
</div>
|
|
|
|
<div class="event" style="--ev-from: var(--lavender); --ev-to: var(--orchid)">
|
|
<div class="event__avatar">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.1 2.1 0 1 1 3 3L12 15l-4 1 1-4z"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="event__head"><span class="v">Renamed</span> <b>«Прага 2024» → «Прага 24»</b></div>
|
|
<div class="event__sub">at <span class="ch">photos.dolgolyov.dev</span></div>
|
|
</div>
|
|
<div class="event__when"><b>Apr 24</b>1d ago</div>
|
|
</div>
|
|
|
|
<div class="event" style="--ev-from: var(--sky); --ev-to: var(--mint)">
|
|
<div class="event__avatar">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="event__head"><span class="v">Memory dispatched</span> <b>«Один год назад»</b></div>
|
|
<div class="event__sub">6 photos · Apr 24, 2025</div>
|
|
</div>
|
|
<div class="event__when"><b>Apr 24</b>1d ago</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
function setTheme(t) {
|
|
document.documentElement.setAttribute('data-theme', t);
|
|
document.getElementById('t-dark').classList.toggle('is-active', t === 'dark');
|
|
document.getElementById('t-pearl').classList.toggle('is-active', t === 'pearl');
|
|
}
|
|
// Toggle the on/off switch
|
|
document.querySelectorAll('.toggle').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
el.classList.toggle('is-off');
|
|
el.querySelector('.toggle__label').textContent = el.classList.contains('is-off') ? 'Paused' : 'Armed';
|
|
});
|
|
});
|
|
// Toggle checkboxes
|
|
document.querySelectorAll('.check-item').forEach(el => {
|
|
el.addEventListener('click', e => { e.preventDefault(); el.classList.toggle('is-on'); });
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|