| name | single-html-dashboard |
| description | Generic project progress dashboard. Per-project `.dashboard/` directory + a single self-contained HTML file that carries its own data + editor UI. Save back to server (or download) to persist edits. Forward the HTML and the recipient has the full product. Triggers on "dashboard", "้กน็ฎ dashboard", "init dashboard", "dashboard render", "save dashboard". |
Single-HTML-Dashboard
A project-agnostic, full-featured browser-side dashboard packed into one HTML file.
Philosophy
The HTML is the product. It contains:
- All items (embedded in a
getInitialData() JS function)
- The full editor UI (kanban, modal forms, password-protected unlock, per-item page editor)
- Browser-side SQLite via sql.js (WASM)
- Save-to-Server / Save-to-Local buttons
- Stats, filters, recent updates, export/import
Forward the HTML file โ recipient has everything. Open it locally โ fully usable read-only.
Two layers
~/.claude/skills/single-html-dashboard/ # skill engine (global)
โโโ SKILL.md
โโโ scripts/
โ โโโ dashboard.py # CRUD + render + serve dispatcher
โ โโโ save_server.py # generic save endpoint (per-project)
โโโ templates/
โ โโโ dashboard.html.src # canonical raw HTML template (full-feature dashboard)
โโโ schemas/
โโโ default.yaml
<project-root>/.dashboard/ # per-project state
โโโ config.yaml # project name/id, status seed, save endpoint, publish target
โโโ items.json # git-friendly mirror (canonical: HTML; mirror: items.json)
โโโ public/
โ โโโ latest.html # render output (served by save_server at GET /)
โ โโโ dashboard_YYYYMMDD_HHMM.html # versioned saves
โโโ backups/
โโโ latest_*.html # backup of prior latest.html on each save
Quick start (in any project)
SCRIPT=$HOME/.claude/skills/single-html-dashboard/scripts/dashboard.py
cd ~/my-project
python3 $SCRIPT init --name "My Project"
python3 $SCRIPT add --json '{"title":"Wire up CI","progressStatus":"Todo","assignee":"me"}'
python3 $SCRIPT add --json '{"title":"Ship v0.1","progressStatus":"In Progress","dependencies":["auth"]}'
python3 $SCRIPT update --id <id> --json '{"progressStatus":"Done"}'
python3 $SCRIPT list
python3 $SCRIPT summary
python3 $SCRIPT serve
Save-to-Server flow
- Browser loads dashboard (data embedded in
getInitialData())
- User edits in browser (status changes, page-editor notes, new items via modal)
- Click "๐พ Save to Server" โ POST full HTML to
config.serve.endpoint (default /api/save)
save_server.py writes:
public/dashboard_YYYYMMDD_HHMM.html (versioned)
public/latest.html (canonical)
backups/latest_<ts>.html (previous version)
items.json (extracted from the saved HTML via regex on getInitialData())
- Old versions pruned (keeps last
serve.max_versions, default 10)
If POST fails โ button falls back to local download. HTML is always portable.
Project config (.dashboard/config.yaml)
project_id: my-project
project_name: My Project
default_password: my-project
data_version: "2.0"
status_options: []
source_options: []
serve:
port: 9876
bind: 127.0.0.1
endpoint: /api/save
host_match: ""
max_versions: 10
publish:
type: local
target: <project>/.dashboard/public
GitHub sync
Push your dashboard to a GitHub repository for version-controlled backup and collaboration. Useful when a dashboard runs on one device but its data needs to be visible from others (or just for a free off-device snapshot).
publish:
type: github
repo_path: /path/to/local/repo
branch: main
commit_prefix: "dashboard:"
html_filename: dashboard.html
push_items_json: true
auto_push: true
python3 $SCRIPT render --publish
python3 $SCRIPT sync
What gets pushed
dashboard.html โ Self-contained HTML (the full product)
items.json โ Extracted data array (git-friendly, clean diffs)
The items.json file is derived from the HTML's getInitialData() function. It exists purely for readable diffs in git history. The HTML remains the canonical artifact. When html_filename is nested under a subdirectory, items.json is written alongside it so multiple dashboards can coexist in one repo.
Built-in features
Everything. UI is unchanged. Functions kept verbatim:
- Password-protected unlock with view-only default
- Project Settings (โ๏ธ) โ editable project name, locked project ID
- Save to Server + Save to Local (with download fallback)
- Unsaved changes indicator + beforeunload warning
- Stats bar (now dynamic: one card per observed status, always Total first)
- Recent Updates section (last 10 modified items)
- Search input + status filter + dependencies filter
- Add / Edit / Delete / View / Page per row
- Full-screen Page editor (notes textarea per item, lastSaved timestamp)
- Export Database (.db sqlite), Export JSON, Export CSV
- Import Database (.db), Import JSON
- Clear All
- Hash-based dynamic colors for unknown statuses/sources
- Back to top floating button
- Toast notifications
What's generalized
- Status / source / dependencies โ free-text with datalist autocomplete that learns from your data
- Stats bar dynamic โ one card per observed status (was 7 hardcoded Chinese labels)
- Filter dropdowns dynamic โ populated from observed values
- PROJECT_CONFIG parameterized from
config.yaml
- Save endpoint URL parameterized (hardcoded prior to v1)
- Smart save detection โ checks
protocol !== 'file:' by default; configurable via serve.host_match
- Save server โ reads
.dashboard/config.yaml for port / bind / endpoint / path
- Runtime injections stripped โ browser-extension and runtime-injected tracking scripts are removed at render time
Commands
| Command | Purpose |
|---|
init --name "<project>" | Scaffold .dashboard/ in CWD + render initial HTML |
add --json '{...}' | Add item; auto re-renders HTML |
update --id <id> --json '{...}' | Patch item; auto re-renders HTML |
remove --id <id> | Delete item; auto re-renders HTML |
list [--status X] [--search "..."] [--json] | List items |
get --id <id> | Print single item JSON |
render [--publish] | Regenerate latest.html (publish copies to config.publish.target) |
sync | Push current latest.html + items.json to GitHub (requires publish.type: github) |
summary | Count items by status |
serve | Start save server using config.serve.* |
Item schema
{
"id": "item_<unix_ts>_<random>",
"progressStatus": "<free-text>",
"title": "<question or short label>",
"description": "<the requirement / detail>",
"component": "<which subsystem>",
"technicalDetails": "<specs, deadlines>",
"assignee": "<who owns this>",
"dependencies": ["<list of free-text labels>"],
"source": "<where this came from>",
"lastUpdated": "YYYY-MM-DD",
"lastModified": "<ISO timestamp>",
"attachments": ["<relative paths>"],
"pageContent": "<notes textarea>",
"pageLastSaved": "<localized timestamp>"
}
Triggers
Activate when the user says:
- "dashboard", "้กน็ฎ dashboard", "tracker", "่ฟๅบฆ็ๆฟ"
- "init dashboard", "set up dashboard for this project"
- "add dashboard item", "update progress status"
- "save dashboard", "dashboard ไฟๅญๅฐๆๅกๅจ"
- "render dashboard", "dashboard ้ๆฐ็ๆ"