diff --git a/CHANGELOG.md b/CHANGELOG.md index 83aaa67..c383365 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.21] - 2026-04-20 + +### Changed +- Dashboard: eliminated double-render flicker — initial paint uses skeleton widgets and a stat-less greeting; real widgets replace skeletons in-place without resetting `container.innerHTML` +- Dashboard: weather widget now derives temperature unit symbol (°C / °F / K) from the `units` field returned by the weather API instead of always showing °C +- Dark mode: removed duplicate `@media (prefers-color-scheme: dark)` block from `tokens.css`; system-preference detection moved to a `matchMedia` listener in `index.html` for flash-free sync +- Tasks: view-toggle (list / Kanban) fades out at 40% opacity during re-render and fades back in, giving visible feedback of the switch + +### Fixed +- Tasks: inline `style="width/height"` on all Lucide icon instances replaced with utility CSS classes (`icon-xs` … `icon-2xl`, `icon-11`) defined in `layout.css` +- Tasks: edit-button inline size overrides removed; replaced with new `.btn--icon-sm` utility class +- Tasks: `textarea` `resize: vertical` and select `min-height: 44px` moved from inline styles to `layout.css` +- Dashboard: `chipIcon` inline style variable eliminated; chip icons now use `class="icon-sm"` +- Dashboard: settings, refresh, chevron, and other action icons converted from inline styles to CSS classes +- Weather API: server now forwards the configured `units` value in the response payload so the frontend can render the correct unit symbol + ## [0.20.20] - 2026-04-20 ### Fixed diff --git a/package.json b/package.json index 9bdab5e..e3ae63f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oikos", - "version": "0.20.20", + "version": "0.20.21", "description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.", "main": "server/index.js", "type": "module", diff --git a/public/index.html b/public/index.html index 53025c7..1765f32 100644 --- a/public/index.html +++ b/public/index.html @@ -40,11 +40,19 @@ - + diff --git a/public/pages/dashboard.js b/public/pages/dashboard.js index 2de3708..3af080d 100644 --- a/public/pages/dashboard.js +++ b/public/pages/dashboard.js @@ -149,21 +149,20 @@ function skeletonWidget(lines = 3) { function renderGreeting(user, stats = {}) { const { urgentCount = 0, todayEventCount = 0, todayMealTitle = null } = stats; - const chipIcon = 'width:12px;height:12px;flex-shrink:0;'; const statChips = []; if (urgentCount > 0) statChips.push(` - + ${urgentCount > 1 ? t('dashboard.urgentTasksChipPlural', { count: urgentCount }) : t('dashboard.urgentTasksChip', { count: urgentCount })} `); if (todayEventCount > 0) statChips.push(` - + ${todayEventCount > 1 ? t('dashboard.eventsChipPlural', { count: todayEventCount }) : t('dashboard.eventsChip', { count: todayEventCount })} `); if (todayMealTitle) statChips.push(` - + ${t('dashboard.todayMealChip', { title: esc(todayMealTitle) })} `); @@ -177,7 +176,7 @@ function renderGreeting(user, stats = {}) { @@ -358,7 +357,8 @@ const WEATHER_ICON_BASE = '/api/v1/weather/icon/'; function renderWeatherWidget(weather) { if (!weather) return ''; - const { city, current, forecast } = weather; + const { city, current, forecast, units } = weather; + const unitSymbol = units === 'imperial' ? '°F' : units === 'standard' ? 'K' : '°C'; const forecastHtml = forecast.map((d, i) => { const date = new Date(d.date + 'T12:00:00'); @@ -379,12 +379,12 @@ function renderWeatherWidget(weather) { return `