chore: release v0.23.5
This commit is contained in:
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.23.5] - 2026-04-22
|
||||
|
||||
### Changed
|
||||
- Dashboard: each widget now uses its module accent color (green for tasks, violet for calendar, orange for meals, pink for shopping, amber for notes) for its header icon, badge, and link instead of the global indigo accent
|
||||
- Dashboard: meal slots now display their type-specific color (amber for breakfast, green for lunch, indigo for dinner, orange for snack) on icon and label when a meal is planned
|
||||
- Dashboard: pinned note cards now show a subtle background tint matching the note's color
|
||||
- Dashboard: widget and card hover lift increased from 1 px to 2 px for more perceptible feedback on desktop
|
||||
- Navigation: active bottom-nav tab now shows a pill-shaped highlight behind the icon for a clearer location indicator
|
||||
- Shopping widget: progress bar height increased from 4 px to 6 px for better visual weight
|
||||
- Empty state icons inside widgets now use the tertiary text color instead of the disabled color for improved visibility
|
||||
|
||||
## [0.23.4] - 2026-04-22
|
||||
|
||||
### Changed
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "oikos",
|
||||
"version": "0.23.4",
|
||||
"version": "0.23.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "oikos",
|
||||
"version": "0.23.4",
|
||||
"version": "0.23.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bcrypt": "^6.0.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "oikos",
|
||||
"version": "0.23.4",
|
||||
"version": "0.23.5",
|
||||
"description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.",
|
||||
"main": "server/index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -215,7 +215,7 @@ function renderGreeting(user, stats = {}) {
|
||||
|
||||
function renderUrgentTasks(tasks) {
|
||||
if (!tasks.length) {
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--tasks">
|
||||
${widgetHeader('check-square', t('nav.tasks'), 0, '/tasks')}
|
||||
<div class="widget__empty">
|
||||
<i data-lucide="check-circle" class="empty-state__icon" style="color:var(--color-success)" aria-hidden="true"></i>
|
||||
@@ -241,7 +241,7 @@ function renderUrgentTasks(tasks) {
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--tasks">
|
||||
${widgetHeader('check-square', t('nav.tasks'), tasks.length, '/tasks')}
|
||||
<div class="widget__body">${items}</div>
|
||||
</div>`;
|
||||
@@ -249,7 +249,7 @@ function renderUrgentTasks(tasks) {
|
||||
|
||||
function renderUpcomingEvents(events) {
|
||||
if (!events.length) {
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--calendar">
|
||||
${widgetHeader('calendar', t('nav.calendar'), 0, '/calendar')}
|
||||
<div class="widget__empty">
|
||||
<i data-lucide="calendar-check" class="empty-state__icon" aria-hidden="true"></i>
|
||||
@@ -280,7 +280,7 @@ function renderUpcomingEvents(events) {
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--calendar">
|
||||
${widgetHeader('calendar', t('nav.calendar'), events.length, '/calendar')}
|
||||
<div class="widget__body">${items}</div>
|
||||
</div>`;
|
||||
@@ -293,7 +293,7 @@ function renderTodayMeals(meals) {
|
||||
const slots = MEAL_ORDER.map((type) => {
|
||||
const meal = meals.find((m) => m.meal_type === type);
|
||||
return `
|
||||
<div class="meal-slot ${meal ? 'meal-slot--filled' : ''}" data-route="/meals" role="button" tabindex="0">
|
||||
<div class="meal-slot ${meal ? 'meal-slot--filled' : ''}" data-type="${type}" data-route="/meals" role="button" tabindex="0">
|
||||
<i data-lucide="${MEAL_ICONS[type]}" class="meal-slot__icon" aria-hidden="true"></i>
|
||||
<div class="meal-slot__type">${mealLabels[type]}</div>
|
||||
<div class="meal-slot__title">${meal ? esc(meal.title) : '-'}</div>
|
||||
@@ -309,7 +309,7 @@ function renderTodayMeals(meals) {
|
||||
|
||||
function renderPinnedNotes(notes) {
|
||||
if (!notes.length) {
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--notes">
|
||||
${widgetHeader('pin', t('nav.notes'), 0, '/notes')}
|
||||
<div class="widget__empty">
|
||||
<i data-lucide="sticky-note" class="empty-state__icon" aria-hidden="true"></i>
|
||||
@@ -326,7 +326,7 @@ function renderPinnedNotes(notes) {
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
return `<div class="widget widget--wide">
|
||||
return `<div class="widget widget--notes widget--wide">
|
||||
${widgetHeader('pin', t('nav.notes'), notes.length, '/notes')}
|
||||
<div class="notes-grid-widget">${items}</div>
|
||||
</div>`;
|
||||
@@ -373,7 +373,7 @@ function renderShoppingLists(lists) {
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="widget">
|
||||
return `<div class="widget widget--shopping">
|
||||
${widgetHeader('shopping-cart', t('nav.shopping'), totalOpen, '/shopping')}
|
||||
<div class="widget__body">${listsHtml}</div>
|
||||
</div>`;
|
||||
@@ -409,7 +409,7 @@ function renderWeatherWidget(weather) {
|
||||
}).join('');
|
||||
|
||||
return `
|
||||
<div class="widget weather-widget" id="weather-widget">
|
||||
<div class="widget widget--weather weather-widget" id="weather-widget">
|
||||
<button class="weather-widget__refresh" id="weather-refresh-btn" aria-label="${t('dashboard.weatherRefresh')}" title="${t('dashboard.weatherRefreshTitle')}">
|
||||
<i data-lucide="refresh-cw" class="icon-md" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
+29
-10
@@ -158,6 +158,19 @@
|
||||
background: var(--color-warning-translucent);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------
|
||||
* Widget-Modul-Akzentfarben
|
||||
* Jedes Widget nutzt seine eigene Modulfarbe für Icon, Badge und Link.
|
||||
* -------------------------------------------------------- */
|
||||
.widget--tasks { --widget-accent: var(--module-tasks); }
|
||||
.widget--calendar { --widget-accent: var(--module-calendar); }
|
||||
.widget--shopping { --widget-accent: var(--module-shopping); }
|
||||
.widget--meals { --widget-accent: var(--module-meals); }
|
||||
.widget--notes { --widget-accent: var(--module-notes); }
|
||||
.widget--budget { --widget-accent: var(--module-budget); }
|
||||
.widget--contacts { --widget-accent: var(--module-contacts); }
|
||||
.widget--weather { --widget-accent: var(--module-dashboard); }
|
||||
|
||||
/* --------------------------------------------------------
|
||||
* Basis-Widget (Card)
|
||||
*
|
||||
@@ -209,12 +222,12 @@
|
||||
.widget__title-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-accent);
|
||||
color: var(--widget-accent, var(--color-accent));
|
||||
}
|
||||
|
||||
.widget__link {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-accent);
|
||||
color: var(--widget-accent, var(--color-accent));
|
||||
font-weight: var(--font-weight-medium);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -230,7 +243,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--color-accent);
|
||||
background-color: var(--widget-accent, var(--color-accent));
|
||||
color: var(--color-text-on-accent);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--font-weight-bold);
|
||||
@@ -260,17 +273,17 @@
|
||||
.widget__empty .empty-state__icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: var(--color-text-disabled);
|
||||
color: var(--color-text-tertiary);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
/* Widget hover lift (desktop) - dezent, max 1px */
|
||||
/* Widget hover lift (desktop) */
|
||||
@media (min-width: 1024px) {
|
||||
.widget {
|
||||
transition: transform var(--transition-fast), box-shadow var(--transition-fast);
|
||||
}
|
||||
.widget:hover {
|
||||
transform: translateY(-1px);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
}
|
||||
@@ -470,6 +483,12 @@
|
||||
border-bottom-right-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
/* Meal-Typ-Farben aus tokens.css */
|
||||
.meal-slot[data-type="breakfast"] { --slot-color: var(--meal-breakfast); }
|
||||
.meal-slot[data-type="lunch"] { --slot-color: var(--meal-lunch); }
|
||||
.meal-slot[data-type="dinner"] { --slot-color: var(--meal-dinner); }
|
||||
.meal-slot[data-type="snack"] { --slot-color: var(--meal-snack); }
|
||||
|
||||
.meal-slot__icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
@@ -478,7 +497,7 @@
|
||||
}
|
||||
|
||||
.meal-slot--filled .meal-slot__icon {
|
||||
color: var(--color-accent);
|
||||
color: var(--slot-color, var(--color-accent));
|
||||
}
|
||||
|
||||
.meal-slot__type {
|
||||
@@ -490,7 +509,7 @@
|
||||
}
|
||||
|
||||
.meal-slot--filled .meal-slot__type {
|
||||
color: var(--color-text-secondary);
|
||||
color: var(--slot-color, var(--color-text-secondary));
|
||||
}
|
||||
|
||||
.meal-slot__title {
|
||||
@@ -571,7 +590,7 @@
|
||||
}
|
||||
|
||||
.shopping-widget-list__progress {
|
||||
height: 4px;
|
||||
height: 6px;
|
||||
background-color: var(--color-surface-3);
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
@@ -649,7 +668,7 @@
|
||||
cursor: pointer;
|
||||
transition: opacity var(--transition-fast), transform var(--transition-fast);
|
||||
border-left: 3px solid var(--note-color, var(--color-accent));
|
||||
background-color: var(--color-surface-2);
|
||||
background-color: color-mix(in srgb, var(--note-color, var(--color-accent)) 6%, var(--color-surface-2));
|
||||
}
|
||||
|
||||
.note-item:hover {
|
||||
|
||||
@@ -408,6 +408,15 @@
|
||||
color: var(--active-module-accent, var(--color-accent));
|
||||
}
|
||||
|
||||
/* Pill-Hintergrund hinter dem Icon (nur Bottom-Nav, nicht Sidebar) */
|
||||
.nav-bottom .nav-item[aria-current="page"] .nav-item__icon-wrap {
|
||||
background-color: color-mix(in srgb, var(--active-module-accent, var(--color-accent)) 14%, transparent);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-1) var(--space-4);
|
||||
margin-bottom: 1px;
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.nav-item__icon {
|
||||
width: var(--space-5);
|
||||
height: var(--space-5);
|
||||
@@ -776,7 +785,7 @@
|
||||
}
|
||||
|
||||
.card--interactive:hover {
|
||||
transform: translateY(-1px);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user