# Boris

A minimal nostr client for bookmark management, built with [applesauce](https://github.com/hzrd149/applesauce).

## Features

- **Nostr Authentication**: Connect using your nostr account via browser extension
- **Bookmark Display**: View your nostr bookmarks as per [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md)
- **Content Classification**: Automatically detect and classify URLs (articles, videos, YouTube, images)
- **Reader Mode**: View article content inline with readable formatting
- **Collapsible Sidebar**: Expand/collapse bookmark list for focused reading
- **Profile Integration**: Display user profile images using applesauce ProfileModel
- **Relative Timestamps**: Human-friendly time display (e.g., "2 hours ago")
- **Event Links**: Quick access to view bookmarks on search.dergigi.com
- **Private Bookmarks**: Support for Amethyst-style hidden/encrypted bookmarks
- **Highlights Panel**: View and manage your NIP-84 highlights in a dedicated collapsible panel
- **Three-Pane Layout**: Bookmarks sidebar, content viewer, and highlights panel working together
- **Minimal UI**: Clean, modern interface focused on bookmark management

## Getting Started

### Prerequisites

- Node.js 18+ 
- npm, pnpm, or yarn

### Installation

1. Clone the repository:
```bash
git clone <your-repo-url>
cd boris
```

2. Install dependencies:
```bash
npm install
# or
pnpm install
# or
yarn install
```

3. Start the development server:
```bash
npm run dev
# or
pnpm dev
# or
yarn dev
```

4. Open your browser and navigate to `http://localhost:3000`

## Usage

1. **Connect**: Click "Connect with Nostr" to authenticate using your nostr account
2. **View Bookmarks**: Once connected, you'll see all your nostr bookmarks in the left sidebar
3. **View Highlights**: Your NIP-84 highlights appear in the right panel
4. **Navigate**: Click on bookmark URLs to view content in the center panel
5. **Collapse Panels**: Use the collapse buttons to hide/show sidebars for focused viewing

## Technical Details

- Built with React and TypeScript
- Uses [applesauce-core](https://github.com/hzrd149/applesauce) for nostr functionality
- Implements [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md) for bookmark management
- Supports both individual bookmarks and bookmark lists

## Development

### Project Structure

```
src/
├── components/
│   ├── Login.tsx                        # Authentication component
│   ├── Bookmarks.tsx                    # Main bookmarks view with layout
│   ├── BookmarkList.tsx                 # Bookmark list sidebar
│   ├── BookmarkItem.tsx                 # Individual bookmark card
│   ├── SidebarHeader.tsx                # Header bar with collapse, profile, logout
│   ├── ContentPanel.tsx                 # Content viewer panel
│   ├── HighlightsPanel.tsx              # Highlights sidebar panel (NIP-84)
│   ├── HighlightItem.tsx                # Individual highlight display
│   ├── IconButton.tsx                   # Reusable icon button component
│   ├── ContentWithResolvedProfiles.tsx  # Profile mention resolver
│   ├── ResolvedMention.tsx              # Nostr mention component
│   └── kindIcon.ts                      # Kind-specific icon mapping
├── services/
│   ├── bookmarkService.ts               # Main bookmark fetching orchestration
│   ├── bookmarkProcessing.ts            # Decryption and processing pipeline
│   ├── bookmarkHelpers.ts               # Shared types, guards, and utilities
│   ├── bookmarkEvents.ts                # Event type handling and deduplication
│   ├── highlightService.ts              # Highlight fetching (NIP-84)
│   └── readerService.ts                 # Content extraction via reader API
├── types/
│   ├── bookmarks.ts                     # Bookmark type definitions
│   ├── highlights.ts                    # Highlight type definitions (NIP-84)
│   ├── nostr.d.ts                       # Nostr type augmentations
│   └── relative-time.d.ts               # relative-time package types
├── utils/
│   ├── bookmarkUtils.tsx                # Bookmark rendering utilities
│   └── helpers.ts                       # General helper functions
├── App.tsx                              # Main application component
├── main.tsx                             # Application entry point
└── index.css                            # Global styles
```

### Private (hidden) bookmarks (Amethyst-style)

We support Amethyst-style private (hidden) bookmark lists alongside public ones (NIP‑51):

- **Detection and unlock**
  - Use `Helpers.hasHiddenTags(evt)` and `Helpers.isHiddenTagsLocked(evt)` to detect hidden tags.
  - First try `Helpers.unlockHiddenTags(evt, signer)`; if that fails, try with `'nip44'`.
  - For events with encrypted `content` that aren’t recognized as supporting hidden tags (e.g. kind 30001), manually decrypt:
    - Prefer `signer.nip44.decrypt(evt.pubkey, evt.content)`, fallback to `signer.nip04.decrypt(evt.pubkey, evt.content)`.

- **Parsing and rendering**
  - Decrypted `content` is JSON `string[][]` (tags). Convert with `Helpers.parseBookmarkTags(hiddenTags)`.
  - Map to `IndividualBookmark[]` via our `processApplesauceBookmarks(..., isPrivate=true)` and append to the private list so they render immediately alongside public items.

- **Caching for downstream helpers**
  - Cache manual results on the event with `BookmarkHiddenSymbol` and also store the decrypted blob under `EncryptedContentSymbol` to aid debugging and hydration.

- **Structure**
  - `src/services/bookmarkService.ts`: orchestrates fetching, hydration, and assembling the final bookmark payload.
  - `src/services/bookmarkProcessing.ts`: decryption/collection pipeline (unlock, manual decrypt, parse, merge).
  - `src/services/bookmarkHelpers.ts`: shared types, guards, mapping, hydration, and symbols.
  - `src/services/bookmarkEvents.ts`: event type and de‑duplication for NIP‑51 lists/sets.

- **Notes**
  - We avoid `any` via narrow type guards for `nip44`/`nip04` decrypt functions.
  - Files are kept small and DRY per project rules.
  - Built on applesauce helpers (`Helpers.getPublicBookmarks`, `Helpers.getHiddenBookmarks`, etc.). See applesauce docs: https://hzrd149.github.io/applesauce/typedoc/modules.html

### Building for Production

```bash
npm run build
# or
pnpm build
# or
yarn build
```

## TODO

### High Priority
- [ ] **Mobile Responsive Design**: Optimize sidebar and content panel for mobile devices
- [ ] **Keyboard Shortcuts**: Add keyboard navigation (collapse sidebar, navigate bookmarks)
- [ ] **Search & Filter**: Add ability to search bookmarks by title, URL, or content
- [ ] **Error Handling**: Improve error states and retry logic for failed fetches
- [ ] **Loading States**: Better skeleton screens and loading indicators

### Medium Priority
- [ ] **Bookmark Creation**: Add ability to create new bookmarks
- [ ] **Bookmark Editing**: Edit existing bookmark metadata and tags
- [ ] **Bookmark Deletion**: Remove bookmarks from lists
- [ ] **Sorting Options**: Sort by date, title, kind, or custom order
- [ ] **Bulk Actions**: Select and perform actions on multiple bookmarks
- [ ] **Video Embeds**: Inline YouTube and video playback for video bookmarks

### Nice to Have
- [ ] **Dark/Light Mode Toggle**: User preference for color scheme
- [ ] **Export Functionality**: Export bookmarks as JSON, CSV, or HTML
- [ ] **Import Bookmarks**: Import from browser bookmarks or other formats
- [ ] **Tags & Categories**: Better organization with custom tags
- [ ] **Bookmark Collections**: Create and manage custom bookmark collections
- [ ] **Offline Support**: Cache bookmarks for offline viewing
- [ ] **Share Bookmarks**: Generate shareable links to bookmark lists
- [ ] **Performance Optimization**: Virtual scrolling for large bookmark lists
- [ ] **Browser Extension**: Quick bookmark saving from any page

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request. Make sure to:

- Follow the existing code style
- Keep files under 210 lines
- Use conventional commits
- Run linter and type checks before submitting

## License

MIT

