Skip to content

Add pin and unpin support for notes #2306

Description

@SnowCait

Summary

Add support for editing NIP-51 pinned notes from nostter.

Pinned notes are already displayed on profiles and under /<npub>/pins, but nostter does not currently provide an action to update the user's kind 10001 pin list.

Users should be able to pin any kind 1 note to their own profile, including notes authored by other users.

Behavior

Add Pin / Unpin actions to the menu for kind 1 notes.

  • Show Pin when the note is not included in the logged-in user's kind 10001.
  • Show Unpin when it is already included.
  • Do not restrict pinning based on the note author.
  • Only expose the actions when the current account can write events.

Pinning must update the logged-in user's kind 10001; it must not modify the pinned note or its author.

Pin list format

Store public pins as e tags.

Newly created tags should always include the note author's pubkey.

When a relay hint is known:

["e", "<event id>", "<relay hint>", "<author pubkey>"]

When no relay hint is known:

["e", "<event id>", "", "<author pubkey>"]

Do not guess a relay hint.

Existing shorter forms must continue to be accepted when reading pin lists.

New pins should be appended to the end of the tag list, following NIP-51 ordering.

Updating the pin list

When pinning:

  • Use the latest kind 10001 as the base.
  • Do not add a duplicate when an e tag with the same event ID already exists.
  • Preserve all unrelated tags.
  • Preserve the existing content.
  • Append the new e tag.
  • Sign and publish the updated kind 10001.

When no kind 10001 exists yet, create one with an empty content.

When unpinning:

  • Remove all e tags referencing the target event ID.
  • Preserve all other tags.
  • Preserve the existing content.
  • If no public pins remain, publish an empty kind 10001 instead of deleting the list event.

Existing content must not be overwritten because NIP-51 may contain private list items there.

State and concurrency

Pin / Unpin operations must not silently overwrite a newer kind 10001 published by another client.

Serialize consecutive Pin / Unpin operations within nostter so that rapid operations do not lose previous changes.

After a successful update, reflect the new state without requiring a page reload in:

  • the note menu
  • the pinned note on the user's profile
  • /<npub>/pins

If publishing fails, revert any optimistic local state and report the failure.

Display

Keep the existing behavior where the last e tag is the primary pinned note shown on the profile. As new pins are appended, the most recently pinned note therefore becomes the profile pin.

The pins page should preserve pin-list ordering rather than relay response order. If the newest pin is displayed first, render the list in reverse tag order so its first item matches the profile pin.

A referenced note may no longer be retrievable from available relays. Do not automatically remove such references from kind 10001.

For the logged-in user's own pin list, unavailable references should still be removable.

Out of scope

  • Events other than kind 1
  • Creating or editing private pinned notes
  • Manual reordering
  • Writing the deprecated kind 30001 / d = "pin" format
  • Automatic migration of deprecated pin lists

References

NIP-51:
https://github.com/nostr-protocol/nips/blob/master/51.md

NIP-01:
https://github.com/nostr-protocol/nips/blob/master/01.md

Existing pinned-notes reader:
https://github.com/SnowCait/nostter/blob/main/web/src/lib/PinnedNotes.ts

Existing profile pinned-note UI:
https://github.com/SnowCait/nostter/blob/main/web/src/lib/components/items/PinnedNote.svelte

Existing pinned-notes page:
https://github.com/SnowCait/nostter/blob/main/web/src/routes/%28app%29/%5Bslug%3Dnpub%5D/pins/%2Bpage.svelte

Existing note menu:
https://github.com/SnowCait/nostter/blob/main/web/src/lib/components/MenuButton.svelte

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions