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:
2026-09-28 15:58:01 +02:00
parent b06a2d1066
commit 8532b63097
20 changed files with 552 additions and 73 deletions
@@ -2,7 +2,10 @@ import type { ReactNode } from 'react';
/**
* Kleines einfarbiges Symbol je Kacheltyp fuer die Kachel-Kopfzeile
* (Design „Mosaik“, Runde 2): 16 px, gedaempftes Grau, rein dekorativ.
* (Design „Mosaik“). Seit Runde 3 als „Chip“: 16-px-Symbol auf einer
* 26-px-Flaeche, beides aus der persoenlichen Akzentfarbe abgeleitet
* (`.widget-icon-chip` in globals.css) — bringt Farbe in die Kacheln, ohne
* bunt zu werden. `plain` ist das nackte graue Symbol (Vorschlagsknoepfe).
*/
const PATHS: Record<string, ReactNode> = {
calendar: (
@@ -64,10 +67,10 @@ const PATHS: Record<string, ReactNode> = {
),
};
export function WidgetIcon({ type }: { type: string }) {
export function WidgetIcon({ type, variant = 'chip' }: { type: string; variant?: 'chip' | 'plain' }) {
const paths = PATHS[type];
if (!paths) return null;
return (
const svg = (
<svg
aria-hidden="true"
data-widget-icon={type}
@@ -80,9 +83,15 @@ export function WidgetIcon({ type }: { type: string }) {
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
className="shrink-0 text-muted-foreground"
className={variant === 'plain' ? 'shrink-0 text-muted-foreground' : 'shrink-0'}
>
{paths}
</svg>
);
if (variant === 'plain') return svg;
return (
<span aria-hidden="true" className="widget-icon-chip">
{svg}
</span>
);
}