mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-04 05:12:38 +02:00
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:
parent
e6433f78c4
commit
b9a66cb417
26 changed files with 1540 additions and 852 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { FindReplacePlugin } from "@platejs/find-replace";
|
||||
import type { AnyPluginConfig } from "platejs";
|
||||
import { TrailingBlockPlugin } from "platejs";
|
||||
|
||||
|
|
@ -17,6 +18,30 @@ import { SelectionKit } from "@/components/editor/plugins/selection-kit";
|
|||
import { SlashCommandKit } from "@/components/editor/plugins/slash-command-kit";
|
||||
import { TableKit } from "@/components/editor/plugins/table-kit";
|
||||
import { ToggleKit } from "@/components/editor/plugins/toggle-kit";
|
||||
import { SearchHighlightLeaf } from "@/components/ui/search-highlight-node";
|
||||
|
||||
/**
|
||||
* Citation-jump highlighter. Re-uses Plate's built-in `FindReplacePlugin`
|
||||
* (decorate-only, no editing surface) to drive the "scroll-to-cited-text"
|
||||
* UX in `EditorPanelContent`. We register it in every preset because:
|
||||
* - Decorate is a no-op when `search` is empty (single getOptions() check
|
||||
* per block), so cost is effectively zero for non-citation viewers.
|
||||
* - Keeping it preset-agnostic means citations work whether the doc is
|
||||
* opened in editable (`full`) or pure-viewer (`readonly`) modes.
|
||||
*
|
||||
* The parent component drives `setOption(FindReplacePlugin, 'search', ...)`
|
||||
* + `editor.api.redecorate()` to trigger highlights, then queries the
|
||||
* editor DOM for `.citation-highlight-leaf` to scroll the first match
|
||||
* into view. (We can't use a `data-*` attribute here — Plate's
|
||||
* `PlateLeaf` runs props through `useNodeAttributes`, which only forwards
|
||||
* `attributes`, `className`, `ref`, `style`; arbitrary `data-*` props are
|
||||
* silently dropped.) See `components/ui/search-highlight-node.tsx` for
|
||||
* the leaf component and `CITATION_HIGHLIGHT_CLASS` constant.
|
||||
*/
|
||||
const CitationFindReplacePlugin = FindReplacePlugin.configure({
|
||||
options: { search: "" },
|
||||
render: { node: SearchHighlightLeaf },
|
||||
});
|
||||
|
||||
/**
|
||||
* Full preset – every plugin kit enabled.
|
||||
|
|
@ -38,6 +63,7 @@ export const fullPreset: AnyPluginConfig[] = [
|
|||
...AutoformatKit,
|
||||
...DndKit,
|
||||
TrailingBlockPlugin,
|
||||
CitationFindReplacePlugin,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -52,6 +78,7 @@ export const minimalPreset: AnyPluginConfig[] = [
|
|||
...LinkKit,
|
||||
...AutoformatKit,
|
||||
TrailingBlockPlugin,
|
||||
CitationFindReplacePlugin,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -68,6 +95,7 @@ export const readonlyPreset: AnyPluginConfig[] = [
|
|||
...CalloutKit,
|
||||
...ToggleKit,
|
||||
...MathKit,
|
||||
CitationFindReplacePlugin,
|
||||
];
|
||||
|
||||
/** All available preset names */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue