Alejandro adf8a62954 feat: add hashtag support to rich editor (#185)
* feat: add automatic hashtag extraction and t tags in POST command

Extract hashtags from post content and automatically add them as t tags to published events.

Changes:
- Add hashtag extraction logic to RichEditor.serializeContent() using Unicode-aware regex
- Update SerializedContent interface to include hashtags field
- Update RichEditor props and callbacks to pass hashtags through the pipeline
- Add t tags for each hashtag in PostViewer.handlePublish()

Hashtags are deduplicated and stored in lowercase (following Nostr convention).
Example: #bitcoin #nostr #Bitcoin → ["t", "bitcoin"], ["t", "nostr"]

* refactor: use NoteBlueprint for automatic hashtag/mention extraction

Replace manual hashtag and mention extraction with applesauce's NoteBlueprint,
which automatically extracts hashtags, mentions, and event quotes from text content.

Changes:
- Simplify SerializedContent interface by removing manually extracted fields
- Remove hashtag extraction regex and mention/eventRef tracking from editors
- Replace manual event building with factory.create(NoteBlueprint, ...)
- Use q tags for event quotes (NIP-18) instead of e tags

Benefits:
- ~70 lines of code removed
- Leverage battle-tested applesauce extraction logic
- Automatic benefits from future applesauce improvements
- Correct semantic tags (q for quotes, p for mentions, t for hashtags)

What still works:
- Custom emoji tags (NIP-30)
- Blob attachments/imeta tags (NIP-92)
- Address references (naddr - not yet in applesauce)
- Client tag

All tests pass (980/980).

* refactor: use NoteReplyBlueprint in NIP-10 adapter

Replace manual NIP-10 tag building with NoteReplyBlueprint, which automatically
handles root/reply markers, p-tag copying, and all the threading logic.

Changes:
- Simplify sendMessage from ~95 lines to ~40 lines
- Remove manual e-tag building with root/reply markers
- Remove manual p-tag deduplication logic
- Use factory.create(NoteReplyBlueprint, parentEvent, content, options)
- Automatically get hashtags, mentions, and event quotes via setShortTextContent

Benefits:
- ~55 lines of complex threading logic removed
- Leverage battle-tested applesauce NIP-10 implementation
- Automatic root detection from parent's existing tags
- Cleaner, more maintainable code

All tests pass (980/980).

* refactor: use GroupMessageBlueprint and ReactionBlueprint in chat adapters

Replace manual event building with applesauce blueprints in all chat adapters.

Changes:
- NIP-29: Use GroupMessageBlueprint for kind 9 messages
  * Auto-handles h-tag, hashtags, mentions, emojis
  * Manually add q-tag for replies (NIP-29 specific)
  * ~15 lines removed

- All adapters (NIP-10, NIP-29, NIP-53, NIP-C7): Use ReactionBlueprint for kind 7 reactions
  * Auto-handles e-tag, k-tag, p-tag, custom emoji support
  * Protocol-specific tags (h-tag, a-tag) added manually
  * ~60 lines removed across 4 adapters

Benefits:
- ~75 lines of code removed total
- Leverage battle-tested applesauce blueprints
- Automatic hashtag, mention, and quote extraction
- Cleaner, more maintainable code

All tests pass (980/980).

* fix: add required previous field to GroupMessageBlueprint options

GroupMessageBlueprintOptions requires a 'previous' field for message threading.
Added empty array for now since we don't support threading yet.

* docs: add comprehensive blueprint documentation to applesauce skills

Added detailed documentation for:
- NoteBlueprint (automatic hashtag/mention/quote extraction)
- NoteReplyBlueprint (NIP-10 threading)
- ReactionBlueprint (kind 7 reactions)
- GroupMessageBlueprint (NIP-29 groups)
- DeleteBlueprint (NIP-09 deletion)
- EventFactory usage patterns
- Before/after examples showing code reduction
- Best practices for using blueprints

This documents the refactoring work done throughout the codebase.

* fix: use single newline separator in TipTap getText() calls

TipTap's getText() uses double newlines (\n\n) by default to separate
block nodes like paragraphs, which was causing extra blank lines in
posted content.

Changed to getText({ blockSeparator: '\n' }) in both RichEditor and
MentionEditor to use single newlines between paragraphs.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 16:20:00 +01:00
2025-12-18 15:46:02 +01:00
👶
2025-12-09 16:26:31 +01:00
2025-12-19 12:49:29 +01:00
2025-12-13 15:06:05 +01:00
2025-12-22 20:40:16 +00:00
2025-12-20 14:25:40 +01:00
2026-01-14 19:24:37 +01:00
👶
2025-12-09 16:26:31 +01:00
👶
2025-12-09 16:26:31 +01:00
👶
2025-12-09 16:26:31 +01:00
2025-12-14 16:50:16 +01:00

Grimoire

A Nostr protocol explorer and developer tool with a tiling window manager interface.

Features

  • Tiling Windows - Each window is a Nostr "app" (profile viewer, event feed, NIP docs, etc.)
  • Command Palette - Unix-style commands via Cmd+K to open apps and navigate
  • Multi-workspace - Virtual desktops with independent layouts
  • Real-time - Reactive event subscriptions with automatic updates

Stack

React 19, TypeScript, Vite, TailwindCSS, Jotai, Dexie, Applesauce

Getting Started

npm install
npm run dev

Scripts

Command Description
npm run dev Start dev server
npm run build Build for production
npm test Run tests in watch mode
npm run lint Lint code
npm run format Format code

License

MIT

Description
No description provided
Readme MIT 14 MiB
Languages
TypeScript 98.9%
CSS 0.8%
JavaScript 0.3%