forked from coracle/flotilla
Use nostr-editor's tag extension
This commit is contained in:
@@ -3,9 +3,9 @@
|
|||||||
import type {Readable} from "svelte/store"
|
import type {Readable} from "svelte/store"
|
||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
|
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
|
||||||
import {NProfileExtension, ImageExtension} from "nostr-editor"
|
import {NProfileExtension, TagExtension as TopicExtension, ImageExtension} from "nostr-editor"
|
||||||
import {createEvent, CHAT_MESSAGE} from "@welshman/util"
|
import {createEvent, CHAT_MESSAGE} from "@welshman/util"
|
||||||
import {TopicExtension, findNodes} from "@lib/tiptap"
|
import {findNodes} from "@lib/tiptap"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import {publishThunk, makeThunk, userRelayUrlsByNom} from "@app/state"
|
import {publishThunk, makeThunk, userRelayUrlsByNom} from "@app/state"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
<NodeViewWrapper class="inline">
|
<NodeViewWrapper class="inline">
|
||||||
<Link
|
<Link
|
||||||
external
|
external
|
||||||
href="https://coracle.social/topics/{node.attrs.name.toLowerCase()}"
|
href="https://coracle.social/topics/{node.attrs.topic.toLowerCase()}"
|
||||||
class={cx("link-content", {"link-content-selected": selected})}>
|
class={cx("link-content", {"link-content-selected": selected})}>
|
||||||
#{node.attrs.name}
|
#{node.attrs.topic}
|
||||||
</Link>
|
</Link>
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
|
|||||||
+15
-1
@@ -1,3 +1,4 @@
|
|||||||
|
import cx from 'classnames'
|
||||||
import type {Writable} from "svelte/store"
|
import type {Writable} from "svelte/store"
|
||||||
import {nprofileEncode} from "nostr-tools/nip19"
|
import {nprofileEncode} from "nostr-tools/nip19"
|
||||||
import {SvelteNodeViewRenderer} from "svelte-tiptap"
|
import {SvelteNodeViewRenderer} from "svelte-tiptap"
|
||||||
@@ -19,9 +20,10 @@ import {
|
|||||||
ImageExtension,
|
ImageExtension,
|
||||||
VideoExtension,
|
VideoExtension,
|
||||||
FileUploadExtension,
|
FileUploadExtension,
|
||||||
|
TagExtension as TopicExtension,
|
||||||
} from "nostr-editor"
|
} from "nostr-editor"
|
||||||
import type {StampedEvent} from "@welshman/util"
|
import type {StampedEvent} from "@welshman/util"
|
||||||
import {LinkExtension, TopicExtension, asInline, createSuggestions} from "@lib/tiptap"
|
import {LinkExtension, asInline, createSuggestions} from "@lib/tiptap"
|
||||||
import GroupComposeMention from "@app/components/GroupComposeMention.svelte"
|
import GroupComposeMention from "@app/components/GroupComposeMention.svelte"
|
||||||
import GroupComposeTopic from "@app/components/GroupComposeTopic.svelte"
|
import GroupComposeTopic from "@app/components/GroupComposeTopic.svelte"
|
||||||
import GroupComposeEvent from "@app/components/GroupComposeEvent.svelte"
|
import GroupComposeEvent from "@app/components/GroupComposeEvent.svelte"
|
||||||
@@ -113,6 +115,18 @@ export const getChatEditorOptions = ({uploading, sendMessage}: ChatComposeEditor
|
|||||||
).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}),
|
).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}),
|
||||||
TopicExtension.extend({
|
TopicExtension.extend({
|
||||||
addNodeView: () => SvelteNodeViewRenderer(GroupComposeTopic),
|
addNodeView: () => SvelteNodeViewRenderer(GroupComposeTopic),
|
||||||
|
renderHTML({mark, HTMLAttributes}) {
|
||||||
|
const attrs = {
|
||||||
|
...mark.attrs,
|
||||||
|
...HTMLAttributes,
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener noreferer',
|
||||||
|
href: `https://coracle.social/topics/${mark.attrs.tag.toLowerCase()}`,
|
||||||
|
class: "underline",
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['a', attrs, 0]
|
||||||
|
},
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
return [
|
return [
|
||||||
createSuggestions({
|
createSuggestions({
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
import {Node, nodePasteRule} from "@tiptap/core"
|
|
||||||
import type {Node as ProsemirrorNode} from "@tiptap/pm/model"
|
|
||||||
import type {MarkdownSerializerState} from "prosemirror-markdown"
|
|
||||||
import {createPasteRuleMatch} from "@lib/tiptap/util"
|
|
||||||
|
|
||||||
export const TOPIC_REGEX = /(?:^|\s)(#[^\s]+)/g
|
|
||||||
|
|
||||||
export interface TopicAttributes {
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "@tiptap/core" {
|
|
||||||
interface Commands<ReturnType> {
|
|
||||||
topic: {
|
|
||||||
insertTopic: (options: {name: string}) => ReturnType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TopicExtension = Node.create({
|
|
||||||
atom: true,
|
|
||||||
name: "topic",
|
|
||||||
group: "inline",
|
|
||||||
inline: true,
|
|
||||||
selectable: true,
|
|
||||||
draggable: true,
|
|
||||||
priority: 1000,
|
|
||||||
addAttributes() {
|
|
||||||
return {
|
|
||||||
name: {default: null},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderText(props) {
|
|
||||||
return "#" + props.node.attrs.name
|
|
||||||
},
|
|
||||||
addStorage() {
|
|
||||||
return {
|
|
||||||
markdown: {
|
|
||||||
serialize(state: MarkdownSerializerState, node: ProsemirrorNode) {
|
|
||||||
state.write(node.attrs.name)
|
|
||||||
},
|
|
||||||
parse: {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addCommands() {
|
|
||||||
return {
|
|
||||||
insertTopic:
|
|
||||||
({name}) =>
|
|
||||||
({commands}) => {
|
|
||||||
return commands.insertContent(
|
|
||||||
{type: this.name, attrs: {name}},
|
|
||||||
{
|
|
||||||
updateSelection: false,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addPasteRules() {
|
|
||||||
return [
|
|
||||||
nodePasteRule({
|
|
||||||
type: this.type,
|
|
||||||
getAttributes: match => match.data,
|
|
||||||
find: text => {
|
|
||||||
const matches = []
|
|
||||||
|
|
||||||
for (const match of text.matchAll(TOPIC_REGEX)) {
|
|
||||||
try {
|
|
||||||
matches.push(createPasteRuleMatch(match, {name: match[0]}))
|
|
||||||
} catch (e) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matches
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from "@lib/tiptap/util"
|
export * from "@lib/tiptap/util"
|
||||||
export {createSuggestions} from "@lib/tiptap/Suggestions"
|
export {createSuggestions} from "@lib/tiptap/Suggestions"
|
||||||
export {TopicExtension} from "@lib/tiptap/TopicExtension"
|
|
||||||
export {LinkExtension} from "@lib/tiptap/LinkExtension"
|
export {LinkExtension} from "@lib/tiptap/LinkExtension"
|
||||||
|
|||||||
Reference in New Issue
Block a user