Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Set `DOCKIFY_DEV_MOCK=true` to use mock SSH client — no real VMs needed for UI

## UI Style Guide

**UI baru atau perubahan UI WAJIB mengikuti `docs/DESIGN-SYSTEM.md`** (token 3 palet × terang/gelap, partial komponen, hierarki aksi, checklist). Rencana revamp: `docs/UI-REVAMP-PLAN.md`. Bagian di bawah ini menjelaskan kondisi sebelum revamp dan akan diganti saat S8.

All styles live in `internal/http/templates/layout.html` (single `<style>` block). Full design tokens and component patterns in `SPEC.md`.

When editing templates or adding new UI:
Expand Down
187 changes: 187 additions & 0 deletions docs/DESIGN-SYSTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# DESIGN-SYSTEM.md — Dockify

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.

## 1. Stack
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`.

## 2. Tema: palet × terang/gelap
- `<html data-palette="indigo|navy|teal" data-theme="light|dark">`. Keduanya **selalu** nilai efektif.
- Preferensi di `localStorage`: `dockify_palette` (`indigo` default) dan `dockify_theme` (`light|dark|system`, **default `system`**). Kunci lama `dockify-theme` dibaca sekali lalu dihapus.
- Skrip bootstrap **inline di `<head>`** (sebelum CSS) menulis kedua atribut + `<meta name="theme-color">`; selama `system`, ikuti `matchMedia('(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 (siklus terang → gelap → sistem, ikon matahari/bulan/monitor, `aria-label` menyebut mode berikutnya) dan di **Settings → Appearance**: segmented "Palette" (Indigo / Navy / Teal) dan segmented "Theme" (Light / Dark / System). Halaman login ikut preferensi yang sama.

## 3. Token lapis 2 (nama tetap, nilai per palet)
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-fill`+`on-brand2` satu aksi pendamping per layar (Deploy App),
`brand2`/`brand2-soft` angka sekunder, `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.

### 3.1 Palet `indigo` (Indigo Dockify, default)
| 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 | `#14b8a6` | `#2dd4bf` |
| on-brand2 | `#042f2e` | `#042f2e` |
| brand2 | `#0f766e` | `#5eead4` |
| brand2-soft | `#dcf5f1` | `#103633` |
| 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)` |

### 3.2 Palet `navy` (Navy Brosur)
| 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 | `#f26a21` | `#f26a21` |
| on-brand2 | `#1b1f3b` | `#1b1f3b` |
| brand2 | `#c2410c` | `#ff9a5c` |
| brand2-soft | `#fdeee4` | `#3a2418` |
| chart | `#178a8c` | `#4fd1d3` |
| chart-soft | `#dff3f3` | `#143339` |
| 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)` |

### 3.3 Palet `teal` (Slate Teal Ops)
| 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 | `#f5a524` | `#f5a524` |
| on-brand2 | `#1a1305` | `#1a1305` |
| brand2 | `#a35a00` | `#f8b95a` |
| brand2-soft | `#fdf0d9` | `#33270f` |
| 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)` |

### 3.4 Lencana status
| 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.

## 4. Tipografi, spasi, radius
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. Target sentuh aksi utama dan toggle ≥44px; chip 32px dengan jarak ≥6px.

## 5. Komponen (partial bersama, varian di partial bukan di pemakaian)
| Kebutuhan | Partial / kelas | Catatan |
| :--- | :--- | :--- |
| Tombol | `.btn` + varian `primary` `brand` `secondary` `ghost` `destructive` `destructive-outline` `link`; ukuran 44 (default) / 36 (`sm`) / 48 (`lg`); ikon 44/40 | satu `primary` per layar/panel; `brand` maksimal satu; dalam satu kelompok varian harus berbeda |
| Input + label | `.field` (label 12.8px/600 + input 16px, 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|danger` (`role=alert` galat); toast `role=status` 4 dtk untuk flash | |
| Pemisah | `.sep` | |
| Ikon | `ui_icon` nama: sun moon monitor logout menu x check alert refresh plus trash external chevron | SVG inline stroke 2 |

### 5.1 Hierarki aksi (K9)
- **Primary** (`accent-fill`): satu per layar: Edit (app/server running), Start (stopped), Deploy (draft), Save, Sign in.
- **Brand** (`brand2-fill`): Deploy App di daftar Apps, Add Server di daftar Servers.
- **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-outline` di **zona bahaya** terpisah (judul "Danger zone", garis atas); konfirmasi selalu lewat alert-dialog dengan kalimat akibat; tombol konfirmasi = `destructive` (isian `danger-fill`, teks putih).
- **Status tercapai** (online, running, sudah init) = tint `ok-bg`/`ok-text` + ikon centang, bukan tombol.

## 6. Layout
- Mobile first 360×740, uji 390×844 dan 1280×800. Tanpa overflow horizontal halaman (hanya baris chip).
- Shell: header ringkas (logo + nama + tombol ikon 44px: 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 44px`, `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-grid` 2 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.

## 7. Performa dan aksesibilitas (diukur, `tests/e2e/ui.mjs`)
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 saat navigasi >150 ms (htmx `hx-boost` opsional). Fokus terlihat 3px `accent`; Escape menutup sheet; `aria-pressed`; `aria-labelledby` di dialog.
Bahasa UI Inggris, label tanpa titik dua, tombol kata kerja spesifik, tanpa emoji.

## 8. Checklist PR UI
- [ ] Semua komponen lewat partial/kelas bersama; elemen native tersisa hanya `select` (K4) dan `dialog`
- [ ] 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
7 changes: 4 additions & 3 deletions docs/UI-REVAMP-PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ Build `go build ./...`, `go vet`, `go test ./...` hijau (Go 1.26.0). Screenshot
- **K3 Komponen = partial bersama** di `internal/http/templates/ui_*.html`: `ui_button` (varian primary/brand/secondary/ghost/destructive/destructive-outline/link; ukuran 44/36/48/ikon), `ui_badge`, `ui_card`, `ui_alert`, `ui_segmented`, `ui_sheet` (dialog/drawer responsif), `ui_icon` (SVG inline stroke 2). Varian diubah di partial, bukan di pemakaian. Inline style ditiadakan.
- **K4 `<select>` native tetap dipakai, digayakan** (border `control`, chevron SVG, 16px). Alasan: 6 select enum sederhana; listbox kustom vanilla JS menambah kode dan risiko aksesibilitas tanpa manfaat. Dicatat sebagai penyimpangan §5 yang disetujui.
- **K5 `<dialog>` native sebagai ResponsiveSheet**: `showModal()` memberi Escape, fokus terkurung, dan backdrop gratis. CSS: ≥700px popup tengah max-w 560 radius 16; <700px panel bawah radius atas 16 + handle 40×4 + safe-area; animasi ≤240 ms, hormati `prefers-reduced-motion`. Semua `confirm()` dan modal inline diganti.
- **K6 Mode gelap**: pindah ke `data-theme` (`light|dark`) + preferensi `localStorage.dockify_theme` (`light|dark|system`, default `system`), skrip inline di `<head>`, satu blok `:root[data-theme=dark]`, tanpa `@media (prefers-color-scheme)` di CSS. Kunci lama `dockify-theme` dibaca sekali lalu dimigrasi.
- **K6 Mode gelap**: pindah ke `data-theme` (`light|dark`) + preferensi `localStorage.dockify_theme` (`light|dark|system`, default `system`), skrip inline di `<head>`, blok `:root[data-palette=X][data-theme=dark]` per palet (K10), tanpa `@media (prefers-color-scheme)` di CSS. Kunci lama `dockify-theme` dibaca sekali lalu dimigrasi.
- **K7 Shell**: header ringkas (logo + tombol ikon 44px tema/keluar) + **tab bar bawah** di <900px (Dashboard, Servers, Apps, Settings; About pindah ke Settings), tab di bawah header mulai ≥900px, konten max 1100px. Tabel jadi daftar kartu baris di <700px (grid kolom tetap `minmax(0,1.3fr) 1fr 1fr 44px`), tabel penuh di ≥700px.
- **K9 Aksi berbahaya = merah** (keputusan user 2026-10-15): Redeploy, Rollback, Init Worker, Prune Disk, Undeploy, Remove Server, Delete Draft, Clear History, Roll Secret, Update Dockify. Pemicu di bar aksi memakai `destructive-outline` (garis + teks `danger`), tombol konfirmasi akhir di alert-dialog memakai `destructive` (isian `danger-fill`). Satu primary per layar tetap berlaku untuk aksi tidak berbahaya (Edit, Start, Deploy draft, Simpan). Konfirmasi selalu lewat alert-dialog dengan kalimat akibatnya.
- **K10 Tiga palet dipakai semua** (keputusan user 2026-10-15): `data-palette=indigo|navy|teal` (default `indigo`) dipilih user di Settings → Appearance; `data-theme` terang/gelap default **mengikuti sistem** (`system`), bisa dipaksa light/dark lewat tombol header atau Settings. Nilai token final di `docs/DESIGN-SYSTEM.md` §3.
- **K8 Pengukuran**: skrip `tests/e2e/ui.mjs` (Playwright dari `~/.local/share/pw-tools`): screenshot 360x740, 390x844, 1280x800 × terang/gelap; cek overflow horizontal; hitung node DOM; waktu navigasi antar halaman utama median 5 ulangan dengan CPU 4x dan latensi 80 ms; cek kontras token (≥4.5:1 teks, ≥3:1 kontrol) di kedua tema. Hasil "sebelum/sesudah" dilampirkan di tiap PR UI.

Di luar cakupan: fitur baru, perubahan API/JSON, perubahan skema DB, terminal xterm (tema xterm tetap hex, dikecualikan dari grep hex), grafik SVG (hanya warnanya diganti token `chart`).
Expand Down Expand Up @@ -88,13 +89,13 @@ PR dengan bukti (screenshot 3 viewport × 2 tema untuk PR UI, tabel perf sebelum

| ID | Langkah | Kriteria selesai | Model | Bukti |
| :--- | :--- | :--- | :--- | :--- |
| S0 | Preview statis 3 opsi warna (HTML tanpa JS, font data URI): layar Dashboard, Apps, App detail, sheet konfirmasi, HP 360 terang+gelap. Opsi: (1) Indigo Dockify (brand sekarang dirapikan), (2) Navy Brosur (palet standar), (3) Slate + Teal "ops". Lalu tulis `docs/DESIGN-SYSTEM.md` dari opsi terpilih dan tambah aturan di `AGENTS.md` | User memilih; DESIGN-SYSTEM.md berisi nilai token kedua tema dengan kontras terhitung | Opus (preview/token, high), leader finalisasi | tautan `share`, tabel kontras |
| S0 ✅ | Preview statis 3 opsi warna (HTML tanpa JS, font data URI): layar Dashboard, Apps, App detail, sheet konfirmasi, HP 360 terang+gelap. Opsi: (1) Indigo Dockify (brand sekarang dirapikan), (2) Navy Brosur (palet standar), (3) Slate + Teal "ops". Lalu tulis `docs/DESIGN-SYSTEM.md` dari opsi terpilih dan tambah aturan di `AGENTS.md` | User memilih; DESIGN-SYSTEM.md berisi nilai token kedua tema dengan kontras terhitung | Opus (preview/token, high), leader finalisasi | tautan `share`, tabel kontras |
| S1 | `app.css` ter-embed + token dua lapis + `data-theme` + skrip head (K2, K6); `login.html` memakai CSS bersama; `layout.html` tinggal struktur | Tampilan setara sebelumnya kecuali warna token; grep hex di template = hanya xterm; tanpa FOUC gelap | Sonnet (medium) | screenshot, grep |
| S2 | Partial komponen (K3, K5): button varian, badge, card, alert, segmented, sheet, icon, toast; ganti 8 `confirm()` + 4 modal inline | Tidak ada `confirm(`; semua tombol pakai varian; Escape/backdrop/fokus jalan | Sonnet; review Opus (UI baru) | screenshot sheet 390 + 1280 |
| S3 | Shell (K7): header, tab bar bawah, tab atas ≥900, container, About → Settings | 360/390 tanpa overflow; `aria-current`; safe-area | Sonnet | screenshot 3 viewport |
| S4 | Dashboard + daftar Servers/Apps: KPI 2x2 di HP, baris kartu <700px, tabel ≥700px, filter satu baris + meta hasil + "Reset filter", urut tetap | DOM ≤12 node per baris; tanpa overflow; filter/urut masih jalan | Sonnet | screenshot, node count |
| S5 | Detail App dan Server: bar aksi berhierarki (satu primary: Edit/Start/Deploy; aksi berbahaya K9 merah `destructive-outline` + alert-dialog; Console/Logs ghost), `detail-grid`, banner status, rentang grafik segmented | Sesuai §7.1, §7.2, K9; tabel inline style = 0 | Sonnet; review Opus | screenshot |
| S6 | Form (apps add/edit, servers add/edit, settings, import/export): label 12.8px, input 16px, select bergaya, modal → sheet, baris env/file/domain memakai grid kolom tetap | Inline style = 0 di template form; iOS tidak zoom | Sonnet | screenshot 390 |
| S6 | Form (apps add/edit, servers add/edit, settings, import/export): label 12.8px, input 16px, select bergaya, modal → sheet, baris env/file/domain memakai grid kolom tetap; Settings → Appearance: segmented Palette (3) dan Theme (Light/Dark/System) (K10) | Inline style = 0 di template form; iOS tidak zoom; palet dan tema tersimpan dan bertahan setelah reload | Sonnet | screenshot 390 |
| S7 | `tests/e2e/ui.mjs` (K8) + perbaikan temuan perf/a11y/kontras | Semua target §9/§10 terpenuhi; tabel sebelum/sesudah | Haiku jalankan (low), Sonnet perbaiki | tabel perf, laporan kontras |
| S8 | Audit akhir leader (worktree `../dockify-audit`), perbarui `SPEC.md` §UI Style Guide → rujuk `docs/DESIGN-SYSTEM.md`, `README` screenshot, release patch | Checklist §11 semua tercentang; `./scripts/release.sh` | Fable | temuan bernomor, tag rilis |

Expand Down
Loading
Loading