Sumber kebenaran tampilan Dockify. UI baru atau perubahan UI WAJIB mengikuti dokumen ini. Diturunkan dari
~/workspace/tencent-dev-ops/standards/UI-STACK-DAN-DESIGN-SYSTEM.md dan diadaptasi ke stack Go (docs/UI-REVAMP-PLAN.md, K1..K10).
Preview asal dan kontras terhitung: docs/design/preview-warna.html, docs/design/kontras.md, generator docs/design/gen.mjs.
Keputusan user 2026-10-15: ketiga palet dipakai dan bisa dipilih user; terang/gelap default mengikuti sistem.
Go html/template + htmx + CSS kustom di internal/http/static/app.css (ikut go:embed, disajikan /static/app.css?v=<versi>).
Tanpa framework CSS, tanpa Node saat build/runtime. Font: Plus Jakarta Sans 400/600/700/800 (UI) dan JetBrains Mono 400/600
(host, port, domain, log, kode) dari Google Fonts display=swap. Ikon: SVG inline stroke 2 lewat partial ui_icon.
<html data-palette="indigo|navy|teal" data-theme="light|dark">. Keduanya selalu nilai efektif.- Preferensi di
localStorage:dockify_palette(indigodefault) dandockify_theme(light|dark|system, defaultsystem). Kunci lamadockify-themedibaca sekali lalu dihapus. - Skrip bootstrap inline di
<head>(sebelum CSS) menulis kedua atribut +<meta name="theme-color">; selamasystem, ikutimatchMedia('(prefers-color-scheme: dark)')dan perubahannya. Tanpa@media (prefers-color-scheme)di CSS. - CSS: lapis 2 didefinisikan per kombinasi:
:root[data-palette=indigo],:root[data-palette=indigo][data-theme=dark], dst. (6 blok). Komponen hanya memakai token lapis 2 (var(--ink),var(--accent-fill)...), tidak pernah hex. - Kontrol: tombol ikon di header (terang → gelap → sistem → lawan dari tema efektif saat itu, supaya setiap klik terlihat berubah; ikon matahari/bulan/monitor,
aria-labelmenyebut mode berikutnya) dan di Settings → Appearance: segmented "Palette" (Indigo / Navy / Teal) dan segmented "Theme" (Light / Dark / System). Halaman login ikut preferensi yang sama.
Kegunaan tiap token sama dengan standar §3: bg latar halaman, surface kartu/header/sheet, sunk permukaan cekung (pill netral, wadah segmented),
line/line-strong pemisah/batas, control batas input/select (≥3:1 terhadap surface), ink/ink2/muted teks (muted hanya ≥12px),
accent teks/garis aksen, accent-fill+on-accent isian aksi utama, accent-soft hover/chip aktif, brand2/brand2-soft seri grafik kedua (RAM, disk, memori, jaringan) dari keluarga hue yang sama dengan aksen; brand2-fill+on-brand2 disediakan tapi tidak dipakai tombol (keputusan user 2026-10-15: semua tombol aksi memakai accent-fill), chart/chart-soft bar dan grafik, ok/warn/danger + -text + -bg status, danger-fill isian tombol konfirmasi hapus, shadow satu-satunya bayangan.
Semua pasangan kontras sudah dihitung (38/38 lolos per palet, lihat docs/design/kontras.md). Jangan ubah nilai tanpa menghitung ulang.
| Token | Terang | Gelap |
|---|---|---|
| bg | #f5f7fb |
#0b1020 |
| surface | #ffffff |
#151b2e |
| sunk | #f1f4f9 |
#0f1426 |
| line | #e2e8f0 |
#262e48 |
| line-strong | #cbd5e1 |
#36405f |
| control | #7a8699 |
#6e7a9c |
| ink | #0f172a |
#e8ebf5 |
| ink2 | #334155 |
#c0c7dc |
| muted | #5b677a |
#929bb8 |
| accent | #4f46e5 |
#a5b4fc |
| accent-fill | #4f46e5 |
#5850ec |
| on-accent | #ffffff |
#ffffff |
| accent-soft | #eef0ff |
#252a55 |
| brand2-fill | #6d28d9 |
#6d28d9 |
| on-brand2 | #ffffff |
#ffffff |
| brand2 | #6d28d9 |
#c4b5fd |
| brand2-soft | #ede9fe |
#2a1d55 |
| chart | #6366f1 |
#818cf8 |
| chart-soft | #e3e5fc |
#252a55 |
| ok | #15803d |
#4ade80 |
| ok-text | #166534 |
#86efac |
| ok-bg | #dcfce7 |
#10301e |
| warn | #b45309 |
#fbbf24 |
| warn-text | #92400e |
#fcd34d |
| warn-bg | #fef3c7 |
#33270a |
| danger | #c81e1e |
#f87171 |
| danger-text | #991b1b |
#fca5a5 |
| danger-bg | #fee2e2 |
#3b1618 |
| danger-fill | #c81e1e |
#c81e1e |
| shadow | 0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.05) |
0 1px 2px rgba(0,0,0,.45) |
| Token | Terang | Gelap |
|---|---|---|
| bg | #eef1f8 |
#0c0f1e |
| surface | #ffffff |
#161a2f |
| sunk | #f5f7fc |
#11142a |
| line | #e1e5f0 |
#272c48 |
| line-strong | #c8cede |
#363c5e |
| control | #7c83ad |
#6b7399 |
| ink | #141a33 |
#e9ebf7 |
| ink2 | #3d4566 |
#bfc4de |
| muted | #656d8c |
#8f95b4 |
| accent | #2b3486 |
#a9b2ff |
| accent-fill | #2b3486 |
#4a54c9 |
| on-accent | #ffffff |
#ffffff |
| accent-soft | #e7e9f8 |
#242a5c |
| brand2-fill | #1e40af |
#1e40af |
| on-brand2 | #ffffff |
#ffffff |
| brand2 | #1e40af |
#93c5fd |
| brand2-soft | #dbeafe |
#1a2a55 |
| chart | #4a54c9 |
#8c96ff |
| chart-soft | #e3e5fb |
#242a5c |
| ok | #15803d |
#4ade80 |
| ok-text | #166534 |
#86efac |
| ok-bg | #dcfce7 |
#10301e |
| warn | #b45309 |
#fbbf24 |
| warn-text | #92400e |
#fcd34d |
| warn-bg | #fef3c7 |
#33270a |
| danger | #c81e1e |
#f87171 |
| danger-text | #991b1b |
#fca5a5 |
| danger-bg | #fee2e2 |
#3b1618 |
| danger-fill | #c81e1e |
#c81e1e |
| shadow | 0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.05) |
0 1px 2px rgba(0,0,0,.45) |
| Token | Terang | Gelap |
|---|---|---|
| bg | #f0f3f5 |
#0a1116 |
| surface | #ffffff |
#131c23 |
| sunk | #f3f6f8 |
#0e161c |
| line | #dde3e8 |
#22303a |
| line-strong | #c5cfd7 |
#314350 |
| control | #74828f |
#687b89 |
| ink | #0f1a22 |
#e6eef2 |
| ink2 | #34434f |
#b9c8d1 |
| muted | #5b6975 |
#8a9ba7 |
| accent | #0e6e78 |
#5fd4dd |
| accent-fill | #0e6e78 |
#0e6e78 |
| on-accent | #ffffff |
#ffffff |
| accent-soft | #e0f1f2 |
#103338 |
| brand2-fill | #075985 |
#075985 |
| on-brand2 | #ffffff |
#ffffff |
| brand2 | #075985 |
#7dd3fc |
| brand2-soft | #e0f2fe |
#0f2a3a |
| chart | #0891b2 |
#38bdf8 |
| chart-soft | #dcf0f6 |
#0f2c3a |
| ok | #15803d |
#4ade80 |
| ok-text | #166534 |
#86efac |
| ok-bg | #dcfce7 |
#10301e |
| warn | #b45309 |
#fbbf24 |
| warn-text | #92400e |
#fcd34d |
| warn-bg | #fef3c7 |
#33270a |
| danger | #c81e1e |
#f87171 |
| danger-text | #991b1b |
#fca5a5 |
| danger-bg | #fee2e2 |
#3b1618 |
| danger-fill | #c81e1e |
#c81e1e |
| shadow | 0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.05) |
0 1px 2px rgba(0,0,0,.45) |
| Status Dockify | Token |
|---|---|
| running, online, success | ok-bg + ok-text (+ titik berdenyut untuk running/online) |
| pending, initializing, deploying, created | warn-bg + warn-text |
| stopped, draft | sunk + ink2, garis line |
| error, failed, offline | danger-bg + danger-text |
| Lencana: 10 sampai 11px, 800, huruf kapital, radius 6, font mono untuk nilai teknis. |
Body 15px/1.5. KPI 24px/800 tracking -0.02em. Angka sekunder 20px/800. Judul kartu 15px/700. Label 12.8px. Meta/chip 11 sampai 12px (chip 600).
Label tab bawah 11px. Input/select 16px. Skala spasi 4px: padding halaman 14 sampai 16px, antar kartu 12px, antar kontrol 8px.
Radius: kartu 16, kontrol/tombol 12, lencana 6, chip/pill penuh. Skala kontrol (dikecilkan dari 44/48, mengikuti hadir S16): input/select/tombol default 40px, sm 34px, lg 44px (satu aksi utama penuh-lebar), ikon 40px (btn-icon) dan 36px (btn-icon-sm), nav desktop 40px, segmen HP 38px. Teks input 16px di HP (iOS zoom), 14px di ≥700px. Desktop ≥700px (kerapatan mengikuti Coolify): input/select/tombol 32px, teks tombol 13px, sm 28px, lg 36px, ikon 32/28px, segmen 26px, chip 28px, padding kartu 16px, nav 36px, body 14px. HP tetap 40px/16px. Chip 32px dengan jarak ≥6px.
| Kebutuhan | Partial / kelas | Catatan |
|---|---|---|
| Tombol | .btn + varian primary secondary ghost destructive destructive-outline link; ukuran 40 (default) / 34 (sm) / 44 (lg); ikon 40/36 |
satu primary per layar/panel; dalam satu kelompok varian harus berbeda |
| Input + label | .field (label 12.8px/600 + input 16px HP, 14px desktop, tinggi 40, border control, fokus outline 3px accent) |
tanpa titik dua di label |
| Select | <select class="select"> native digayakan + chevron SVG |
penyimpangan K4 yang disetujui |
| Dialog / alert-dialog / drawer | ui_sheet: <dialog class="sheet"> + openSheet(id)/closeSheet(id); ≥700px popup tengah max-w 560 radius 16 max-h 86dvh; <700px panel bawah max-w 560 radius atas 16 handle 40×4 max-h 92dvh + safe-area; animasi ≤240 ms; hormati prefers-reduced-motion; tutup via X, backdrop, Escape; tanpa tautan "Tutup" di bawah |
menggantikan semua confirm() dan modal inline |
| Kartu | .card = surface + border line + shadow, radius 16 |
bayangan hanya di sini |
| Lencana | .badge .badge-<status> |
§3.4 |
| Segmented | ui_segmented: wadah sunk radius 12, segmen aktif surface + bayangan, aria-pressed |
rentang grafik, Simple/Advanced, Palette/Theme |
| Chip filter | .chips satu baris scroll horizontal tanpa scrollbar, pudar tepi kanan; chip "All" di depan; aktif = accent-soft + teks accent; meta hasil + "Reset filter" di bawah |
tidak pernah isian penuh |
| Progress | .bar (chart di atas chart-soft) |
gauge CPU/RAM/Disk |
| Alert / toast | `.alert-ok | warn |
| Pemisah | .sep |
|
| Ikon | ui_icon nama: sun moon monitor logout menu x check alert refresh plus trash external chevron |
SVG inline stroke 2 |
- Primary (
accent-fill): satu per layar: Edit (app/server running), Start (stopped), Deploy (draft), Save, Sign in, Deploy App (daftar Apps), Add Server (daftar Servers). Tidak ada warna tombol kedua; semua palet memakai keluarga hue aksennya sendiri. - Secondary: Stop, Cancel, Save as Draft, tombol ikon header.
- Ghost: Console, Tail 50/200/500, Copy, Show.
- Aksi berbahaya = merah: Redeploy, Rollback, Init Worker, Prune Disk, Undeploy, Remove Server, Delete Draft, Clear History, Roll Secret, Update Dockify, Redeploy All. Pemicu =
destructive-outlinedi zona bahaya terpisah (judul "Danger zone", garis atas); konfirmasi selalu lewat alert-dialog dengan kalimat akibat; tombol konfirmasi =destructive(isiandanger-fill, teks putih). - Status tercapai (online, running, sudah init) = tint
ok-bg/ok-text+ ikon centang, bukan tombol.
- Mobile first 360×740, uji 390×844 dan 1280×800. Tanpa overflow horizontal halaman (hanya baris chip).
- Shell: header ringkas (logo + nama + tombol ikon 40px: tema, keluar) + tab bar bawah <900px (Dashboard, Servers, Apps, Settings; ikon + label 11px, garis aktif,
aria-current,env(safe-area-inset-bottom)). ≥900px: tab pindah ke bawah header, konten max 1100px, kartu grid 2 kolom. About pindah ke Settings. - Daftar: <700px baris kartu (grid
minmax(0,1.3fr) 1fr 1fr 36px,white-space:nowrap), ≥700px tabel. KPI grid 2×2 di HP, 4 kolom di desktop. - Panel detail: header (nama 18/800 + meta 12.8 muted + X) → banner status →
detail-grid2 kolom (dt 11/800 kapital muted, dd 14/600) → seksi berjudul (12.8/800 kapital, garis atas) → aksi (grid 2 kolom, primary penuh lebar) → zona bahaya.
Viewport 390, CPU 4×, latensi 80 ms, median 5 ulangan: navigasi antar halaman utama ≤300 ms (localhost). DOM ≤12 node per baris daftar, <2.500 node untuk 200 baris.
Garis progres 3px (#progress) saat navigasi boosted >150 ms, hormati reduced-motion. Fokus terlihat 3px accent; Escape menutup sheet; aria-pressed; aria-labelledby di dialog.
<body hx-boost="true" hx-ext="preload,head-support" hx-target="#main" hx-select="#main" hx-swap="outerHTML show:none">. Setiap halaman kerja membungkus seluruh isi (konten, sheet,<template>, skrip inline) dalam satu<div class="container" id="main" data-nav="{{.Nav}}">; header, tab bar, dan head tetap.login.htmltidak memuat htmx; form logouthx-boost="false".- Elemen htmx lain di dalam halaman (stats card, segmented) wajib
hx-targetsendiri danhx-select="unset"agar tidak mewarisi#main. - Skrip halaman idempoten: dipanggil pada
DOMContentLoadeddanhtmx:afterSettle, dengan guarddata-init(lihatlist.js,formatTimesdiapp.js). Listener kedocument/windowdari skrip inline dilarang (menumpuk setiap swap): pasang ke#mainatau elemen di dalamnya. Sumber daya hidup (WebSocket, xterm) mendaftar fungsi pembersih kewindow.dockifyCleanups;app.jsmemanggilnya padahtmx:beforeSwaptarget#main.charts.jsdanconsole.jsdimuatdefer: skrip inline yang memanggilnya saat parse dibungkusdockifyReady(fn)(app.js; menunggu DOMContentLoaded pada load penuh, langsung jalan setelah swap). Pembersih yang dipasang saat aksi user (Console) didaftarkan saat aksi itu, bukan sekali saat skrip dimuat. - Form dengan
onsubmityang bisa membatalkan harus memvalidasi lagi dihtmx:beforeRequest(htmx tetap mengirim saatonsubmitmengembalikan false). - Respons tanpa
#main(redirect ke login) jatuh ke load penuh; 4xx/5xx boosted tetap di-swap (halaman error). - Preload: atribut
preload="mousedown"(touchstart otomatis) pada nav dan tautan baris; server menjawab permintaanHX-PreloadeddenganCache-Control: private, max-age=5. - PWA:
static/manifest.webmanifest,sw.js?v=AssetVersion(hanya/static/*, cache-first; HTML/API tidak pernah di-cache),Service-Worker-Allowed: ../.
Bahasa UI Inggris, label tanpa titik dua, tombol kata kerja spesifik, tanpa emoji.
- Semua komponen lewat partial/kelas bersama; elemen native tersisa hanya
select(K4) dandialog - Tanpa hex di template dan CSS komponen (kecuali tema xterm); tanpa
style=""inline baru - 3 palet × terang/gelap dicek; kontras tidak diubah tanpa hitung ulang
- Tanpa overflow horizontal di 360 dan 390; ≥900 rapi
- Hierarki §5.1: satu primary; aksi berbahaya merah outline + alert-dialog; status = tint
- Sheet responsif: popup tengah di desktop, panel bawah di HP
- Target sentuh, fokus, Escape
- Angka perf §7 dilaporkan (sebelum/sesudah) bila menyentuh daftar/navigasi
-
go build ./... && go vet ./... && go test ./...hijau; screenshot 360/390/1280 × terang/gelap terlampir