Add description to pins
This commit is contained in:
parent
f20414975d
commit
774e2da463
6 changed files with 64 additions and 11 deletions
|
|
@ -49,6 +49,9 @@
|
||||||
<strong class="truncate min-w-0 pr-8">{pin.title}</strong>
|
<strong class="truncate min-w-0 pr-8">{pin.title}</strong>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if pin.description}
|
||||||
|
<Content event={{content: pin.description, tags: []}} {url} />
|
||||||
|
{/if}
|
||||||
{#if pin.value[0] === "i"}
|
{#if pin.value[0] === "i"}
|
||||||
<Content event={{content, tags: []}} {url} />
|
<Content event={{content, tags: []}} {url} />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@
|
||||||
|
|
||||||
const {url, address, reference}: Props = $props()
|
const {url, address, reference}: Props = $props()
|
||||||
|
|
||||||
const submit = async ({title, topics, value}: PinFormValues) => {
|
const submit = async ({title, topics, value, content}: PinFormValues) => {
|
||||||
const params = referenceToPin(value)
|
const params = referenceToPin(value)
|
||||||
|
|
||||||
if (!params) return "Please enter a valid URL or nostr link."
|
if (!params) return "Please enter a valid URL or nostr link."
|
||||||
|
|
||||||
return createPin(url, {...params, boards: [address], title, topics})
|
return createPin(url, {...params, boards: [address], title, topics, description: content})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
const {url, pin}: Props = $props()
|
const {url, pin}: Props = $props()
|
||||||
|
|
||||||
const submit = async ({title, topics, value}: PinFormValues) => {
|
const submit = async ({title, topics, value, content}: PinFormValues) => {
|
||||||
const params = referenceToPin(value)
|
const params = referenceToPin(value)
|
||||||
|
|
||||||
if (!params) return "Please enter a valid URL or nostr link."
|
if (!params) return "Please enter a valid URL or nostr link."
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
boards: pin.boards,
|
boards: pin.boards,
|
||||||
title,
|
title,
|
||||||
topics,
|
topics,
|
||||||
|
description: content,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -30,5 +31,10 @@
|
||||||
heading="Edit Link"
|
heading="Edit Link"
|
||||||
action="Save changes"
|
action="Save changes"
|
||||||
successMessage="Link updated!"
|
successMessage="Link updated!"
|
||||||
values={{title: pin.title, topics: pin.topics, value: pinToReference(pin)}}
|
values={{
|
||||||
|
title: pin.title,
|
||||||
|
topics: pin.topics,
|
||||||
|
value: pinToReference(pin),
|
||||||
|
content: pin.description,
|
||||||
|
}}
|
||||||
{submit} />
|
{submit} />
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,14 @@
|
||||||
title: string
|
title: string
|
||||||
topics: string[]
|
topics: string[]
|
||||||
value: string
|
value: string
|
||||||
|
content: string
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {writable} from "svelte/store"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
|
import GallerySend from "@assets/icons/gallery-send.svg?dataurl"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
|
|
@ -20,6 +23,8 @@
|
||||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||||
import StringMultiInput from "@lib/components/StringMultiInput.svelte"
|
import StringMultiInput from "@lib/components/StringMultiInput.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
|
import EditorContent from "@app/editor/EditorContent.svelte"
|
||||||
|
import {makeEditor} from "@app/editor"
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
import {clearModals} from "@app/modal"
|
import {clearModals} from "@app/modal"
|
||||||
|
|
||||||
|
|
@ -37,15 +42,20 @@
|
||||||
let title = $state(values.title ?? "")
|
let title = $state(values.title ?? "")
|
||||||
let topics = $state<string[]>(values.topics ?? [])
|
let topics = $state<string[]>(values.topics ?? [])
|
||||||
let value = $state(values.value ?? "")
|
let value = $state(values.value ?? "")
|
||||||
|
let content = $state<string | object>(values.content ?? "")
|
||||||
let loading = $state(false)
|
let loading = $state(false)
|
||||||
|
|
||||||
|
const uploading = writable(false)
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
loading = true
|
loading = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const error = await submit({title, topics, value})
|
const ed = await editor
|
||||||
|
const description = ed.getText({blockSeparator: "\n"}).trim()
|
||||||
|
const error = await submit({title, topics, value, content: description})
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
pushToast({theme: "error", message: error})
|
pushToast({theme: "error", message: error})
|
||||||
|
|
@ -57,6 +67,14 @@
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onChange = (json: object) => {
|
||||||
|
content = json
|
||||||
|
}
|
||||||
|
|
||||||
|
const editor = makeEditor({url, submit: onSubmit, uploading, onChange, content})
|
||||||
|
|
||||||
|
const selectFiles = () => editor.then(ed => ed.chain().selectFiles().run())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal>
|
<Modal>
|
||||||
|
|
@ -76,6 +94,29 @@
|
||||||
placeholder="Optional title" />
|
placeholder="Optional title" />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Field>
|
</Field>
|
||||||
|
<Field>
|
||||||
|
{#snippet label()}
|
||||||
|
Description
|
||||||
|
{/snippet}
|
||||||
|
{#snippet input()}
|
||||||
|
<div class="relative z-feature flex gap-2">
|
||||||
|
<div class="input-editor grow overflow-hidden">
|
||||||
|
<EditorContent {editor} />
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
data-tip="Add an image"
|
||||||
|
class="button button-neutral button-input tip"
|
||||||
|
onclick={selectFiles}
|
||||||
|
disabled={loading}>
|
||||||
|
{#if $uploading}
|
||||||
|
<Spinner size="xs" />
|
||||||
|
{:else}
|
||||||
|
<Icon icon={GallerySend} />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
{#snippet label()}
|
{#snippet label()}
|
||||||
Topics
|
Topics
|
||||||
|
|
@ -101,7 +142,10 @@
|
||||||
<Icon icon={AltArrowLeft} />
|
<Icon icon={AltArrowLeft} />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button class="button button-primary" onclick={onSubmit} disabled={loading || !value.trim()}>
|
<Button
|
||||||
|
class="button button-primary"
|
||||||
|
onclick={onSubmit}
|
||||||
|
disabled={loading || $uploading || !value.trim()}>
|
||||||
<Spinner {loading}>{action}</Spinner>
|
<Spinner {loading}>{action}</Spinner>
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export type Pin = {
|
||||||
pubkey: string
|
pubkey: string
|
||||||
identifier: string
|
identifier: string
|
||||||
boards: string[]
|
boards: string[]
|
||||||
comment: string
|
description: string
|
||||||
title: string
|
title: string
|
||||||
topics: string[]
|
topics: string[]
|
||||||
// The pin's content reference: the first e/a/i tag found, e.g. ["e", <id>],
|
// The pin's content reference: the first e/a/i tag found, e.g. ["e", <id>],
|
||||||
|
|
@ -63,7 +63,7 @@ export const readPin = (event: TrustedEvent): Pin => ({
|
||||||
pubkey: event.pubkey,
|
pubkey: event.pubkey,
|
||||||
identifier: getTagValue("d", event.tags) ?? "",
|
identifier: getTagValue("d", event.tags) ?? "",
|
||||||
boards: getTagValues("A", event.tags),
|
boards: getTagValues("A", event.tags),
|
||||||
comment: event.content,
|
description: event.content,
|
||||||
title: getTagValue("title", event.tags) ?? "",
|
title: getTagValue("title", event.tags) ?? "",
|
||||||
topics: getTagValues("t", event.tags),
|
topics: getTagValues("t", event.tags),
|
||||||
value: event.tags.find(tag => ["e", "a", "i"].includes(tag[0])) ?? [],
|
value: event.tags.find(tag => ["e", "a", "i"].includes(tag[0])) ?? [],
|
||||||
|
|
@ -118,14 +118,14 @@ const makeBoardTemplate = ({
|
||||||
const makePinTemplate = ({
|
const makePinTemplate = ({
|
||||||
identifier = "",
|
identifier = "",
|
||||||
boards = [],
|
boards = [],
|
||||||
comment = "",
|
description = "",
|
||||||
title = "",
|
title = "",
|
||||||
topics = [],
|
topics = [],
|
||||||
value = [],
|
value = [],
|
||||||
}: Partial<Pin>) => ({
|
}: Partial<Pin>) => ({
|
||||||
kind: PIN,
|
kind: PIN,
|
||||||
created_at: now(),
|
created_at: now(),
|
||||||
content: comment,
|
content: description,
|
||||||
tags: [
|
tags: [
|
||||||
// Reuse the identifier when editing so the addressable event is replaced;
|
// Reuse the identifier when editing so the addressable event is replaced;
|
||||||
// fall back to a random one for new pins.
|
// fall back to a random one for new pins.
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
if (!value) return $pins
|
if (!value) return $pins
|
||||||
|
|
||||||
return $pins.filter(pin =>
|
return $pins.filter(pin =>
|
||||||
[pin.title, pin.comment, pin.value[0] === "i" ? pin.value[1] : "", ...pin.topics].some(
|
[pin.title, pin.description, pin.value[0] === "i" ? pin.value[1] : "", ...pin.topics].some(
|
||||||
field => field?.toLowerCase().includes(value),
|
field => field?.toLowerCase().includes(value),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue