This commit is contained in:
Timothy Jaeryang Baek 2025-09-14 18:08:31 -04:00
parent cae7ad8c70
commit 22e11760a1
4 changed files with 39 additions and 7 deletions

View file

@ -420,6 +420,22 @@ input[type='number'] {
content: '\200B'; content: '\200B';
} }
.tiptap .suggestion {
border-radius: 0.4rem;
box-decoration-break: clone;
padding: 0.1rem 0.3rem;
@apply bg-purple-100/20 text-purple-900 dark:bg-purple-500/20 dark:text-purple-100;
}
.tiptap .suggestion::after {
content: '\200B';
}
.tiptap .suggestion.is-empty::after {
content: '\00A0';
border-bottom: 1px dotted rgba(31, 41, 55, 0.12);
}
.input-prose .tiptap ul[data-type='taskList'] { .input-prose .tiptap ul[data-type='taskList'] {
list-style: none; list-style: none;
margin-left: 0; margin-left: 0;

View file

@ -15,7 +15,7 @@
const select = (index: number) => { const select = (index: number) => {
const item = filteredItems[index]; const item = filteredItems[index];
if (item) command(item); if (item) command({ id: item.id, label: item.name });
}; };
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {

View file

@ -91,6 +91,18 @@
} }
}); });
// Convert TipTap mention spans -> <@id>
turndownService.addRule('mentions', {
filter: (node) => node.nodeName === 'SPAN' && node.getAttribute('data-type') === 'mention',
replacement: (_content, node: HTMLElement) => {
const id = node.getAttribute('data-id') || '';
// TipTap stores the trigger char in data-mention-suggestion-char (usually "@")
const ch = node.getAttribute('data-mention-suggestion-char') || '@';
// Emit <@id> style, e.g. <@llama3.2:latest>
return `<${ch}${id}>`;
}
});
import { onMount, onDestroy, tick, getContext } from 'svelte'; import { onMount, onDestroy, tick, getContext } from 'svelte';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
@ -100,7 +112,7 @@
import { Fragment, DOMParser } from 'prosemirror-model'; import { Fragment, DOMParser } from 'prosemirror-model';
import { EditorState, Plugin, PluginKey, TextSelection, Selection } from 'prosemirror-state'; import { EditorState, Plugin, PluginKey, TextSelection, Selection } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view'; import { Decoration, DecorationSet } from 'prosemirror-view';
import { Editor, Extension } from '@tiptap/core'; import { Editor, Extension, mergeAttributes } from '@tiptap/core';
// Yjs imports // Yjs imports
import * as Y from 'yjs'; import * as Y from 'yjs';
@ -142,9 +154,6 @@
import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants'; import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
import { all, createLowlight } from 'lowlight'; import { all, createLowlight } from 'lowlight';
import MentionList from '../channel/MessageInput/MentionList.svelte';
import { getSuggestionRenderer } from './RichTextInput/suggestions.js';
export let oncompositionstart = (e) => {}; export let oncompositionstart = (e) => {};
export let oncompositionend = (e) => {}; export let oncompositionend = (e) => {};
export let onChange = (e) => {}; export let onChange = (e) => {};
@ -1054,7 +1063,6 @@
htmlValue = editor.getHTML(); htmlValue = editor.getHTML();
jsonValue = editor.getJSON(); jsonValue = editor.getJSON();
mdValue = turndownService mdValue = turndownService
.turndown( .turndown(
htmlValue htmlValue

View file

@ -19,6 +19,7 @@ export function getSuggestionRenderer(Component: any, ComponentProps = {}) {
target: container, target: container,
props: { props: {
char: props?.text, char: props?.text,
query: props?.query,
command: (item) => { command: (item) => {
props.command({ id: item.id, label: item.label }); props.command({ id: item.id, label: item.label });
}, },
@ -54,7 +55,14 @@ export function getSuggestionRenderer(Component: any, ComponentProps = {}) {
onUpdate: (props: any) => { onUpdate: (props: any) => {
if (!component) return; if (!component) return;
component.$set({ query: props.query });
component.$set({
query: props.query,
command: (item) => {
props.command({ id: item.id, label: item.label });
}
});
if (props.clientRect && popup) { if (props.clientRect && popup) {
popup.setProps({ getReferenceClientRect: props.clientRect as any }); popup.setProps({ getReferenceClientRect: props.clientRect as any });
} }