fix(web): Notiz-Widget folgt dem Hell/Dunkel-Schalter von Tessera statt der Systemeinstellung

- useTheme (next-themes) + mounted-Guard wie changelog-view.tsx
- data-color-mode am Wurzel-Div folgt resolvedTheme statt fest 'auto'
- zwei neue Tests (dark/light) via vi.hoisted-Themenzustand

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 13:55:18 +02:00
parent b16e4b8e67
commit 4c2495bb64
2 changed files with 44 additions and 1 deletions
@@ -12,6 +12,14 @@ vi.mock('next-intl', () => ({
},
}));
// quick-260916-j4f: gehobener Themenzustand, damit die Variable trotz
// Hoisting der Mocks und des statischen Imports weiter unten sicher
// initialisiert ist (Muster changelog-page.test.tsx).
const themeMock = vi.hoisted(() => ({ resolvedTheme: 'light' as 'light' | 'dark' }));
vi.mock('next-themes', () => ({
useTheme: () => ({ resolvedTheme: themeMock.resolvedTheme }),
}));
// Mock @uiw/react-md-editor — provide a minimal textarea-based substitute.
// Im Modus 'preview' wird stattdessen ein Vorschau-Div gerendert, das fuer
// jede Aufgabenzeile ein Kaestchen enthaelt (quick-260916-iex) — nutzt die
@@ -85,6 +93,7 @@ describe('NoteWidget', () => {
beforeEach(() => {
vi.useFakeTimers();
themeMock.resolvedTheme = 'light';
fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
ok: true,
json: async () => ({}),
@@ -290,4 +299,26 @@ describe('NoteWidget', () => {
});
expect(fetchSpy).toHaveBeenCalledTimes(1);
});
it('setzt data-color-mode auf dark, wenn Tessera auf Dunkel steht', () => {
themeMock.resolvedTheme = 'dark';
const { container } = render(
<NoteWidget instanceId="note-t1" config={{}} isEditMode={false} />,
);
expect(container.querySelector('[data-color-mode]')?.getAttribute('data-color-mode')).toBe(
'dark',
);
});
it('setzt data-color-mode auf light, wenn Tessera auf Hell steht', () => {
themeMock.resolvedTheme = 'light';
const { container } = render(
<NoteWidget instanceId="note-t1" config={{}} isEditMode={false} />,
);
expect(container.querySelector('[data-color-mode]')?.getAttribute('data-color-mode')).toBe(
'light',
);
});
});
@@ -2,6 +2,7 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslations } from 'next-intl';
import { useTheme } from 'next-themes';
import MDEditor, { commands } from '@uiw/react-md-editor';
import rehypeSanitize from 'rehype-sanitize';
import type { WidgetProps } from '../widget-registry';
@@ -41,6 +42,17 @@ const NOTE_COMMANDS = [
export function NoteWidget({ instanceId, config }: WidgetProps) {
const t = useTranslations('widgets');
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
// quick-260916-j4f: folgt dem Tessera-Schalter statt der
// Betriebssystem-Einstellung, Muster changelog-view.tsx.
const colorMode: 'light' | 'dark' = mounted && resolvedTheme === 'dark' ? 'dark' : 'light';
const [title, setTitle] = useState<string>(
(config.title as string) || t('note.defaultTitle'),
);
@@ -128,7 +140,7 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
);
return (
<div className="flex h-full flex-col overflow-hidden" data-color-mode="auto">
<div className="flex h-full flex-col overflow-hidden" data-color-mode={colorMode}>
{/* Header: title + pencil toggle */}
<div className="relative flex items-center border-b border-border px-1.5 py-1.5 gap-2">
<input