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.
10 KiB
10 KiB
Phase 4: Visual & Styling Enhancements
Status: ✅ Complete Parent plan: PLAN.md Domain: frontend
Objective
Implement all 6 visual/styling features: glassmorphism cards, board-level themes, animated status rings, card size options, custom CSS injection, and wallpaper backgrounds.
Tasks
4.1 Glassmorphism Card Style
- Add card style system to theme store — extend
src/lib/stores/theme.svelte.ts:- New property:
cardStyle: 'solid' | 'glass' | 'outline'(default: 'solid') - Persist to localStorage, broadcast across tabs
- New property:
- Add CSS classes in
src/app.css:.card-solid— current default card style.card-glass—backdrop-filter: blur(12px); background: hsl(var(--card) / 0.6); border: 1px solid hsl(var(--border) / 0.3).card-outline—background: transparent; border: 1px solid hsl(var(--border))
- Update widget/card components to use dynamic card style class
- Add card style picker to theme settings UI (3-way toggle: solid/glass/outline)
4.2 Board-Level Themes
- Create
src/lib/components/board/BoardThemeProvider.svelte- Reads board's themeHue, themeSaturation, backgroundType from board data
- Overrides CSS variables when viewing that board (--primary-h, --primary-s)
- Smooth transition when switching boards (CSS transition on :root variables)
- Restores global theme when navigating away from the board
- Update board edit form to include theme settings:
- Hue slider (0-360 with color preview)
- Saturation slider (0-100)
- Background type selector (mesh/particles/aurora/none/wallpaper)
- Update board data loading to include theme fields
- Fix updateBoard server action to extract theme fields from formData
- Fix backgroundType validator to accept all background types (mesh/particles/aurora/wallpaper/none)
4.3 Animated SVG Status Ring
- Create
src/lib/components/app/AnimatedStatusRing.svelte- SVG circle around app icon with status-dependent animation:
- Online: animated green fill sweep (stroke-dashoffset animation)
- Offline: pulsing red ring (opacity animation)
- Degraded: partial yellow arc (75% fill, subtle pulse)
- Unknown: gray dashed ring (rotating dash pattern)
- Props: status, size (scales with card size), animated (boolean)
- SVG circle around app icon with status-dependent animation:
- Replace static status dots in AppWidget.svelte with AnimatedStatusRing
- Ensure ring scales appropriately with compact/medium/large card sizes
4.4 Card Size Options
- Add
CardSizesupport to section and board levels:- Per-section:
section.cardSizeoverrides board default - Per-board:
board.cardSizeas fallback - Global default: 'medium'
- Per-section:
- Create card size variants in widget components:
compact— icon + name only, smaller padding, single row gridmedium— current default (icon + name + status + description on hover)large— icon + name + description + sparkline + tags, more padding
- Add card size picker to section edit form (DraggableSection) and board settings
- Update WidgetGrid to adjust grid columns based on card size
- Wire up onUpdateSection handler through DraggableBoard to board edit page
4.5 Custom CSS Injection
- Create
src/lib/components/settings/CustomCssEditor.svelte- Textarea with monospace font for custom CSS
- Live preview toggle
- Sanitization: strip
<script>tags, limit selectors to.app-scopeor descendant selectors
- Add custom CSS field to admin system settings form (SettingsForm.svelte)
- Add per-board custom CSS field to board edit form
- Create
src/lib/components/layout/CustomCssInjector.svelte- Injects
<style>tag with sanitized CSS from system settings + current board - Wraps CSS in
.custom-css-scopeto prevent breaking critical UI
- Injects
- Add CustomCssInjector to root layout
4.6 Wallpaper Backgrounds
- Create
src/lib/components/background/WallpaperBackground.svelte- Displays uploaded image or Unsplash URL as board background
- Configurable: blur amount (0-20px), overlay opacity (0-1), parallax (boolean), position (fixed/scroll)
- Fallback to procedural background if wallpaper fails to load
- Add wallpaper upload endpoint:
src/routes/api/wallpaper/+server.ts- Accept image upload (PNG, JPG, WebP), save to
static/uploads/wallpapers/ - Return URL path
- Max file size: 5MB
- Accept image upload (PNG, JPG, WebP), save to
- Add wallpaper configuration to board edit form:
- Image upload button or URL input
- Blur slider, overlay opacity slider
- Parallax toggle
- Integrate WallpaperBackground into AmbientBackground component (new background type)
- Optional Unsplash integration (deferred — requires external API key infrastructure)
Files to Modify/Create
src/lib/stores/theme.svelte.ts— extend with cardStylesrc/app.css— add glassmorphism classessrc/lib/components/board/BoardThemeProvider.svelte— newsrc/lib/components/app/AnimatedStatusRing.svelte— newsrc/lib/components/widget/AppWidget.svelte— modify (use AnimatedStatusRing)src/lib/components/widget/WidgetGrid.svelte— modify (card size grid)src/lib/components/settings/CustomCssEditor.svelte— newsrc/lib/components/layout/CustomCssInjector.svelte— newsrc/lib/components/background/WallpaperBackground.svelte— newsrc/routes/api/wallpaper/+server.ts— new- Board edit form components — modify
- Section edit form components — modify
- Root layout — modify (add CustomCssInjector)
Acceptance Criteria
- Glassmorphism effect works in both light and dark mode, ambient bg bleeds through
- Board themes override global theme smoothly, restore on navigation
- Status rings animate correctly for all 4 statuses
- Card sizes adjust grid layout and widget content appropriately
- Custom CSS is properly sandboxed (cannot break critical UI elements)
- Wallpaper backgrounds display correctly with all configuration options
- All visual changes respect dark/light mode
Notes
- Glassmorphism requires
backdrop-filtersupport (all modern browsers) - Board theme transitions: use CSS
transition: --primary-h 0.3s, --primary-s 0.3son :root - Custom CSS sanitization: use a simple regex-based approach to strip dangerous selectors, or wrap all custom CSS in a scoped parent selector
- Wallpaper upload: reuse existing upload infrastructure if available (check static/uploads/)
Review Checklist
- All tasks completed
- 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
- 4.1 Glassmorphism: Theme store already had
cardStyleproperty with localStorage persistence and broadcast sync. CSS classes.card-solid,.card-glass,.card-outlineexist inapp.csswith dark mode variants. AppWidget uses dynamiccard-${theme.cardStyle}class. ThemeCustomizer has 3-way card style picker. - 4.2 Board-Level Themes: BoardThemeProvider applies board-specific
--primary-h/--primary-sCSS variables and now properly restores global theme values on cleanup. Board edit form has hue slider, saturation slider, background type selector, and card size picker. Fixed theupdateBoardserver action to extract all theme fields from formData. FixedupdateBoardSchemabackgroundType enum to acceptmesh/particles/aurora/wallpaper/none. - 4.3 Animated SVG Status Ring: AnimatedStatusRing component renders an SVG circle with 4 status-dependent animations (fill sweep for online, pulse opacity for offline, degraded pulse for degraded, rotating dash for unknown). Replaces status dots in AppWidget at all 3 card sizes.
- 4.4 Card Size Options: Section-level
cardSizeoverrides board-level default. WidgetGrid adjusts grid columns per card size. AppWidget renders compact/medium/large variants. Added card size picker dropdown to DraggableSection with onUpdateSection handler wired through DraggableBoard to the board edit page. - 4.5 Custom CSS Injection: CustomCssEditor with validation, sanitization, and live preview. CustomCssInjector sanitizes and injects
<style>tag scoped to.custom-css-scope. Added to root layout for system-level CSS and board view page for board-level CSS. Added CustomCssEditor to admin SettingsForm for system-wide CSS. - 4.6 Wallpaper Backgrounds: WallpaperBackground component with blur, overlay, parallax, and position options. Upload API endpoint at
/api/wallpaperwith type/size validation. Board edit form has upload, URL input, blur slider, overlay slider, and parallax toggle. Integrated into AmbientBackground. Unsplash integration deferred.
What the next phase needs to know
- All visual/styling features are implemented and wired end-to-end
- The
updateBoardSchemabackgroundType now uses inline string enum['mesh', 'particles', 'aurora', 'wallpaper', 'none']instead of theBackgroundTypeconstant (which only hadnone/color/wallpaper) - BoardThemeProvider now imports
themestore to restore global values on cleanup - DraggableSection and DraggableBoard now support an optional
onUpdateSectioncallback for section-level edits (currently used for cardSize) - System-level custom CSS is loaded in the root layout server data and injected via CustomCssInjector
- Board-level custom CSS is injected on the board view page via CustomCssInjector
- Unsplash integration was deferred as it requires external API key management infrastructure
Potential concerns
- The
BackgroundTypeconstant inconstants.ts(none/color/wallpaper) does not match the actual background types used by the theme system (mesh/particles/aurora/wallpaper/none). The validator was fixed to use inline strings, but the constant may cause confusion if used elsewhere. - The board edit form uses native HTML forms with
use:enhance— theme fields are now extracted in the server action but numeric parsing from formData strings could produce NaN if invalid input sneaks through. The Zod schema provides a safety net. - Custom CSS sanitization is regex-based. It blocks common XSS vectors but is not a full CSS parser. A determined attacker with admin access could potentially craft CSS that affects layout outside
.custom-css-scope.