feat(web): Notiz-Widget — Aufgabenlisten in der Ansicht abhakbar
- Hilfsmodul note-task-list.tsx mit isTaskLine/toggleTaskLine (GFM-konforme Regex, Code-Zaeune werden uebersprungen) und NoteCheckbox (kein disabled) - previewOptions des Notiz-Widgets reicht components.input = NoteCheckbox durch react-markdown nach rehypeSanitize durch (bleibt aktiv, T-IEX-01) - Klick im Vorschau-Container kippt genau die N-te Aufgabenzeile und speichert sofort (verwirft einen laufenden Tipp-Entprell-Timer) - Hinweis: note-task-list als .tsx statt .ts angelegt (Komponente braucht JSX) — Abweichung dokumentiert in SUMMARY.md - 16 neue/erweiterte Tests gruen, tsc Exit 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,27 @@ import MDEditor, { commands } from '@uiw/react-md-editor';
|
||||
import rehypeSanitize from 'rehype-sanitize';
|
||||
import type { WidgetProps } from '../widget-registry';
|
||||
import { updateWidgetConfig } from '@/lib/dashboard-api';
|
||||
import { NoteCheckbox, toggleTaskLine } from './note-task-list';
|
||||
|
||||
const DEBOUNCE_MS = 1500;
|
||||
|
||||
// quick-260916-iex: Aufgabenlisten sind in der Ansicht direkt abhakbar —
|
||||
// `components.input` ersetzt das per rehypeSanitize deaktivierte `input`
|
||||
// durch NoteCheckbox (siehe note-task-list.tsx). Stabile Konstante ausserhalb
|
||||
// der Komponente, damit react-markdown nicht bei jedem Render neu diffed.
|
||||
// Typ direkt von MDEditor abgeleitet statt aus dem transitiven Paket
|
||||
// `@uiw/react-markdown-preview` importiert (das ist keine direkte
|
||||
// Dependency von apps/web und daher unter pnpms strikter Isolation nicht
|
||||
// von hier aus aufloesbar).
|
||||
type PreviewOptions = NonNullable<
|
||||
React.ComponentProps<typeof MDEditor>['previewOptions']
|
||||
>;
|
||||
|
||||
const PREVIEW_OPTIONS: PreviewOptions = {
|
||||
rehypePlugins: [[rehypeSanitize]],
|
||||
components: { input: NoteCheckbox },
|
||||
};
|
||||
|
||||
const NOTE_COMMANDS = [
|
||||
commands.bold,
|
||||
commands.italic,
|
||||
@@ -83,6 +101,32 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
|
||||
[scheduleSave, content],
|
||||
);
|
||||
|
||||
// quick-260916-iex: Klick auf ein Aufgaben-Kaestchen in der Ansicht kippt
|
||||
// genau diese Zeile und speichert sofort (kein Entprellen — ein Klick ist
|
||||
// eine abgeschlossene Handlung). Ein noch laufender Entprell-Timer aus dem
|
||||
// Tippen wird verworfen, damit er den ungekippten Text nicht nachschiebt.
|
||||
const handlePreviewClick = useCallback(
|
||||
(event: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (isEditing) return;
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLInputElement) || target.type !== 'checkbox') {
|
||||
return;
|
||||
}
|
||||
const boxes = Array.from(
|
||||
event.currentTarget.querySelectorAll<HTMLInputElement>(
|
||||
'input[type="checkbox"]',
|
||||
),
|
||||
);
|
||||
const index = boxes.indexOf(target);
|
||||
const next = toggleTaskLine(content, index);
|
||||
if (next === content) return;
|
||||
setContent(next);
|
||||
clearTimeout(timerRef.current);
|
||||
void save(next, title);
|
||||
},
|
||||
[isEditing, content, title, save],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col overflow-hidden" data-color-mode="auto">
|
||||
{/* Header: title + pencil toggle */}
|
||||
@@ -123,7 +167,11 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
|
||||
</div>
|
||||
|
||||
{/* Content: preview or editor */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div
|
||||
className="flex-1 overflow-auto"
|
||||
data-testid="note-preview"
|
||||
onClick={handlePreviewClick}
|
||||
>
|
||||
<MDEditor
|
||||
data-testid="md-editor"
|
||||
value={content}
|
||||
@@ -133,9 +181,7 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
|
||||
hideToolbar={!isEditing}
|
||||
height="100%"
|
||||
visibleDragbar={false}
|
||||
previewOptions={{
|
||||
rehypePlugins: [[rehypeSanitize]],
|
||||
}}
|
||||
previewOptions={PREVIEW_OPTIONS}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user