Commit Graph

29 Commits

Author SHA1 Message Date
Alejandro
dd6b30b82e Add NIP-85 Trusted Assertions support with renderers (#252)
* feat: add NIP-85 Trusted Assertions feed & detail renderers

Add support for NIP-85 Trusted Assertion events (kinds 30382-30385) and
the Trusted Provider Declaration (kind 10040) with kind constants,
helper library, and feed + detail renderers.

- Add kind entries for 10040, 30382, 30383, 30384, 30385 to EVENT_KINDS
- Create src/lib/nip85-helpers.ts with cached helpers for parsing
  assertion data (user, event, address, external) and provider lists
- Create shared TrustedAssertionRenderer for all 4 assertion kinds with
  rank bar, subject display, and compact metrics preview
- Create TrustedAssertionDetailRenderer with full metrics table,
  rank visualization, topics, and raw tag fallback
- Create TrustedProviderListRenderer/DetailRenderer for kind 10040
  with provider table and encrypted entries indicator
- Register all renderers in kinds/index.tsx

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* refactor: extract NIP-73 helpers and shared ExternalIdentifierDisplay

Move getExternalIdentifierIcon() and getExternalIdentifierLabel() from
nip22-helpers.ts into a new nip73-helpers.ts since they are NIP-73
utilities, not NIP-22 specific. Add inferExternalIdentifierType() and
getExternalIdentifierHref() helpers.

Create shared ExternalIdentifierDisplay components (inline + block
variants) that use proper NIP-73 type-specific icons (Globe for web,
BookOpen for ISBN, Podcast for podcasts, Film for ISAN, etc.) instead
of a generic ExternalLink icon.

- Kind 1111 renderer now uses ExternalIdentifierInline for root scope
- Kind 30385 assertion renderer uses ExternalIdentifierInline (feed)
  and ExternalIdentifierBlock (detail) for NIP-73 subjects
- nip22-helpers.ts re-exports from nip73-helpers for compatibility

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* fix: UI polish for NIP-85 renderers

Address review feedback across all NIP-85 components:

Icon: Replace BarChart3 with ShieldCheck for assertion kind constants
(30382-30385) — communicates "verified trust data" vs generic analytics.

Feed renderer: Subject is now the visual anchor (ClickableEventTitle)
with kind label as a small outline Badge above it. Rank bar widened to
w-32, color-coded green/yellow/red by score threshold. Fix "Zaps Recd"
abbreviation to "Zaps In".

Detail renderer: Metrics grouped into Activity, Zaps, Moderation
sections with uppercase section headers. Kind 30384 addresses now
show "Kind X by <UserName> / d-tag" instead of raw hex. ExternalMetrics
type badges now show NIP-73 icons + friendly labels (getExternalTypeLabel)
instead of raw k-tag values like "podcast:item:guid".

Provider list: Feed uses compact Badge for kind:tag + count summary.
Detail uses stacked cards instead of 3-column table for narrow panels.

ExternalIdentifierBlock: Linked blocks now show dotted underline on
label + ExternalLink icon for clear click affordance.

Add getExternalTypeLabel() to nip73-helpers for k-value display names.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* fix: use Progress component for rank bars, consistent sats formatting

Replace custom rank bar divs with the existing Progress UI component
(with new indicatorClassName prop for color-coded fills).

Make sat amount displays consistent with zap receipt renderer pattern:
value and "sats" unit are rendered as separate elements — numeric value
in font-medium, unit in smaller muted text — matching how Kind9735
displays amounts across the app.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* fix: use RelayLink for relay URLs, remove redundant kindTag, add relay hints

Provider list renderers now use RelayLink instead of raw relay URL
strings — shows favicon, insecure ws:// warning, opens relay detail
on click.

Remove kindTag display from provider cards — it's an internal
protocol detail redundant in the UI context.

Pass relay hints from provider entries to UserName so profiles can
be fetched from the relay the provider actually publishes to.

Add UserName relayHints prop (forwarded to useProfile).

Add RelayLink and UserName to Shared Components section in CLAUDE.md
so they're consistently used across the codebase.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* docs: expand shared components section in CLAUDE.md

Add BaseEventContainer, ClickableEventTitle, RichText, QuotedEvent,
and CustomEmoji to the shared components reference. These are the
core building blocks used across all kind renderers — documenting
them prevents re-implementation and ensures consistent patterns.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* docs: trim shared components list in CLAUDE.md

Remove BaseEventContainer and QuotedEvent — these are internal
patterns that kind renderer authors already know from context,
not general-purpose components that get misused or forgotten.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* feat: show metric type labels in trusted assertion feed view

Add Label components to the assertion feed renderer so you can see at a
glance which metrics an assertion carries (Followers, Posts, Zaps, etc.)
instead of just numeric values. Also swap Badge → Label for the kind
indicator for visual consistency.

Replace hardcoded green/yellow/red rank colors with theme variables
(success/warning/destructive) in both feed and detail renderers so the
rank bar works correctly across all themes.

Add Label to CLAUDE.md shared components list (22 imports across the
codebase).

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* feat: show provider kind tag in trusted provider list renderers

Add Label with formatKindTag() to both feed and detail views so each
provider row shows what it provides (e.g. "User Assertion: Rank").
Also swap Badge → Label for consistency with the assertion renderers.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

* fix: stabilize relayHints in useProfile to prevent fetch abort loop

relayHints was used directly in the useEffect dependency array, so
callers passing a new array literal (e.g. [p.relay]) on every render
caused the effect to re-run each cycle — aborting the previous network
fetch before it could complete. The IndexedDB fast-path masked this in
the feed view (profiles already cached), but the detail view showed
raw pubkeys because profiles were never fetched from the network.

Wrap relayHints in a JSON.stringify-based useMemo (same pattern as
useStableArray) so the effect only re-runs when the actual relay
values change.

https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 09:14:14 +01:00
Alejandro
8f2f055566 feat: repository tree visualization (#31)
* docs: add plan for repository tree visualization feature

Comprehensive plan covering:
- git-natural-api library analysis and API documentation
- useGitTree/useGitBlob hooks for fetching git data
- FileTreeView component using Radix Collapsible
- Shiki migration with on-demand language loading
- Multi-server fallback for redundant clone URLs
- Dexie caching for offline access

* docs: add comprehensive Shiki migration plan

Detailed plan for migrating from Prism.js to Shiki with lazy loading:
- Analysis of all 8 components using SyntaxHighlight
- Shiki service with singleton highlighter and on-demand language loading
- Custom Grimoire dark theme matching current Prism styles
- Language alias mapping for 50+ extensions
- React hook for async highlighting with loading states
- CSS theme preserving minimalistic dark aesthetics
- Migration steps with rollback plan

* feat: migrate syntax highlighting from Prism.js to Shiki

Replace Prism.js with Shiki for syntax highlighting with several key improvements:

- Lazy loading: Languages loaded on-demand via dynamic imports instead of bundling all upfront
- Broader language support: 200+ TextMate grammars vs 11 statically imported
- Singleton highlighter: Core languages (JS, TS, JSON, diff, bash) preloaded, others loaded on first use

New files:
- src/lib/shiki.ts: Shiki service with highlightCode(), normalizeLanguage(), language aliases
- src/hooks/useHighlightedCode.ts: React hook for async highlighting with loading states
- src/styles/shiki-theme.css: Grimoire dark theme matching previous minimalistic style

Updated components:
- SyntaxHighlight: Now uses Shiki with graceful loading/error states
- CodeSnippetRenderer/DetailRenderer: Simplified, removed manual language mapping
- MarkdownContent: Removed type casts, any language now supported

Removed:
- prismjs and @types/prismjs dependencies
- src/styles/prism-theme.css

* feat: add repository file tree visualization

Add file tree explorer to the Repository detail renderer (kind 30617)
using @fiatjaf/git-natural-api for fetching git trees via HTTP.

New files:
- src/lib/git-types.ts: TypeScript types for DirectoryTree, SelectedFile, etc.
- src/hooks/useGitTree.ts: Hook to fetch git repository tree from clone URLs
  - Tries multiple clone URLs in sequence
  - Uses getDirectoryTreeAt with filter capability when available
  - Falls back to shallowCloneRepositoryAt otherwise
- src/hooks/useGitBlob.ts: Hook to fetch individual file content by hash
  - Detects binary files
  - Returns both raw Uint8Array and decoded text
- src/components/ui/FileTreeView.tsx: Recursive tree view component
  - Collapsible directories with chevron icons
  - File icons based on extension (code, json, text, image, etc.)
  - Alphabetical sorting with directories first
- src/components/nostr/kinds/RepositoryFilesSection.tsx: Main integration
  - Side-by-side tree and file preview layout
  - Syntax-highlighted file content using existing SyntaxHighlight
  - Binary file detection with appropriate UI
  - Loading/error states

Modified:
- RepositoryDetailRenderer.tsx: Added RepositoryFilesSection below relays

Dependencies:
- Added @fiatjaf/git-natural-api from JSR

* fix: improve repository tree visualization UX

- Collapse directories by default in file tree
- Hide files section on tree loading error
- Add code-like skeleton loader with file header
- Fix syntax highlight size jump between loading/loaded states
- Replace purple accent with grayscale theme
- Preload Rust and Markdown languages for reliable highlighting

* refactor: improve git tree and syntax highlighting

- Remove shallow clone fallback from useGitTree, only use no-blobs fetch
  Servers without filter capability are skipped instead of downloading blobs
- Add light theme support for Shiki syntax highlighting
  Theme is automatically selected based on current color scheme

* fix: improve dark theme contrast for syntax highlighting

* fix: address code review issues

- useGitTree: use useStableArray for cloneUrls to fix dependency tracking
- useGitTree/useGitBlob: add isMounted checks to prevent state updates after unmount
- RepositoryFilesSection: remove unnecessary useMemo for language
- FileTreeView: use path instead of hash for React keys
- shiki: track failed languages to avoid repeated console warnings

* fix: improve dark theme contrast for syntax highlighting

- Add CSS variables for syntax highlighting instead of hardcoded colors
- Add --syntax-constant and --syntax-tag variables to light and dark themes
- Use high contrast colors for dark mode (bright green strings, purple keywords)
- Simplify Shiki transformer to output CSS classes instead of inline styles
- Remove unused parameters from transformer callback

* fix: restore syntax highlighting colors

Revert the CSS class-based approach which was failing to classify tokens.
Instead, keep Shiki's inline styles from the theme and only remove
backgrounds to let CSS handle those. The theme colors now provide
syntax highlighting directly.

* feat: add copy button and CSS variable-based syntax highlighting

- Add copy button next to file name in file viewer header (icon-only)
- Use Shiki's createCssVariablesTheme for proper theme integration
- Map Shiki CSS variables to our theme system variables
- Syntax highlighting now works correctly across all themes (light/dark)

* refactor: create IconCopyButton component and use CopyCheck consistently

- Add IconCopyButton component for reusable icon-only copy buttons
- Refactor RepositoryFilesSection to use IconCopyButton
- Replace Check with CopyCheck in ChatMessageContextMenu
- Replace Check with CopyCheck in BaseEventRenderer
- Use text-success instead of text-green-500 for consistency

* fix: add HTML, CSS, TOML to core languages and expand token mappings

- Add html, css, toml to CORE_LANGUAGES for eager loading
- Add variableDefaults to cssVarsTheme for proper initialization
- Expand shiki-theme.css with more token type mappings:
  - HTML/XML: tag, attribute, attr-value
  - CSS: selector, property
  - Additional: variable, operator, number, boolean, regex, etc.

* fix: improve diff line spacing with flex layout

- Use flex-col with gap-0 on code element for tight line packing
- Reduce line-height from 1.5 to 1.4 for tighter spacing
- Add .line display:block with min-height for consistent sizing
- Simplify diff background styling (remove negative margin hack)

* fix: improve code block line spacing and wrap long lines

- Increase line-height from 1.4 to 1.5 for better readability
- Use pre-wrap instead of pre to allow long line wrapping
- Add overflow-wrap: break-word to break long URLs/strings

* chore: remove planning docs

* chore: update @fiatjaf/git-natural-api to 0.2.3

* fix: make code blocks horizontally scrollable with full-width diff backgrounds

- Use white-space: pre for horizontal scrolling instead of wrapping
- Add width: fit-content and min-width: 100% to code element
- Ensure diff line backgrounds extend full width when scrolling

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-30 12:35:59 +01:00
Alejandro
34bad20ce9 Fix logo SVG centering and regenerate icons (#218)
The SVG path extended slightly beyond the viewBox (bezier control points
reached x=121.464 while viewBox ended at x=121), while the left edge was
flush at x=0. This caused uneven spacing.

Changed viewBox from "0 0 121 160" to "-0.5 0 122 160" to add equal
0.5px margins on both sides, properly centering the logo content.

https://claude.ai/code/session_019PGCQHRovoNE81udohhU3R

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 11:07:43 +01:00
Alejandro
569388c135 Add PWA icon generation and Grimoire logo component (#214)
* feat: add Grimoire logo SVG and generate PWA assets

- Add logo.svg with the official Grimoire logo and gradient
- Create GrimoireLogo React component for use in the app
- Add scripts/generate-pwa-icons.mjs to generate all PWA icons from SVG
- Regenerate all favicon and PWA icons from the new logo
- Update mobile welcome screen to show the logo instead of text

* feat: use transparent backgrounds for PWA icons and add theme gradient option

- Update generate-pwa-icons.mjs to output PNGs with transparent backgrounds
- Add gradient prop to GrimoireLogo component ("original" or "theme")
- Theme gradient matches text-grimoire-gradient CSS (yellow -> orange -> purple -> cyan)
- Mobile welcome screen now uses theme gradient to match ASCII art

* feat: use original gradient for mobile welcome logo

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-26 11:46:17 +01:00
Alejandro
7b7b24d41a feat: add client tag support to all event creation (#191)
* feat: add client tag support to all event creation

Implements a global settings system to control whether the Grimoire client tag
should be included in all published events. This allows users to opt-in or
opt-out of identifying their client in published events.

Changes:
- Created global settings service (src/services/settings.ts) with reactive
  BehaviorSubject for app-wide configuration
- Created useSettings hook (src/hooks/useSettings.ts) for React components
- Migrated PostViewer from local settings to global settings system
- Added client tag support to:
  - Post publishing (PostViewer.tsx)
  - Spell publishing (publish-spell.ts)
  - Event deletion (delete-event.ts)
  - NIP-29 chat messages, reactions, join/leave, and group bookmarks
    (nip-29-adapter.ts)
  - Zap requests (create-zap-request.ts)

The client tag setting defaults to enabled (true) for backward compatibility.
Users can toggle this in the post composer settings dropdown.

All event creation locations now check settingsManager.getSetting("includeClientTag")
before adding the GRIMOIRE_CLIENT_TAG to event tags.

* refactor: exclude client tags from NIP-29 and zap requests

Remove client tag support from NIP-29 adapter events and zap requests
as these events may be rejected by servers with large tags or have
specific size constraints.

Changes:
- Removed client tag from NIP-29 chat messages (kind 9)
- Removed client tag from NIP-29 reactions (kind 7)
- Removed client tag from NIP-29 join/leave requests (kind 9021, 9022)
- Removed client tag from NIP-29 group bookmarks (kind 10009)
- Removed client tag from zap requests (kind 9734)

Client tags remain enabled for:
- Regular posts (kind 1)
- Spell publishing (kind 777)
- Event deletion (kind 5)

This ensures maximum compatibility with relay servers and LNURL endpoints
while still providing client identification for standard events.

* feat: implement comprehensive namespaced settings system

Redesigned the settings system with proper namespacing, type safety, validation,
and migration support. This provides a solid foundation for all app configuration.

Settings Structure:
- post: Post composition settings (client tag, relay selection)
- appearance: UI/theme settings (theme, compact mode, font size, animations)
- relay: Relay configuration (fallback, discovery, outbox, timeouts)
- privacy: Privacy settings (read receipts, content warnings, link warnings)
- database: Caching settings (max events, cleanup, IndexedDB options)
- notifications: Browser notifications preferences
- developer: Debug and experimental features

Key Features:
- Fully typed with TypeScript interfaces for each namespace
- Automatic validation with fallback to defaults for invalid data
- Migration system from old flat structure to namespaced structure
- Backwards compatible with old "grimoire-settings" localStorage key
- Import/export functionality for settings backup/restore
- Reactive updates via RxJS BehaviorSubject
- Section-level and individual setting updates
- Reset individual sections or all settings

Changes:
- Created comprehensive AppSettings interface with 7 namespaced sections
- Implemented SettingsManager class with reactive updates and persistence
- Updated useSettings hook to support namespaced API
- Updated PostViewer, publish-spell, and delete-event to use new API
  (settingsManager.getSetting("post", "includeClientTag"))
- Added extensive inline documentation for all settings

Migration:
- Automatically migrates old includeClientTag setting to post.includeClientTag
- Moves data from "grimoire-settings" to "grimoire-settings-v2" key
- Validates all loaded settings and fills in defaults for missing values

This foundation will support future settings UI with tabbed interface.

* feat: add comprehensive settings UI with Post and Appearance sections

Created a minimal MVP settings system accessible via command palette and user menu.
Settings are organized in a clean tabbed interface with two initial sections.

UI Features:
- SettingsViewer component with sidebar navigation
- Post section: Toggle to include Grimoire client tag in published events
- Appearance section:
  - Theme selector (light/dark/system)
  - Toggle to show/hide client tags in event UI ("via Grimoire" etc)

Integration:
- Added "settings" command to command palette
- Added "Settings" option to user menu (before Support Grimoire)
- Registered "settings" as new AppId in window system

Display Logic:
- BaseEventRenderer now honors settings.appearance.showClientTags
- When disabled, "via Grimoire" and other client tags are hidden from events
- Setting applies instantly across all event renderers

Technical Details:
- SettingsViewer uses existing UI components (Checkbox, Button, Label)
- Leverages useSettings hook for reactive updates
- Settings persist to localStorage via settingsManager
- Simple button group for theme selection instead of dropdown
- Clean two-column layout with icons for each section

This provides a solid foundation for adding more settings sections later
(relay config, privacy, database, notifications, developer options).

* refactor: redesign settings UI with shadcn Tabs and cleaner layout

Simplified the settings UI to be more minimal and follow Grimoire patterns:

Changes:
- Use shadcn Tabs component instead of custom sidebar navigation
- Remove non-working theme selector (no theme system implemented yet)
- Use regular <label> elements with htmlFor instead of custom Label component
- Shorter, cleaner copy throughout
- Properly remove unused theme-related imports from user menu
- Follow Grimoire UI patterns (similar to SettingsDialog)

Settings sections:
- Post: Include client tag setting
- Appearance: Show client tags setting

The UI is now cleaner, uses proper form semantics, and matches the rest
of Grimoire's design system.

* feat: add working theme selector and improve settings UI

Added fully functional theme selector and improved the settings UI with
better components and cleaner copy.

Changes:
- Created Switch component (shadcn/radix-ui) for boolean settings
- Added working theme selector that integrates with existing theme system
- Uses useTheme hook to display available themes (Dark, Light, Plan9)
- Reordered sections: Appearance first, Post second
- Reordered settings: Theme first in Appearance section
- Replaced Checkbox with Switch for better UX on boolean toggles
- Simplified copy: "Add Grimoire tag to published events" instead of listing kinds
- Simplified copy: "Display client identifiers in events" instead of "via Grimoire" mention
- Better layout: Label/description on left, Switch on right

Settings now use proper form components:
- Switch for boolean toggles (include client tag, show client tags)
- Button group for theme selection
- Clean justify-between layout for settings rows

The theme selector works immediately - clicking Dark/Light/Plan9 applies
the theme instantly via the existing ThemeProvider context.

* refactor: improve settings UI with Select, icons, and better spacing

Enhanced the settings UI with shadcn Select component, tab icons, and
improved typography and spacing.

Changes:
- Created Select component (shadcn/radix-ui) for dropdowns
- Added icons to tabs: Palette for Appearance, FileEdit for Post
- Replaced button group theme selector with Select dropdown (w-48)
- Added gap-4 between labels and switches for better spacing
- Increased setting names from text-sm to text-base (bigger)
- Reduced help text from text-sm to text-xs (smaller)
- Added gap-3 between "Theme" label and Select
- Added font-medium to "Theme" label for consistency

Layout improvements:
- Theme selector now uses Select with 192px width
- All setting rows have gap-4 between content and controls
- Consistent text hierarchy: font-medium for labels, text-xs for descriptions
- Tab triggers have gap-2 between icon and text

The Select component is properly integrated with the theme system and
displays Dark, Light, and Plan9 options with checkmark indicators.

* refactor: use horizontal layout for theme selector

Aligned theme selector with other settings by using horizontal layout:
- Label and description on left, Select on right
- Added gap-4 for consistent spacing
- Changed label from text-sm to text-base font-medium
- Added helpful description: 'Choose your color scheme'
- Added id='theme' for accessibility

Now all settings follow the same visual pattern.

* refactor: reduce theme selector width for compact display

Changed theme selector from w-48 (192px) to w-32 (128px) since
theme names are short (Dark, Light, Plan9). More compact and
better proportioned for the content.

* fix: pass 'settings' command string when opening from menu

Changed the command string from 'Settings' to 'settings' when opening
the settings window from the user menu. This ensures clicking edit on
the settings window shows the correct command: 'settings'

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 23:11:25 +01:00
Alejandro
53f29b9b63 fix: improve tooltip contrast across all themes (#192)
* fix: improve tooltip contrast across all themes

CRITICAL FIX: Plan 9 theme had a catastrophic contrast failure where
tooltip text (HSL 60, 100%, 96%) was nearly identical to the background
(HSL 60, 100%, 94%), creating a ~1:1 contrast ratio that made tooltips
completely unreadable.

Changes:
- Added dedicated `tooltip` and `tooltipForeground` colors to theme system
- Updated all three built-in themes (dark, light, plan9) with proper colors
- Modified tooltip component to use new colors instead of primary/primary-foreground
- Added rounded corners and shadow to tooltips for better visual separation

Theme-specific tooltip colors:
- Dark theme: Dark blue-gray background (#217.2 32.6% 17.5%) with light text
- Light theme: Very dark background (#222.2 47.4% 11.2%) with light text
- Plan 9 theme: Dark blue (#220 50% 25%) with pale yellow text

All tooltip colors now meet WCAG AA standards (4.5:1+ contrast ratio) and
are clearly visible against their respective theme backgrounds.

Files modified:
- src/lib/themes/types.ts: Added tooltip color types
- src/lib/themes/builtin/*.ts: Added tooltip colors to all themes
- src/lib/themes/apply.ts: Apply tooltip CSS variables on theme change
- src/index.css: Added tooltip CSS variables for light/dark themes
- tailwind.config.js: Exposed tooltip colors as Tailwind utilities
- src/components/ui/tooltip.tsx: Use new tooltip colors with improved styling

* fix: increase dark mode tooltip lightness for better visibility

Dark mode tooltips were too dark (17.5% lightness) against the very dark
background (4.9% lightness), making the tooltip box hard to distinguish.

Changes:
- Increased dark mode tooltip lightness from 17.5% to 30%
- This provides ~6:1 contrast ratio between tooltip and background
- Tooltip box now clearly visible against dark background
- Text contrast remains excellent (light text on medium-dark background)

The tooltip now stands out properly while maintaining high text readability.

* fix: improve ChatViewer group tooltip contrast in dark mode

The group description tooltip in ChatViewer had poor contrast due to
using `text-primary-foreground` color classes that conflicted with
the new tooltip background colors.

Issues fixed:
1. Description text using `text-primary-foreground/90` - replaced with `opacity-90`
2. Protocol button using `bg-primary-foreground/20` with `text-primary-foreground`
   (light-on-light, ~1.5:1 contrast) - now uses `bg-tooltip-foreground/20`
3. All other text using `text-primary-foreground` variants - replaced with `opacity-*`

This allows the text to inherit the correct `text-tooltip-foreground` color
from the TooltipContent component, ensuring proper contrast against the
`bg-tooltip` background in all themes.

Files modified:
- src/components/ChatViewer.tsx: Updated tooltip text color classes

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 22:59:01 +01:00
Alejandro
5fa2a1c9b8 feat: Add context menu for chat message interactions (#94)
Add right-click/long-press context menu to chat messages with event interactions:
- Reply to message
- Copy message text
- Open event detail (opens in new window)
- Copy event ID (nevent/naddr with relay hints)
- View raw JSON

Implements the same EventMenu pattern used in feed renderers, providing
consistent UX across the app. No visible UI elements added - menu appears
only on right-click or long-press (mobile).

Components added:
- src/components/ui/context-menu.tsx - Radix UI context menu primitives
- src/components/chat/ChatMessageContextMenu.tsx - Chat-specific context menu
- Integrated into MessageItem in ChatViewer.tsx

Dependencies:
- Added @radix-ui/react-context-menu

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-14 18:09:19 +01:00
Alejandro
280a395187 Make grouplist viewer mobile friendly with sidebar (#72)
* feat: make GroupListViewer mobile-friendly with Sheet sidebar

- Add Sheet component for mobile drawer behavior
- Add Separator component for UI dividers
- Add Sidebar component with mobile/desktop variants
- Update GroupListViewer to show sheet-based sidebar on mobile (<768px)
  and resizable sidebar on desktop
- Mobile view includes toggle button in header and auto-closes on selection

* refactor: integrate sidebar toggle into ChatViewer header

- Add headerPrefix prop to ChatViewer for custom header content
- Pass sidebar toggle button via headerPrefix on mobile
- Remove duplicate mobile header from GroupListViewer
- Reduces vertical space usage by reusing ChatViewer's existing header

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-13 11:52:52 +01:00
Alejandro Gómez
6d01ee33ef feat: implement unified chat system with NIP-C7 and NIP-29 support
Core Architecture:
- Protocol adapter pattern for chat implementations
- Base adapter interface with protocol-specific implementations
- Auto-detection of protocol from identifier format
- Reactive message loading via EventStore observables

Protocol Implementations:
- NIP-C7 adapter: Simple chat (kind 9) with npub/nprofile support
- NIP-29 adapter: Relay-based groups with member roles and moderation
- Protocol-aware reply message loading with relay hints
- Proper NIP-29 members/admins fetching using #d tags

UI Components:
- ChatViewer: Main chat interface with virtualized message timeline
- ChatMessage: Message rendering with reply preview
- ReplyPreview: Auto-loading replied-to messages from relays
- MembersDropdown: Virtualized member list with role labels
- RelaysDropdown: Connection status for chat relays
- ChatComposer: Message input with send functionality

Command System:
- chat command with identifier parsing and auto-detection
- Support for npub, nprofile, NIP-05, and relay'group-id formats
- Integration with window system and dynamic titles

NIP-29 Specific:
- Fetch kind:39000 (metadata), kind:39001 (admins), kind:39002 (members)
- Extract roles from p tags: ["p", "<pubkey>", "<role1>", "<role2>"]
- Role normalization (admin, moderator, host, member)
- Single group relay connection management

Testing:
- Comprehensive chat parser tests
- Protocol adapter test structure
- All tests passing (704 tests)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 21:38:23 +01:00
Alejandro Gómez
fc63b3c685 fix: event publication 2025-12-21 21:50:09 +01:00
Alejandro Gómez
78a8c8e5b2 chore: apply prettier formatting fixes
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 20:12:40 +01:00
Alejandro Gómez
5d9ff3cf56 feat: implement Nostr Wallet Connect (NWC)
- Add applesauce-wallet-connect dependency
- Create WalletService for managing NWC connection
- Create WalletViewer component for UI
- Register 'wallet' command
- Fix build errors in spell/spellbook components due to applesauce-actions upgrade
2025-12-21 18:07:55 +01:00
Alejandro Gómez
2987a37e65 feat: spells 2025-12-20 14:25:40 +01:00
Alejandro Gómez
a6650ff6e1 fix: type errors 2025-12-18 16:00:56 +01:00
Alejandro Gómez
5cc97484b5 fix: improved balanced window algo 2025-12-18 15:45:34 +01:00
Alejandro Gómez
3fba62b316 ui: simpler streams 2025-12-18 15:29:01 +01:00
Alejandro Gómez
d624b5b05a ui: simplify layout settings and add smooth animations
- Remove success notification when applying layouts (keep only errors)
- Add CSS transitions for smooth window resizing/repositioning
- Replace large settings Dialog with compact Popover
- Reduce settings UI from ~220 lines to ~97 lines
- Remove verbose descriptions and preview section
- Make settings match site's minimal UI patterns
- Settings now update live without Save/Cancel buttons
- Create popover.tsx component using Radix UI primitives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 12:55:26 +01:00
Alejandro Gómez
6c6f3728c0 ui: adjust spacing for quote skeletons 2025-12-18 11:10:30 +01:00
Alejandro Gómez
390290d2eb wip: skeletons 2025-12-15 22:19:28 +01:00
Alejandro Gómez
5dd885b888 feat: community NIPs 2025-12-15 15:42:11 +01:00
Alejandro Gómez
19cdde0110 feat: syntax highlighting 2025-12-15 13:11:59 +01:00
Alejandro Gómez
6560dc203c ui: query viewer improvements 2025-12-14 15:34:07 +01:00
Alejandro Gómez
b8d05e40c7 feat: export to JSONL 2025-12-14 12:21:09 +01:00
Alejandro Gómez
a4d9720358 feat: copy kind 2025-12-13 15:22:48 +01:00
Alejandro Gómez
6568daf944 wip: relay pool view and auth 2025-12-13 15:06:05 +01:00
Alejandro Gómez
32160480e2 feat: kind links 2025-12-12 22:22:28 +01:00
Alejandro Gómez
b7fbaf5e46 feat: copy bech32 2025-12-11 21:54:02 +01:00
Alejandro Gómez
38f5461b54 chore: setup eslint and prettier with code formatting 2025-12-11 13:00:25 +01:00
Alejandro Gómez
cd41034b2f 👶 2025-12-09 16:26:31 +01:00