mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 02:26:37 +00:00
feat(dashboards): v2.7 widget catalog — file-reading widgets, sparkline, typed status, project-wide watch
Major project-dashboard release. Five new widget types (markdown_file, log_tail, cron_status, image, status_grid), inline sparkline on stat, typed status enum shared by list + status_grid, structured WidgetErrorCard, and a project-wide .scarf/ directory watch that picks up files cron jobs write next to dashboard.json. - ProjectDashboard: extend DashboardWidget with path/lines/jobId/cells/gridColumns/sparkline; add StatusGridCell + ListItemStatus (lenient parse with synonyms) - HermesFileWatcher: watch each project's .scarf/ dir alongside dashboard.json (local FSEvents + remote SSH mtime poll); updateProjectWatches signature now takes dashboardPaths + scarfDirs - New widget views: CronStatus, Image, LogTail, MarkdownFile, StatusGrid, plus WidgetErrorCard for structured failure messaging; legacy "Unknown" placeholder replaced everywhere - WidgetPathResolver: project-root-anchored path resolution that rejects absolute paths + ".." escapes pre and post canonicalization - Stat widget gains optional inline sparkline (pure SwiftUI Path, no Charts dep); list widget rows route through typed status with semantic icons + ScarfColor tints - iOS list widget + unsupported card adopt typed status + warning-toned error card (parity with Mac error styling); new widget types remain Mac-only - Site mirror: widgets.js renders all five new types (file-reading widgets show annotated catalog placeholders), sparkline SVG, status-grid grid; styles.css adds typed-status palette + error-card + sparkline + grid styles - Catalog validator: tools/widget-schema.json is the single source of truth; build-catalog.py loads it and enforces per-type required fields. 8 new test cases in test_build_catalog.py covering schema load, v2.7 additions, and missing-required rejection - Template-author skill (SKILL.md) gains v2.7 Widget Catalog section + canonical status guidance; CONTRIBUTING.md points authors at widget-schema.json; template-author bundle rebuilt - Localizable.xcstrings picks up auto-extracted strings for the previously-shipped OAuth keepalive feature - Release notes drafted at releases/v2.7.0/RELEASE_NOTES.md Backwards compatible — existing dashboard.json renders byte-identically, status synonyms (ok/up/down/active/etc.) keep working. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -411,6 +411,64 @@ h1, h2, h3 { line-height: 1.25; }
|
||||
}
|
||||
.widget-list-status[data-status="up"] { background: rgba(42,168,118,0.18); color: var(--accent-dark); }
|
||||
.widget-list-status[data-status="down"] { background: rgba(217,83,79,0.18); color: var(--red); }
|
||||
/* v2.7 typed semantic statuses (mirrors ScarfDesign palette + Swift ListItemStatus enum). */
|
||||
.widget-list-status.status-success { background: rgba(42,168,118,0.18); color: var(--accent-dark); }
|
||||
.widget-list-status.status-warning { background: rgba(240,173,78,0.20); color: var(--orange); }
|
||||
.widget-list-status.status-danger { background: rgba(217,83,79,0.18); color: var(--red); }
|
||||
.widget-list-status.status-info { background: rgba(91,143,225,0.20); color: var(--blue); }
|
||||
.widget-list-status.status-pending { background: rgba(0,0,0,0.06); color: var(--fg-muted); }
|
||||
.widget-list-status.status-done { background: rgba(42,168,118,0.14); color: var(--accent-dark); }
|
||||
.widget-list-status.status-neutral { background: rgba(0,0,0,0.06); color: var(--fg-muted); }
|
||||
.widget-list-status.status-unknown { background: rgba(0,0,0,0.06); color: var(--fg-muted); font-style: italic; }
|
||||
.widget-list-item-done .widget-list-text { text-decoration: line-through; color: var(--fg-muted); }
|
||||
|
||||
/* v2.7 structured widget error card (mirrors Swift WidgetErrorCard). */
|
||||
.widget-error {
|
||||
background: rgba(240,173,78,0.08);
|
||||
border: 1px solid rgba(240,173,78,0.30);
|
||||
}
|
||||
.widget-error-head { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
|
||||
.widget-error-icon { color: var(--orange); font-size: 14px; }
|
||||
.widget-error-reason { font-size: 14px; color: var(--fg); }
|
||||
.widget-error-hint { margin-top: 4px; font-size: 11px; color: var(--fg-muted); }
|
||||
|
||||
/* v2.7 cron_status / log_tail / markdown_file (catalog preview placeholders). */
|
||||
.widget-cron-status, .widget-log-tail, .widget-markdown-file { padding: 12px; }
|
||||
.widget-cron-head { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
|
||||
.widget-cron-icon { font-size: 14px; color: var(--fg-muted); }
|
||||
.widget-cron-meta { font-size: 13px; color: var(--fg); font-family: monospace; }
|
||||
.widget-cron-hint { margin-top: 6px; font-size: 11px; color: var(--fg-muted); font-style: italic; }
|
||||
|
||||
/* v2.7 image widget. */
|
||||
.widget-image { padding: 12px; }
|
||||
.widget-image-img { display: block; max-width: 100%; height: auto; margin-top: 8px; border-radius: 4px; }
|
||||
|
||||
/* v2.7 status_grid widget — compact NxM grid with semantic-status swatches. */
|
||||
.widget-status-grid { padding: 12px; }
|
||||
.widget-status-grid-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cols, 6), 1fr);
|
||||
gap: 4px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.widget-status-grid-cell { display: flex; flex-direction: column; gap: 2px; align-items: center; }
|
||||
.widget-status-grid-swatch { width: 100%; height: 18px; border-radius: 3px; }
|
||||
.widget-status-grid-label { font-size: 9px; color: var(--fg-muted); text-align: center; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.widget-status-grid-swatch.status-success { background: rgba(42,168,118,0.85); }
|
||||
.widget-status-grid-swatch.status-warning { background: rgba(240,173,78,0.85); }
|
||||
.widget-status-grid-swatch.status-danger { background: rgba(217,83,79,0.85); }
|
||||
.widget-status-grid-swatch.status-info { background: rgba(91,143,225,0.85); }
|
||||
.widget-status-grid-swatch.status-pending { background: rgba(120,120,120,0.40); }
|
||||
.widget-status-grid-swatch.status-done { background: rgba(42,168,118,0.55); }
|
||||
.widget-status-grid-swatch.status-neutral { background: rgba(120,120,120,0.30); }
|
||||
|
||||
/* v2.7 sparkline under stat value. Inherits color from widget-stat data-color. */
|
||||
.widget-stat-sparkline { display: block; margin-top: 4px; width: 100%; }
|
||||
.widget-stat[data-color="accent"] .widget-stat-sparkline,
|
||||
.widget-stat[data-color="green"] .widget-stat-sparkline { color: var(--accent-dark); }
|
||||
.widget-stat[data-color="red"] .widget-stat-sparkline { color: var(--red); }
|
||||
.widget-stat[data-color="blue"] .widget-stat-sparkline { color: var(--blue); }
|
||||
.widget-stat[data-color="orange"] .widget-stat-sparkline { color: var(--orange); }
|
||||
|
||||
/* chart */
|
||||
.widget-chart-svg { width: 100%; height: auto; margin-top: 8px; }
|
||||
|
||||
Reference in New Issue
Block a user