fix(quick-260916-dyv): Mindestgroessen inhaltsgetrieben (kleinste bedienbare Kachel je Typ), gespeicherte Minima ueberschrieben, Stoppuhr-Bedienleiste kompakt
- WIDGET_CONSTRAINTS: Minima aus dem Innenaufbau gerechnet (clock 2/2, search 6/2, calendar 3/3, note 4/4, calculator 3/9, favorites 3/3, link 3/2, stopwatch 4/3), Vorgaben unveraendert; Test A pinnt alle 32 Werte per toEqual - dashboard-grid.tsx: effectiveLayouts (useMemo) ueberschreibt minW/minH jedes gespeicherten Eintrags in jedem Breakpoint aus den Konstanten und hebt zu kleine w/h auf das Minimum an — RGL 2.2.3 nimmt gespeicherte Eintraege woertlich (synchronizeLayoutWithChildren) und liest data-grid nur ohne Eintrag - dashboard-grid.test.tsx: Test 5 angepasst, Test 9 (Ueberschreibung je Breakpoint, unbekannter Typ unveraendert) und Test 9b (h 8 -> 9, w >= minW bleibt) - stopwatch-widget.tsx: Bedienleiste px-2 py-1 text-xs, Zeile gap-1 py-1, damit Stop + Runde + Reset in 4 Spalten passen und die Kachel auf 4x3 schrumpfen kann Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Responsive, noCompactor } from 'react-grid-layout';
|
||||
import type { ResponsiveLayouts } from 'react-grid-layout';
|
||||
import 'react-grid-layout/css/styles.css';
|
||||
@@ -17,14 +17,72 @@ import { TesseraLogo } from '@/components/brand/tessera-logo';
|
||||
const BREAKPOINTS = { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 };
|
||||
const COLS = { lg: 24, md: 20, sm: 12, xs: 8, xxs: 2 };
|
||||
|
||||
interface LayoutItemShape {
|
||||
i: string;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
minW?: number;
|
||||
minH?: number;
|
||||
}
|
||||
|
||||
interface DashboardGridProps {
|
||||
layouts: Record<string, Array<{ i: string; x: number; y: number; w: number; h: number }>>;
|
||||
layouts: Record<string, Array<LayoutItemShape>>;
|
||||
widgets: Array<{ id: string; widgetType: string; config: Record<string, unknown> }>;
|
||||
isEditMode: boolean;
|
||||
onLayoutChange: (allLayouts: ResponsiveLayouts) => void;
|
||||
onRemoveWidget: (id: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* quick-260916-dyv: Gespeicherte minW/minH aus den Konstanten ueberschreiben.
|
||||
*
|
||||
* Warum: react-grid-layout 2.2.3 nimmt in `synchronizeLayoutWithChildren`
|
||||
* (chunk-WGL5FSZH.mjs:559-562) fuer jedes Kind MIT Eintrag im `layout` den
|
||||
* Eintrag per `cloneLayoutItem` woertlich — inklusive minW/minH — und liest
|
||||
* `data-grid` nur fuer Kinder OHNE Eintrag. Gespeicherte Anordnungen tragen
|
||||
* minW/minH (RGL liefert sie in `onLayoutChange`, 260916-bwo hat sie verdoppelt
|
||||
* persistiert). Eine Aenderung von WIDGET_CONSTRAINTS allein aendert fuer
|
||||
* bestehende Widgets also NICHTS. Deshalb: in JEDEM Breakpoint minW/minH jedes
|
||||
* Eintrags eines bekannten Typs aus der Tabelle setzen; die Konstanten sind
|
||||
* die einzige Quelle (T-DYV-01: manipulierte Minima wirken nicht).
|
||||
*
|
||||
* Liegt die gespeicherte Groesse UNTER dem neuen Minimum (z. B. Rechner mit
|
||||
* h 8, neues minH 9), wird w/h auf das Minimum angehoben: RGL selbst klemmt
|
||||
* w/h nur beim Vergroessern/Verkleinern (`minMaxSize.constrainSize`,
|
||||
* chunk-KDANGDDL.mjs:26-31; `minConstraints` an `Resizable`,
|
||||
* chunk-WGL5FSZH.mjs:472-475), rendert die zu kleine Kachel aber woertlich —
|
||||
* der Rechner bliebe bis zum ersten Anfassen unten abgeschnitten.
|
||||
* Unbekannte Typen bleiben unveraendert; das Eingabeobjekt wird nicht mutiert.
|
||||
*/
|
||||
function applyConstraintMinima(
|
||||
layouts: Record<string, Array<LayoutItemShape>>,
|
||||
widgets: Array<{ id: string; widgetType: string }>,
|
||||
): Record<string, Array<LayoutItemShape>> {
|
||||
const typeById = new Map<string, string>();
|
||||
for (const w of widgets) typeById.set(w.id, w.widgetType);
|
||||
|
||||
const result: Record<string, Array<LayoutItemShape>> = {};
|
||||
for (const key of Object.keys(layouts)) {
|
||||
const entries = layouts[key];
|
||||
if (!Array.isArray(entries)) continue;
|
||||
result[key] = entries.map((entry) => {
|
||||
const type = typeById.get(entry.i);
|
||||
const constraints = type ? WIDGET_CONSTRAINTS[type as WidgetType] : undefined;
|
||||
if (!constraints) return { ...entry };
|
||||
return {
|
||||
...entry,
|
||||
w: Math.max(entry.w, constraints.minW),
|
||||
h: Math.max(entry.h, constraints.minH),
|
||||
minW: constraints.minW,
|
||||
minH: constraints.minH,
|
||||
};
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard grid wrapper using react-grid-layout v2 Responsive component.
|
||||
* Renders widgets in a draggable/resizable grid when in edit mode.
|
||||
@@ -53,6 +111,11 @@ export function DashboardGrid({
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
// quick-260916-dyv: minW/minH (und zu kleine w/h) aus WIDGET_CONSTRAINTS —
|
||||
// siehe applyConstraintMinima. Vor dem Leerzustand, damit die Hook-Reihenfolge
|
||||
// stabil bleibt.
|
||||
const effectiveLayouts = useMemo(() => applyConstraintMinima(layouts, widgets), [layouts, widgets]);
|
||||
|
||||
// Empty state (D-02)
|
||||
if (widgets.length === 0) {
|
||||
return (
|
||||
@@ -77,7 +140,7 @@ export function DashboardGrid({
|
||||
width={width}
|
||||
breakpoints={BREAKPOINTS}
|
||||
cols={COLS}
|
||||
layouts={layouts as ResponsiveLayouts}
|
||||
layouts={effectiveLayouts as ResponsiveLayouts}
|
||||
rowHeight={20}
|
||||
margin={[8, 8] as [number, number]}
|
||||
// containerPadding bewusst nicht gesetzt: react-grid-layout 2.2.3 nimmt
|
||||
@@ -98,7 +161,7 @@ export function DashboardGrid({
|
||||
<div
|
||||
key={widget.id}
|
||||
data-grid={{
|
||||
...(layouts.lg?.find((l) => l.i === widget.id) ?? {
|
||||
...(effectiveLayouts.lg?.find((l) => l.i === widget.id) ?? {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: constraints?.defaultW ?? 4,
|
||||
|
||||
Reference in New Issue
Block a user