feat: integrate Milkdown editor for note-taking functionality

- Added Milkdown dependencies: @milkdown/kit, @milkdown/react, @milkdown/theme-nord.
- Implemented MilkdownEditor component for rich text editing in notes.
- Updated /notes/$noteId route to include editable title and auto-saving functionality.
- Enhanced UI with loading states, saving indicators, and delete confirmation dialog.
- Applied Milkdown-specific CSS overrides for consistent theming and styling.
- Improved note update logic with debounced saving and cleanup on unmount.
This commit is contained in:
Roberto Musso
2026-02-22 22:47:05 +01:00
parent 7860ca6ad1
commit 2308158976
9 changed files with 3016 additions and 34 deletions

View File

@@ -69,7 +69,7 @@ export function AppShell({ children }: AppShellProps) {
className="text-[9px] text-muted-foreground/30 tracking-widest uppercase font-medium"
style={{ writingMode: 'vertical-rl', transform: 'rotate(180deg)' }}
>
keep scrolling up for AI
scrolling up for Adiuva
</span>
</div>
</div>

View File

@@ -0,0 +1,47 @@
import { useRef } from 'react';
import { Editor, rootCtx, defaultValueCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { history } from '@milkdown/kit/plugin/history';
import { listener, listenerCtx } from '@milkdown/kit/plugin/listener';
import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react';
import '@milkdown/kit/prose/view/style/prosemirror.css';
interface MilkdownEditorProps {
initialContent: string;
onChange: (markdown: string) => void;
}
function MilkdownInner({ initialContent, onChange }: MilkdownEditorProps) {
const onChangeRef = useRef(onChange);
onChangeRef.current = onChange;
useEditor((root) =>
Editor.make()
.config((ctx) => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, initialContent);
})
.use(commonmark)
.use(history)
.use(listener)
.config((ctx) => {
ctx.get(listenerCtx).markdownUpdated((_ctx, markdown, prevMarkdown) => {
if (markdown !== prevMarkdown) {
onChangeRef.current(markdown);
}
});
}),
[]
);
return <Milkdown />;
}
export function MilkdownEditor(props: MilkdownEditorProps) {
return (
<MilkdownProvider>
<MilkdownInner {...props} />
</MilkdownProvider>
);
}