Add description to pins

This commit is contained in:
Jon Staab 2026-07-06 11:53:12 -07:00
parent f20414975d
commit 774e2da463
6 changed files with 64 additions and 11 deletions

View file

@ -49,6 +49,9 @@
<strong class="truncate min-w-0 pr-8">{pin.title}</strong>
{/if}
{/if}
{#if pin.description}
<Content event={{content: pin.description, tags: []}} {url} />
{/if}
{#if pin.value[0] === "i"}
<Content event={{content, tags: []}} {url} />
{:else}

View file

@ -10,12 +10,12 @@
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)
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>

View file

@ -9,7 +9,7 @@
const {url, pin}: Props = $props()
const submit = async ({title, topics, value}: PinFormValues) => {
const submit = async ({title, topics, value, content}: PinFormValues) => {
const params = referenceToPin(value)
if (!params) return "Please enter a valid URL or nostr link."
@ -21,6 +21,7 @@
boards: pin.boards,
title,
topics,
description: content,
})
}
</script>
@ -30,5 +31,10 @@
heading="Edit Link"
action="Save changes"
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} />

View file

@ -3,11 +3,14 @@
title: string
topics: string[]
value: string
content: string
}
</script>
<script lang="ts">
import {writable} from "svelte/store"
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 Button from "@lib/components/Button.svelte"
import Field from "@lib/components/Field.svelte"
@ -20,6 +23,8 @@
import ModalFooter from "@lib/components/ModalFooter.svelte"
import StringMultiInput from "@lib/components/StringMultiInput.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 {clearModals} from "@app/modal"
@ -37,15 +42,20 @@
let title = $state(values.title ?? "")
let topics = $state<string[]>(values.topics ?? [])
let value = $state(values.value ?? "")
let content = $state<string | object>(values.content ?? "")
let loading = $state(false)
const uploading = writable(false)
const back = () => history.back()
const onSubmit = async () => {
loading = true
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) {
pushToast({theme: "error", message: error})
@ -57,6 +67,14 @@
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>
<Modal>
@ -76,6 +94,29 @@
placeholder="Optional title" />
{/snippet}
</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>
{#snippet label()}
Topics
@ -101,7 +142,10 @@
<Icon icon={AltArrowLeft} />
Go back
</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>
</Button>
</ModalFooter>

View file

@ -36,7 +36,7 @@ export type Pin = {
pubkey: string
identifier: string
boards: string[]
comment: string
description: string
title: string
topics: string[]
// 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,
identifier: getTagValue("d", event.tags) ?? "",
boards: getTagValues("A", event.tags),
comment: event.content,
description: event.content,
title: getTagValue("title", event.tags) ?? "",
topics: getTagValues("t", event.tags),
value: event.tags.find(tag => ["e", "a", "i"].includes(tag[0])) ?? [],
@ -118,14 +118,14 @@ const makeBoardTemplate = ({
const makePinTemplate = ({
identifier = "",
boards = [],
comment = "",
description = "",
title = "",
topics = [],
value = [],
}: Partial<Pin>) => ({
kind: PIN,
created_at: now(),
content: comment,
content: description,
tags: [
// Reuse the identifier when editing so the addressable event is replaced;
// fall back to a random one for new pins.

View file

@ -44,7 +44,7 @@
if (!value) return $pins
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),
),
)