Created
September 9, 2026 14:43
-
-
Save pmdroid/00ce13b49c6493e84ea2e39358a45f4c to your computer and use it in GitHub Desktop.
BarkVisor Create App: Immich and Plex (Big Bear fields). Not shipped UI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>BarkVisor — Create Immich</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg: #0a0e14; | |
| --surface: #10151d; | |
| --surface-2: #151c26; | |
| --border: #1f2833; | |
| --text: #e4e4e2; | |
| --text-secondary: #b8b8b4; | |
| --text-dim: #6e6e6c; | |
| --accent: #0090f8; | |
| --green: #34d399; | |
| --red: #f87171; | |
| --amber: #fbbf24; | |
| --radius: 2px; | |
| } | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: 'Inter', -apple-system, sans-serif; | |
| font-size: 14px; | |
| min-height: 100vh; | |
| } | |
| .layout { display: flex; width: 1280px; margin: 0 auto; min-height: 100vh; } | |
| /* Sidebar */ | |
| .sidebar { | |
| width: 220px; | |
| flex-shrink: 0; | |
| background: rgba(8,12,18,0.92); | |
| border-right: 1px solid var(--border); | |
| padding: 18px 12px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| position: sticky; | |
| top: 0; | |
| height: 100vh; | |
| } | |
| .brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 16px; } | |
| .logo { | |
| width: 22px; height: 22px; border-radius: 5px; | |
| background: var(--accent); | |
| display: flex; align-items: center; justify-content: center; gap: 2px; | |
| } | |
| .logo span { width: 2.5px; background: #fff; border-radius: 1px; } | |
| .logo span:nth-child(1) { height: 8px; } | |
| .logo span:nth-child(2) { height: 13px; } | |
| .logo span:nth-child(3) { height: 10px; } | |
| .logo span:nth-child(4) { height: 6px; } | |
| .brand-name { font-weight: 700; font-size: 15px; letter-spacing: -0.01em; } | |
| .scope { | |
| margin: 0 4px 14px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| color: var(--text-secondary); | |
| font-size: 12px; | |
| padding: 7px 10px; | |
| display: flex; justify-content: space-between; align-items: center; | |
| } | |
| .scope .chev { color: var(--text-dim); font-size: 10px; } | |
| .nav-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); padding: 10px 10px 4px; } | |
| .nav-item { | |
| display: flex; align-items: center; gap: 10px; | |
| padding: 7px 10px; | |
| border-radius: var(--radius); | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| font-size: 13px; | |
| font-weight: 500; | |
| } | |
| .nav-item.active { background: rgba(0,144,248,0.12); color: var(--accent); } | |
| .nav-item .dot-ic { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.7; } | |
| /* Main (dimmed behind overlay) */ | |
| .main { flex: 1; padding: 28px 32px 60px; filter: brightness(0.45); pointer-events: none; user-select: none; } | |
| h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; } | |
| .ops-sub { color: var(--text-dim); font-size: 13px; margin-top: 6px; margin-bottom: 20px; } | |
| .ghost-sheet { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); height: 420px; } | |
| /* Magazine overlay */ | |
| .overlay { | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(4,6,10,0.72); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 50; | |
| } | |
| .magazine { | |
| width: 720px; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| background: #0d1219; | |
| border: 1px solid #26303d; | |
| border-radius: 6px; | |
| box-shadow: 0 24px 80px rgba(0,0,0,0.6); | |
| padding: 26px 28px 22px; | |
| } | |
| .mag-head { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 4px; } | |
| .mag-title { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; display: flex; align-items: center; gap: 10px; } | |
| .picked { | |
| display: inline-flex; align-items: center; gap: 6px; | |
| font-size: 11px; font-weight: 600; | |
| padding: 3px 9px; | |
| border-radius: 999px; | |
| background: rgba(0,144,248,0.12); | |
| color: var(--accent); | |
| } | |
| .mag-close { | |
| background: none; border: none; color: var(--text-dim); | |
| font-size: 18px; cursor: pointer; line-height: 1; padding: 2px 6px; | |
| } | |
| .steps { display: flex; align-items: center; gap: 8px; margin: 10px 0 22px; font-size: 12px; } | |
| .step { display: flex; align-items: center; gap: 7px; color: var(--text-dim); font-weight: 500; } | |
| .step .n { | |
| width: 20px; height: 20px; border-radius: 50%; | |
| border: 1px solid var(--border); | |
| display: inline-flex; align-items: center; justify-content: center; | |
| font-size: 11px; font-weight: 600; | |
| } | |
| .step.done { color: var(--green); } | |
| .step.done .n { border-color: var(--green); background: rgba(52,211,153,0.1); } | |
| .step.current { color: var(--accent); } | |
| .step.current .n { border-color: var(--accent); background: rgba(0,144,248,0.12); } | |
| .step-sep { width: 26px; height: 1px; background: var(--border); } | |
| /* Form */ | |
| .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; } | |
| .field { display: flex; flex-direction: column; gap: 6px; } | |
| .field.full { grid-column: 1 / -1; } | |
| .field label { font-size: 12px; font-weight: 600; color: var(--text-secondary); } | |
| .field label .req { color: var(--red); } | |
| .input, .select { | |
| font-family: inherit; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| color: var(--text); | |
| font-size: 13px; | |
| padding: 9px 11px; | |
| outline: none; | |
| } | |
| .input:focus, .select:focus { border-color: var(--accent); } | |
| .input.mono { font-family: ui-monospace, 'SF Mono', monospace; font-size: 12px; } | |
| .field .help { font-size: 11px; color: var(--text-dim); } | |
| /* Device picker cards */ | |
| .device-pick { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } | |
| .dev-card { | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| background: var(--surface); | |
| padding: 12px 14px; | |
| cursor: pointer; | |
| } | |
| .dev-card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: rgba(0,144,248,0.05); } | |
| .dev-card .dn { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; } | |
| .dev-card .dn .odot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); } | |
| .dev-card .ds { font-size: 11.5px; color: var(--text-dim); margin-top: 4px; } | |
| /* Runtime options */ | |
| .rt-list { display: flex; flex-direction: column; gap: 8px; } | |
| .rt-opt { | |
| display: flex; align-items: center; gap: 12px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| background: var(--surface); | |
| padding: 11px 14px; | |
| cursor: pointer; | |
| } | |
| .rt-opt.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: rgba(0,144,248,0.05); } | |
| .rt-opt.disabled { opacity: 0.5; cursor: not-allowed; } | |
| .radio { | |
| width: 15px; height: 15px; border-radius: 50%; | |
| border: 1.5px solid var(--text-dim); | |
| flex-shrink: 0; | |
| display: flex; align-items: center; justify-content: center; | |
| } | |
| .rt-opt.selected .radio { border-color: var(--accent); } | |
| .rt-opt.selected .radio::after { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); } | |
| .rt-opt .rt-name { font-size: 13px; font-weight: 600; } | |
| .rt-opt .rt-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; } | |
| .rt-badge { | |
| margin-left: auto; | |
| font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; | |
| color: var(--amber); | |
| border: 1px solid rgba(251,191,36,0.4); | |
| padding: 2px 7px; | |
| border-radius: var(--radius); | |
| } | |
| .section-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); font-weight: 600; margin: 22px 0 12px; padding-top: 18px; border-top: 1px solid var(--border); } | |
| /* Env rows */ | |
| .env-row { display: grid; grid-template-columns: 1fr 1fr 30px; gap: 8px; margin-bottom: 8px; align-items: center; } | |
| .env-del { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 14px; } | |
| .env-del:hover { color: var(--red); } | |
| .add-row { background: none; border: none; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; padding: 2px 0; font-family: inherit; } | |
| /* Digest + URL preview */ | |
| .digest-box { | |
| display: flex; align-items: center; gap: 10px; | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| padding: 10px 12px; | |
| font-family: ui-monospace, 'SF Mono', monospace; | |
| font-size: 11.5px; | |
| color: var(--text-secondary); | |
| } | |
| .digest-box .dg-label { font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; } | |
| .url-preview { | |
| display: flex; align-items: center; gap: 10px; | |
| background: rgba(52,211,153,0.06); | |
| border: 1px solid rgba(52,211,153,0.25); | |
| border-radius: var(--radius); | |
| padding: 10px 12px; | |
| font-size: 12.5px; | |
| } | |
| .url-preview .up-label { color: var(--text-dim); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } | |
| .url-preview a { color: var(--green); text-decoration: none; font-family: ui-monospace, monospace; font-size: 12px; } | |
| .mag-foot { | |
| display: flex; align-items: center; justify-content: space-between; | |
| margin-top: 24px; padding-top: 16px; | |
| border-top: 1px solid var(--border); | |
| } | |
| .mag-actions { display: flex; gap: 8px; } | |
| .btn { | |
| font-family: inherit; | |
| font-size: 12.5px; font-weight: 600; | |
| border-radius: var(--radius); | |
| padding: 8px 16px; | |
| cursor: pointer; | |
| border: 1px solid var(--border); | |
| background: var(--surface-2); | |
| color: var(--text); | |
| } | |
| .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; } | |
| .mock-footer { | |
| position: fixed; | |
| bottom: 10px; right: 16px; | |
| color: var(--text-dim); | |
| font-size: 11px; | |
| z-index: 60; | |
| } | |
| .path-row { display: flex; gap: 8px; } | |
| .path-row .input { flex: 1; } | |
| .path-row .btn { white-space: nowrap; } | |
| .secret-row { display: flex; gap: 8px; } | |
| .secret-row .input { flex: 1; } | |
| .locked { | |
| font-size: 11px; color: var(--text-dim); | |
| background: var(--surface); | |
| border: 1px dashed var(--border); | |
| border-radius: var(--radius); | |
| padding: 8px 11px; | |
| } | |
| .warn-bar { | |
| background: rgba(251,191,36,0.08); | |
| border: 1px solid rgba(251,191,36,0.35); | |
| color: var(--amber); | |
| font-size: 12px; | |
| padding: 9px 12px; | |
| border-radius: var(--radius); | |
| margin-bottom: 16px; | |
| } | |
| .field.err .input { border-color: var(--red); } | |
| .field.err .help { color: var(--red); } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="layout"> | |
| <aside class="sidebar"> | |
| <div class="brand"> | |
| <div class="logo"><span></span><span></span><span></span><span></span></div> | |
| <div class="brand-name">BarkVisor</div> | |
| </div> | |
| <div class="scope">All Devices <span class="chev">▾</span></div> | |
| <div class="nav-label">Home</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Dashboard</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Devices</a> | |
| <a class="nav-item active" href="#"><span class="dot-ic"></span>Workloads</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Ollama</a> | |
| <div class="nav-label">Library</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Images</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Disks</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Networks</a> | |
| <div class="nav-label">System</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Logs</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Settings</a> | |
| </aside> | |
| <main class="main"> | |
| <h1>Workloads</h1> | |
| <div class="ops-sub">Virtual machines and Docker apps across your devices.</div> | |
| <div class="ghost-sheet"></div> | |
| </main> | |
| </div> | |
| <div class="overlay"> | |
| <div class="magazine"> | |
| <div class="mag-head"> | |
| <div class="mag-title">Create App <span class="picked">Immich · Big Bear</span></div> | |
| <button class="mag-close">✕</button> | |
| </div> | |
| <div class="steps"> | |
| <span class="step done"><span class="n">✓</span>Gallery</span> | |
| <span class="step-sep"></span> | |
| <span class="step current"><span class="n">2</span>Configure</span> | |
| <span class="step-sep"></span> | |
| <span class="step"><span class="n">3</span>Review</span> | |
| </div> | |
| <div class="form-grid"> | |
| <div class="field"> | |
| <label>Name <span class="req">*</span></label> | |
| <input class="input" value="immich"> | |
| </div> | |
| <div class="field"> | |
| <label>Open UI</label> | |
| <input class="input mono" value="http://192.168.1.20:2283"> | |
| <span class="help">Port 2283 on Basement Linux LAN.</span> | |
| </div> | |
| <div class="field full"> | |
| <label>Device <span class="req">*</span></label> | |
| <div class="device-pick"> | |
| <div class="dev-card"> | |
| <div class="dn"><span class="odot"></span>Studio Mac</div> | |
| <div class="ds">macOS · docker compose ok</div> | |
| </div> | |
| <div class="dev-card selected"> | |
| <div class="dn"><span class="odot"></span>Basement Linux</div> | |
| <div class="ds">Ubuntu 24.04 · x86_64 · Docker 27.3</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section-label">Folders</div> | |
| <div class="form-grid"> | |
| <div class="field full err"> | |
| <label>Library upload <span class="req">*</span></label> | |
| <div class="path-row"> | |
| <input class="input mono" placeholder="Choose a folder on Basement Linux"> | |
| <button class="btn">Choose</button> | |
| </div> | |
| <span class="help">Maps to /usr/src/app/upload. Required. Photos you already have, or a new empty folder.</span> | |
| </div> | |
| <div class="field"> | |
| <label>Postgres data</label> | |
| <div class="locked">Created for you · …/workloads/immich/volumes/pgdata</div> | |
| </div> | |
| <div class="field"> | |
| <label>ML model cache</label> | |
| <div class="locked">Created for you · …/workloads/immich/volumes/model-cache</div> | |
| </div> | |
| </div> | |
| <div class="section-label">Secrets</div> | |
| <div class="form-grid"> | |
| <div class="field full"> | |
| <label>Database password <span class="req">*</span></label> | |
| <div class="secret-row"> | |
| <input class="input mono" type="password" value="generated-ok"> | |
| <button class="btn">Regenerate</button> | |
| </div> | |
| <span class="help">DB_PASSWORD / POSTGRES_PASSWORD. Written to .env 0600, not shown again in the API.</span> | |
| </div> | |
| </div> | |
| <div class="section-label">Bundled (not asked)</div> | |
| <div class="locked">Postgres + Redis + machine-learning stay on the compose network. DB_HOSTNAME=immich-postgres, REDIS_HOSTNAME=immich-redis, ML URL=http://immich-machine-learning:3003.</div> | |
| <div class="section-label">Image</div> | |
| <div class="digest-box"> | |
| <span class="dg-label">Digest</span> | |
| ghcr.io/immich-app/immich-server:v3.1.0@sha256:b434cb…0ceb | |
| <span style="margin-left:auto;color:var(--green);font-family:'Inter',sans-serif;font-size:11px;font-weight:600;">Pinned · amd64 + arm64</span> | |
| </div> | |
| <div class="mag-foot"> | |
| <button class="btn">← Back</button> | |
| <div class="mag-actions"> | |
| <button class="btn">Cancel</button> | |
| <button class="btn primary" disabled style="opacity:.45">Review & Create</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mock-footer">Mockup · Immich from Big Bear · not shipped UI</div> | |
| </body></html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>BarkVisor — Create Plex</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg: #0a0e14; | |
| --surface: #10151d; | |
| --surface-2: #151c26; | |
| --border: #1f2833; | |
| --text: #e4e4e2; | |
| --text-secondary: #b8b8b4; | |
| --text-dim: #6e6e6c; | |
| --accent: #0090f8; | |
| --green: #34d399; | |
| --red: #f87171; | |
| --amber: #fbbf24; | |
| --radius: 2px; | |
| } | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: 'Inter', -apple-system, sans-serif; | |
| font-size: 14px; | |
| min-height: 100vh; | |
| } | |
| .layout { display: flex; width: 1280px; margin: 0 auto; min-height: 100vh; } | |
| /* Sidebar */ | |
| .sidebar { | |
| width: 220px; | |
| flex-shrink: 0; | |
| background: rgba(8,12,18,0.92); | |
| border-right: 1px solid var(--border); | |
| padding: 18px 12px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| position: sticky; | |
| top: 0; | |
| height: 100vh; | |
| } | |
| .brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 16px; } | |
| .logo { | |
| width: 22px; height: 22px; border-radius: 5px; | |
| background: var(--accent); | |
| display: flex; align-items: center; justify-content: center; gap: 2px; | |
| } | |
| .logo span { width: 2.5px; background: #fff; border-radius: 1px; } | |
| .logo span:nth-child(1) { height: 8px; } | |
| .logo span:nth-child(2) { height: 13px; } | |
| .logo span:nth-child(3) { height: 10px; } | |
| .logo span:nth-child(4) { height: 6px; } | |
| .brand-name { font-weight: 700; font-size: 15px; letter-spacing: -0.01em; } | |
| .scope { | |
| margin: 0 4px 14px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| color: var(--text-secondary); | |
| font-size: 12px; | |
| padding: 7px 10px; | |
| display: flex; justify-content: space-between; align-items: center; | |
| } | |
| .scope .chev { color: var(--text-dim); font-size: 10px; } | |
| .nav-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); padding: 10px 10px 4px; } | |
| .nav-item { | |
| display: flex; align-items: center; gap: 10px; | |
| padding: 7px 10px; | |
| border-radius: var(--radius); | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| font-size: 13px; | |
| font-weight: 500; | |
| } | |
| .nav-item.active { background: rgba(0,144,248,0.12); color: var(--accent); } | |
| .nav-item .dot-ic { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.7; } | |
| /* Main (dimmed behind overlay) */ | |
| .main { flex: 1; padding: 28px 32px 60px; filter: brightness(0.45); pointer-events: none; user-select: none; } | |
| h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; } | |
| .ops-sub { color: var(--text-dim); font-size: 13px; margin-top: 6px; margin-bottom: 20px; } | |
| .ghost-sheet { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); height: 420px; } | |
| /* Magazine overlay */ | |
| .overlay { | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(4,6,10,0.72); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 50; | |
| } | |
| .magazine { | |
| width: 720px; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| background: #0d1219; | |
| border: 1px solid #26303d; | |
| border-radius: 6px; | |
| box-shadow: 0 24px 80px rgba(0,0,0,0.6); | |
| padding: 26px 28px 22px; | |
| } | |
| .mag-head { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 4px; } | |
| .mag-title { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; display: flex; align-items: center; gap: 10px; } | |
| .picked { | |
| display: inline-flex; align-items: center; gap: 6px; | |
| font-size: 11px; font-weight: 600; | |
| padding: 3px 9px; | |
| border-radius: 999px; | |
| background: rgba(0,144,248,0.12); | |
| color: var(--accent); | |
| } | |
| .mag-close { | |
| background: none; border: none; color: var(--text-dim); | |
| font-size: 18px; cursor: pointer; line-height: 1; padding: 2px 6px; | |
| } | |
| .steps { display: flex; align-items: center; gap: 8px; margin: 10px 0 22px; font-size: 12px; } | |
| .step { display: flex; align-items: center; gap: 7px; color: var(--text-dim); font-weight: 500; } | |
| .step .n { | |
| width: 20px; height: 20px; border-radius: 50%; | |
| border: 1px solid var(--border); | |
| display: inline-flex; align-items: center; justify-content: center; | |
| font-size: 11px; font-weight: 600; | |
| } | |
| .step.done { color: var(--green); } | |
| .step.done .n { border-color: var(--green); background: rgba(52,211,153,0.1); } | |
| .step.current { color: var(--accent); } | |
| .step.current .n { border-color: var(--accent); background: rgba(0,144,248,0.12); } | |
| .step-sep { width: 26px; height: 1px; background: var(--border); } | |
| /* Form */ | |
| .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; } | |
| .field { display: flex; flex-direction: column; gap: 6px; } | |
| .field.full { grid-column: 1 / -1; } | |
| .field label { font-size: 12px; font-weight: 600; color: var(--text-secondary); } | |
| .field label .req { color: var(--red); } | |
| .input, .select { | |
| font-family: inherit; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| color: var(--text); | |
| font-size: 13px; | |
| padding: 9px 11px; | |
| outline: none; | |
| } | |
| .input:focus, .select:focus { border-color: var(--accent); } | |
| .input.mono { font-family: ui-monospace, 'SF Mono', monospace; font-size: 12px; } | |
| .field .help { font-size: 11px; color: var(--text-dim); } | |
| /* Device picker cards */ | |
| .device-pick { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } | |
| .dev-card { | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| background: var(--surface); | |
| padding: 12px 14px; | |
| cursor: pointer; | |
| } | |
| .dev-card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: rgba(0,144,248,0.05); } | |
| .dev-card .dn { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; } | |
| .dev-card .dn .odot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); } | |
| .dev-card .ds { font-size: 11.5px; color: var(--text-dim); margin-top: 4px; } | |
| /* Runtime options */ | |
| .rt-list { display: flex; flex-direction: column; gap: 8px; } | |
| .rt-opt { | |
| display: flex; align-items: center; gap: 12px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| background: var(--surface); | |
| padding: 11px 14px; | |
| cursor: pointer; | |
| } | |
| .rt-opt.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: rgba(0,144,248,0.05); } | |
| .rt-opt.disabled { opacity: 0.5; cursor: not-allowed; } | |
| .radio { | |
| width: 15px; height: 15px; border-radius: 50%; | |
| border: 1.5px solid var(--text-dim); | |
| flex-shrink: 0; | |
| display: flex; align-items: center; justify-content: center; | |
| } | |
| .rt-opt.selected .radio { border-color: var(--accent); } | |
| .rt-opt.selected .radio::after { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); } | |
| .rt-opt .rt-name { font-size: 13px; font-weight: 600; } | |
| .rt-opt .rt-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; } | |
| .rt-badge { | |
| margin-left: auto; | |
| font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; | |
| color: var(--amber); | |
| border: 1px solid rgba(251,191,36,0.4); | |
| padding: 2px 7px; | |
| border-radius: var(--radius); | |
| } | |
| .section-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); font-weight: 600; margin: 22px 0 12px; padding-top: 18px; border-top: 1px solid var(--border); } | |
| /* Env rows */ | |
| .env-row { display: grid; grid-template-columns: 1fr 1fr 30px; gap: 8px; margin-bottom: 8px; align-items: center; } | |
| .env-del { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 14px; } | |
| .env-del:hover { color: var(--red); } | |
| .add-row { background: none; border: none; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; padding: 2px 0; font-family: inherit; } | |
| /* Digest + URL preview */ | |
| .digest-box { | |
| display: flex; align-items: center; gap: 10px; | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| padding: 10px 12px; | |
| font-family: ui-monospace, 'SF Mono', monospace; | |
| font-size: 11.5px; | |
| color: var(--text-secondary); | |
| } | |
| .digest-box .dg-label { font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; } | |
| .url-preview { | |
| display: flex; align-items: center; gap: 10px; | |
| background: rgba(52,211,153,0.06); | |
| border: 1px solid rgba(52,211,153,0.25); | |
| border-radius: var(--radius); | |
| padding: 10px 12px; | |
| font-size: 12.5px; | |
| } | |
| .url-preview .up-label { color: var(--text-dim); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } | |
| .url-preview a { color: var(--green); text-decoration: none; font-family: ui-monospace, monospace; font-size: 12px; } | |
| .mag-foot { | |
| display: flex; align-items: center; justify-content: space-between; | |
| margin-top: 24px; padding-top: 16px; | |
| border-top: 1px solid var(--border); | |
| } | |
| .mag-actions { display: flex; gap: 8px; } | |
| .btn { | |
| font-family: inherit; | |
| font-size: 12.5px; font-weight: 600; | |
| border-radius: var(--radius); | |
| padding: 8px 16px; | |
| cursor: pointer; | |
| border: 1px solid var(--border); | |
| background: var(--surface-2); | |
| color: var(--text); | |
| } | |
| .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; } | |
| .mock-footer { | |
| position: fixed; | |
| bottom: 10px; right: 16px; | |
| color: var(--text-dim); | |
| font-size: 11px; | |
| z-index: 60; | |
| } | |
| .path-row { display: flex; gap: 8px; } | |
| .path-row .input { flex: 1; } | |
| .path-row .btn { white-space: nowrap; } | |
| .secret-row { display: flex; gap: 8px; } | |
| .secret-row .input { flex: 1; } | |
| .locked { | |
| font-size: 11px; color: var(--text-dim); | |
| background: var(--surface); | |
| border: 1px dashed var(--border); | |
| border-radius: var(--radius); | |
| padding: 8px 11px; | |
| } | |
| .warn-bar { | |
| background: rgba(251,191,36,0.08); | |
| border: 1px solid rgba(251,191,36,0.35); | |
| color: var(--amber); | |
| font-size: 12px; | |
| padding: 9px 12px; | |
| border-radius: var(--radius); | |
| margin-bottom: 16px; | |
| } | |
| .field.err .input { border-color: var(--red); } | |
| .field.err .help { color: var(--red); } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="layout"> | |
| <aside class="sidebar"> | |
| <div class="brand"> | |
| <div class="logo"><span></span><span></span><span></span><span></span></div> | |
| <div class="brand-name">BarkVisor</div> | |
| </div> | |
| <div class="scope">All Devices <span class="chev">▾</span></div> | |
| <div class="nav-label">Home</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Dashboard</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Devices</a> | |
| <a class="nav-item active" href="#"><span class="dot-ic"></span>Workloads</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Ollama</a> | |
| <div class="nav-label">Library</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Images</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Disks</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Networks</a> | |
| <div class="nav-label">System</div> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Logs</a> | |
| <a class="nav-item" href="#"><span class="dot-ic"></span>Settings</a> | |
| </aside> | |
| <main class="main"> | |
| <h1>Workloads</h1> | |
| <div class="ops-sub">Virtual machines and Docker apps across your devices.</div> | |
| <div class="ghost-sheet"></div> | |
| </main> | |
| </div> | |
| <div class="overlay"> | |
| <div class="magazine"> | |
| <div class="mag-head"> | |
| <div class="mag-title">Create App <span class="picked">Plex · Big Bear</span></div> | |
| <button class="mag-close">✕</button> | |
| </div> | |
| <div class="steps"> | |
| <span class="step done"><span class="n">✓</span>Gallery</span> | |
| <span class="step-sep"></span> | |
| <span class="step current"><span class="n">2</span>Configure</span> | |
| <span class="step-sep"></span> | |
| <span class="step"><span class="n">3</span>Review</span> | |
| </div> | |
| <div class="warn-bar">Big Bear compose uses network_mode host. BarkVisor publishes 32400 on the Device LAN instead. Host network stays on the allowlist reject list.</div> | |
| <div class="form-grid"> | |
| <div class="field"> | |
| <label>Name <span class="req">*</span></label> | |
| <input class="input" value="plex"> | |
| </div> | |
| <div class="field"> | |
| <label>Open UI</label> | |
| <input class="input mono" value="http://192.168.1.20:32400"> | |
| <span class="help">linuxserver/plex web UI.</span> | |
| </div> | |
| <div class="field full"> | |
| <label>Device <span class="req">*</span></label> | |
| <div class="device-pick"> | |
| <div class="dev-card"> | |
| <div class="dn"><span class="odot"></span>Studio Mac</div> | |
| <div class="ds">macOS · docker compose ok</div> | |
| </div> | |
| <div class="dev-card selected"> | |
| <div class="dn"><span class="odot"></span>Basement Linux</div> | |
| <div class="ds">Ubuntu 24.04 · x86_64 · Docker 27.3</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section-label">Folders</div> | |
| <div class="form-grid"> | |
| <div class="field"> | |
| <label>Config</label> | |
| <div class="locked">Created for you · …/workloads/plex/volumes/config</div> | |
| </div> | |
| <div class="field"></div> | |
| <div class="field full"> | |
| <label>Movies <span class="req">*</span></label> | |
| <div class="path-row"> | |
| <input class="input mono" value="/mnt/media/movies"> | |
| <button class="btn">Choose</button> | |
| </div> | |
| <span class="help">Maps to /movies on linuxserver/plex.</span> | |
| </div> | |
| <div class="field full err"> | |
| <label>TV shows <span class="req">*</span></label> | |
| <div class="path-row"> | |
| <input class="input mono" placeholder="Choose a folder on Basement Linux"> | |
| <button class="btn">Choose</button> | |
| </div> | |
| <span class="help">Maps to /tv. Required before Review.</span> | |
| </div> | |
| </div> | |
| <div class="section-label">Environment</div> | |
| <div class="form-grid"> | |
| <div class="field"> | |
| <label>PUID</label> | |
| <input class="input mono" value="1000"> | |
| <span class="help">From the barkvisor user on this Device.</span> | |
| </div> | |
| <div class="field"> | |
| <label>PGID</label> | |
| <input class="input mono" value="1000"> | |
| </div> | |
| <div class="field"> | |
| <label>TZ</label> | |
| <input class="input" value="Europe/Berlin"> | |
| </div> | |
| <div class="field"> | |
| <label>VERSION</label> | |
| <input class="input mono" value="docker"> | |
| </div> | |
| </div> | |
| <div class="section-label">Secrets</div> | |
| <div class="form-grid"> | |
| <div class="field full"> | |
| <label>Plex claim token</label> | |
| <div class="secret-row"> | |
| <input class="input mono" type="password" placeholder="claim-… from plex.tv/claim"> | |
| </div> | |
| <span class="help">Optional. PLEX_CLAIM expires in four minutes. Stored in .env 0600.</span> | |
| </div> | |
| </div> | |
| <div class="section-label">Image</div> | |
| <div class="digest-box"> | |
| <span class="dg-label">Digest</span> | |
| linuxserver/plex:1.43.3@sha256:de95bb…10107 | |
| <span style="margin-left:auto;color:var(--green);font-family:'Inter',sans-serif;font-size:11px;font-weight:600;">Pinned · amd64 + arm64</span> | |
| </div> | |
| <div class="mag-foot"> | |
| <button class="btn">← Back</button> | |
| <div class="mag-actions"> | |
| <button class="btn">Cancel</button> | |
| <button class="btn primary" disabled style="opacity:.45">Review & Create</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mock-footer">Mockup · Plex from Big Bear · not shipped UI</div> | |
| </body></html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment