feat(web): Design Mosaik Runde 3 - Reiter in der Seitenleiste, lebendigere Kacheln
- Dashboard-Reiter stehen in der aufgeklappten Seitenleiste als Liste unter "Dashboard" (Ziehen sortiert senkrecht, Umbenennen/Loeschen/Neu im Bearbeitungsmodus); eingeklappt und auf dem Handy wie bisher in der Kopfzeile. Die Kopfzeile zeigt sonst den Namen des Dashboards. - Begruessung einzeilig auf Hoehe der Befehlsleiste. - Kachel-Groesse: kollidiert die gezogene Groesse mit einem Nachbarn, wird nur die freie Achse uebernommen - vorher verwarf react-grid-layout mit preventCollision die ganze Aenderung, sobald die Maus eine Zeile nach unten wackelte (Favoriten liessen sich deshalb oft nicht schmaler ziehen). - Ansicht: belegte Spalten mittig, Begruessung/Befehlsleiste ruecken mit. - Kalender: einzeilige Terminliste mit "Heute"/"Morgen" in Akzentfarbe, Ort im Tooltip, Standardhoehe 16 statt 12. - Hintergrund "Bluete" im Dunkelmodus weggelassen (Farbstufen), Ersatz Nebel. - Kacheln: Symbol-Chip in der Akzentfarbe, leichtes Anheben beim Zeigen, gestaffeltes Einblenden beim Laden (ohne bei reduzierter Bewegung). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
BACKGROUND_PRESETS,
|
||||
DARK_FALLBACK_ID,
|
||||
loadDashboardBackground,
|
||||
presetBackground,
|
||||
saveDashboardBackground,
|
||||
@@ -44,11 +45,13 @@ describe('dashboard-background (Design „Mosaik“, Prototyp)', () => {
|
||||
expect(loadDashboardBackground('u1')).toEqual({ kind: 'none' });
|
||||
});
|
||||
|
||||
it('jeder eingebaute Hintergrund hat eine helle und eine dunkle Fassung', () => {
|
||||
it('jeder eingebaute Hintergrund liefert hell und dunkel ein Bild (dunkel notfalls den Ersatz)', () => {
|
||||
for (const preset of BACKGROUND_PRESETS) {
|
||||
expect(presetBackground(preset.id, false)).toBeTruthy();
|
||||
expect(presetBackground(preset.id, true)).toBeTruthy();
|
||||
expect(presetBackground(preset.id, false)).not.toBe(presetBackground(preset.id, true));
|
||||
}
|
||||
// Runde 3: „Bluete“ hat keine dunkle Fassung, dunkel greift der Ersatz.
|
||||
expect(presetBackground('bloom', true)).toBe(presetBackground(DARK_FALLBACK_ID, true));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,9 +75,17 @@ export interface BackgroundPreset {
|
||||
/** Uebersetzungsschluessel unter `dashboard.background.presets`. */
|
||||
labelKey: string;
|
||||
light: string;
|
||||
dark: string;
|
||||
/**
|
||||
* `null` = im Dunkelmodus nicht angeboten (Runde 3). Wer den Hintergrund
|
||||
* im hellen Modus gewaehlt hat, sieht im dunklen den Ersatz
|
||||
* {@link DARK_FALLBACK_ID}.
|
||||
*/
|
||||
dark: string | null;
|
||||
}
|
||||
|
||||
/** Ersatz im Dunkelmodus fuer Hintergruende ohne dunkle Fassung. */
|
||||
export const DARK_FALLBACK_ID: BackgroundPresetId = 'mist';
|
||||
|
||||
// Runde 2: nur Gelb-, Grau- und Graphittoene — keine bunten Modulfarben.
|
||||
export const BACKGROUND_PRESETS: BackgroundPreset[] = [
|
||||
{ id: 'mist', labelKey: 'mist', light: '#e4e9f1', dark: '#1d2330' },
|
||||
@@ -86,7 +94,10 @@ export const BACKGROUND_PRESETS: BackgroundPreset[] = [
|
||||
id: 'bloom',
|
||||
labelKey: 'bloom',
|
||||
light: bloom('#eceef1', '#f0e9c6', '#d3d7de', '#dddbd5'),
|
||||
dark: bloom('#1b1d22', '#37342a', '#2a2e35', '#2f2e2a'),
|
||||
// Runde 3: im Dunkelmodus weggelassen — der weichgezeichnete Verlauf
|
||||
// zwischen sehr dunklen Toenen zeigt sichtbare Farbstufen (8 Bit reichen
|
||||
// dort nicht), auch mit Korn. Ersatz: DARK_FALLBACK_ID.
|
||||
dark: null,
|
||||
},
|
||||
{
|
||||
id: 'dunes',
|
||||
@@ -105,7 +116,9 @@ export const BACKGROUND_PRESETS: BackgroundPreset[] = [
|
||||
export function presetBackground(id: BackgroundPresetId, dark: boolean): string | null {
|
||||
const preset = BACKGROUND_PRESETS.find((p) => p.id === id);
|
||||
if (!preset) return null;
|
||||
return dark ? preset.dark : preset.light;
|
||||
if (!dark) return preset.light;
|
||||
if (preset.dark !== null) return preset.dark;
|
||||
return BACKGROUND_PRESETS.find((p) => p.id === DARK_FALLBACK_ID)?.dark ?? null;
|
||||
}
|
||||
|
||||
function storageKey(userId: string): string {
|
||||
|
||||
Reference in New Issue
Block a user