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:
@@ -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.
|
// Mock @uiw/react-md-editor — provide a minimal textarea-based substitute.
|
||||||
// Im Modus 'preview' wird stattdessen ein Vorschau-Div gerendert, das fuer
|
// Im Modus 'preview' wird stattdessen ein Vorschau-Div gerendert, das fuer
|
||||||
// jede Aufgabenzeile ein Kaestchen enthaelt (quick-260916-iex) — nutzt die
|
// jede Aufgabenzeile ein Kaestchen enthaelt (quick-260916-iex) — nutzt die
|
||||||
@@ -85,6 +93,7 @@ describe('NoteWidget', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
themeMock.resolvedTheme = 'light';
|
||||||
fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: async () => ({}),
|
json: async () => ({}),
|
||||||
@@ -290,4 +299,26 @@ describe('NoteWidget', () => {
|
|||||||
});
|
});
|
||||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
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 { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useTheme } from 'next-themes';
|
||||||
import MDEditor, { commands } from '@uiw/react-md-editor';
|
import MDEditor, { commands } from '@uiw/react-md-editor';
|
||||||
import rehypeSanitize from 'rehype-sanitize';
|
import rehypeSanitize from 'rehype-sanitize';
|
||||||
import type { WidgetProps } from '../widget-registry';
|
import type { WidgetProps } from '../widget-registry';
|
||||||
@@ -41,6 +42,17 @@ const NOTE_COMMANDS = [
|
|||||||
|
|
||||||
export function NoteWidget({ instanceId, config }: WidgetProps) {
|
export function NoteWidget({ instanceId, config }: WidgetProps) {
|
||||||
const t = useTranslations('widgets');
|
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>(
|
const [title, setTitle] = useState<string>(
|
||||||
(config.title as string) || t('note.defaultTitle'),
|
(config.title as string) || t('note.defaultTitle'),
|
||||||
);
|
);
|
||||||
@@ -128,7 +140,7 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
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 */}
|
{/* Header: title + pencil toggle */}
|
||||||
<div className="relative flex items-center border-b border-border px-1.5 py-1.5 gap-2">
|
<div className="relative flex items-center border-b border-border px-1.5 py-1.5 gap-2">
|
||||||
<input
|
<input
|
||||||
|
|||||||
Reference in New Issue
Block a user