forked from coracle/flotilla
Lint
This commit is contained in:
@@ -1,45 +1,57 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from 'svelte'
|
||||
import type {Readable} from 'svelte/store'
|
||||
import {nprofileEncode} from 'nostr-tools/nip19'
|
||||
import {createEditor, type Editor, EditorContent, SvelteNodeViewRenderer} from 'svelte-tiptap'
|
||||
import {Extension} from '@tiptap/core'
|
||||
import Code from '@tiptap/extension-code'
|
||||
import CodeBlock from '@tiptap/extension-code-block'
|
||||
import Document from '@tiptap/extension-document'
|
||||
import Dropcursor from '@tiptap/extension-dropcursor'
|
||||
import Gapcursor from '@tiptap/extension-gapcursor'
|
||||
import History from '@tiptap/extension-history'
|
||||
import Paragraph from '@tiptap/extension-paragraph'
|
||||
import Text from '@tiptap/extension-text'
|
||||
import HardBreakExtension from '@tiptap/extension-hard-break'
|
||||
import {Bolt11Extension, NProfileExtension, NEventExtension, NAddrExtension, ImageExtension, VideoExtension, FileUploadExtension} from 'nostr-editor'
|
||||
import type {StampedEvent} from '@welshman/util'
|
||||
import {createEvent, CHAT_MESSAGE} from '@welshman/util'
|
||||
import {LinkExtension, TopicExtension, 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 GroupComposeTopic from '@app/components/GroupComposeTopic.svelte'
|
||||
import GroupComposeEvent from '@app/components/GroupComposeEvent.svelte'
|
||||
import GroupComposeImage from '@app/components/GroupComposeImage.svelte'
|
||||
import GroupComposeBolt11 from '@app/components/GroupComposeBolt11.svelte'
|
||||
import GroupComposeVideo from '@app/components/GroupComposeVideo.svelte'
|
||||
import GroupComposeLink from '@app/components/GroupComposeLink.svelte'
|
||||
import GroupComposeSuggestions from '@app/components/GroupComposeSuggestions.svelte'
|
||||
import GroupComposeTopicSuggestion from '@app/components/GroupComposeTopicSuggestion.svelte'
|
||||
import GroupComposeProfileSuggestion from '@app/components/GroupComposeProfileSuggestion.svelte'
|
||||
import {signer, INDEXER_RELAYS} from '@app/base'
|
||||
import {searchProfiles, publishThunk, makeThunk, searchTopics, userRelayUrlsByNom, getWriteRelayUrls, displayProfileByPubkey, getRelaySelectionsByPubkey} from '@app/state'
|
||||
import {getPubkeyHints, makeMention, makeIMeta} from '@app/commands'
|
||||
import {onMount} from "svelte"
|
||||
import type {Readable} from "svelte/store"
|
||||
import {nprofileEncode} from "nostr-tools/nip19"
|
||||
import {createEditor, type Editor, EditorContent, SvelteNodeViewRenderer} from "svelte-tiptap"
|
||||
import Code from "@tiptap/extension-code"
|
||||
import CodeBlock from "@tiptap/extension-code-block"
|
||||
import Document from "@tiptap/extension-document"
|
||||
import Dropcursor from "@tiptap/extension-dropcursor"
|
||||
import Gapcursor from "@tiptap/extension-gapcursor"
|
||||
import History from "@tiptap/extension-history"
|
||||
import Paragraph from "@tiptap/extension-paragraph"
|
||||
import Text from "@tiptap/extension-text"
|
||||
import HardBreakExtension from "@tiptap/extension-hard-break"
|
||||
import {
|
||||
Bolt11Extension,
|
||||
NProfileExtension,
|
||||
NEventExtension,
|
||||
NAddrExtension,
|
||||
ImageExtension,
|
||||
VideoExtension,
|
||||
FileUploadExtension,
|
||||
} from "nostr-editor"
|
||||
import type {StampedEvent} from "@welshman/util"
|
||||
import {createEvent, CHAT_MESSAGE} from "@welshman/util"
|
||||
import {LinkExtension, TopicExtension, 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 GroupComposeTopic from "@app/components/GroupComposeTopic.svelte"
|
||||
import GroupComposeEvent from "@app/components/GroupComposeEvent.svelte"
|
||||
import GroupComposeImage from "@app/components/GroupComposeImage.svelte"
|
||||
import GroupComposeBolt11 from "@app/components/GroupComposeBolt11.svelte"
|
||||
import GroupComposeVideo from "@app/components/GroupComposeVideo.svelte"
|
||||
import GroupComposeLink from "@app/components/GroupComposeLink.svelte"
|
||||
import GroupComposeSuggestions from "@app/components/GroupComposeSuggestions.svelte"
|
||||
import GroupComposeTopicSuggestion from "@app/components/GroupComposeTopicSuggestion.svelte"
|
||||
import GroupComposeProfileSuggestion from "@app/components/GroupComposeProfileSuggestion.svelte"
|
||||
import {signer} from "@app/base"
|
||||
import {
|
||||
searchProfiles,
|
||||
publishThunk,
|
||||
makeThunk,
|
||||
searchTopics,
|
||||
userRelayUrlsByNom,
|
||||
} from "@app/state"
|
||||
import {getPubkeyHints, makeMention, makeIMeta} from "@app/commands"
|
||||
|
||||
export let nom
|
||||
|
||||
let editor: Readable<Editor>
|
||||
let uploading = false
|
||||
|
||||
const asInline = (extend: Record<string, any>) =>
|
||||
({inline: true, group: 'inline', ...extend})
|
||||
const asInline = (extend: Record<string, any>) => ({inline: true, group: "inline", ...extend})
|
||||
|
||||
const addFile = () => $editor.chain().selectFiles().run()
|
||||
|
||||
@@ -53,8 +65,12 @@
|
||||
tags: [
|
||||
["h", nom],
|
||||
...findNodes(TopicExtension.name, json).map(t => ["t", t.attrs!.name.toLowerCase()]),
|
||||
...findNodes(NProfileExtension.name, json).map(m => makeMention(m.attrs!.pubkey, m.attrs!.relays)),
|
||||
...findNodes(ImageExtension.name, json).map(({attrs: {src, sha256: x}}: any) => makeIMeta(src, {x, ox: x})),
|
||||
...findNodes(NProfileExtension.name, json).map(m =>
|
||||
makeMention(m.attrs!.pubkey, m.attrs!.relays),
|
||||
),
|
||||
...findNodes(ImageExtension.name, json).map(({attrs: {src, sha256: x}}: any) =>
|
||||
makeIMeta(src, {x, ox: x}),
|
||||
),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -78,9 +94,9 @@
|
||||
HardBreakExtension.extend({
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
'Shift-Enter': () => this.editor.commands.setHardBreak(),
|
||||
'Mod-Enter': () => this.editor.commands.setHardBreak(),
|
||||
'Enter': () => {
|
||||
"Shift-Enter": () => this.editor.commands.setHardBreak(),
|
||||
"Mod-Enter": () => this.editor.commands.setHardBreak(),
|
||||
Enter: () => {
|
||||
if (this.editor.getText().trim()) {
|
||||
uploadFiles()
|
||||
|
||||
@@ -90,19 +106,21 @@
|
||||
return false
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
LinkExtension.extend({
|
||||
addNodeView: () => SvelteNodeViewRenderer(GroupComposeLink),
|
||||
}),
|
||||
Bolt11Extension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeBolt11)})),
|
||||
Bolt11Extension.extend(
|
||||
asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeBolt11)}),
|
||||
),
|
||||
NProfileExtension.extend({
|
||||
addNodeView: () => SvelteNodeViewRenderer(GroupComposeMention),
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
createSuggestions({
|
||||
char: '@',
|
||||
name: 'nprofile',
|
||||
char: "@",
|
||||
name: "nprofile",
|
||||
editor: this.editor,
|
||||
search: searchProfiles,
|
||||
select: (pubkey: string, props: any) => {
|
||||
@@ -115,23 +133,27 @@
|
||||
suggestionsComponent: GroupComposeSuggestions,
|
||||
}),
|
||||
]
|
||||
}
|
||||
},
|
||||
}),
|
||||
NEventExtension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeEvent)})),
|
||||
NAddrExtension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeEvent)})),
|
||||
ImageExtension
|
||||
.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeImage)}))
|
||||
.configure({defaultUploadUrl: 'https://nostr.build', defaultUploadType: 'nip96'}),
|
||||
VideoExtension
|
||||
.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeVideo)}))
|
||||
.configure({defaultUploadUrl: 'https://nostr.build', defaultUploadType: 'nip96'}),
|
||||
NEventExtension.extend(
|
||||
asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeEvent)}),
|
||||
),
|
||||
NAddrExtension.extend(
|
||||
asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeEvent)}),
|
||||
),
|
||||
ImageExtension.extend(
|
||||
asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeImage)}),
|
||||
).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}),
|
||||
VideoExtension.extend(
|
||||
asInline({addNodeView: () => SvelteNodeViewRenderer(GroupComposeVideo)}),
|
||||
).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}),
|
||||
TopicExtension.extend({
|
||||
addNodeView: () => SvelteNodeViewRenderer(GroupComposeTopic),
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
createSuggestions({
|
||||
char: '#',
|
||||
name: 'topic',
|
||||
char: "#",
|
||||
name: "topic",
|
||||
editor: this.editor,
|
||||
search: searchTopics,
|
||||
select: (name: string, props: any) => props.command({name}),
|
||||
@@ -155,13 +177,16 @@
|
||||
},
|
||||
}),
|
||||
],
|
||||
content: '',
|
||||
content: "",
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex gap-2 relative z-feature border-t border-solid border-base-100 p-2 shadow-top-xl bg-base-100">
|
||||
<Button on:click={addFile} class="bg-base-300 rounded-box w-10 h-10 center hover:bg-base-200 transition-colors">
|
||||
<div
|
||||
class="shadow-top-xl relative z-feature flex gap-2 border-t border-solid border-base-100 bg-base-100 p-2">
|
||||
<Button
|
||||
on:click={addFile}
|
||||
class="center h-10 w-10 rounded-box bg-base-300 transition-colors hover:bg-base-200">
|
||||
{#if uploading}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import Icon from '@lib/components/Icon.svelte'
|
||||
import Button from '@lib/components/Button.svelte'
|
||||
import {clip} from '@app/toast'
|
||||
import cx from "classnames"
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import {clip} from "@app/toast"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let selected: NodeViewProps['selected']
|
||||
export let node: NodeViewProps["node"]
|
||||
export let selected: NodeViewProps["selected"]
|
||||
|
||||
const copy = () => clip(node.attrs.lnbc)
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class="inline">
|
||||
<Button on:click={copy} class={cx("link-content", {'link-content-selected': selected})}>
|
||||
<Button on:click={copy} class={cx("link-content", {"link-content-selected": selected})}>
|
||||
<Icon icon="bolt" size={3} class="inline-block translate-y-px" />
|
||||
{node.attrs.lnbc.slice(0, 16)}...
|
||||
</Button>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import {ellipsize} from '@welshman/lib'
|
||||
import {type TrustedEvent, fromNostrURI, Address} from '@welshman/util'
|
||||
import Link from '@lib/components/Link.svelte'
|
||||
import {deriveEvent} from '@app/state'
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import {ellipsize} from "@welshman/lib"
|
||||
import {type TrustedEvent, fromNostrURI, Address} from "@welshman/util"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import {deriveEvent} from "@app/state"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let node: NodeViewProps["node"]
|
||||
|
||||
const displayEvent = (e: TrustedEvent) =>
|
||||
e?.content.length > 1 ? ellipsize(e.content, 50) : fromNostrURI(nevent || naddr).slice(0, 16) + '...'
|
||||
e?.content.length > 1
|
||||
? ellipsize(e.content, 50)
|
||||
: fromNostrURI(nevent || naddr).slice(0, 16) + "..."
|
||||
|
||||
$: ({identifier, pubkey, kind, id, relays = [], nevent, naddr} = node.attrs)
|
||||
$: event = deriveEvent(id || new Address(kind, pubkey, identifier).toString(), relays)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import Icon from '@lib/components/Icon.svelte'
|
||||
import cx from "classnames"
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let selected: NodeViewProps['selected']
|
||||
export let node: NodeViewProps["node"]
|
||||
export let selected: NodeViewProps["selected"]
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class={cx("inline link-content", {'link-content-selected': selected})}>
|
||||
<NodeViewWrapper class={cx("link-content inline", {"link-content-selected": selected})}>
|
||||
<Icon icon="paperclip" size={3} class="inline-block translate-y-px" />
|
||||
{node.attrs.file.name}
|
||||
</NodeViewWrapper>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import {displayUrl} from '@welshman/lib'
|
||||
import Icon from '@lib/components/Icon.svelte'
|
||||
import Link from '@lib/components/Link.svelte'
|
||||
import cx from "classnames"
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import {displayUrl} from "@welshman/lib"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let selected: NodeViewProps['selected']
|
||||
export let node: NodeViewProps["node"]
|
||||
export let selected: NodeViewProps["selected"]
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class="inline">
|
||||
<Link external href={node.attrs.url} class={cx("link-content", {'link-content-selected': selected})}>
|
||||
<Link
|
||||
external
|
||||
href={node.attrs.url}
|
||||
class={cx("link-content", {"link-content-selected": selected})}>
|
||||
<Icon icon="link-round" size={3} class="inline-block translate-y-px" />
|
||||
{displayUrl(node.attrs.url)}
|
||||
</Link>
|
||||
</NodeViewWrapper>
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import {displayProfile} from '@welshman/util'
|
||||
import Link from '@lib/components/Link.svelte'
|
||||
import {deriveProfile} from '@app/state'
|
||||
import cx from "classnames"
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import {displayProfile} from "@welshman/util"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import {deriveProfile} from "@app/state"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let selected: NodeViewProps['selected']
|
||||
export let node: NodeViewProps["node"]
|
||||
export let selected: NodeViewProps["selected"]
|
||||
|
||||
$: profile = deriveProfile(node.attrs.pubkey, node.attrs.relays)
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class="inline">
|
||||
<Link external href="https://njump.me/{node.attrs.nprofile}" class={cx("link-content", {'link-content-selected': selected})}>
|
||||
<Link
|
||||
external
|
||||
href="https://njump.me/{node.attrs.nprofile}"
|
||||
class={cx("link-content", {"link-content-selected": selected})}>
|
||||
@{displayProfile($profile)}
|
||||
</Link>
|
||||
</NodeViewWrapper>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {deriveProfileDisplay} from '@app/state'
|
||||
import {deriveProfileDisplay} from "@app/state"
|
||||
|
||||
export let value
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import {throttle} from "throttle-debounce"
|
||||
import {slide} from "svelte/transition"
|
||||
import {clamp} from "@welshman/lib"
|
||||
import {theme} from '@app/theme'
|
||||
import {theme} from "@app/theme"
|
||||
|
||||
export let term
|
||||
export let search
|
||||
@@ -23,13 +23,13 @@
|
||||
items = $search.searchValues(term).slice(0, 30)
|
||||
})
|
||||
|
||||
const setIndex = (newIndex: number, block: ScrollLogicalPosition) => {
|
||||
const setIndex = (newIndex: number, block: any) => {
|
||||
index = clamp([0, items.length - 1], newIndex)
|
||||
element.querySelector(`button:nth-child(${index})`)?.scrollIntoView({block})
|
||||
}
|
||||
|
||||
export const onKeyDown = (e: any) => {
|
||||
if (['Enter', 'Tab'].includes(e.code)) {
|
||||
if (["Enter", "Tab"].includes(e.code)) {
|
||||
const value = items[index]
|
||||
|
||||
if (value) {
|
||||
@@ -41,7 +41,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (e.code === 'Space' && term && allowCreate) {
|
||||
if (e.code === "Space" && term && allowCreate) {
|
||||
select(term)
|
||||
return true
|
||||
}
|
||||
@@ -68,7 +68,7 @@
|
||||
class="mt-2 flex max-h-[350px] flex-col overflow-y-auto overflow-x-hidden shadow-xl">
|
||||
{#if term && allowCreate}
|
||||
<button
|
||||
class="cursor-pointer px-4 py-2 text-left hover:bg-primary hover:text-primary-content transition-colors white-space-nowrap overflow-hidden text-ellipsis min-w-0"
|
||||
class="white-space-nowrap min-w-0 cursor-pointer overflow-hidden text-ellipsis px-4 py-2 text-left transition-colors hover:bg-primary hover:text-primary-content"
|
||||
on:mousedown|preventDefault
|
||||
on:click|preventDefault={() => select(term)}>
|
||||
Use "<svelte:component this={component} value={term} />"
|
||||
@@ -76,7 +76,7 @@
|
||||
{/if}
|
||||
{#each items as value, i (value)}
|
||||
<button
|
||||
class="cursor-pointer px-4 py-2 text-left hover:bg-primary hover:text-primary-content transition-colors white-space-nowrap overflow-hidden text-ellipsis min-w-0"
|
||||
class="white-space-nowrap min-w-0 cursor-pointer overflow-hidden text-ellipsis px-4 py-2 text-left transition-colors hover:bg-primary hover:text-primary-content"
|
||||
class:bg-primary={index === i}
|
||||
class:text-primary-content={index === i}
|
||||
on:mousedown|preventDefault
|
||||
@@ -86,7 +86,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
{#if loading}
|
||||
<div transition:slide|local class="flex gap-2 bg-tinted-700 px-4 py-2 text-neutral-200">
|
||||
<div transition:slide|local class="bg-tinted-700 flex gap-2 px-4 py-2 text-neutral-200">
|
||||
<div>
|
||||
<i class="fa fa-circle-notch fa-spin" />
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import Link from '@lib/components/Link.svelte'
|
||||
import cx from "classnames"
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let selected: NodeViewProps['selected']
|
||||
export let node: NodeViewProps["node"]
|
||||
export let selected: NodeViewProps["selected"]
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class="inline">
|
||||
<Link external href="https://coracle.social/topics/{node.attrs.name.toLowerCase()}" class={cx("link-content", {'link-content-selected': selected})}>
|
||||
<Link
|
||||
external
|
||||
href="https://coracle.social/topics/{node.attrs.name.toLowerCase()}"
|
||||
class={cx("link-content", {"link-content-selected": selected})}>
|
||||
#{node.attrs.name}
|
||||
</Link>
|
||||
</NodeViewWrapper>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import type {NodeViewProps} from '@tiptap/core'
|
||||
import {NodeViewWrapper} from 'svelte-tiptap'
|
||||
import Icon from '@lib/components/Icon.svelte'
|
||||
import type {NodeViewProps} from "@tiptap/core"
|
||||
import {NodeViewWrapper} from "svelte-tiptap"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
|
||||
export let node: NodeViewProps['node']
|
||||
export let node: NodeViewProps["node"]
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper class="inline link-content">
|
||||
<NodeViewWrapper class="link-content inline">
|
||||
<Icon icon="paperclip" size={3} class="inline-block translate-y-px" />
|
||||
{node.attrs.file.name}
|
||||
</NodeViewWrapper>
|
||||
|
||||
@@ -5,13 +5,19 @@
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {deriveEvents} from "@welshman/store"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import {GROUP_REPLY, REACTION, ZAP_RESPONSE, displayRelayUrl, getAncestorTags, displayPubkey} from "@welshman/util"
|
||||
import {fly, fade} from "@lib/transition"
|
||||
import {formatTimestampAsTime} from '@lib/util'
|
||||
import {
|
||||
GROUP_REPLY,
|
||||
REACTION,
|
||||
ZAP_RESPONSE,
|
||||
displayRelayUrl,
|
||||
getAncestorTags,
|
||||
} from "@welshman/util"
|
||||
import {fly} from "@lib/transition"
|
||||
import {formatTimestampAsTime} from "@lib/util"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Avatar from "@lib/components/Avatar.svelte"
|
||||
import {repository} from '@app/base'
|
||||
import {repository} from "@app/base"
|
||||
import type {PublishStatusData} from "@app/state"
|
||||
import {deriveProfile, deriveProfileDisplay, deriveEvent, publishStatusData} from "@app/state"
|
||||
|
||||
@@ -19,31 +25,31 @@
|
||||
export let showPubkey: boolean
|
||||
|
||||
const colors = [
|
||||
['amber', twColors.amber[600]],
|
||||
['blue', twColors.blue[600]],
|
||||
['cyan', twColors.cyan[600]],
|
||||
['emerald', twColors.emerald[600]],
|
||||
['fuchsia', twColors.fuchsia[600]],
|
||||
['green', twColors.green[600]],
|
||||
['indigo', twColors.indigo[600]],
|
||||
['sky', twColors.sky[600]],
|
||||
['lime', twColors.lime[600]],
|
||||
['orange', twColors.orange[600]],
|
||||
['pink', twColors.pink[600]],
|
||||
['purple', twColors.purple[600]],
|
||||
['red', twColors.red[600]],
|
||||
['rose', twColors.rose[600]],
|
||||
['sky', twColors.sky[600]],
|
||||
['teal', twColors.teal[600]],
|
||||
['violet', twColors.violet[600]],
|
||||
['yellow', twColors.yellow[600]],
|
||||
['zinc', twColors.zinc[600]],
|
||||
["amber", twColors.amber[600]],
|
||||
["blue", twColors.blue[600]],
|
||||
["cyan", twColors.cyan[600]],
|
||||
["emerald", twColors.emerald[600]],
|
||||
["fuchsia", twColors.fuchsia[600]],
|
||||
["green", twColors.green[600]],
|
||||
["indigo", twColors.indigo[600]],
|
||||
["sky", twColors.sky[600]],
|
||||
["lime", twColors.lime[600]],
|
||||
["orange", twColors.orange[600]],
|
||||
["pink", twColors.pink[600]],
|
||||
["purple", twColors.purple[600]],
|
||||
["red", twColors.red[600]],
|
||||
["rose", twColors.rose[600]],
|
||||
["sky", twColors.sky[600]],
|
||||
["teal", twColors.teal[600]],
|
||||
["violet", twColors.violet[600]],
|
||||
["yellow", twColors.yellow[600]],
|
||||
["zinc", twColors.zinc[600]],
|
||||
]
|
||||
|
||||
const profile = deriveProfile(event.pubkey)
|
||||
const profileDisplay = deriveProfileDisplay(event.pubkey)
|
||||
const reactions = deriveEvents(repository, {filters: [{kinds: [REACTION], '#e': [event.id]}]})
|
||||
const zaps = deriveEvents(repository, {filters: [{kinds: [ZAP_RESPONSE], '#e': [event.id]}]})
|
||||
const reactions = deriveEvents(repository, {filters: [{kinds: [REACTION], "#e": [event.id]}]})
|
||||
const zaps = deriveEvents(repository, {filters: [{kinds: [ZAP_RESPONSE], "#e": [event.id]}]})
|
||||
const {replies} = getAncestorTags(event.tags)
|
||||
const parentId = replies[0]?.[1]
|
||||
const parentHints = [replies[0]?.[2]].filter(Boolean)
|
||||
@@ -52,8 +58,8 @@
|
||||
const ps = derived(publishStatusData, $m => Object.values($m[event.id] || {}))
|
||||
|
||||
const displayReaction = (content: string) => {
|
||||
if (content === '+') return "❤️"
|
||||
if (content === '-') return "👎"
|
||||
if (content === "+") return "❤️"
|
||||
if (content === "-") return "👎"
|
||||
return content
|
||||
}
|
||||
|
||||
@@ -65,7 +71,8 @@
|
||||
$: parentProfileDisplay = deriveProfileDisplay(parentPubkey)
|
||||
$: isPublished = findStatus($ps, [PublishStatus.Success])
|
||||
$: isPending = findStatus($ps, [PublishStatus.Pending]) && event.created_at > now() - 30
|
||||
$: failure = !isPending && !isPublished && findStatus($ps, [PublishStatus.Failure, PublishStatus.Timeout])
|
||||
$: failure =
|
||||
!isPending && !isPublished && findStatus($ps, [PublishStatus.Failure, PublishStatus.Timeout])
|
||||
</script>
|
||||
|
||||
<div in:fly class="group relative flex flex-col gap-1 p-2 transition-colors hover:bg-base-300">
|
||||
@@ -86,25 +93,26 @@
|
||||
{#if showPubkey}
|
||||
<Avatar src={$profile?.picture} class="border border-solid border-base-content" size={10} />
|
||||
{:else}
|
||||
<div class="min-w-10 max-w-10 w-10" />
|
||||
<div class="w-10 min-w-10 max-w-10" />
|
||||
{/if}
|
||||
<div class="-mt-1">
|
||||
{#if showPubkey}
|
||||
<div class="flex gap-2 items-center">
|
||||
<strong class="text-sm" style="color: {colorValue}" data-color={colorName}>{$profileDisplay}</strong>
|
||||
<span class="opacity-50 text-xs">{formatTimestampAsTime(event.created_at)}</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<strong class="text-sm" style="color: {colorValue}" data-color={colorName}
|
||||
>{$profileDisplay}</strong>
|
||||
<span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span>
|
||||
</div>
|
||||
{/if}
|
||||
<p class="text-sm">
|
||||
{event.content}
|
||||
{#if isPending}
|
||||
<span class="ml-1 flex-inline gap-1">
|
||||
<span class="loading loading-spinner h-3 w-3 mx-1 translate-y-px" />
|
||||
<span class="flex-inline ml-1 gap-1">
|
||||
<span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px" />
|
||||
<span class="opacity-50">Sending...</span>
|
||||
</span>
|
||||
{:else if failure}
|
||||
<span
|
||||
class="ml-1 flex-inline gap-1 tooltip cursor-pointer"
|
||||
class="flex-inline tooltip ml-1 cursor-pointer gap-1"
|
||||
data-tip="{failure.message} ({displayRelayUrl(failure.url)})">
|
||||
<Icon icon="danger" class="translate-y-px" size={3} />
|
||||
<span class="opacity-50">Failed to send!</span>
|
||||
@@ -114,9 +122,9 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if $reactions.length > 0 || $zaps.length > 0}
|
||||
<div class="text-xs ml-12">
|
||||
<div class="ml-12 text-xs">
|
||||
{#each groupBy(e => e.content, $reactions).entries() as [content, events]}
|
||||
<Button class="btn btn-neutral btn-xs rounded-full mr-2 flex-inline gap-1">
|
||||
<Button class="flex-inline btn btn-neutral btn-xs mr-2 gap-1 rounded-full">
|
||||
<span>{displayReaction(content)}</span>
|
||||
{#if events.length > 1}
|
||||
<span>{events.length}</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {displayRelayUrl} from '@welshman/util'
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import {first} from '@welshman/lib'
|
||||
import {makeSecret, getNip07, Nip46Broker} from "@welshman/signer"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
@@ -26,10 +25,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
const onSuccess = async (session: Session) => {
|
||||
const onSuccess = async (session: Session, relays: string[] = []) => {
|
||||
addSession(session)
|
||||
|
||||
await loadUserData(session.pubkey)
|
||||
await loadUserData(session.pubkey, relays)
|
||||
|
||||
pushToast({message: "Successfully logged in!"})
|
||||
clearModal()
|
||||
@@ -50,7 +49,7 @@
|
||||
const broker = Nip46Broker.get(pubkey, secret, handler)
|
||||
|
||||
if (await broker.connect("", nip46Perms)) {
|
||||
await onSuccess({method: "nip46", pubkey, secret, handler})
|
||||
await onSuccess({method: "nip46", pubkey, secret, handler}, relays)
|
||||
} else {
|
||||
pushToast({
|
||||
theme: "error",
|
||||
@@ -93,7 +92,12 @@
|
||||
<div class="flex items-center gap-2" slot="input">
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<Icon icon="user-rounded" />
|
||||
<input bind:value={username} disabled={loading} class="grow" type="text" placeholder="username" />
|
||||
<input
|
||||
bind:value={username}
|
||||
disabled={loading}
|
||||
class="grow"
|
||||
type="text"
|
||||
placeholder="username" />
|
||||
<span>@{handler.domain}</span>
|
||||
</label>
|
||||
{#if getNip07()}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative w-14 bg-base-100 flex-shrink-0 pt-4" bind:this={element}>
|
||||
<div class="relative w-14 flex-shrink-0 bg-base-100 pt-4" bind:this={element}>
|
||||
<div
|
||||
class="absolute z-nav-active ml-2 h-[144px] w-12 bg-base-300"
|
||||
style={`top: ${$activeOffset}px`} />
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<script lang="ts">
|
||||
import {append, remove} from "@welshman/lib"
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import {goto} from "$app/navigation"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import InfoNip29 from "@app/components/InfoNip29.svelte"
|
||||
import {pushModal, clearModal} from "@app/modal"
|
||||
import {pushToast} from "@app/toast"
|
||||
import type {PublishStatusData} from "@app/state"
|
||||
import {deriveGroup, displayGroup, relayUrlsByNom} from "@app/state"
|
||||
import {sendJoinRequest, addGroupMemberships} from "@app/commands"
|
||||
|
||||
@@ -30,7 +27,7 @@
|
||||
const [ok, message] = await sendJoinRequest(nom, url)
|
||||
|
||||
if (!ok) {
|
||||
return pushToast({theme: 'error', message})
|
||||
return pushToast({theme: "error", message})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user