publish kind 9 quote after room content creation for cross-client interoperability
This commit is contained in:
+1
-1
@@ -327,7 +327,7 @@
|
|||||||
|
|
||||||
.note-editor .tiptap {
|
.note-editor .tiptap {
|
||||||
--tiptap-object-bg: var(--color-base-200);
|
--tiptap-object-bg: var(--color-base-200);
|
||||||
@apply input rounded-box h-auto min-h-32 p-[.65rem] pb-6;
|
@apply input rounded-box block h-auto min-h-32 w-full p-[.65rem] pb-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-editor .tiptap {
|
.input-editor .tiptap {
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {url, h}: Props = $props()
|
const {url, h, shareToChat = false}: Props = $props()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CalendarEventForm {url} {h}>
|
<CalendarEventForm {url} {h} {shareToChat}>
|
||||||
{#snippet header()}
|
{#snippet header()}
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<ModalTitle>Create an Event</ModalTitle>
|
<ModalTitle>Create an Event</ModalTitle>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import {randomId, HOUR} from "@welshman/lib"
|
import {randomId, HOUR} from "@welshman/lib"
|
||||||
import {makeEvent, EVENT_TIME} from "@welshman/util"
|
import {makeEvent, EVENT_TIME} from "@welshman/util"
|
||||||
import {publishThunk} from "@welshman/app"
|
import {publishThunk, waitForThunkError} from "@welshman/app"
|
||||||
import {preventDefault} from "@lib/html"
|
import {preventDefault} from "@lib/html"
|
||||||
import {daysBetween} from "@lib/util"
|
import {daysBetween} from "@lib/util"
|
||||||
import GallerySend from "@assets/icons/gallery-send.svg?dataurl"
|
import GallerySend from "@assets/icons/gallery-send.svg?dataurl"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
import {DraftKey} from "@app/util/drafts"
|
import {DraftKey} from "@app/util/drafts"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
import {canEnforceNip70} from "@app/core/commands"
|
import {canEnforceNip70, publishRoomQuote} from "@app/core/commands"
|
||||||
|
|
||||||
type Values = {
|
type Values = {
|
||||||
d: string
|
d: string
|
||||||
@@ -36,11 +36,12 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
header: Snippet
|
header: Snippet
|
||||||
initialValues?: Values
|
initialValues?: Values
|
||||||
}
|
}
|
||||||
|
|
||||||
let {url, h, header, initialValues}: Props = $props()
|
let {url, h, shareToChat = false, header, initialValues}: Props = $props()
|
||||||
|
|
||||||
const draftKey = new DraftKey<Values>(`calendar:${url}:${h ?? ""}`)
|
const draftKey = new DraftKey<Values>(`calendar:${url}:${h ?? ""}`)
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
const selectFiles = () => editor.then(ed => ed.chain().selectFiles().run())
|
const selectFiles = () => editor.then(ed => ed.chain().selectFiles().run())
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if ($uploading) return
|
if ($uploading || loading) return
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
@@ -92,22 +93,42 @@
|
|||||||
...ed.storage.nostr.getEditorTags(),
|
...ed.storage.nostr.getEditorTags(),
|
||||||
]
|
]
|
||||||
|
|
||||||
if (await shouldProtect) {
|
loading = true
|
||||||
tags.push(PROTECTED)
|
|
||||||
|
try {
|
||||||
|
const protect = await shouldProtect
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
|
tags.push(PROTECTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
tags.push(["h", h])
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = makeEvent(EVENT_TIME, {content, tags})
|
||||||
|
const calendarThunk = publishThunk({event, relays: [url]})
|
||||||
|
const error = await waitForThunkError(calendarThunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return pushToast({theme: "error", message: error})
|
||||||
|
}
|
||||||
|
|
||||||
|
draftKey.clear()
|
||||||
|
history.back()
|
||||||
|
|
||||||
|
if (shareToChat) {
|
||||||
|
publishRoomQuote({url, h, parent: calendarThunk.event, protect})
|
||||||
|
}
|
||||||
|
|
||||||
|
pushToast({message: "Your event has been saved!"})
|
||||||
|
} finally {
|
||||||
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h) {
|
|
||||||
tags.push(["h", h])
|
|
||||||
}
|
|
||||||
|
|
||||||
const event = makeEvent(EVENT_TIME, {content, tags})
|
|
||||||
|
|
||||||
pushToast({message: "Your event has been saved!"})
|
|
||||||
publishThunk({event, relays: [url]})
|
|
||||||
draftKey.clear()
|
|
||||||
history.back()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loading = $state(false)
|
||||||
|
|
||||||
const d = $state(initialValues?.d ?? randomId())
|
const d = $state(initialValues?.d ?? randomId())
|
||||||
let title = $state(initialValues?.title ?? "")
|
let title = $state(initialValues?.title ?? "")
|
||||||
let location = $state(initialValues?.location ?? "")
|
let location = $state(initialValues?.location ?? "")
|
||||||
@@ -158,7 +179,11 @@
|
|||||||
<div class="input-editor grow overflow-hidden">
|
<div class="input-editor grow overflow-hidden">
|
||||||
<EditorContent {editor} />
|
<EditorContent {editor} />
|
||||||
</div>
|
</div>
|
||||||
<Button data-tip="Add an image" class="center btn tooltip" onclick={selectFiles}>
|
<Button
|
||||||
|
data-tip="Add an image"
|
||||||
|
class="center btn tooltip"
|
||||||
|
onclick={selectFiles}
|
||||||
|
disabled={loading}>
|
||||||
{#if $uploading}
|
{#if $uploading}
|
||||||
<span class="loading loading-spinner loading-xs"></span>
|
<span class="loading loading-spinner loading-xs"></span>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -197,12 +222,12 @@
|
|||||||
</Field>
|
</Field>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" onclick={back}>
|
<Button class="btn btn-link" onclick={back} disabled={loading}>
|
||||||
<Icon icon={AltArrowLeft} />
|
<Icon icon={AltArrowLeft} />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary" disabled={$uploading}>
|
<Button type="submit" class="btn btn-primary" disabled={$uploading || loading}>
|
||||||
<Spinner loading={$uploading}>Save Event</Spinner>
|
<Spinner loading={$uploading || loading}>Save Event</Spinner>
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {url, h}: Props = $props()
|
const {url, h, shareToChat = false}: Props = $props()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ClassifiedForm {url} {h}>
|
<ClassifiedForm {url} {h} {shareToChat}>
|
||||||
{#snippet header()}
|
{#snippet header()}
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<ModalTitle>Create a Classified Listing</ModalTitle>
|
<ModalTitle>Create a Classified Listing</ModalTitle>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import type {Snippet} from "svelte"
|
import type {Snippet} from "svelte"
|
||||||
import {removeUndefined, randomId, uniq} from "@welshman/lib"
|
import {removeUndefined, randomId, uniq} from "@welshman/lib"
|
||||||
import {makeEvent, CLASSIFIED} from "@welshman/util"
|
import {makeEvent, CLASSIFIED} from "@welshman/util"
|
||||||
import {publishThunk} from "@welshman/app"
|
import {publishThunk, waitForThunkError} from "@welshman/app"
|
||||||
import {isMobile, preventDefault} from "@lib/html"
|
import {isMobile, preventDefault} from "@lib/html"
|
||||||
import {normalizeTopic} from "@lib/util"
|
import {normalizeTopic} from "@lib/util"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
import {PROTECTED} from "@app/core/state"
|
import {PROTECTED} from "@app/core/state"
|
||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
import {DraftKey} from "@app/util/drafts"
|
import {DraftKey} from "@app/util/drafts"
|
||||||
import {canEnforceNip70, uploadFile} from "@app/core/commands"
|
import {canEnforceNip70, publishRoomQuote, uploadFile} from "@app/core/commands"
|
||||||
|
|
||||||
type Values = {
|
type Values = {
|
||||||
d: string
|
d: string
|
||||||
@@ -37,11 +37,12 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
header: Snippet
|
header: Snippet
|
||||||
initialValues?: Values
|
initialValues?: Values
|
||||||
}
|
}
|
||||||
|
|
||||||
let {url, h, header, initialValues}: Props = $props()
|
let {url, h, shareToChat = false, header, initialValues}: Props = $props()
|
||||||
|
|
||||||
const draftKey = new DraftKey<Values>(`classified:${url}:${h ?? ""}`)
|
const draftKey = new DraftKey<Values>(`classified:${url}:${h ?? ""}`)
|
||||||
|
|
||||||
@@ -87,7 +88,9 @@
|
|||||||
tags.push(["t", topic])
|
tags.push(["t", topic])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await shouldProtect) {
|
const protect = await shouldProtect
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
tags.push(PROTECTED)
|
tags.push(PROTECTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +117,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishThunk({
|
const classifiedThunk = publishThunk({
|
||||||
relays: [url],
|
relays: [url],
|
||||||
event: makeEvent(CLASSIFIED, {content, tags}),
|
event: makeEvent(CLASSIFIED, {content, tags}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const error = await waitForThunkError(classifiedThunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return pushToast({theme: "error", message: error})
|
||||||
|
}
|
||||||
|
|
||||||
draftKey.clear()
|
draftKey.clear()
|
||||||
history.back()
|
history.back()
|
||||||
|
|
||||||
|
if (shareToChat) {
|
||||||
|
publishRoomQuote({url, h, parent: classifiedThunk.event, protect})
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,15 +22,15 @@
|
|||||||
|
|
||||||
const {url, h, onClick}: Props = $props()
|
const {url, h, onClick}: Props = $props()
|
||||||
|
|
||||||
const createGoal = () => pushModal(GoalCreate, {url, h})
|
const createGoal = () => pushModal(GoalCreate, {url, h, shareToChat: true})
|
||||||
|
|
||||||
const createCalendarEvent = () => pushModal(CalendarEventCreate, {url, h})
|
const createCalendarEvent = () => pushModal(CalendarEventCreate, {url, h, shareToChat: true})
|
||||||
|
|
||||||
const createThread = () => pushModal(ThreadCreate, {url, h})
|
const createThread = () => pushModal(ThreadCreate, {url, h, shareToChat: true})
|
||||||
|
|
||||||
const createClassified = () => pushModal(ClassifiedCreate, {url, h})
|
const createClassified = () => pushModal(ClassifiedCreate, {url, h, shareToChat: true})
|
||||||
|
|
||||||
const createPoll = () => pushModal(PollCreate, {url, h})
|
const createPoll = () => pushModal(PollCreate, {url, h, shareToChat: true})
|
||||||
|
|
||||||
let ul: Element
|
let ul: Element
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
<NoteContentMinimal trimParent {url} event={$quote} />
|
<NoteContentMinimal trimParent {url} event={$quote} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<NoteCard event={$quote} {url} class="bg-alt rounded-box p-4">
|
<NoteCard noShadow event={$quote} {url} class="bg-alt rounded-box p-4">
|
||||||
<NoteContentMinimal {url} event={$quote} />
|
<NoteContentMinimal {url} event={$quote} />
|
||||||
</NoteCard>
|
</NoteCard>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const observer = new ResizeObserver(() => {
|
const observer = new ResizeObserver(() => {
|
||||||
spacer!.style.minHeight = `${form!.offsetHeight}px`
|
spacer!.style.minHeight = `${form!.offsetHeight + 60}px`
|
||||||
})
|
})
|
||||||
|
|
||||||
observer.observe(form!)
|
observer.observe(form!)
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
in:fly
|
in:fly
|
||||||
bind:this={form}
|
bind:this={form}
|
||||||
onsubmit={preventDefault(submit)}
|
onsubmit={preventDefault(submit)}
|
||||||
class="left-content bottom-sai right-sai ml-2 pl-2 fixed z-feature">
|
class="left-content bottom-sai right-sai fixed z-feature mb-14 md:mb-0 w-full md:w-auto pr-2">
|
||||||
<div class="card2 mx-2 my-2 bg-alt shadow-md">
|
<div class="card2 mx-2 my-2 bg-alt shadow-md">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div class="note-editor grow overflow-hidden">
|
<div class="note-editor grow overflow-hidden">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import {makeEvent, ZAP_GOAL} from "@welshman/util"
|
import {makeEvent, ZAP_GOAL} from "@welshman/util"
|
||||||
import {publishThunk} from "@welshman/app"
|
import {publishThunk, waitForThunkError} from "@welshman/app"
|
||||||
import {isMobile, preventDefault} from "@lib/html"
|
import {isMobile, preventDefault} from "@lib/html"
|
||||||
import Paperclip from "@assets/icons/paperclip-2.svg?dataurl"
|
import Paperclip from "@assets/icons/paperclip-2.svg?dataurl"
|
||||||
import Bolt from "@assets/icons/bolt.svg?dataurl"
|
import Bolt from "@assets/icons/bolt.svg?dataurl"
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
import FieldInline from "@lib/components/FieldInline.svelte"
|
import FieldInline from "@lib/components/FieldInline.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||||
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
||||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
import {PROTECTED} from "@app/core/state"
|
import {PROTECTED} from "@app/core/state"
|
||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
import {DraftKey} from "@app/util/drafts"
|
import {DraftKey} from "@app/util/drafts"
|
||||||
import {canEnforceNip70} from "@app/core/commands"
|
import {canEnforceNip70, publishRoomQuote} from "@app/core/commands"
|
||||||
|
|
||||||
type Values = {
|
type Values = {
|
||||||
title: string
|
title: string
|
||||||
@@ -33,9 +34,10 @@
|
|||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
initialValues?: Values
|
initialValues?: Values
|
||||||
|
shareToChat?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
let {url, h, initialValues}: Props = $props()
|
let {url, h, initialValues, shareToChat = false}: Props = $props()
|
||||||
|
|
||||||
const draftKey = new DraftKey<Values>(`goal:${url}:${h ?? ""}`)
|
const draftKey = new DraftKey<Values>(`goal:${url}:${h ?? ""}`)
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
const selectFiles = () => editor.then(ed => ed.commands.selectFiles())
|
const selectFiles = () => editor.then(ed => ed.commands.selectFiles())
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if ($uploading) return
|
if ($uploading || loading) return
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
@@ -78,23 +80,43 @@
|
|||||||
["relays", url],
|
["relays", url],
|
||||||
]
|
]
|
||||||
|
|
||||||
if (await shouldProtect) {
|
loading = true
|
||||||
tags.push(PROTECTED)
|
|
||||||
|
try {
|
||||||
|
const protect = await shouldProtect
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
|
tags.push(PROTECTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
tags.push(["h", h])
|
||||||
|
}
|
||||||
|
|
||||||
|
const goalThunk = publishThunk({
|
||||||
|
relays: [url],
|
||||||
|
event: makeEvent(ZAP_GOAL, {content: title, tags}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = await waitForThunkError(goalThunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return pushToast({theme: "error", message: error})
|
||||||
|
}
|
||||||
|
|
||||||
|
draftKey.clear()
|
||||||
|
history.back()
|
||||||
|
|
||||||
|
if (shareToChat) {
|
||||||
|
publishRoomQuote({url, h, parent: goalThunk.event, protect})
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h) {
|
|
||||||
tags.push(["h", h])
|
|
||||||
}
|
|
||||||
|
|
||||||
publishThunk({
|
|
||||||
relays: [url],
|
|
||||||
event: makeEvent(ZAP_GOAL, {content: title, tags}),
|
|
||||||
})
|
|
||||||
|
|
||||||
draftKey.clear()
|
|
||||||
history.back()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loading = $state(false)
|
||||||
|
|
||||||
let title = $state(initialValues?.title ?? "")
|
let title = $state(initialValues?.title ?? "")
|
||||||
let amount = $state(initialValues?.amount ?? 1000)
|
let amount = $state(initialValues?.amount ?? 1000)
|
||||||
let content = $state(initialValues?.content ?? "")
|
let content = $state(initialValues?.content ?? "")
|
||||||
@@ -154,7 +176,8 @@
|
|||||||
<Button
|
<Button
|
||||||
data-tip="Add an image"
|
data-tip="Add an image"
|
||||||
class="tooltip tooltip-left absolute bottom-1 right-2"
|
class="tooltip tooltip-left absolute bottom-1 right-2"
|
||||||
onclick={selectFiles}>
|
onclick={selectFiles}
|
||||||
|
disabled={loading}>
|
||||||
{#if $uploading}
|
{#if $uploading}
|
||||||
<span class="loading loading-spinner loading-xs"></span>
|
<span class="loading loading-spinner loading-xs"></span>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -169,16 +192,16 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<div class="flex grow justify-end">
|
<div class="flex grow justify-end">
|
||||||
<label class="input input-bordered flex items-center gap-2">
|
<label class="input input-bordered flex w-auto items-center gap-2">
|
||||||
<Icon icon={Bolt} />
|
<Icon icon={Bolt} />
|
||||||
<input bind:value={amount} type="number" class="w-28" />
|
<input bind:value={amount} type="number" class="w-28 grow" />
|
||||||
<p class="opacity-50">sats</p>
|
<p class="shrink-0 opacity-50">sats</p>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
<input
|
<input
|
||||||
class="range range-primary -mt-2"
|
class="range range-primary -mt-2 w-full"
|
||||||
type="range"
|
type="range"
|
||||||
min="1000"
|
min="1000"
|
||||||
max="100000"
|
max="100000"
|
||||||
@@ -188,10 +211,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" onclick={back}>
|
<Button class="btn btn-link" onclick={back} disabled={loading}>
|
||||||
<Icon icon={AltArrowLeft} />
|
<Icon icon={AltArrowLeft} />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary">Create Goal</Button>
|
<Button type="submit" class="btn btn-primary" disabled={$uploading || loading}>
|
||||||
|
<Spinner {loading}>Create Goal</Spinner>
|
||||||
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
children,
|
children,
|
||||||
minimal = false,
|
minimal = false,
|
||||||
hideProfile = false,
|
hideProfile = false,
|
||||||
|
noShadow = false,
|
||||||
url,
|
url,
|
||||||
...restProps
|
...restProps
|
||||||
}: {
|
}: {
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
children: Snippet
|
children: Snippet
|
||||||
minimal?: boolean
|
minimal?: boolean
|
||||||
hideProfile?: boolean
|
hideProfile?: boolean
|
||||||
|
noShadow?: boolean
|
||||||
url?: string
|
url?: string
|
||||||
class?: string
|
class?: string
|
||||||
} = $props()
|
} = $props()
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
let muted = $state($isEventMuted(event))
|
let muted = $state($isEventMuted(event))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 shadow-md {restProps.class}">
|
<div class="flex flex-col gap-2 {restProps.class}" class:shadow-md={!noShadow}>
|
||||||
{#if muted}
|
{#if muted}
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="row-2 relative">
|
<div class="row-2 relative">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {insertAt, now, randomId, removeAt, removeUndefined} from "@welshman/lib"
|
import {insertAt, now, randomId, removeAt, removeUndefined} from "@welshman/lib"
|
||||||
import {makeEvent} from "@welshman/util"
|
import {makeEvent} from "@welshman/util"
|
||||||
import {publishThunk} from "@welshman/app"
|
import {publishThunk, waitForThunkError} from "@welshman/app"
|
||||||
import {Poll} from "nostr-tools/kinds"
|
import {Poll} from "nostr-tools/kinds"
|
||||||
import {isMobile, preventDefault} from "@lib/html"
|
import {isMobile, preventDefault} from "@lib/html"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
import FieldInline from "@lib/components/FieldInline.svelte"
|
import FieldInline from "@lib/components/FieldInline.svelte"
|
||||||
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||||
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
||||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
import {PROTECTED} from "@app/core/state"
|
import {PROTECTED} from "@app/core/state"
|
||||||
import {canEnforceNip70} from "@app/core/commands"
|
import {canEnforceNip70, publishRoomQuote} from "@app/core/commands"
|
||||||
import {DraftKey} from "@app/util/drafts"
|
import {DraftKey} from "@app/util/drafts"
|
||||||
import type {PollType} from "@app/util/polls"
|
import type {PollType} from "@app/util/polls"
|
||||||
|
|
||||||
@@ -40,9 +41,10 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {url, h}: Props = $props()
|
const {url, h, shareToChat = false}: Props = $props()
|
||||||
const draftKey = new DraftKey<Values>(`poll:${url}:${h ?? ""}`)
|
const draftKey = new DraftKey<Values>(`poll:${url}:${h ?? ""}`)
|
||||||
const initialValues = draftKey.get()
|
const initialValues = draftKey.get()
|
||||||
|
|
||||||
@@ -102,6 +104,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
|
if (loading) return
|
||||||
|
|
||||||
if (!title.trim()) {
|
if (!title.trim()) {
|
||||||
return pushToast({theme: "error", message: "Please provide a title for your poll."})
|
return pushToast({theme: "error", message: "Please provide a title for your poll."})
|
||||||
}
|
}
|
||||||
@@ -130,19 +134,39 @@
|
|||||||
tags.push(["h", h])
|
tags.push(["h", h])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await shouldProtect) {
|
loading = true
|
||||||
tags.push(PROTECTED)
|
|
||||||
|
try {
|
||||||
|
const protect = await shouldProtect
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
|
tags.push(PROTECTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pollThunk = publishThunk({
|
||||||
|
relays: [url],
|
||||||
|
event: makeEvent(Poll, {content: title.trim(), tags}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = await waitForThunkError(pollThunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return pushToast({theme: "error", message: error})
|
||||||
|
}
|
||||||
|
|
||||||
|
draftKey.clear()
|
||||||
|
history.back()
|
||||||
|
|
||||||
|
if (shareToChat) {
|
||||||
|
publishRoomQuote({url, h, parent: pollThunk.event, protect})
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
publishThunk({
|
|
||||||
relays: [url],
|
|
||||||
event: makeEvent(Poll, {content: title.trim(), tags}),
|
|
||||||
})
|
|
||||||
|
|
||||||
draftKey.clear()
|
|
||||||
history.back()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loading = $state(false)
|
||||||
|
|
||||||
let draggedOptionId = $state<string | undefined>()
|
let draggedOptionId = $state<string | undefined>()
|
||||||
let title = $state(initialValues?.title ?? "")
|
let title = $state(initialValues?.title ?? "")
|
||||||
let pollType = $state<PollType>(initialValues?.pollType ?? "singlechoice")
|
let pollType = $state<PollType>(initialValues?.pollType ?? "singlechoice")
|
||||||
@@ -246,10 +270,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" onclick={back}>
|
<Button class="btn btn-link" onclick={back} disabled={loading}>
|
||||||
<Icon icon={AltArrowLeft} />
|
<Icon icon={AltArrowLeft} />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary">Create Poll</Button>
|
<Button type="submit" class="btn btn-primary" disabled={loading}>
|
||||||
|
<Spinner {loading}>Create Poll</Spinner>
|
||||||
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
import type {Filter} from "@welshman/util"
|
import type {Filter} from "@welshman/util"
|
||||||
import {deriveEventsDesc, deriveEventsById} from "@welshman/store"
|
import {deriveEventsDesc, deriveEventsById} from "@welshman/store"
|
||||||
import {formatTimestampRelative} from "@welshman/lib"
|
import {formatTimestampRelative} from "@welshman/lib"
|
||||||
import {NOTE, ROOMS, COMMENT} from "@welshman/util"
|
import {NOTE, ROOMS, COMMENT, MESSAGE} from "@welshman/util"
|
||||||
import {repository, loadRelayList} from "@welshman/app"
|
import {repository, loadRelayList} from "@welshman/app"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ProfileSpaces from "@app/components/ProfileSpaces.svelte"
|
import ProfileSpaces from "@app/components/ProfileSpaces.svelte"
|
||||||
import {deriveGroupList, getSpaceUrlsFromGroupList, MESSAGE_KINDS} from "@app/core/state"
|
import {deriveGroupList, getSpaceUrlsFromGroupList} from "@app/core/state"
|
||||||
import {goToEvent} from "@app/util/routes"
|
import {goToEvent} from "@app/util/routes"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
load({
|
load({
|
||||||
filters: [
|
filters: [
|
||||||
{authors: [pubkey], kinds: [ROOMS]},
|
{authors: [pubkey], kinds: [ROOMS]},
|
||||||
{authors: [pubkey], limit: 1, kinds: [NOTE, COMMENT, ...MESSAGE_KINDS]},
|
{authors: [pubkey], limit: 1, kinds: [NOTE, COMMENT, MESSAGE]},
|
||||||
],
|
],
|
||||||
relays: Router.get().FromPubkeys([pubkey]).getUrls(),
|
relays: Router.get().FromPubkeys([pubkey]).getUrls(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,14 +8,9 @@
|
|||||||
import {getRoomItemPath} from "@app/util/routes"
|
import {getRoomItemPath} from "@app/util/routes"
|
||||||
|
|
||||||
const props: ComponentProps<typeof NoteContent> = $props()
|
const props: ComponentProps<typeof NoteContent> = $props()
|
||||||
const MESSAGE_MIN_LENGTH = 5000
|
|
||||||
const MESSAGE_MAX_LENGTH = 5500
|
|
||||||
|
|
||||||
const path = getRoomItemPath(props.url!, props.event)
|
const path = getRoomItemPath(props.url!, props.event)
|
||||||
const minLength =
|
const minLength = 5000
|
||||||
props.minLength ?? (props.event.kind === MESSAGE ? MESSAGE_MIN_LENGTH : undefined)
|
const maxLength = 5500
|
||||||
const maxLength =
|
|
||||||
props.maxLength ?? (props.event.kind === MESSAGE ? MESSAGE_MAX_LENGTH : undefined)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={cx("text-sm", {"card2 card2-sm bg-alt": props.event.kind !== MESSAGE})}>
|
<div class={cx("text-sm", {"card2 card2-sm bg-alt": props.event.kind !== MESSAGE})}>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import {makeEvent, THREAD} from "@welshman/util"
|
import {makeEvent, THREAD} from "@welshman/util"
|
||||||
import {publishThunk} from "@welshman/app"
|
import {publishThunk, waitForThunkError} from "@welshman/app"
|
||||||
import {isMobile, preventDefault} from "@lib/html"
|
import {isMobile, preventDefault} from "@lib/html"
|
||||||
import Paperclip from "@assets/icons/paperclip-2.svg?dataurl"
|
import Paperclip from "@assets/icons/paperclip-2.svg?dataurl"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||||
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
||||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
import {PROTECTED} from "@app/core/state"
|
import {PROTECTED} from "@app/core/state"
|
||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
import {DraftKey} from "@app/util/drafts"
|
import {DraftKey} from "@app/util/drafts"
|
||||||
import {canEnforceNip70} from "@app/core/commands"
|
import {canEnforceNip70, publishRoomQuote} from "@app/core/commands"
|
||||||
|
|
||||||
type Values = {
|
type Values = {
|
||||||
content?: string | object
|
content?: string | object
|
||||||
@@ -29,9 +30,10 @@
|
|||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
h?: string
|
h?: string
|
||||||
|
shareToChat?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const {url, h}: Props = $props()
|
const {url, h, shareToChat = false}: Props = $props()
|
||||||
const draftKey = new DraftKey<Values>(`thread:${url}:${h ?? ""}`)
|
const draftKey = new DraftKey<Values>(`thread:${url}:${h ?? ""}`)
|
||||||
const initialValues = draftKey.get()
|
const initialValues = draftKey.get()
|
||||||
const shouldProtect = canEnforceNip70(url)
|
const shouldProtect = canEnforceNip70(url)
|
||||||
@@ -43,7 +45,7 @@
|
|||||||
const selectFiles = () => editor.then(ed => ed.commands.selectFiles())
|
const selectFiles = () => editor.then(ed => ed.commands.selectFiles())
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if ($uploading) return
|
if ($uploading || loading) return
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
@@ -64,23 +66,43 @@
|
|||||||
|
|
||||||
const tags = [...ed.storage.nostr.getEditorTags(), ["title", title]]
|
const tags = [...ed.storage.nostr.getEditorTags(), ["title", title]]
|
||||||
|
|
||||||
if (await shouldProtect) {
|
loading = true
|
||||||
tags.push(PROTECTED)
|
|
||||||
|
try {
|
||||||
|
const protect = await shouldProtect
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
|
tags.push(PROTECTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
tags.push(["h", h])
|
||||||
|
}
|
||||||
|
|
||||||
|
const threadThunk = publishThunk({
|
||||||
|
relays: [url],
|
||||||
|
event: makeEvent(THREAD, {content, tags}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = await waitForThunkError(threadThunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return pushToast({theme: "error", message: error})
|
||||||
|
}
|
||||||
|
|
||||||
|
draftKey.clear()
|
||||||
|
history.back()
|
||||||
|
|
||||||
|
if (shareToChat) {
|
||||||
|
publishRoomQuote({url, h, parent: threadThunk.event, protect})
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h) {
|
|
||||||
tags.push(["h", h])
|
|
||||||
}
|
|
||||||
|
|
||||||
publishThunk({
|
|
||||||
relays: [url],
|
|
||||||
event: makeEvent(THREAD, {content, tags}),
|
|
||||||
})
|
|
||||||
|
|
||||||
draftKey.clear()
|
|
||||||
history.back()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loading = $state(false)
|
||||||
|
|
||||||
let title = $state(initialValues?.title ?? "")
|
let title = $state(initialValues?.title ?? "")
|
||||||
let content = $state(initialValues?.content ?? "")
|
let content = $state(initialValues?.content ?? "")
|
||||||
|
|
||||||
@@ -138,7 +160,8 @@
|
|||||||
<Button
|
<Button
|
||||||
data-tip="Add an image"
|
data-tip="Add an image"
|
||||||
class="tooltip tooltip-left absolute bottom-1 right-2"
|
class="tooltip tooltip-left absolute bottom-1 right-2"
|
||||||
onclick={selectFiles}>
|
onclick={selectFiles}
|
||||||
|
disabled={loading}>
|
||||||
{#if $uploading}
|
{#if $uploading}
|
||||||
<span class="loading loading-spinner loading-xs"></span>
|
<span class="loading loading-spinner loading-xs"></span>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -148,10 +171,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" onclick={back}>
|
<Button class="btn btn-link" onclick={back} disabled={loading}>
|
||||||
<Icon icon={AltArrowLeft} />
|
<Icon icon={AltArrowLeft} />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary">Create Thread</Button>
|
<Button type="submit" class="btn btn-primary" disabled={$uploading || loading}>
|
||||||
|
<Spinner {loading}>Create Thread</Spinner>
|
||||||
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {PollResponse} from "nostr-tools/kinds"
|
|||||||
import {
|
import {
|
||||||
DELETE,
|
DELETE,
|
||||||
REPORT,
|
REPORT,
|
||||||
|
MESSAGE,
|
||||||
PROFILE,
|
PROFILE,
|
||||||
MESSAGING_RELAYS,
|
MESSAGING_RELAYS,
|
||||||
RELAYS,
|
RELAYS,
|
||||||
@@ -122,6 +123,34 @@ export const prependParent = (
|
|||||||
return {content, tags}
|
return {content, tags}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const publishRoomQuote = ({
|
||||||
|
url,
|
||||||
|
h,
|
||||||
|
parent,
|
||||||
|
protect,
|
||||||
|
delay,
|
||||||
|
}: {
|
||||||
|
url: string
|
||||||
|
h?: string
|
||||||
|
parent: TrustedEvent
|
||||||
|
protect: boolean
|
||||||
|
delay?: number
|
||||||
|
}) => {
|
||||||
|
const tags: string[][] = []
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
tags.push(["h", h])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protect) {
|
||||||
|
tags.push(PROTECTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = makeEvent(MESSAGE, prependParent(parent, {content: "", tags}, url))
|
||||||
|
|
||||||
|
return publishThunk({relays: [url], event, delay})
|
||||||
|
}
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
|
|
||||||
export const broadcastUserData = async (relays: string[]) => {
|
export const broadcastUserData = async (relays: string[]) => {
|
||||||
|
|||||||
@@ -329,8 +329,6 @@ if (ENABLE_ZAPS) {
|
|||||||
|
|
||||||
export const CONTENT_KINDS = [ZAP_GOAL, EVENT_TIME, THREAD, CLASSIFIED, Poll]
|
export const CONTENT_KINDS = [ZAP_GOAL, EVENT_TIME, THREAD, CLASSIFIED, Poll]
|
||||||
|
|
||||||
export const MESSAGE_KINDS = [...CONTENT_KINDS, MESSAGE]
|
|
||||||
|
|
||||||
export const DM_KINDS = [DIRECT_MESSAGE, DIRECT_MESSAGE_FILE]
|
export const DM_KINDS = [DIRECT_MESSAGE, DIRECT_MESSAGE_FILE]
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
RELAY_MEMBERS,
|
RELAY_MEMBERS,
|
||||||
RELAY_ADD_MEMBER,
|
RELAY_ADD_MEMBER,
|
||||||
RELAY_REMOVE_MEMBER,
|
RELAY_REMOVE_MEMBER,
|
||||||
|
MESSAGE,
|
||||||
isSignedEvent,
|
isSignedEvent,
|
||||||
unionFilters,
|
unionFilters,
|
||||||
getTagValue,
|
getTagValue,
|
||||||
@@ -43,7 +44,6 @@ import {
|
|||||||
} from "@welshman/app"
|
} from "@welshman/app"
|
||||||
import {
|
import {
|
||||||
REACTION_KINDS,
|
REACTION_KINDS,
|
||||||
MESSAGE_KINDS,
|
|
||||||
CONTENT_KINDS,
|
CONTENT_KINDS,
|
||||||
INDEXER_RELAYS,
|
INDEXER_RELAYS,
|
||||||
loadSettings,
|
loadSettings,
|
||||||
@@ -281,7 +281,7 @@ const syncSpace = (url: string, rooms: string[]) => {
|
|||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
filters: [
|
filters: [
|
||||||
{kinds: [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS], "#d": [room]},
|
{kinds: [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS], "#d": [room]},
|
||||||
{kinds: MESSAGE_KINDS, since, "#h": [room]},
|
{kinds: [MESSAGE, ...CONTENT_KINDS], since, "#h": [room]},
|
||||||
makeCommentFilter(CONTENT_KINDS, {since, "#h": [room]}),
|
makeCommentFilter(CONTENT_KINDS, {since, "#h": [room]}),
|
||||||
{
|
{
|
||||||
kinds: [ROOM_DELETE, ROOM_JOIN, ROOM_LEAVE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER],
|
kinds: [ROOM_DELETE, ROOM_JOIN, ROOM_LEAVE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER],
|
||||||
@@ -305,7 +305,7 @@ const syncSpace = (url: string, rooms: string[]) => {
|
|||||||
url,
|
url,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
filters: [
|
filters: [
|
||||||
{kinds: [...relayKinds, ...roomMetaKinds, ...roomMemberKinds, ...MESSAGE_KINDS]},
|
{kinds: [...relayKinds, ...roomMetaKinds, ...roomMemberKinds, ...CONTENT_KINDS, MESSAGE]},
|
||||||
makeCommentFilter(CONTENT_KINDS, {since}),
|
makeCommentFilter(CONTENT_KINDS, {since}),
|
||||||
{kinds: [PollResponse], since},
|
{kinds: [PollResponse], since},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import {pubkey, tracker, repository, relaysByUrl} from "@welshman/app"
|
|||||||
import {assoc, prop, first, identity, groupBy, now} from "@welshman/lib"
|
import {assoc, prop, first, identity, groupBy, now} from "@welshman/lib"
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
import type {TrustedEvent} from "@welshman/util"
|
||||||
import {deriveEventsByIdByUrl} from "@welshman/store"
|
import {deriveEventsByIdByUrl} from "@welshman/store"
|
||||||
import {sortEventsDesc, getTagValue} from "@welshman/util"
|
import {sortEventsDesc, getTagValue, MESSAGE} from "@welshman/util"
|
||||||
import {makeSpacePath, makeRoomPath, makeSpaceChatPath, makeChatPath} from "@app/util/routes"
|
import {makeSpacePath, makeRoomPath, makeSpaceChatPath, makeChatPath} from "@app/util/routes"
|
||||||
import {
|
import {
|
||||||
MESSAGE_KINDS,
|
CONTENT_KINDS,
|
||||||
notificationSettings,
|
notificationSettings,
|
||||||
chatsById,
|
chatsById,
|
||||||
userGroupList,
|
userGroupList,
|
||||||
@@ -85,7 +85,7 @@ export const allNotifications = derived(
|
|||||||
deriveEventsByIdByUrl({
|
deriveEventsByIdByUrl({
|
||||||
tracker,
|
tracker,
|
||||||
repository,
|
repository,
|
||||||
filters: [{kinds: MESSAGE_KINDS}, makeCommentFilter(MESSAGE_KINDS)],
|
filters: [{kinds: [MESSAGE, ...CONTENT_KINDS]}, makeCommentFilter(CONTENT_KINDS)],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
identity,
|
identity,
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import {
|
|||||||
getRelaysFromList,
|
getRelaysFromList,
|
||||||
getTagValue,
|
getTagValue,
|
||||||
matchFilters,
|
matchFilters,
|
||||||
|
MESSAGE,
|
||||||
type Filter,
|
type Filter,
|
||||||
type TrustedEvent,
|
type TrustedEvent,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {
|
import {
|
||||||
DM_KINDS,
|
DM_KINDS,
|
||||||
CONTENT_KINDS,
|
CONTENT_KINDS,
|
||||||
MESSAGE_KINDS,
|
|
||||||
notificationSettings,
|
notificationSettings,
|
||||||
pushState,
|
pushState,
|
||||||
shouldNotify,
|
shouldNotify,
|
||||||
@@ -45,7 +45,10 @@ export type PushPermissionResult = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const onNotification = call(() => {
|
export const onNotification = call(() => {
|
||||||
const allFilters = [{kinds: [...MESSAGE_KINDS, ...DM_KINDS]}, makeCommentFilter(MESSAGE_KINDS)]
|
const allFilters = [
|
||||||
|
{kinds: [MESSAGE, ...CONTENT_KINDS, ...DM_KINDS]},
|
||||||
|
makeCommentFilter(CONTENT_KINDS),
|
||||||
|
]
|
||||||
const filters = allFilters.map(assoc("since", now()))
|
const filters = allFilters.map(assoc("since", now()))
|
||||||
const subscribers: Subscriber<TrustedEvent>[] = []
|
const subscribers: Subscriber<TrustedEvent>[] = []
|
||||||
|
|
||||||
@@ -158,7 +161,7 @@ export const syncRelaySubscriptions = (
|
|||||||
userSettingsValues,
|
userSettingsValues,
|
||||||
]).subscribe(
|
]).subscribe(
|
||||||
throttle(3000, ([$userSpaceUrls, {spaces, mentions}, {alerts}]) => {
|
throttle(3000, ([$userSpaceUrls, {spaces, mentions}, {alerts}]) => {
|
||||||
const baseFilters = [{kinds: MESSAGE_KINDS}, makeCommentFilter(CONTENT_KINDS)]
|
const baseFilters = [{kinds: [MESSAGE, ...CONTENT_KINDS]}, makeCommentFilter(CONTENT_KINDS)]
|
||||||
|
|
||||||
for (const url of $userSpaceUrls) {
|
for (const url of $userSpaceUrls) {
|
||||||
const {notify = true, exceptions = []} = alerts.find(spec({url})) || {}
|
const {notify = true, exceptions = []} = alerts.find(spec({url})) || {}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"aria-pressed"?: boolean
|
"aria-pressed"?: boolean
|
||||||
} = $props()
|
} = $props()
|
||||||
|
|
||||||
const className = $derived(`text-left ${restProps.class}`)
|
const className = $derived(`text-left cursor-pointer ${restProps.class}`)
|
||||||
|
|
||||||
const onClick = (e: Event) => {
|
const onClick = (e: Event) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {Snippet} from "svelte"
|
import type {Snippet} from "svelte"
|
||||||
|
|
||||||
let {
|
type Props = {
|
||||||
children,
|
|
||||||
root,
|
|
||||||
initiallyVisible = false,
|
|
||||||
estimatedHeight = 48,
|
|
||||||
}: {
|
|
||||||
children: Snippet
|
children: Snippet
|
||||||
root?: HTMLElement
|
root?: HTMLElement
|
||||||
initiallyVisible?: boolean
|
initiallyVisible?: boolean
|
||||||
estimatedHeight?: number
|
estimatedHeight?: number
|
||||||
} = $props()
|
}
|
||||||
|
|
||||||
|
const {children, root, initiallyVisible = false, estimatedHeight = 48}: Props = $props()
|
||||||
|
|
||||||
let visible = $state(initiallyVisible)
|
let visible = $state(initiallyVisible)
|
||||||
let height = $state(estimatedHeight)
|
let height = $state(estimatedHeight)
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
deriveRoom,
|
deriveRoom,
|
||||||
deriveUserRoomMembershipStatus,
|
deriveUserRoomMembershipStatus,
|
||||||
getRoomType,
|
getRoomType,
|
||||||
MESSAGE_KINDS,
|
|
||||||
MembershipStatus,
|
MembershipStatus,
|
||||||
PROTECTED,
|
PROTECTED,
|
||||||
RoomType,
|
RoomType,
|
||||||
@@ -366,7 +365,7 @@
|
|||||||
url,
|
url,
|
||||||
at: at || now(),
|
at: at || now(),
|
||||||
element: element!,
|
element: element!,
|
||||||
filters: [{kinds: [...MESSAGE_KINDS, ROOM_ADD_MEMBER], "#h": [h]}],
|
filters: [{kinds: [MESSAGE, ROOM_ADD_MEMBER], "#h": [h]}],
|
||||||
onBackwardExhausted: () => {
|
onBackwardExhausted: () => {
|
||||||
loadingBackward = false
|
loadingBackward = false
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
import RoomCompose from "@app/components/RoomCompose.svelte"
|
import RoomCompose from "@app/components/RoomCompose.svelte"
|
||||||
import RoomComposeEdit from "@src/app/components/RoomComposeEdit.svelte"
|
import RoomComposeEdit from "@src/app/components/RoomComposeEdit.svelte"
|
||||||
import RoomComposeParent from "@app/components/RoomComposeParent.svelte"
|
import RoomComposeParent from "@app/components/RoomComposeParent.svelte"
|
||||||
import {userSettingsValues, decodeRelay, PROTECTED, MESSAGE_KINDS} from "@app/core/state"
|
import {userSettingsValues, decodeRelay, PROTECTED} from "@app/core/state"
|
||||||
import {prependParent, canEnforceNip70, publishDelete} from "@app/core/commands"
|
import {prependParent, canEnforceNip70, publishDelete} from "@app/core/commands"
|
||||||
import {checked} from "@app/util/notifications"
|
import {checked} from "@app/util/notifications"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
@@ -258,7 +258,7 @@
|
|||||||
url,
|
url,
|
||||||
at: at || now(),
|
at: at || now(),
|
||||||
element: element!,
|
element: element!,
|
||||||
filters: [{kinds: [...MESSAGE_KINDS, RELAY_ADD_MEMBER]}],
|
filters: [{kinds: [MESSAGE, RELAY_ADD_MEMBER]}],
|
||||||
onBackwardExhausted: () => {
|
onBackwardExhausted: () => {
|
||||||
loadingBackward = false
|
loadingBackward = false
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user