[[Parsed Page]]
'; + + editor.commands.setContent(html); + + const json = editor.getJSON(); + const wikis = json.content?.[0]?.content?.filter( + (n: any) => n.type === 'wikilink', + ); + expect(wikis).toHaveLength(1); + expect(wikis![0].attrs.pageId).toBe('page-uuid-4'); + expect(wikis![0].attrs.title).toBe('Parsed Page'); + + editor.destroy(); + }); +}); diff --git a/apps/client/src/features/acadenice/wikilinks/extension/wikilink-extension.ts b/apps/client/src/features/acadenice/wikilinks/extension/wikilink-extension.ts new file mode 100644 index 00000000..4d8cf619 --- /dev/null +++ b/apps/client/src/features/acadenice/wikilinks/extension/wikilink-extension.ts @@ -0,0 +1,235 @@ +import { + Node, + nodeInputRule, + type NodeViewRendererProps, +} from '@tiptap/core'; +import { ReactNodeViewRenderer } from '@tiptap/react'; +import { Plugin, PluginKey } from '@tiptap/pm/state'; +import { Suggestion, type SuggestionOptions } from '@tiptap/suggestion'; +import { renderWikilinkSuggestion } from './wikilink-suggestion'; + +/** + * Wikilink Tiptap extension (R3.2). + * + * Implements the Obsidian-style [[Page Title]] and [[Page Title|alias]] syntax. + * + * Node attrs: + * - pageId : resolved UUID of the target page (null when unresolved) + * - title : canonical title of the target page + * - alias : optional display alias (text shown in editor) + * + * Rendering: + * - React NodeView: a styled link chip. + * - Unresolved (pageId === null): applies 'broken-wikilink' class (red / italic). + * + * Input rule: + * - Typing [[ opens the suggestion popup (reuses Tiptap Suggestion). + * - Pressing Esc or selecting a page closes the popup and inserts the node. + * + * The suggestion popup searches pages via `GET /api/search/suggestions?q=...` + * (same endpoint used by the native @mention system). + */ + +export interface WikilinkAttrs { + pageId: string | null; + title: string; + alias: string | null; +} + +const WIKILINK_INPUT_REGEX = /\[\[$/ as const; +const WIKILINK_PARSE_REGEX = + /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/ as const; + +declare module '@tiptap/core' { + interface Commands