feat: add task comments feature with CRUD operations
- Introduced a new `task_comments` table in the database schema. - Implemented task comments API endpoints for listing, creating, and deleting comments. - Enhanced the task detail dialog to display comments and allow users to add new comments. - Updated task row component to handle click events for viewing task details. - Added a theme provider to manage light/dark mode across the application. - Refactored Milkdown editor to use Crepe for improved markdown editing experience. - Updated global styles to accommodate new editor and theme changes. - Enhanced task filtering and sorting functionality in the tasks page.
This commit is contained in:
@@ -1,47 +1,49 @@
|
||||
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 { useEffect, useRef } from 'react';
|
||||
import { Crepe, CrepeFeature } from '@milkdown/crepe';
|
||||
|
||||
import '@milkdown/kit/prose/view/style/prosemirror.css';
|
||||
import '@milkdown/crepe/theme/common/style.css';
|
||||
import '@milkdown/crepe/theme/nord.css';
|
||||
|
||||
interface MilkdownEditorProps {
|
||||
initialContent: string;
|
||||
onChange: (markdown: string) => void;
|
||||
}
|
||||
|
||||
function MilkdownInner({ initialContent, onChange }: MilkdownEditorProps) {
|
||||
export function MilkdownEditor({ initialContent, onChange }: MilkdownEditorProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const crepeRef = useRef<Crepe | null>(null);
|
||||
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);
|
||||
}
|
||||
});
|
||||
}),
|
||||
[]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
return <Milkdown />;
|
||||
}
|
||||
const crepe = new Crepe({
|
||||
root: containerRef.current,
|
||||
defaultValue: initialContent,
|
||||
featureConfigs: {
|
||||
[CrepeFeature.Placeholder]: {
|
||||
text: 'Start writing...',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function MilkdownEditor(props: MilkdownEditorProps) {
|
||||
return (
|
||||
<MilkdownProvider>
|
||||
<MilkdownInner {...props} />
|
||||
</MilkdownProvider>
|
||||
);
|
||||
crepe.on((listener) => {
|
||||
listener.markdownUpdated((_ctx, markdown, prevMarkdown) => {
|
||||
if (markdown !== prevMarkdown) {
|
||||
onChangeRef.current(markdown);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
crepe.create();
|
||||
crepeRef.current = crepe;
|
||||
|
||||
return () => {
|
||||
crepe.destroy();
|
||||
crepeRef.current = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return <div ref={containerRef} className="milkdown-container" />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user