feat: various UI fixes, prompt optimizations, and allowing duplicate docs

- Updated `content_hash` in the `Document` model to remove global uniqueness, allowing identical content across different paths.
- Enhanced `_create_document` function to handle path uniqueness and prevent session-poisoning from `IntegrityError`.
- Added detailed comments for clarity on the changes and their implications.
- Introduced new citation handling in the editor for improved user experience with citation jumps.
- Updated package dependencies in the frontend for better functionality.
This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-28 21:30:53 -07:00
parent e6433f78c4
commit b9a66cb417
26 changed files with 1540 additions and 852 deletions

View file

@ -12,6 +12,12 @@ import { type EditorPreset, presetMap } from "@/components/editor/presets";
import { escapeMdxExpressions } from "@/components/editor/utils/escape-mdx";
import { Editor, EditorContainer } from "@/components/ui/editor";
/** Live editor instance returned by `usePlateEditor`. Exposed via the
* `onEditorReady` prop so callers (e.g. `EditorPanelContent`) can drive
* plugin options imperatively most notably setting
* `FindReplacePlugin`'s `search` option for citation-jump highlights. */
export type PlateEditorInstance = ReturnType<typeof usePlateEditor>;
export interface PlateEditorProps {
/** Markdown string to load as initial content */
markdown?: string;
@ -62,6 +68,15 @@ export interface PlateEditorProps {
* without modifying the core editor component.
*/
extraPlugins?: AnyPluginConfig[];
/**
* Called whenever the live editor instance (re)mounts, with `null` on
* unmount. Used by callers that need to drive plugin options imperatively
* e.g. `EditorPanelContent` setting `FindReplacePlugin`'s `search`
* option for citation-jump highlights. The callback is invoked exactly
* once per editor lifetime (the parent's `key` prop forces a fresh
* editor when needed, e.g. on edit-mode toggle).
*/
onEditorReady?: (editor: PlateEditorInstance | null) => void;
}
function PlateEditorContent({
@ -100,6 +115,7 @@ export function PlateEditor({
defaultEditing = false,
preset = "full",
extraPlugins = [],
onEditorReady,
}: PlateEditorProps) {
const lastMarkdownRef = useRef(markdown);
const lastHtmlRef = useRef(html);
@ -156,6 +172,21 @@ export function PlateEditor({
: undefined,
});
// Expose the live editor instance to imperative callers (e.g. citation
// jump highlights). We deliberately don't depend on `onEditorReady`
// itself in the cleanup closure — callers commonly pass an arrow that
// closes over a stable ref setter, but if they pass a freshly-bound
// callback per render, the `onEditorReady?.(editor)` re-fires which is
// idempotent for ref-style setters.
const onEditorReadyRef = useRef(onEditorReady);
useEffect(() => {
onEditorReadyRef.current = onEditorReady;
}, [onEditorReady]);
useEffect(() => {
onEditorReadyRef.current?.(editor);
return () => onEditorReadyRef.current?.(null);
}, [editor]);
// Update editor content when html prop changes externally
useEffect(() => {
if (html !== undefined && html !== lastHtmlRef.current) {