diff --git a/components/tiptap/TiptapHashtagList.vue b/components/tiptap/TiptapHashtagList.vue
new file mode 100644
index 00000000..15e57c92
--- /dev/null
+++ b/components/tiptap/TiptapHashtagList.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
diff --git a/composables/tiptap.ts b/composables/tiptap.ts
index fa610a31..fe3d9ae0 100644
--- a/composables/tiptap.ts
+++ b/composables/tiptap.ts
@@ -12,7 +12,7 @@ import Code from '@tiptap/extension-code'
import { Plugin } from 'prosemirror-state'
import type { Ref } from 'vue'
-import { HashSuggestion, MentionSuggestion } from './tiptap/suggestion'
+import { HashtagSuggestion, MentionSuggestion } from './tiptap/suggestion'
import { CodeBlockShiki } from './tiptap/shiki'
import { CustomEmoji } from './tiptap/custom-emoji'
import { Emoji } from './tiptap/emoji'
@@ -54,9 +54,9 @@ export function useTiptap(options: UseTiptapOptions) {
suggestion: MentionSuggestion,
}),
Mention
- .extend({ name: 'hastag' })
+ .extend({ name: 'hashtag' })
.configure({
- suggestion: HashSuggestion,
+ suggestion: HashtagSuggestion,
}),
Placeholder.configure({
placeholder: placeholder.value,
diff --git a/composables/tiptap/suggestion.ts b/composables/tiptap/suggestion.ts
index 7b8975e7..7445164a 100644
--- a/composables/tiptap/suggestion.ts
+++ b/composables/tiptap/suggestion.ts
@@ -3,7 +3,9 @@ import tippy from 'tippy.js'
import { VueRenderer } from '@tiptap/vue-3'
import type { SuggestionOptions } from '@tiptap/suggestion'
import { PluginKey } from 'prosemirror-state'
+import type { Component } from 'vue'
import TiptapMentionList from '~/components/tiptap/TiptapMentionList.vue'
+import TiptapHashtagList from '~/components/tiptap/TiptapHashtagList.vue'
export const MentionSuggestion: Partial = {
pluginKey: new PluginKey('mention'),
@@ -17,29 +19,32 @@ export const MentionSuggestion: Partial = {
return results.value.accounts
},
- render: createSuggestionRenderer(),
+ render: createSuggestionRenderer(TiptapMentionList),
}
-export const HashSuggestion: Partial = {
+export const HashtagSuggestion: Partial = {
pluginKey: new PluginKey('hashtag'),
char: '#',
- items({ query }) {
- // TODO: query
- return [
- 'TODO HASH QUERY',
- ].filter(item => item.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5)
+ async items({ query }) {
+ if (query.length === 0)
+ return []
+
+ const paginator = useMasto().search({ q: query, type: 'hashtags', limit: 25, resolve: true })
+ const results = await paginator.next()
+
+ return results.value.hashtags
},
- render: createSuggestionRenderer(),
+ render: createSuggestionRenderer(TiptapHashtagList),
}
-function createSuggestionRenderer(): SuggestionOptions['render'] {
+function createSuggestionRenderer(component: Component): SuggestionOptions['render'] {
return () => {
- let component: VueRenderer
+ let renderer: VueRenderer
let popup: Instance
return {
onStart(props) {
- component = new VueRenderer(TiptapMentionList, {
+ renderer = new VueRenderer(component, {
props,
editor: props.editor,
})
@@ -50,7 +55,7 @@ function createSuggestionRenderer(): SuggestionOptions['render'] {
popup = tippy(document.body, {
getReferenceClientRect: props.clientRect as GetReferenceClientRect,
appendTo: () => document.body,
- content: component.element,
+ content: renderer.element,
showOnCreate: true,
interactive: true,
trigger: 'manual',
@@ -60,11 +65,11 @@ function createSuggestionRenderer(): SuggestionOptions['render'] {
// Use arrow function here because Nuxt will transform it incorrectly as Vue hook causing the build to fail
onBeforeUpdate: (props) => {
- component.updateProps({ ...props, isPending: true })
+ renderer.updateProps({ ...props, isPending: true })
},
onUpdate(props) {
- component.updateProps({ ...props, isPending: false })
+ renderer.updateProps({ ...props, isPending: false })
if (!props.clientRect)
return
@@ -79,12 +84,12 @@ function createSuggestionRenderer(): SuggestionOptions['render'] {
popup?.hide()
return true
}
- return component?.ref?.onKeyDown(props.event)
+ return renderer?.ref?.onKeyDown(props.event)
},
onExit() {
popup?.destroy()
- component?.destroy()
+ renderer?.destroy()
},
}
}
diff --git a/styles/tiptap.css b/styles/tiptap.css
index 606e19f9..5ba87138 100644
--- a/styles/tiptap.css
+++ b/styles/tiptap.css
@@ -6,6 +6,7 @@
opacity: 0.4;
}
-span[data-type='mention'] {
+span[data-type='mention'],
+span[data-type='hashtag'] {
--at-apply: text-primary;
}