From dc4dcb1ea215cb81573abd4dd47a6858c2867919 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Thu, 22 Aug 2024 16:16:35 -0700 Subject: [PATCH] Work on compose --- src/app.css | 12 +- src/app/components/GroupCompose.svelte | 131 ++++++++++-------- src/app/components/GroupComposeImage.svelte | 3 +- src/app/components/GroupComposeMention.svelte | 2 +- .../GroupComposeProfileSuggestion.svelte | 8 +- .../components/GroupComposeSuggestions.svelte | 12 +- src/lib/tiptap/LinkExtension.ts | 16 +-- src/lib/tiptap/Mention.ts | 3 - src/lib/tiptap/{common.ts => Suggestions.ts} | 68 ++++----- src/lib/tiptap/Topic.ts | 3 - src/lib/tiptap/index.ts | 21 ++- src/lib/util.ts | 9 +- 12 files changed, 159 insertions(+), 129 deletions(-) delete mode 100644 src/lib/tiptap/Mention.ts rename src/lib/tiptap/{common.ts => Suggestions.ts} (70%) delete mode 100644 src/lib/tiptap/Topic.ts diff --git a/src/app.css b/src/app.css index 52fc1b6f..f77d4e0a 100644 --- a/src/app.css +++ b/src/app.css @@ -84,8 +84,18 @@ @apply shadow-[0_20px_25px_-5px_rgb(0,0,0,0.1)_0_8px_10px_-6px_rgb(0,0,0,0.1)]; } +/* tiptap */ + .tiptap { - @apply rounded-box bg-base-100 px-4 p-2; + @apply rounded-box bg-base-300 px-4 p-2 max-h-[350px] overflow-y-auto; +} + +.tiptap pre code { + @apply link-content w-full block; +} + +.tiptap p code { + @apply link-content; } .link-content { diff --git a/src/app/components/GroupCompose.svelte b/src/app/components/GroupCompose.svelte index 7851043a..d2533b23 100644 --- a/src/app/components/GroupCompose.svelte +++ b/src/app/components/GroupCompose.svelte @@ -2,10 +2,15 @@ import {onMount} from 'svelte' import type {Readable} from 'svelte/store' import {createEditor, type Editor, EditorContent, SvelteNodeViewRenderer} from 'svelte-tiptap' + import {Extension} from '@tiptap/core' import StarterKit from '@tiptap/starter-kit' + import HardBreakExtension from '@tiptap/extension-hard-break' import {NostrExtension} from 'nostr-editor' import type {StampedEvent} from '@welshman/util' - import {LinkExtension, Mention, Topic} from '@lib/tiptap' + import {createEvent, CHAT_MESSAGE} from '@welshman/util' + import {LinkExtension, createSuggestions, findNodes} from '@lib/tiptap' + import Icon from '@lib/components/Icon.svelte' + import Button from '@lib/components/Button.svelte' import GroupComposeMention from '@app/components/GroupComposeMention.svelte' import GroupComposeEvent from '@app/components/GroupComposeEvent.svelte' import GroupComposeImage from '@app/components/GroupComposeImage.svelte' @@ -19,12 +24,31 @@ import {searchProfiles, searchTopics, displayProfileByPubkey} from '@app/state' let editor: Readable + let uploading = false const asInline = (extend: Record) => ({inline: true, group: 'inline', ...extend}) + const addFile = () => $editor.chain().selectFiles().run() + + const uploadFiles = () => $editor.chain().uploadFiles().run() + + const sendMessage = () => { + console.log($editor.getJSON()) + console.log(findNodes($editor.getJSON(), 'mention')) + console.log(findNodes($editor.getJSON(), 'nprofile')) + console.log(findNodes($editor.getJSON(), 'nevent')) + console.log(findNodes($editor.getJSON(), 'naddr')) + console.log(findNodes($editor.getJSON(), 'image')) + createEvent(CHAT_MESSAGE, { + content: '', + tags: [], + }) + } + onMount(() => { editor = createEditor({ + autofocus: true, extensions: [ StarterKit.configure({ blockquote: false, @@ -36,6 +60,19 @@ listItem: false, orderedList: false, strike: false, + hardBreak: false, + }), + HardBreakExtension.extend({ + addKeyboardShortcuts() { + return { + 'Shift-Enter': () => this.editor.commands.setHardBreak(), + 'Mod-Enter': () => { + uploadFiles() + + return true + }, + } + } }), LinkExtension.extend({ addNodeView: () => SvelteNodeViewRenderer(GroupComposeLink), @@ -56,70 +93,56 @@ image: {defaultUploadUrl: 'https://nostr.build', defaultUploadType: 'nip96'}, fileUpload: { immediateUpload: false, - sign: async (event: StampedEvent) => $signer!.sign(event), - onDrop() { - // setPending(true) + sign: (event: StampedEvent) => { + uploading = true + + return $signer!.sign(event) }, - onComplete(currentEditor: any) { - console.log('Upload Completed', currentEditor.getText()) - // setPending(false) + onComplete: () => { + uploading = false + sendMessage() }, }, }), - Mention.configure( - (() => { - let suggestions: GroupComposeSuggestions - - const mapProps = (props: any) => ({ - term: props.query, - select: (id: string) => props.command({id}), - search: searchProfiles, - component: GroupComposeProfileSuggestion, - }) - - return { - getLabel: displayProfileByPubkey, - tippyOptions: {arrow: false, theme: "transparent"}, - onStart: ({target, props}) => { - suggestions = new GroupComposeSuggestions({target, props: mapProps(props)}) - }, - onUpdate: ({props}) => suggestions.$set(mapProps(props)), - onKeyDown: ({event}) => suggestions.onKeyDown(event), - onExit: () => suggestions.$destroy(), - } - })(), - ), - Topic.configure( - (() => { - let suggestions: GroupComposeSuggestions - - const mapProps = (props: any) => ({ - term: props.query, - select: (id: string) => props.command({id}), - search: searchTopics, - component: GroupComposeTopicSuggestion, - }) - - return { - tippyOptions: {arrow: false, theme: "transparent"}, - onStart: ({target, props}) => { - suggestions = new GroupComposeSuggestions({target, props: mapProps(props)}) - }, - onUpdate: ({props}) => suggestions.$set(mapProps(props)), - onKeyDown: ({event}) => suggestions.onKeyDown(event), - onExit: () => suggestions.$destroy(), - } - })(), - ), + createSuggestions('mention').configure({ + char: '@', + search: searchProfiles, + select: (pubkey: string, props: any) => props.command({pubkey}), + suggestionComponent: GroupComposeProfileSuggestion, + suggestionsComponent: GroupComposeSuggestions, + }).extend({ + addAttributes: () => ({pubkey: {default: null}}), + addNodeView: () => SvelteNodeViewRenderer(GroupComposeMention), + }), + createSuggestions('topic').configure({ + char: '#', + search: searchTopics, + select: (name: string, props: any) => props.command({name}), + suggestionComponent: GroupComposeTopicSuggestion, + suggestionsComponent: GroupComposeSuggestions, + }).extend({ + addAttributes: () => ({name: {default: null}}), + addNodeView: () => SvelteNodeViewRenderer(GroupComposeMention), + }), ], content: '', onUpdate: () => { // console.log('update', $editor.getJSON(), $editor.getText()) }, }) + console.log($editor) }) -
- +
+ +
+ +
diff --git a/src/app/components/GroupComposeImage.svelte b/src/app/components/GroupComposeImage.svelte index 4a0487b7..2b8fe970 100644 --- a/src/app/components/GroupComposeImage.svelte +++ b/src/app/components/GroupComposeImage.svelte @@ -5,9 +5,10 @@ import Icon from '@lib/components/Icon.svelte' export let node: NodeViewProps['node'] + export let selected: NodeViewProps['selected'] - + {node.attrs.file.name} diff --git a/src/app/components/GroupComposeMention.svelte b/src/app/components/GroupComposeMention.svelte index cc14aeef..d50b8b52 100644 --- a/src/app/components/GroupComposeMention.svelte +++ b/src/app/components/GroupComposeMention.svelte @@ -12,5 +12,5 @@ - @{displayProfile($profile)} + @{displayProfile($profile)} diff --git a/src/app/components/GroupComposeProfileSuggestion.svelte b/src/app/components/GroupComposeProfileSuggestion.svelte index a8758cd5..c60e3f83 100644 --- a/src/app/components/GroupComposeProfileSuggestion.svelte +++ b/src/app/components/GroupComposeProfileSuggestion.svelte @@ -1,7 +1,9 @@ -
- @{value} -
+@{$display} diff --git a/src/app/components/GroupComposeSuggestions.svelte b/src/app/components/GroupComposeSuggestions.svelte index d3ba72fd..0d1610ec 100644 --- a/src/app/components/GroupComposeSuggestions.svelte +++ b/src/app/components/GroupComposeSuggestions.svelte @@ -4,6 +4,7 @@ import {throttle} from "throttle-debounce" import {slide} from "svelte/transition" import {clamp} from "@welshman/lib" + import {theme} from '@app/theme' export let term export let search @@ -53,16 +54,15 @@ {#if items.length > 0}
+ class="mt-2 flex max-h-[350px] flex-col overflow-y-auto overflow-x-hidden shadow-xl"> {#each items as value, i (value)}