Merge pull request #1 from ulsklyc/redesign/frontend-v2

design: Frontend-Redesign v2
This commit is contained in:
ulsklyc
2026-03-25 23:51:32 +01:00
committed by GitHub
16 changed files with 1206 additions and 509 deletions
+10 -11
View File
@@ -85,7 +85,7 @@ function widgetHeader(icon, title, count, linkHref, linkLabel = 'Alle') {
${badge}
</span>
<a href="${linkHref}" data-route="${linkHref}" class="widget__link">
${linkLabel} <i data-lucide="chevron-right" style="width:12px;height:12px;vertical-align:-2px;"></i>
${linkLabel}
</a>
</div>
`;
@@ -97,13 +97,11 @@ function widgetHeader(icon, title, count, linkHref, linkLabel = 'Alle') {
function skeletonWidget(lines = 3) {
const lineHtml = Array.from({ length: lines }, (_, i) => `
<div class="skeleton skeleton-line ${i % 2 === 0 ? 'skeleton-line--full' : 'skeleton-line--medium'}"
style="margin-bottom:var(--space-2)"></div>
<div class="skeleton skeleton-line ${i % 2 === 0 ? 'skeleton-line--full' : 'skeleton-line--medium'}"></div>
`).join('');
return `
<div class="widget-skeleton">
<div class="skeleton skeleton-line skeleton-line--short"
style="height:16px;margin-bottom:var(--space-4)"></div>
<div class="skeleton skeleton-line skeleton-line--short"></div>
${lineHtml}
</div>
`;
@@ -116,20 +114,21 @@ 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(`<span class="greeting-chip greeting-chip--warn">
<i data-lucide="alert-circle" style="width:12px;height:12px;"></i>
<i data-lucide="alert-circle" style="${chipIcon}"></i>
${urgentCount} dring. Aufgabe${urgentCount > 1 ? 'n' : ''}
</span>`);
if (todayEventCount > 0)
statChips.push(`<span class="greeting-chip">
<i data-lucide="calendar" style="width:12px;height:12px;"></i>
<i data-lucide="calendar" style="${chipIcon}"></i>
${todayEventCount} Termin${todayEventCount > 1 ? 'e' : ''} heute
</span>`);
if (todayMealTitle)
statChips.push(`<span class="greeting-chip">
<i data-lucide="utensils" style="width:12px;height:12px;"></i>
<i data-lucide="utensils" style="${chipIcon}"></i>
Heute: ${todayMealTitle}
</span>`);
@@ -149,7 +148,7 @@ function renderUrgentTasks(tasks) {
return `<div class="widget">
${widgetHeader('check-square', 'Aufgaben', 0, '/tasks')}
<div class="widget__empty">
<i data-lucide="check-circle" style="width:32px;height:32px;color:var(--color-success);margin-bottom:var(--space-2);"></i>
<i data-lucide="check-circle" class="empty-state__icon" style="color:var(--color-success)"></i>
<div>Alles erledigt</div>
</div>
</div>`;
@@ -182,7 +181,7 @@ function renderUpcomingEvents(events) {
return `<div class="widget">
${widgetHeader('calendar', 'Termine', 0, '/calendar')}
<div class="widget__empty">
<i data-lucide="calendar-check" style="width:32px;height:32px;color:var(--color-text-disabled);margin-bottom:var(--space-2);"></i>
<i data-lucide="calendar-check" class="empty-state__icon"></i>
<div>Keine Termine</div>
</div>
</div>`;
@@ -239,7 +238,7 @@ function renderPinnedNotes(notes) {
return `<div class="widget">
${widgetHeader('pin', 'Pinnwand', 0, '/notes')}
<div class="widget__empty">
<i data-lucide="sticky-note" style="width:32px;height:32px;color:var(--color-text-disabled);margin-bottom:var(--space-2);"></i>
<i data-lucide="sticky-note" class="empty-state__icon"></i>
<div>Keine angepinnten Notizen</div>
</div>
</div>`;
+13 -2
View File
@@ -116,12 +116,20 @@ async function renderPage(route) {
renderAppShell(app);
}
const content = document.getElementById('page-content') || app;
// Alte Seite kurz ausfaden, falls vorhanden
const oldPage = content.querySelector('.page-transition');
if (oldPage) {
oldPage.classList.add('page-transition--out');
await new Promise(r => setTimeout(r, 120));
}
// Seiten-Wrapper bereits jetzt in den DOM einfügen, damit
// document.getElementById() in render() die richtigen Elemente findet.
const pageWrapper = document.createElement('div');
pageWrapper.className = 'page-transition';
pageWrapper.style.animation = 'page-in 0.2s ease forwards';
const content = document.getElementById('page-content') || app;
content.replaceChildren(pageWrapper);
await module.render(pageWrapper, { user: currentUser });
@@ -236,7 +244,10 @@ function showToast(message, type = 'default', duration = 3000) {
toast.setAttribute('role', 'alert');
container.appendChild(toast);
setTimeout(() => toast.remove(), duration);
setTimeout(() => {
toast.classList.add('toast--out');
toast.addEventListener('animationend', () => toast.remove(), { once: true });
}, duration);
}
// --------------------------------------------------------
+13 -6
View File
@@ -56,10 +56,17 @@
* -------------------------------------------------------- */
.budget-summary {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
flex-shrink: 0;
}
@media (min-width: 480px) {
.budget-summary {
grid-template-columns: repeat(3, 1fr);
gap: var(--space-3);
padding: var(--space-4);
flex-shrink: 0;
}
}
.budget-summary-card {
@@ -191,8 +198,8 @@
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border);
padding: var(--space-2) var(--space-4);
border-bottom: 1px solid var(--color-border-subtle);
cursor: pointer;
transition: background-color var(--transition-fast);
}
@@ -283,7 +290,7 @@
.budget-modal-overlay {
position: fixed;
inset: 0;
background-color: rgba(0,0,0,0.5);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
@@ -366,7 +373,7 @@
.amount-type-btn {
padding: var(--space-2) var(--space-3);
border-radius: 6px;
border-radius: var(--radius-xs);
border: none;
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
+22 -18
View File
@@ -73,7 +73,7 @@
font-size: var(--text-xs);
font-weight: var(--font-weight-medium);
padding: var(--space-1) var(--space-2);
border-radius: 6px;
border-radius: var(--radius-xs);
border: none;
background: none;
color: var(--color-text-secondary);
@@ -83,6 +83,10 @@
white-space: nowrap;
}
.cal-toolbar__view-btn:hover:not(.cal-toolbar__view-btn--active) {
color: var(--color-text-primary);
}
.cal-toolbar__view-btn--active {
background-color: var(--color-surface);
color: var(--color-text-primary);
@@ -125,8 +129,8 @@
}
.month-day {
border-right: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border);
border-right: 1px solid var(--color-border-subtle);
border-bottom: 1px solid var(--color-border-subtle);
padding: var(--space-1);
min-height: 80px;
cursor: pointer;
@@ -171,10 +175,10 @@
}
.month-day__event {
font-size: 11px;
font-size: var(--text-xs);
font-weight: var(--font-weight-medium);
padding: 1px 5px;
border-radius: 3px;
border-radius: var(--radius-xs);
margin-bottom: 2px;
white-space: nowrap;
overflow: hidden;
@@ -185,7 +189,7 @@
}
.month-day__more {
font-size: 11px;
font-size: var(--text-xs);
color: var(--color-text-secondary);
padding: 1px 4px;
cursor: pointer;
@@ -215,7 +219,7 @@
.week-view__day-header {
padding: var(--space-2) var(--space-1);
text-align: center;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--color-border-subtle);
}
.week-view__day-name {
@@ -273,7 +277,7 @@
}
.week-view__time-label {
font-size: 10px;
font-size: var(--text-xs);
color: var(--color-text-disabled);
white-space: nowrap;
}
@@ -285,7 +289,7 @@
}
.week-view__col {
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--color-border-subtle);
position: relative;
}
@@ -294,7 +298,7 @@
left: 0;
right: 0;
height: 1px;
background-color: var(--color-border);
background-color: var(--color-border-subtle);
pointer-events: none;
}
@@ -323,9 +327,9 @@
position: absolute;
left: 2px;
right: 2px;
border-radius: 4px;
border-radius: var(--radius-xs);
padding: 2px 5px;
font-size: 11px;
font-size: var(--text-xs);
font-weight: var(--font-weight-medium);
color: #ffffff;
overflow: hidden;
@@ -346,7 +350,7 @@
}
.week-event__time {
font-size: 10px;
font-size: var(--text-xs);
opacity: 0.85;
}
@@ -391,7 +395,7 @@
.day-view__col {
flex: 1;
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--color-border-subtle);
position: relative;
}
@@ -514,7 +518,7 @@
.event-modal-overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
@@ -700,15 +704,15 @@
}
.allday-cell {
border-left: 1px solid var(--color-border);
border-left: 1px solid var(--color-border-subtle);
padding: 2px;
}
.allday-event {
font-size: 11px;
font-size: var(--text-xs);
font-weight: var(--font-weight-medium);
padding: 1px 6px;
border-radius: 3px;
border-radius: var(--radius-xs);
color: #ffffff;
white-space: nowrap;
overflow: hidden;
+7 -2
View File
@@ -98,6 +98,11 @@
min-height: 30px;
}
.contact-filter-chip:hover:not(.contact-filter-chip--active) {
border-color: var(--color-text-secondary);
color: var(--color-text-primary);
}
.contact-filter-chip--active {
background-color: var(--color-accent);
border-color: var(--color-accent);
@@ -136,7 +141,7 @@
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border-subtle);
cursor: pointer;
transition: background-color var(--transition-fast);
}
@@ -231,7 +236,7 @@
.contact-modal-overlay {
position: fixed;
inset: 0;
background-color: rgba(0,0,0,0.5);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
+157 -130
View File
@@ -16,13 +16,24 @@
@media (min-width: 1024px) {
.dashboard {
padding: var(--space-8);
padding-bottom: var(--space-16);
padding: var(--space-6) var(--space-8);
padding-bottom: var(--space-12);
}
}
@media (min-width: 1440px) {
.dashboard {
padding: var(--space-6) var(--space-10);
}
}
/* --------------------------------------------------------
* Widget-Grid
*
* Mobile: 1 Spalte
* Tablet: 2 Spalten
* Desktop: 3 Spalten
* Wide: 4 Spalten (ab 1440px)
* -------------------------------------------------------- */
.dashboard__grid {
display: grid;
@@ -43,6 +54,7 @@
@media (min-width: 1024px) {
.dashboard__grid {
grid-template-columns: repeat(3, 1fr);
gap: var(--space-5);
}
.widget--wide {
@@ -50,13 +62,29 @@
}
}
@media (min-width: 1440px) {
.dashboard__grid {
grid-template-columns: repeat(4, 1fr);
}
/* Wide-Widgets nehmen 2 von 4 Spalten ein */
.widget--wide {
grid-column: span 2;
}
/* Greeting-Widget über alle 4 Spalten */
.widget-greeting {
grid-column: 1 / -1;
}
}
/* --------------------------------------------------------
* Begrüßungs-Widget
* -------------------------------------------------------- */
.widget-greeting {
background: linear-gradient(135deg, var(--color-accent) 0%, #5B9FFF 100%);
background: linear-gradient(135deg, var(--color-accent) 0%, #6BA3FF 100%);
border-radius: var(--radius-md);
padding: var(--space-5) var(--space-6);
padding: var(--space-4) var(--space-5);
color: #ffffff;
grid-column: 1 / -1;
}
@@ -64,16 +92,22 @@
.widget-greeting__content {
display: flex;
flex-direction: column;
gap: var(--space-1);
gap: 2px;
}
.widget-greeting__title {
font-size: var(--text-2xl);
font-size: var(--text-xl);
font-weight: var(--font-weight-bold);
}
@media (min-width: 1024px) {
.widget-greeting__title {
font-size: var(--text-2xl);
}
}
.widget-greeting__date {
font-size: var(--text-base);
font-size: var(--text-sm);
opacity: 0.85;
}
@@ -81,20 +115,19 @@
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
margin-top: var(--space-3);
margin-top: var(--space-2);
}
.greeting-chip {
display: inline-flex;
align-items: center;
gap: 4px;
background: rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.18);
color: #ffffff;
font-size: var(--text-xs);
font-weight: var(--font-weight-medium);
padding: 3px var(--space-2);
padding: 2px var(--space-2);
border-radius: var(--radius-full);
backdrop-filter: blur(4px);
}
.greeting-chip--warn {
@@ -103,6 +136,9 @@
/* --------------------------------------------------------
* Basis-Widget (Card)
*
* Kompaktes Padding: 12px Header, 12px Body.
* Internes Spacing: 812px (enger als vorher 1624px).
* -------------------------------------------------------- */
.widget {
background-color: var(--color-surface);
@@ -117,12 +153,11 @@
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-4) var(--space-4) var(--space-3);
border-bottom: 1px solid var(--color-border);
padding: var(--space-3) var(--space-4) var(--space-2);
}
.widget__title {
font-size: var(--text-base);
font-size: var(--text-sm);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
display: flex;
@@ -131,18 +166,23 @@
}
.widget__title-icon {
width: 18px;
height: 18px;
width: 16px;
height: 16px;
color: var(--color-accent);
}
.widget__link {
font-size: var(--text-sm);
font-size: var(--text-xs);
color: var(--color-accent);
font-weight: var(--font-weight-medium);
display: inline-flex;
align-items: center;
gap: 2px;
transition: opacity var(--transition-fast);
}
.widget__link:hover {
opacity: 0.7;
}
.widget__badge {
@@ -151,10 +191,10 @@
justify-content: center;
background-color: var(--color-accent);
color: #ffffff;
font-size: 10px;
font-size: var(--text-2xs);
font-weight: var(--font-weight-bold);
min-width: 18px;
height: 18px;
min-width: 16px;
height: 16px;
padding: 0 4px;
border-radius: var(--radius-full);
line-height: 1;
@@ -162,40 +202,48 @@
.widget__body {
flex: 1;
padding: var(--space-3) var(--space-4);
padding: var(--space-2) var(--space-4) var(--space-3);
}
.widget__empty {
padding: var(--space-6) var(--space-4);
padding: var(--space-5) var(--space-4);
text-align: center;
color: var(--color-text-secondary);
color: var(--color-text-tertiary);
font-size: var(--text-sm);
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-2);
gap: var(--space-1);
}
/* Widget hover lift (desktop) */
.widget__empty .empty-state__icon {
width: 28px;
height: 28px;
color: var(--color-text-disabled);
margin-bottom: var(--space-1);
}
/* Widget hover lift (desktop) — dezent, max 1px */
@media (min-width: 1024px) {
.widget {
transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.widget:hover {
transform: translateY(-2px);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
}
/* --------------------------------------------------------
* Aufgaben-Widget
* Kompakte Items: 8px vertikales Padding, enger Spacing.
* -------------------------------------------------------- */
.task-item {
display: flex;
align-items: flex-start;
gap: var(--space-3);
padding: var(--space-3) 0;
border-bottom: 1px solid var(--color-border);
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--color-border-subtle);
cursor: pointer;
transition: opacity var(--transition-fast);
}
@@ -205,19 +253,21 @@
}
.task-item:hover {
opacity: 0.75;
opacity: 0.7;
}
.task-item__priority {
width: 8px;
height: 8px;
width: 7px;
height: 7px;
border-radius: var(--radius-full);
flex-shrink: 0;
margin-top: 6px;
margin-top: 5px;
}
.task-item__priority--urgent { background-color: var(--color-priority-urgent); }
.task-item__priority--high { background-color: var(--color-priority-high); }
.task-item__priority--medium { background-color: var(--color-priority-medium); }
.task-item__priority--low { background-color: var(--color-priority-low); }
.task-item__content {
flex: 1;
@@ -231,12 +281,13 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: var(--line-height-snug);
}
.task-item__meta {
font-size: var(--text-xs);
color: var(--color-text-secondary);
margin-top: 2px;
color: var(--color-text-tertiary);
margin-top: 1px;
}
.task-item__meta--overdue {
@@ -245,27 +296,29 @@
}
.task-item__avatar {
width: 24px;
height: 24px;
width: 22px;
height: 22px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-size: 9px;
font-weight: var(--font-weight-bold);
color: #ffffff;
flex-shrink: 0;
margin-top: 1px;
}
/* --------------------------------------------------------
* Termine-Widget
* Kompakt: Farbbalken + Inhalt, enge Abstände.
* -------------------------------------------------------- */
.event-item {
display: flex;
align-items: stretch;
gap: var(--space-3);
padding: var(--space-3) 0;
border-bottom: 1px solid var(--color-border);
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--color-border-subtle);
cursor: pointer;
transition: opacity var(--transition-fast);
}
@@ -275,7 +328,7 @@
}
.event-item:hover {
opacity: 0.75;
opacity: 0.7;
}
.event-item__bar {
@@ -297,23 +350,24 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: var(--line-height-snug);
}
.event-item__time {
font-size: var(--text-xs);
color: var(--color-text-secondary);
margin-top: 2px;
color: var(--color-text-tertiary);
margin-top: 1px;
display: flex;
align-items: center;
gap: var(--space-1);
}
.event-time-badge {
font-size: 10px;
font-size: var(--text-2xs);
font-weight: var(--font-weight-semibold);
padding: 1px 5px;
border-radius: var(--radius-full);
background-color: var(--color-surface-2);
background-color: var(--color-surface-3);
color: var(--color-text-secondary);
}
@@ -341,13 +395,13 @@
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-1);
padding: var(--space-3) var(--space-2);
gap: 2px;
padding: var(--space-2) var(--space-1);
background-color: var(--color-surface);
cursor: pointer;
transition: background-color var(--transition-fast);
text-align: center;
min-height: 88px;
min-height: 72px;
}
.meal-slot:hover {
@@ -363,8 +417,8 @@
}
.meal-slot__icon {
width: 20px;
height: 20px;
width: 18px;
height: 18px;
color: var(--color-text-disabled);
flex-shrink: 0;
}
@@ -374,7 +428,7 @@
}
.meal-slot__type {
font-size: 10px;
font-size: var(--text-2xs);
font-weight: var(--font-weight-semibold);
color: var(--color-text-disabled);
text-transform: uppercase;
@@ -430,50 +484,6 @@
transform: translateY(-1px);
}
/* legacy (old .note-item had margin-bottom, now grid handles gap) */
/* --------------------------------------------------------
* Alte Essen-Listen-Styles (Fallback, nicht mehr primär)
* -------------------------------------------------------- */
.meal-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) 0;
border-bottom: 1px solid var(--color-border);
cursor: pointer;
transition: opacity var(--transition-fast);
}
.meal-item:last-child {
border-bottom: none;
}
.meal-item:hover {
opacity: 0.75;
}
.meal-item__type-badge {
font-size: var(--text-xs);
font-weight: var(--font-weight-semibold);
padding: 2px var(--space-2);
border-radius: var(--radius-xs);
background-color: var(--color-accent-light);
color: var(--color-accent);
white-space: nowrap;
flex-shrink: 0;
min-width: 72px;
text-align: center;
}
.meal-item__title {
font-size: var(--text-sm);
color: var(--color-text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.note-item__title {
font-size: var(--text-sm);
font-weight: var(--font-weight-semibold);
@@ -495,9 +505,12 @@
/* --------------------------------------------------------
* Wetter-Widget
*
* Eigener Gradient, überschreibt .widget Hintergrund.
* Kompakt: Icon kleiner, Forecast enger.
* -------------------------------------------------------- */
.weather-widget {
background: linear-gradient(135deg, #1a73e8 0%, #0f4fa8 100%);
background: linear-gradient(135deg, var(--color-accent) 0%, #1E5CB3 100%);
color: #ffffff;
}
@@ -505,47 +518,47 @@
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-4) var(--space-5);
padding: var(--space-3) var(--space-4);
}
.weather-widget__temp {
font-size: var(--text-4xl, 2.25rem);
font-size: var(--text-4xl);
font-weight: var(--font-weight-bold);
line-height: 1;
margin-bottom: var(--space-1);
}
.weather-widget__desc {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
text-transform: capitalize;
margin-bottom: 2px;
}
.weather-widget__city {
.weather-widget__desc {
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
text-transform: capitalize;
margin-bottom: 1px;
}
.weather-widget__city {
font-size: var(--text-xs);
opacity: 0.85;
margin-bottom: var(--space-2);
margin-bottom: var(--space-1);
}
.weather-widget__meta {
font-size: var(--text-xs);
opacity: 0.75;
line-height: 1.4;
opacity: 0.7;
line-height: 1.3;
}
.weather-widget__icon {
width: 80px;
height: 80px;
width: 64px;
height: 64px;
flex-shrink: 0;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
}
.weather-forecast {
display: flex;
border-top: 1px solid rgba(255,255,255,0.2);
padding: var(--space-3) var(--space-5);
gap: var(--space-4);
border-top: 1px solid rgba(255, 255, 255, 0.15);
padding: var(--space-2) var(--space-4);
gap: var(--space-3);
}
.weather-forecast__day {
@@ -564,13 +577,13 @@
}
.weather-forecast__icon {
width: 32px;
height: 32px;
width: 28px;
height: 28px;
}
.weather-forecast__temps {
display: flex;
gap: var(--space-2);
gap: var(--space-1);
font-size: var(--text-xs);
}
@@ -579,27 +592,28 @@
}
.weather-forecast__low {
opacity: 0.65;
opacity: 0.6;
}
/* --------------------------------------------------------
* Skeleton-Zustände (pro Widget)
* Kompakt: gleiches Spacing wie echte Widgets.
* -------------------------------------------------------- */
.widget-skeleton {
background-color: var(--color-surface);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
padding: var(--space-4);
padding: var(--space-3) var(--space-4);
}
.skeleton-line {
height: 14px;
height: 12px;
margin-bottom: var(--space-2);
border-radius: var(--radius-xs);
}
.skeleton-line--short { width: 40%; }
.skeleton-line--medium { width: 65%; }
.skeleton-line--short { width: 35%; }
.skeleton-line--medium { width: 60%; }
.skeleton-line--full { width: 100%; }
/* --------------------------------------------------------
@@ -623,8 +637,8 @@
}
.fab-main {
width: 56px;
height: 56px;
width: 52px;
height: 52px;
border-radius: var(--radius-full);
background-color: var(--color-accent);
color: #ffffff;
@@ -633,18 +647,31 @@
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform var(--transition-base), background-color var(--transition-fast);
transition:
transform var(--transition-base),
background-color var(--transition-fast);
border: none;
flex-shrink: 0;
}
@media (min-width: 1024px) {
.fab-main {
width: 48px;
height: 48px;
}
}
.fab-main:hover {
background-color: var(--color-accent-hover);
}
.fab-main:active {
transform: scale(0.95);
}
.fab-main--open {
transform: rotate(45deg);
background-color: var(--color-text-secondary);
background-color: var(--neutral-600);
}
.fab-actions {
@@ -683,8 +710,8 @@
}
.fab-action__btn {
width: 44px;
height: 44px;
width: 40px;
height: 40px;
border-radius: var(--radius-full);
background-color: var(--color-surface);
color: var(--color-accent);
+574 -114
View File
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -65,7 +65,7 @@
}
.day-column {
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border-subtle);
}
.day-column:last-child {
@@ -103,14 +103,14 @@
.day-slots {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(2, 1fr);
gap: var(--space-2);
padding: 0 var(--space-4) var(--space-4);
padding: 0 var(--space-4) var(--space-3);
}
@media (max-width: 600px) {
@media (min-width: 600px) {
.day-slots {
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(4, 1fr);
}
}
@@ -118,7 +118,7 @@
* Mahlzeit-Slot
* -------------------------------------------------------- */
.meal-slot {
min-height: 80px;
min-height: 72px;
border-radius: var(--radius-sm);
border: 1.5px dashed var(--color-border);
background-color: var(--color-surface);
@@ -142,11 +142,11 @@
padding: var(--space-1) var(--space-2) 0;
}
/* Slot-Typ-Farben */
.meal-slot[data-type="breakfast"] .meal-slot__type-label { color: #FF9500; }
.meal-slot[data-type="lunch"] .meal-slot__type-label { color: #34C759; }
.meal-slot[data-type="dinner"] .meal-slot__type-label { color: #007AFF; }
.meal-slot[data-type="snack"] .meal-slot__type-label { color: #FF6B35; }
/* Slot-Typ-Farben — zentrale Tokens aus tokens.css */
.meal-slot[data-type="breakfast"] .meal-slot__type-label { color: var(--meal-breakfast); }
.meal-slot[data-type="lunch"] .meal-slot__type-label { color: var(--meal-lunch); }
.meal-slot[data-type="dinner"] .meal-slot__type-label { color: var(--meal-dinner); }
.meal-slot[data-type="snack"] .meal-slot__type-label { color: var(--meal-snack); }
.meal-slot__add-btn {
flex: 1;
@@ -236,7 +236,7 @@
.meal-card__action-btn:hover {
color: var(--color-danger);
background-color: var(--color-surface-2, rgba(0,0,0,0.04));
background-color: var(--color-surface-2);
}
.meal-card__action-btn--shopping:hover {
@@ -249,7 +249,7 @@
.meal-modal-overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
@@ -483,10 +483,10 @@
border-radius: var(--radius-full);
}
.meal-type-badge--breakfast { background: #FFF3E0; color: #FF9500; }
.meal-type-badge--lunch { background: #E8F5E9; color: #2E7D32; }
.meal-type-badge--dinner { background: #E3F2FF; color: #007AFF; }
.meal-type-badge--snack { background: #FBE9E7; color: #FF6B35; }
.meal-type-badge--breakfast { background: var(--meal-breakfast-light); color: var(--meal-breakfast); }
.meal-type-badge--lunch { background: var(--meal-lunch-light); color: var(--meal-lunch); }
.meal-type-badge--dinner { background: var(--meal-dinner-light); color: var(--meal-dinner); }
.meal-type-badge--snack { background: var(--meal-snack-light); color: var(--meal-snack); }
/* --------------------------------------------------------
* Leer-Zustand
+14 -14
View File
@@ -77,12 +77,12 @@
}
.note-card:hover {
transform: translateY(-2px);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.note-card--pinned {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
box-shadow: var(--shadow-md);
}
.note-card__pin {
@@ -92,7 +92,7 @@
width: 24px;
height: 24px;
border-radius: var(--radius-full);
background: rgba(0,0,0,0.1);
background: var(--color-overlay-light);
border: none;
cursor: pointer;
display: flex;
@@ -101,12 +101,12 @@
min-height: unset;
opacity: 0;
transition: opacity var(--transition-fast), background-color var(--transition-fast);
color: rgba(0,0,0,0.6);
color: var(--color-text-primary);
}
.note-card--pinned .note-card__pin {
opacity: 1;
background: rgba(0,0,0,0.15);
background: var(--color-overlay-light);
}
.note-card:hover .note-card__pin {
@@ -114,21 +114,21 @@
}
.note-card__pin:hover {
background: rgba(0,0,0,0.2);
background: var(--color-overlay);
}
.note-card__title {
font-size: var(--text-sm);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-1);
color: rgba(0,0,0,0.8);
color: var(--color-text-primary);
padding-right: var(--space-6);
}
.note-card__content {
font-size: var(--text-sm);
line-height: var(--line-height-relaxed);
color: rgba(0,0,0,0.75);
color: var(--color-text-secondary);
word-break: break-word;
white-space: pre-wrap;
}
@@ -143,7 +143,7 @@
justify-content: space-between;
margin-top: var(--space-2);
padding-top: var(--space-2);
border-top: 1px solid rgba(0,0,0,0.08);
border-top: 1px solid var(--color-border-subtle);
}
.note-card__creator {
@@ -151,7 +151,7 @@
align-items: center;
gap: var(--space-1);
font-size: var(--text-xs);
color: rgba(0,0,0,0.5);
color: var(--color-text-tertiary);
}
.note-card__avatar {
@@ -171,14 +171,14 @@
width: 24px;
height: 24px;
border-radius: var(--radius-full);
background: rgba(0,0,0,0.08);
background: var(--color-overlay-light);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
min-height: unset;
color: rgba(0,0,0,0.5);
color: var(--color-text-tertiary);
opacity: 0;
transition: opacity var(--transition-fast), background-color var(--transition-fast);
}
@@ -188,7 +188,7 @@
}
.note-card__delete:hover {
background: rgba(255,59,48,0.2);
background: var(--color-danger-light);
color: var(--color-danger);
}
@@ -219,7 +219,7 @@
.note-modal-overlay {
position: fixed;
inset: 0;
background-color: rgba(0,0,0,0.5);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
+12
View File
@@ -19,6 +19,8 @@ html {
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
@@ -69,6 +71,16 @@ button, [role="button"], input[type="checkbox"], input[type="radio"] {
border-radius: var(--radius-xs);
}
/* Reduzierte Bewegung (Barrierefreiheit) */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Versteckte, aber zugängliche Elemente */
.sr-only {
position: absolute;
+63 -68
View File
@@ -1,11 +1,11 @@
/**
* Modul: Einstellungen (Settings)
* Zweck: Styles für die Settings-Seite
* Abhängigkeiten: tokens.css
* Abhängigkeiten: tokens.css, layout.css
*/
/* --------------------------------------------------------
Seiten-Layout
Seiten-Layout — nutzt layout-center (max 720px)
-------------------------------------------------------- */
.settings-page {
@@ -18,23 +18,23 @@
-------------------------------------------------------- */
.settings-banner {
padding: 12px 16px;
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-sm);
margin-bottom: 16px;
font-size: 14px;
font-weight: 500;
margin-bottom: var(--space-4);
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
}
.settings-banner--success {
background: rgba(52, 199, 89, 0.12);
background: var(--color-success-light);
color: var(--color-success);
border: 1px solid rgba(52, 199, 89, 0.3);
border: 1px solid var(--color-success);
}
.settings-banner--error {
background: rgba(255, 59, 48, 0.1);
background: var(--color-danger-light);
color: var(--color-danger);
border: 1px solid rgba(255, 59, 48, 0.25);
border: 1px solid var(--color-danger);
}
/* --------------------------------------------------------
@@ -42,16 +42,16 @@
-------------------------------------------------------- */
.settings-section {
margin-bottom: 32px;
margin-bottom: var(--space-8);
}
.settings-section__title {
font-size: 13px;
font-weight: 600;
font-size: var(--text-xs);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-secondary);
margin: 0 0 10px 4px;
letter-spacing: 0.05em;
color: var(--color-text-tertiary);
margin: 0 0 var(--space-2) var(--space-1);
}
/* --------------------------------------------------------
@@ -62,8 +62,14 @@
background: var(--color-surface);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
padding: 20px;
margin-bottom: 12px;
padding: var(--space-4);
margin-bottom: var(--space-3);
}
@media (min-width: 1024px) {
.settings-card {
padding: var(--space-5);
}
}
.settings-card--hidden {
@@ -71,9 +77,9 @@
}
.settings-card__title {
font-size: 15px;
font-weight: 600;
margin: 0 0 16px;
font-size: var(--text-base);
font-weight: var(--font-weight-semibold);
margin: 0 0 var(--space-3);
color: var(--color-text-primary);
}
@@ -84,17 +90,17 @@
.settings-user-info {
display: flex;
align-items: center;
gap: 16px;
gap: var(--space-3);
}
.settings-user-info__name {
font-size: 17px;
font-weight: 600;
font-size: var(--text-md);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
}
.settings-user-info__username {
font-size: 13px;
font-size: var(--text-sm);
color: var(--color-text-secondary);
margin-top: 2px;
}
@@ -104,23 +110,23 @@
-------------------------------------------------------- */
.settings-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
width: 44px;
height: 44px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 700;
font-size: var(--text-lg);
font-weight: var(--font-weight-bold);
color: #fff;
flex-shrink: 0;
user-select: none;
}
.settings-avatar--sm {
width: 36px;
height: 36px;
font-size: 13px;
width: 32px;
height: 32px;
font-size: var(--text-sm);
}
/* --------------------------------------------------------
@@ -130,30 +136,30 @@
.settings-form {
display: flex;
flex-direction: column;
gap: 14px;
gap: var(--space-3);
}
.settings-form-actions {
display: flex;
gap: 10px;
gap: var(--space-2);
flex-wrap: wrap;
}
.form-error {
font-size: 13px;
font-size: var(--text-sm);
color: var(--color-danger);
padding: 8px 12px;
background: rgba(255, 59, 48, 0.08);
padding: var(--space-2) var(--space-3);
background: var(--color-danger-light);
border-radius: var(--radius-sm);
}
.form-hint {
font-size: 13px;
font-size: var(--text-sm);
color: var(--color-text-secondary);
}
.form-input--color {
padding: 4px 8px;
padding: var(--space-1) var(--space-2);
height: 44px;
cursor: pointer;
}
@@ -165,13 +171,13 @@
.settings-sync-header {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 14px;
gap: var(--space-3);
margin-bottom: var(--space-3);
}
.settings-sync-logo {
width: 40px;
height: 40px;
width: 36px;
height: 36px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
@@ -180,23 +186,23 @@
}
.settings-sync-logo--google {
background: #f8f9fa;
background: var(--color-surface-2);
border: 1px solid var(--color-border);
}
.settings-sync-logo--apple {
background: #1c1c1e;
color: #fff;
background: var(--neutral-900);
color: var(--neutral-50);
}
.settings-sync-info__name {
font-size: 15px;
font-weight: 600;
font-size: var(--text-base);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
}
.settings-sync-info__status {
font-size: 13px;
font-size: var(--text-sm);
color: var(--color-text-secondary);
margin-top: 2px;
}
@@ -207,7 +213,7 @@
.settings-sync-actions {
display: flex;
gap: 10px;
gap: var(--space-2);
flex-wrap: wrap;
}
@@ -217,17 +223,17 @@
.settings-members {
list-style: none;
margin: 0 0 16px;
margin: 0 0 var(--space-4);
padding: 0;
display: flex;
flex-direction: column;
gap: 10px;
gap: var(--space-3);
}
.settings-member {
display: flex;
align-items: center;
gap: 12px;
gap: var(--space-3);
}
.settings-member__info {
@@ -237,8 +243,8 @@
.settings-member__name {
display: block;
font-size: 15px;
font-weight: 500;
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
color: var(--color-text-primary);
white-space: nowrap;
overflow: hidden;
@@ -247,7 +253,7 @@
.settings-member__meta {
display: block;
font-size: 12px;
font-size: var(--text-xs);
color: var(--color-text-secondary);
margin-top: 1px;
}
@@ -263,14 +269,3 @@
.settings-logout-btn {
width: 100%;
}
/* --------------------------------------------------------
Dark Mode
-------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
.settings-sync-logo--google {
background: #2c2c2e;
border-color: var(--color-border);
}
}
+20 -6
View File
@@ -55,6 +55,11 @@
min-height: 36px;
}
.list-tab:hover:not(.list-tab--active) {
border-color: var(--color-text-secondary);
color: var(--color-text-primary);
}
.list-tab--active {
background-color: var(--color-accent);
border-color: var(--color-accent);
@@ -149,7 +154,7 @@
.quick-add__input {
width: 100%;
padding: var(--space-3) var(--space-4);
padding-right: 80px;
padding-right: var(--space-20, 80px);
border-radius: var(--radius-sm);
border: 1.5px solid var(--color-border);
background-color: var(--color-surface);
@@ -187,7 +192,9 @@
}
.quick-add__cat {
width: 130px;
width: auto;
min-width: 100px;
max-width: 160px;
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-sm);
border: 1.5px solid var(--color-border);
@@ -274,7 +281,7 @@
text-transform: uppercase;
letter-spacing: 0.06em;
padding: var(--space-2) 0 var(--space-1);
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border-subtle);
margin-bottom: var(--space-1);
display: flex;
align-items: center;
@@ -293,10 +300,10 @@
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-1);
border-bottom: 1px solid var(--color-border);
padding: var(--space-2) var(--space-1);
border-bottom: 1px solid var(--color-border-subtle);
transition: opacity var(--transition-fast);
min-height: 48px;
min-height: 44px;
}
.shopping-item:last-child { border-bottom: none; }
@@ -324,6 +331,13 @@
.item-check--checked {
background-color: var(--color-success);
border-color: var(--color-success);
animation: check-pop 0.2s var(--ease-out);
}
@keyframes check-pop {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.item-check__icon {
+33 -16
View File
@@ -65,6 +65,10 @@
cursor: pointer;
}
.group-toggle__btn:hover:not(.group-toggle__btn--active) {
color: var(--color-text-primary);
}
.group-toggle__btn--active {
background-color: var(--color-surface);
color: var(--color-text-primary);
@@ -103,6 +107,11 @@
min-height: 34px;
}
.filter-chip:hover:not(.filter-chip--active) {
border-color: var(--color-text-secondary);
color: var(--color-text-primary);
}
.filter-chip--active {
background-color: var(--color-accent-light);
border-color: var(--color-accent);
@@ -118,7 +127,7 @@
border-radius: var(--radius-full);
background-color: var(--color-accent);
color: #fff;
font-size: 10px;
font-size: var(--text-2xs);
line-height: 1;
}
@@ -232,13 +241,14 @@
.task-card--done {
opacity: 0.6;
transition: opacity var(--transition-base);
}
.task-card__main {
display: flex;
align-items: flex-start;
gap: var(--space-3);
padding: var(--space-4);
padding: var(--space-3);
}
/* Status-Checkbox */
@@ -261,6 +271,13 @@
.task-status-btn--done {
border-color: var(--color-success);
background-color: var(--color-success);
animation: check-pop 0.2s var(--ease-out);
}
@keyframes check-pop {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.task-status-btn--in_progress {
@@ -312,10 +329,10 @@
border-radius: var(--radius-xs);
}
.priority-badge--low { color: var(--color-priority-low); background-color: #8E8E9322; }
.priority-badge--medium { color: var(--color-priority-medium); background-color: #FF950022; }
.priority-badge--high { color: var(--color-priority-high); background-color: #FF6B3522; }
.priority-badge--urgent { color: var(--color-priority-urgent); background-color: #FF3B3022; }
.priority-badge--low { color: var(--color-priority-low); background-color: var(--color-priority-low-bg); }
.priority-badge--medium { color: var(--color-priority-medium); background-color: var(--color-priority-medium-bg); }
.priority-badge--high { color: var(--color-priority-high); background-color: var(--color-priority-high-bg); }
.priority-badge--urgent { color: var(--color-priority-urgent); background-color: var(--color-priority-urgent-bg); }
.priority-dot {
width: 6px;
@@ -349,7 +366,7 @@
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-size: var(--text-2xs);
font-weight: var(--font-weight-bold);
color: #fff;
flex-shrink: 0;
@@ -357,7 +374,7 @@
/* Subtask-Fortschrittsbalken */
.subtask-progress {
padding: 0 var(--space-4) var(--space-3);
padding: 0 var(--space-3) var(--space-2);
display: flex;
align-items: center;
gap: var(--space-2);
@@ -387,8 +404,8 @@
/* Subtask-Liste (eingeklappt/ausgeklappt) */
.subtask-list {
border-top: 1px solid var(--color-border);
padding: var(--space-2) var(--space-4);
border-top: 1px solid var(--color-border-subtle);
padding: var(--space-2) var(--space-3);
display: none;
}
@@ -399,7 +416,7 @@
align-items: center;
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border-subtle);
}
.subtask-item:last-child { border-bottom: none; }
@@ -461,7 +478,7 @@
.modal-backdrop {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
background-color: var(--color-overlay);
z-index: var(--z-modal);
display: flex;
align-items: flex-end;
@@ -551,7 +568,7 @@
border-radius: var(--radius-full);
background-color: var(--color-danger);
color: #fff;
font-size: 10px;
font-size: var(--text-2xs);
font-weight: var(--font-weight-bold);
margin-left: auto;
}
@@ -561,15 +578,15 @@
* -------------------------------------------------------- */
.kanban-board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: 1fr;
gap: var(--space-3);
align-items: start;
min-height: 60vh;
}
@media (max-width: 640px) {
@media (min-width: 640px) {
.kanban-board {
grid-template-columns: 1fr;
grid-template-columns: repeat(3, 1fr);
}
}
+222 -80
View File
@@ -1,59 +1,147 @@
/**
* Modul: Design Tokens
* Zweck: CSS Custom Properties für das gesamte Design-System
* Zweck: CSS Custom Properties fuer das gesamte Design-System
* Abhängigkeiten: keine
*
* Aufbau:
* 1. Neutral-Farbskala (50950)
* 2. Akzentfarben + Semantische Farben
* 3. Modul-Akzentfarben
* 4. Mahlzeit-Typ-Farben
* 5. Prioritäten
* 6. Overlay / Backdrop
* 7. Schatten
* 8. Border-Radien
* 9. Typografie
* 10. Abstände (4px-Raster)
* 11. Layout
* 12. Sidebar
* 13. Übergänge
* 14. Z-Indizes
* 15. Dark Mode
*/
:root {
/* --------------------------------------------------------
* Farben — Neutrals
* 1. Farben — Neutral-Skala
* Leicht warmgetönt (kein reines Grau) für einladende Atmosphäre.
* Benannt als --neutral-{stufe} für direkte Nutzung,
* plus semantische Aliase (--color-bg, --color-surface etc.)
* die bestehender Code bereits referenziert.
* -------------------------------------------------------- */
--color-bg: #F5F5F7;
--neutral-50: #FAFAF8;
--neutral-100: #F5F4F1;
--neutral-150: #EFEEE9;
--neutral-200: #E8E7E2;
--neutral-250: #DDDCD7;
--neutral-300: #D1D0CB;
--neutral-400: #B5B4AF;
--neutral-500: #8E8D89;
--neutral-600: #6C6B67;
--neutral-700: #4A4A46;
--neutral-800: #2E2E2B;
--neutral-900: #1C1C1A;
--neutral-950: #121211;
/* Semantische Aliase (abwärtskompatibel) */
--color-bg: var(--neutral-100);
--color-surface: #FFFFFF;
--color-surface-2: #F0F0F5;
--color-border: #E5E5EA;
--color-text-primary: #1C1C1E;
--color-text-secondary: #6C6C70; /* WCAG AA: ~5.2:1 auf weißem Hintergrund */
--color-text-disabled: #C7C7CC;
--color-surface-2: var(--neutral-50);
--color-surface-3: var(--neutral-150);
--color-border: var(--neutral-200);
--color-border-subtle: var(--neutral-150);
--color-text-primary: var(--neutral-900);
--color-text-secondary: var(--neutral-600); /* WCAG AA: ~5.0:1 auf weiß */
--color-text-tertiary: var(--neutral-500);
--color-text-disabled: var(--neutral-300);
/* --------------------------------------------------------
* Farben — Akzent (konfigurierbar)
* 2. Farben — Akzent (konfigurierbar)
* Wärmerer Blauton statt reinem Corporate-Blau.
* -------------------------------------------------------- */
--color-accent: #007AFF;
--color-accent-hover: #0056CC;
--color-accent-light: #E3F2FF;
--color-btn-primary: #0066DB; /* WCAG AA: ~5.0:1 auf weiß (Buttons mit weißem Text) */
--color-btn-primary-hover: #0056CC;
--color-accent: #3478F6;
--color-accent-hover: #2860D0;
--color-accent-active: #1E4FA8;
--color-accent-light: #EBF2FF;
--color-accent-subtle: #D6E5FF;
--color-btn-primary: #2C6BE0; /* WCAG AA: ~4.8:1 auf weiß (weißer Text) */
--color-btn-primary-hover: #2258BA;
/* --------------------------------------------------------
* Farben — Semantisch
* 3. Farben — Semantisch
* -------------------------------------------------------- */
--color-success: #34C759;
--color-success-light: #E3F9EB;
--color-warning: #FF9500;
--color-warning-light: #FFF3E0;
--color-danger: #FF3B30;
--color-danger-light: #FFE5E3;
--color-info: #5AC8FA;
--color-info-light: #E5F7FF;
--color-success: #2DA44E;
--color-success-hover: #258B3E;
--color-success-light: #DAFBE1;
--color-warning: #E6930A;
--color-warning-hover: #C97D08;
--color-warning-light: #FFF4D4;
--color-danger: #E5534B;
--color-danger-hover: #CC403A;
--color-danger-light: #FFE2E0;
--color-info: #54AEFF;
--color-info-hover: #3A94E5;
--color-info-light: #DDF4FF;
/* --------------------------------------------------------
* Farben — Prioritäten
* 4. Farben — Modul-Akzente
* Jedes Modul hat eine eigene dezente Akzentfarbe.
* Einsatz in Modul-Headern, Icons, aktiven States.
* -------------------------------------------------------- */
--color-priority-low: #8E8E93;
--color-priority-medium: #FF9500;
--color-priority-high: #FF6B35;
--color-priority-urgent: #FF3B30;
--module-dashboard: #3478F6; /* Blau — Übersicht, neutral */
--module-tasks: #2DA44E; /* Grün — Erledigung, Fortschritt */
--module-calendar: #8250DF; /* Violett — Termine, Zeit */
--module-meals: #E6930A; /* Orange — Essen, Wärme */
--module-shopping: #D4511E; /* Rot-Orange — Einkaufen, Aktion */
--module-notes: #BF8700; /* Gold — Notizen, Pinnwand */
--module-contacts: #0969DA; /* Kräftiges Blau — Kontakte */
--module-budget: #1A7F5A; /* Teal — Finanzen, Stabilität */
--module-settings: #6E7781; /* Grau — Konfiguration */
/* --------------------------------------------------------
* Schatten
* 5. Farben — Mahlzeit-Typen
* Zentrale Tokens statt Hardcoding in meals.css
* -------------------------------------------------------- */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.04), 0 1px 6px rgba(0,0,0,0.04);
--shadow-md: 0 4px 12px rgba(0,0,0,0.07), 0 1px 3px rgba(0,0,0,0.04);
--shadow-lg: 0 12px 32px rgba(0,0,0,0.09), 0 2px 8px rgba(0,0,0,0.05);
--meal-breakfast: #E6930A;
--meal-breakfast-light: #FFF4D4;
--meal-lunch: #2DA44E;
--meal-lunch-light: #DAFBE1;
--meal-dinner: #3478F6;
--meal-dinner-light: #EBF2FF;
--meal-snack: #D4511E;
--meal-snack-light: #FFECE3;
/* --------------------------------------------------------
* Border-Radien
* 6. Farben — Prioritäten
* -------------------------------------------------------- */
--color-priority-low: var(--neutral-500);
--color-priority-medium: #E6930A;
--color-priority-high: #D4511E;
--color-priority-urgent: #E5534B;
/* Hintergrundfarben für Priority-Badges */
--color-priority-low-bg: rgba(142, 141, 137, 0.12);
--color-priority-medium-bg: rgba(230, 147, 10, 0.12);
--color-priority-high-bg: rgba(212, 81, 30, 0.12);
--color-priority-urgent-bg: rgba(229, 83, 75, 0.12);
/* --------------------------------------------------------
* 7. Overlay / Backdrop
* -------------------------------------------------------- */
--color-overlay: rgba(0, 0, 0, 0.45);
--color-overlay-light: rgba(0, 0, 0, 0.2);
/* --------------------------------------------------------
* 8. Schatten
* 3 Stufen: subtle (Karten), medium (Dropdowns, Hover),
* elevated (Modals, FAB).
* -------------------------------------------------------- */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 4px rgba(0, 0, 0, 0.03);
--shadow-md: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.04);
/* --------------------------------------------------------
* 9. Border-Radien
* -------------------------------------------------------- */
--radius-xs: 4px;
--radius-sm: 8px;
@@ -63,32 +151,43 @@
--radius-full: 9999px;
/* --------------------------------------------------------
* Typografie
* 10. Typografie
* System-Font-Stack laut Redesign-Spec.
* Skala von xs (12px) bis 4xl (36px).
* -------------------------------------------------------- */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', system-ui, sans-serif;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-mono: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace;
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.8125rem; /* 13px */
--text-base: 1rem; /* 16px */
--text-md: 1.0625rem; /* 17px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
/* Size-Skala */
--text-2xs: 0.625rem; /* 10px — Micro-Labels (Nav, Avatare) */
--text-xs: 0.75rem; /* 12px — Captions, Badges */
--text-sm: 0.8125rem; /* 13px — Small/Secondary */
--text-base: 0.875rem; /* 14px — Body (Desktop), kompakter */
--text-md: 1rem; /* 16px — Body (Mobile), Inputs */
--text-lg: 1.125rem; /* 18px — Section-Title */
--text-xl: 1.25rem; /* 20px — Subtitle */
--text-2xl: 1.5rem; /* 24px — Page-Title */
--text-3xl: 1.875rem; /* 30px — Page-Title Desktop */
--text-4xl: 2.25rem; /* 36px — Hero/Greeting */
--line-height-tight: 1.2;
/* Line-Heights */
--line-height-tight: 1.25;
--line-height-snug: 1.375;
--line-height-base: 1.5;
--line-height-relaxed: 1.75;
--line-height-relaxed: 1.625;
/* Font-Weights */
--font-weight-regular: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
/* --------------------------------------------------------
* Abstände
* 11. Abstände — 4px-Raster
* -------------------------------------------------------- */
--space-0: 0px;
--space-px: 1px;
--space-0h: 2px;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
@@ -101,61 +200,104 @@
--space-16: 64px;
/* --------------------------------------------------------
* Layout
* 12. Layout
* -------------------------------------------------------- */
--nav-height-mobile: 64px;
--sidebar-width: 64px; /* collapsed icon-only (10241279px) */
--sidebar-width-expanded: 200px; /* full sidebar (1280px+) */
--content-max-width: 1200px;
--nav-height-mobile: 56px;
--sidebar-width: 56px; /* collapsed icon-only (10241279px) */
--sidebar-width-expanded: 220px; /* full sidebar (1280px+), max 240px laut Spec */
--content-max-width: 1280px;
/* Sidebar Neumorphismus */
--sidebar-bg: #E8E8EE;
--sidebar-shadow-light: rgba(255, 255, 255, 0.82);
--sidebar-shadow-dark: rgba(148, 148, 170, 0.28);
/* --------------------------------------------------------
* 13. Sidebar
* Reduzierter Neumorphismus — subtilere Schatten.
* -------------------------------------------------------- */
--sidebar-bg: var(--neutral-100);
--sidebar-shadow-light: rgba(255, 255, 255, 0.6);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.08);
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
/* --------------------------------------------------------
* Übergänge
* 14. Übergänge
* fast=150ms, base=250ms, slow=400ms (laut Redesign-Spec)
* -------------------------------------------------------- */
--transition-fast: 0.1s ease;
--transition-base: 0.2s ease;
--transition-slow: 0.3s ease;
--transition-fast: 0.15s ease;
--transition-base: 0.25s ease;
--transition-slow: 0.4s ease;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
/* --------------------------------------------------------
* Z-Indizes
* 15. Z-Indizes
* -------------------------------------------------------- */
--z-base: 0;
--z-card: 1;
--z-sticky: 10;
--z-dropdown: 50;
--z-nav: 100;
--z-modal: 200;
--z-toast: 300;
}
/* --------------------------------------------------------
/* ================================================================
* Dark Mode
* -------------------------------------------------------- */
* ================================================================ */
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #1C1C1E;
--color-surface: #2C2C2E;
--color-surface-2: #3A3A3C;
--color-border: #3A3A3C;
--color-text-primary: #F5F5F7;
--color-text-secondary: #AEAEB2; /* WCAG AA: ~4.6:1 auf #2C2C2E */
--color-text-disabled: #48484A;
/* Neutral-Skala invertiert (warm-dunkel) */
--neutral-50: #1A1A18;
--neutral-100: #222220;
--neutral-150: #2A2A28;
--neutral-200: #333331;
--neutral-250: #3D3D3A;
--neutral-300: #48484A;
--neutral-400: #636360;
--neutral-500: #8E8D89;
--neutral-600: #AEADB0; /* WCAG AA: ~4.8:1 auf #2A2A28 */
--neutral-700: #C8C7C3;
--neutral-800: #E2E1DC;
--neutral-900: #F5F4F1;
--neutral-950: #FAFAF8;
--sidebar-bg: #19191D;
--sidebar-shadow-light: rgba(255, 255, 255, 0.05);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.55);
/* Semantische Aliase folgen automatisch via var(--neutral-*) */
--color-surface: #2A2A28;
--color-surface-2: #1A1A18;
--color-surface-3: #333331;
--color-accent-light: #1A3A5C;
--color-success-light: #1A3A26;
--color-warning-light: #3A2800;
--color-danger-light: #3A1A1A;
--color-info-light: #1A3A4A;
/* Sidebar */
--sidebar-bg: #1A1A18;
--sidebar-shadow-light: rgba(255, 255, 255, 0.04);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.4);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
/* Akzent-Light-Varianten (dunkler Hintergrund) */
--color-accent-light: #1A2D4D;
--color-accent-subtle: #162442;
--color-success-light: #1A3325;
--color-warning-light: #332400;
--color-danger-light: #3D1C1A;
--color-info-light: #1A2D40;
/* Modul-Akzente bleiben im Dark Mode gleich (genug Kontrast) */
/* Mahlzeit-Typ Light-Varianten */
--meal-breakfast-light: #332400;
--meal-lunch-light: #1A3325;
--meal-dinner-light: #1A2D4D;
--meal-snack-light: #3D2010;
/* Priority-Badge Hintergründe */
--color-priority-low-bg: rgba(142, 141, 137, 0.18);
--color-priority-medium-bg: rgba(230, 147, 10, 0.18);
--color-priority-high-bg: rgba(212, 81, 30, 0.18);
--color-priority-urgent-bg: rgba(229, 83, 75, 0.18);
/* Overlay */
--color-overlay: rgba(0, 0, 0, 0.6);
--color-overlay-light: rgba(0, 0, 0, 0.35);
/* Schatten stärker im Dark Mode */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.45);
}
}
+3 -3
View File
@@ -12,9 +12,9 @@
* API: Immer Netzwerk (kein Caching von Nutzerdaten)
*/
const SHELL_CACHE = 'oikos-shell-v9';
const PAGES_CACHE = 'oikos-pages-v9';
const ASSETS_CACHE = 'oikos-assets-v9';
const SHELL_CACHE = 'oikos-shell-v10';
const PAGES_CACHE = 'oikos-pages-v10';
const ASSETS_CACHE = 'oikos-assets-v10';
const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE];
// App-Shell: sofort benötigt für ersten Render
+6 -2
View File
@@ -30,6 +30,7 @@ const PORT = process.env.PORT || 3000;
// --------------------------------------------------------
// Security-Middleware
// --------------------------------------------------------
const isSecure = process.env.SESSION_SECURE !== 'false';
app.use(helmet({
contentSecurityPolicy: {
directives: {
@@ -45,13 +46,16 @@ app.use(helmet({
fontSrc: ["'self'"],
objectSrc: ["'none'"],
frameSrc: ["'none'"],
// upgrade-insecure-requests nur mit HTTPS aktivieren
upgradeInsecureRequests: isSecure ? [] : null,
},
},
hsts: {
// HSTS nur mit HTTPS aktivieren
hsts: isSecure ? {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
} : false,
}));
// Trust Proxy für korrekte IP hinter Nginx