mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 22:54:30 +01:00
e83976e5e018052344b46fbd6c6c44059d25fe0c
- Update package.json name field - Update README.md title and references - Update HTML page title
Boris
A minimal nostr client for bookmark management, built with applesauce.
Features
- Nostr Authentication: Connect using your nostr account via browser extension
- Bookmark Display: View your nostr bookmarks as per NIP-51
- 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
- Minimal UI: Clean, modern interface focused on bookmark management
Getting Started
Prerequisites
- Node.js 18+
- npm, pnpm, or yarn
Installation
- Clone the repository:
git clone <your-repo-url>
cd boris
- Install dependencies:
npm install
# or
pnpm install
# or
yarn install
- Start the development server:
npm run dev
# or
pnpm dev
# or
yarn dev
- Open your browser and navigate to
http://localhost:3000
Usage
- Connect: Click "Connect with Nostr" to authenticate using your nostr account
- View Bookmarks: Once connected, you'll see all your nostr bookmarks
- Navigate: Click on bookmark URLs to open them in a new tab
Technical Details
- Built with React and TypeScript
- Uses applesauce-core for nostr functionality
- Implements NIP-51 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
│ ├── 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
│ └── readerService.ts # Content extraction via reader API
├── types/
│ ├── bookmarks.ts # Bookmark type definitions
│ ├── 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)andHelpers.isHiddenTagsLocked(evt)to detect hidden tags. - First try
Helpers.unlockHiddenTags(evt, signer); if that fails, try with'nip44'. - For events with encrypted
contentthat aren’t recognized as supporting hidden tags (e.g. kind 30001), manually decrypt:- Prefer
signer.nip44.decrypt(evt.pubkey, evt.content), fallback tosigner.nip04.decrypt(evt.pubkey, evt.content).
- Prefer
- Use
-
Parsing and rendering
- Decrypted
contentis JSONstring[][](tags). Convert withHelpers.parseBookmarkTags(hiddenTags). - Map to
IndividualBookmark[]via ourprocessApplesauceBookmarks(..., isPrivate=true)and append to the private list so they render immediately alongside public items.
- Decrypted
-
Caching for downstream helpers
- Cache manual results on the event with
BookmarkHiddenSymboland also store the decrypted blob underEncryptedContentSymbolto aid debugging and hydration.
- Cache manual results on the event with
-
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
anyvia narrow type guards fornip44/nip04decrypt 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
- We avoid
Building for Production
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
Languages
TypeScript
89.6%
CSS
9.4%
Shell
0.6%
JavaScript
0.2%
HTML
0.2%