1c0a7cb850
Phase 4 — New Widget Types: - Clock/Weather, System Stats, RSS/Feed, Calendar, Markdown, Metric/Counter, Link Group, Camera/Stream widgets - Backend services with caching for each data source - Full creation form with dynamic config fields per type Phase 5 — Visual & Styling Enhancements: - Glassmorphism card style (solid/glass/outline) - Board-level themes with per-board hue/saturation - Animated SVG status rings replacing static dots - Card size options (compact/medium/large) - Custom CSS injection (admin + per-board, sanitized) - Wallpaper backgrounds with blur/overlay/parallax Phase 6 — Functional Features: - Favorites bar with drag-and-drop reordering - Recent apps tracking with privacy toggle - Uptime dashboard page (/status, guest-accessible) - Notifications system (Discord/Slack/Telegram/HTTP webhooks) - App tags with filtering in board view - Multi-URL app cards with expandable sub-links - Personal API tokens with scoped permissions - Audit log with retention and admin viewer Phase 7 — Quality of Life: - Onboarding wizard (5-step first-launch setup) - App URL health preview with favicon/title detection - Board templates (4 built-in + custom import/export) - Keyboard shortcut overlay (j/k nav, 1-9 boards, ? help) 212 files changed, 15641 insertions, 980 deletions. Build, lint, type check, and 222 tests all pass.
179 lines
8.9 KiB
Markdown
179 lines
8.9 KiB
Markdown
# Phase 3: New Widget Components
|
|
|
|
**Status:** ✅ Complete
|
|
**Parent plan:** [PLAN.md](./PLAN.md)
|
|
**Domain:** frontend
|
|
|
|
## Objective
|
|
|
|
Build all 8 new widget UI components with polished design, integrate them into the existing WidgetRenderer and WidgetCreationForm, and ensure they work with the drag-and-drop system.
|
|
|
|
## Tasks
|
|
|
|
### 3.1 Clock/Weather Widget
|
|
|
|
- [x] Create `src/lib/components/widget/ClockWeatherWidget.svelte`
|
|
- Digital clock: large time display with configurable timezone, date below
|
|
- Analog clock: SVG clock face with hour/minute/second hands, smooth animation via $effect
|
|
- Weather section (optional): current temp, condition icon (Lucide), location label
|
|
- Fetches weather from `/api/widgets/weather` on mount + interval
|
|
- Config-driven: clockStyle (analog|digital), showWeather, timezone
|
|
|
|
### 3.2 System Stats Widget
|
|
|
|
- [x] Create `src/lib/components/widget/SystemStatsWidget.svelte`
|
|
- Donut/gauge charts for each metric (CPU, RAM, disk) using SVG
|
|
- Threshold coloring: green (<60%), yellow (60-85%), red (>85%) via CSS classes
|
|
- Auto-refresh at configurable interval
|
|
- Fetches from `/api/widgets/system-stats`
|
|
- Compact layout: metrics side-by-side with labels below
|
|
|
|
### 3.3 RSS/Feed Widget
|
|
|
|
- [x] Create `src/lib/components/widget/RssFeedWidget.svelte`
|
|
- List of feed items: title + relative date
|
|
- Expandable summary on click (slide transition)
|
|
- Link icon to open in new tab
|
|
- Fetches from `/api/widgets/rss`
|
|
- Loading skeleton while fetching
|
|
- Empty state when feed has no items
|
|
|
|
### 3.4 Calendar Widget
|
|
|
|
- [x] Create `src/lib/components/widget/CalendarWidget.svelte`
|
|
- Compact event list grouped by day (Today, Tomorrow, then dates)
|
|
- Color dot per calendar source
|
|
- Time range display (or "All day")
|
|
- Location shown if available
|
|
- Fetches from `/api/widgets/calendar`
|
|
- Empty state: "No upcoming events"
|
|
|
|
### 3.5 Markdown Widget
|
|
|
|
- [x] Create `src/lib/components/widget/MarkdownWidget.svelte`
|
|
- Rendered markdown view (default) using `marked` + `isomorphic-dompurify`
|
|
- Edit mode: split-pane with textarea left, preview right
|
|
- Syntax highlighting for code blocks (use existing `marked` setup or add `highlight.js`)
|
|
- Toggle edit/view mode button
|
|
- Save updates config via API
|
|
- Proper typography styling for headers, lists, code, blockquotes
|
|
|
|
### 3.6 Metric/Counter Widget
|
|
|
|
- [x] Create `src/lib/components/widget/MetricWidget.svelte`
|
|
- Large centered number with unit suffix
|
|
- Label below the number
|
|
- Trend arrow: up (green), down (red), flat (gray) — SVG arrow icon
|
|
- Auto-refresh at interval
|
|
- Fetches from `/api/widgets/metric`
|
|
- Number formatting (locale-aware, abbreviate large numbers)
|
|
|
|
### 3.7 Link Group Widget
|
|
|
|
- [x] Create `src/lib/components/widget/LinkGroupWidget.svelte`
|
|
- Compact vertical list of links with optional icons
|
|
- Each link: icon (Lucide or none) + label, opens in new tab
|
|
- Collapsible header if config.collapsible is true (slide transition)
|
|
- Hover highlight on each link row
|
|
- No external data fetching — config-driven only
|
|
|
|
### 3.8 Camera/Stream Widget
|
|
|
|
- [x] Create `src/lib/components/widget/CameraStreamWidget.svelte`
|
|
- Snapshot mode: `<img>` tag refreshed at interval via `/api/widgets/camera`
|
|
- MJPEG mode: direct `<img src={streamUrl}>` (continuous stream)
|
|
- HLS mode: `<video>` tag with HLS.js (lazy-loaded if needed)
|
|
- Click opens fullscreen modal (use Bits UI Dialog)
|
|
- Aspect ratio from config (default 16:9)
|
|
- Loading state and error fallback image
|
|
|
|
### 3.9 Update WidgetRenderer
|
|
|
|
- [x] Update `src/lib/components/widget/WidgetRenderer.svelte`
|
|
- Add cases for all 8 new widget types
|
|
- Import new widget components
|
|
- Parse config and pass correct props
|
|
|
|
### 3.10 Update WidgetCreationForm
|
|
|
|
- [x] Update `src/lib/components/widget/WidgetCreationForm.svelte`
|
|
- Add all 8 new widget types to the type picker (with icons and labels)
|
|
- Add dynamic config form fields for each new type:
|
|
- Clock: timezone select, clock style toggle, weather checkbox, lat/lng inputs
|
|
- System Stats: source URL, source type select, metrics checkboxes, refresh interval
|
|
- RSS: feed URL input, max items slider, show summary checkbox
|
|
- Calendar: iCal URL list (add/remove), days ahead slider
|
|
- Markdown: content textarea (full height)
|
|
- Metric: label, source type select, value/URL/query inputs based on source, unit, refresh
|
|
- Link Group: link list (add/remove rows with label+URL+icon), collapsible checkbox
|
|
- Camera: stream URL, type select, refresh interval, aspect ratio select
|
|
|
|
## Files to Modify/Create
|
|
|
|
- `src/lib/components/widget/ClockWeatherWidget.svelte` — new
|
|
- `src/lib/components/widget/SystemStatsWidget.svelte` — new
|
|
- `src/lib/components/widget/RssFeedWidget.svelte` — new
|
|
- `src/lib/components/widget/CalendarWidget.svelte` — new
|
|
- `src/lib/components/widget/MarkdownWidget.svelte` — new
|
|
- `src/lib/components/widget/MetricWidget.svelte` — new
|
|
- `src/lib/components/widget/LinkGroupWidget.svelte` — new
|
|
- `src/lib/components/widget/CameraStreamWidget.svelte` — new
|
|
- `src/lib/components/widget/WidgetRenderer.svelte` — modify
|
|
- `src/lib/components/widget/WidgetCreationForm.svelte` — modify
|
|
|
|
## Acceptance Criteria
|
|
|
|
- All 8 widgets render correctly with sample config data
|
|
- Widgets that fetch external data show loading states and handle errors gracefully
|
|
- Edit/create form correctly generates config JSON for each widget type
|
|
- WidgetRenderer routes to the correct component for each type
|
|
- All widgets work with the drag-and-drop system (no interference)
|
|
- Widgets use existing design system (Tailwind classes, CSS variables, dark mode support)
|
|
- Responsive: widgets adapt to different container widths
|
|
|
|
## Notes
|
|
|
|
- Follow existing widget component patterns (see AppWidget.svelte, BookmarkWidget.svelte)
|
|
- Use Svelte 5 runes: $props for inputs, $state for local state, $derived for computed, $effect for side effects
|
|
- Use onMount for initial data fetches, setInterval for auto-refresh (clean up in onDestroy or $effect return)
|
|
- All external data fetches go through the backend API (no direct client-side calls to external services)
|
|
- Keep each widget component focused — extract shared utilities if patterns repeat
|
|
|
|
## Review Checklist
|
|
|
|
- [x] All tasks completed
|
|
- [x] Code follows project conventions
|
|
- [ ] No unintended side effects
|
|
- [ ] Build passes (Big Bang: code quality check only)
|
|
- [ ] Tests pass (Big Bang: skipped for intermediate phase)
|
|
|
|
## Handoff to Next Phase
|
|
|
|
### What was done
|
|
|
|
- Created 8 new widget components: ClockWeatherWidget, SystemStatsWidget, RssFeedWidget, CalendarWidget, MarkdownWidget, MetricWidget, LinkGroupWidget, CameraStreamWidget
|
|
- Updated WidgetRenderer to route all 8 new widget types to their components with parsed config props
|
|
- Updated WidgetCreationForm with all 8 new widget types in the type picker (13 total) and dynamic config forms for each
|
|
- Updated WidgetGrid to include new full-width widget types (system_stats, rss, calendar, markdown, camera)
|
|
|
|
### What the next phase needs to know
|
|
|
|
- All widget components follow the established pattern: `interface Props { config: XxxWidgetConfig }` with `$props()`
|
|
- ClockWeatherWidget supports digital, analog, and 24h clock styles; analog uses SVG; weather fetches from `/api/widgets/weather`
|
|
- SystemStatsWidget renders SVG donut/gauge charts with threshold coloring (green/yellow/red)
|
|
- RssFeedWidget has expandable summaries using Svelte `slide` transition
|
|
- CalendarWidget groups events by day (Today, Tomorrow, date) with color dots per calendar source
|
|
- MarkdownWidget reuses the project's existing `marked` + `isomorphic-dompurify` setup (same as NoteWidget); has split-pane edit mode with save-to-API
|
|
- MetricWidget supports static, JSON, and Prometheus sources; shows trend arrows and abbreviates large numbers
|
|
- LinkGroupWidget is config-driven only (no API fetch); supports collapsible mode
|
|
- CameraStreamWidget supports image/MJPEG/HLS modes; HLS uses lazy-loaded `hls.js`; has a custom fullscreen modal overlay
|
|
- WidgetCreationForm uses IconGrid for type selection (5 columns) and dynamic form sections per type
|
|
- All interval-based refreshes use `$effect` cleanup pattern for proper teardown
|
|
|
|
### Potential concerns
|
|
|
|
- CameraStreamWidget fullscreen modal is a custom implementation (not Bits UI Dialog as spec suggested) because it avoids adding a component dependency for a simple overlay. If consistency with other modals is needed, it could be refactored to use Bits UI Dialog.
|
|
- HLS.js is dynamically imported (`import('hls.js')`); if hls.js is not installed as a dependency, the import will fail gracefully and fall back to native HLS support (Safari). The project may need `npm install hls.js` if HLS camera streams are used.
|
|
- MarkdownWidget save uses PATCH to `/api/widgets/{id}` which must exist in the API routes (standard widget update endpoint).
|
|
- The WidgetCreationForm is now a larger component (~500 lines) due to 13 widget types. If this becomes unwieldy, consider extracting per-type form sections into subcomponents.
|