docs: add AI agent reference documentation
This commit is contained in:
362
AGENTS.md
Normal file
362
AGENTS.md
Normal file
@@ -0,0 +1,362 @@
|
||||
# AGENTS.md
|
||||
|
||||
This document is designed to help AI Agents better understand and modify the Jumble project.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Jumble is a user-friendly Nostr client for exploring relay feeds.
|
||||
|
||||
- **Project Name**: Jumble
|
||||
- **Main Tech Stack**: React 18 + TypeScript + Vite
|
||||
- **UI Framework**: Tailwind CSS + Radix UI
|
||||
- **State Management**: Jotai
|
||||
- **Core Protocol**: Nostr (using nostr-tools)
|
||||
|
||||
## Technical Architecture
|
||||
|
||||
### Core Dependencies
|
||||
|
||||
- **Build Tool**: Vite 5.x
|
||||
- **Frontend Framework**: React 18.3.x + TypeScript
|
||||
- **Styling Solution**:
|
||||
- Tailwind CSS (primary styling framework)
|
||||
- Radix UI (unstyled component library)
|
||||
- next-themes (theme management)
|
||||
- tailwindcss-animate (animations)
|
||||
- **State Management**: Jotai 2.x
|
||||
- **Routing**: path-to-regexp (custom routing solution)
|
||||
- **Rich Text Editor**: TipTap 2.x
|
||||
- **Nostr Protocol**: nostr-tools 2.x
|
||||
- **Other Key Libraries**:
|
||||
- i18next (internationalization)
|
||||
- dayjs (date handling)
|
||||
- flexsearch (search)
|
||||
- qr-code-styling (QR codes)
|
||||
- yet-another-react-lightbox (image viewer)
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
jumble/
|
||||
├── src/
|
||||
│ ├── components/ # React components
|
||||
│ │ ├── ui/ # Base UI components (shadcn/ui style)
|
||||
│ │ └── ... # Other feature components
|
||||
│ ├── providers/ # React Context Providers
|
||||
│ ├── services/ # Business logic service layer
|
||||
│ ├── hooks/ # Custom React Hooks
|
||||
│ ├── lib/ # Utility functions and libraries
|
||||
│ ├── types/ # TypeScript type definitions
|
||||
│ ├── pages/ # Page components
|
||||
| | ├── primary # Primary page components (Left column)
|
||||
│ │ └── secondary # secondary page components (Right column)
|
||||
│ ├── layouts/ # Layout components
|
||||
│ ├── i18n/ # Internationalization resources
|
||||
| | ├── locales # Localization files
|
||||
│ │ └── index.tx # Basic i18n setup
|
||||
│ ├── assets/ # Static assets
|
||||
│ ├── App.tsx # App root component
|
||||
│ ├── PageManager.tsx # Page manager (custom routing logic)
|
||||
│ ├── routes # Route configuration
|
||||
| | ├── primary.tsx # Primary routes (Left column)
|
||||
│ │ └── secondary.tsx # Secondary routes (Right column)
|
||||
│ └── constants.ts # Constants definition
|
||||
├── public/ # Public static assets
|
||||
└── resources/ # Design resources
|
||||
```
|
||||
|
||||
## Development Guide
|
||||
|
||||
### Environment Setup
|
||||
|
||||
### Environment Setup
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Lint code
|
||||
npm run lint
|
||||
|
||||
# Format code
|
||||
npm run format
|
||||
```
|
||||
|
||||
## Code Conventions
|
||||
|
||||
### Component Development
|
||||
|
||||
1. **Component Structure**: Each major feature component is typically in its own folder, containing index.tsx and related sub-components
|
||||
2. **Styling**: Use Tailwind CSS utility classes, complex components can use class-variance-authority (cva)
|
||||
3. **Type Safety**: All components should have explicit TypeScript type definitions
|
||||
4. **State Management**:
|
||||
- Use Jotai atoms for global state management
|
||||
- Use Context Providers for cross-component data
|
||||
|
||||
### Service Layer (Services)
|
||||
|
||||
Service files located in `src/services/` encapsulate business logic:
|
||||
|
||||
- `client.service.ts` - Nostr client core logic for fetching and publishing events
|
||||
- `indexed-db.service.ts` - IndexedDB data storage
|
||||
- `local-storage.service.ts` - LocalStorage management
|
||||
- `media-upload.service.ts` - Media upload service
|
||||
- `translation.service.ts` - Translation service
|
||||
- `lightning.service.ts` - Lightning Network integration
|
||||
- `relay-info.service.ts` - Relay information management
|
||||
- `blossom.service.ts` - Blossom integration
|
||||
- `custom-emoji.service.ts` - Custom emoji management
|
||||
- `libre-translate.service.ts` - LibreTranslate API integration
|
||||
- `media-manager.service.ts` - Managing media play state
|
||||
- `modal-manager.service.ts` - Managing modal stack for back navigation (ensures modals close one by one before actual page navigation)
|
||||
- `note-stats.service.ts` - Note statistics storage and retrieval (likes, zaps, reposts)
|
||||
- `poll-results.service.ts` - Poll results storage and retrieval
|
||||
- `post-editor-cache.service.ts` - Caching post editor content to prevent data loss
|
||||
- `web.push.service.ts` - Web metadata fetching for link previews
|
||||
|
||||
### Providers Architecture
|
||||
|
||||
The app uses a multi-layered Provider nesting structure (see `App.tsx`):
|
||||
|
||||
```
|
||||
ScreenSizeProvider
|
||||
└─ UserPreferencesProvider
|
||||
└─ ThemeProvider
|
||||
└─ ContentPolicyProvider
|
||||
└─ NostrProvider
|
||||
└─ ... (more providers)
|
||||
```
|
||||
|
||||
Pay attention to Provider dependencies when modifying functionality.
|
||||
|
||||
And some Providers are placed in `PageManager.tsx` because they need to use the `usePrimaryPage` and `useSecondaryPage` hooks.
|
||||
|
||||
### Routing System
|
||||
|
||||
- Route configuration in `src/routes/primary.tsx` and `src/routes/secondary.tsx`
|
||||
- Using `PageManager.tsx` to manage page navigation, rendering, and state. Normally, you don't need to modify this file.
|
||||
- Primary pages (left column) use key-based navigation
|
||||
- Secondary pages (right column) use path-based navigation with stack support
|
||||
- More details in "Adding a New Page" section below
|
||||
|
||||
### Internationalization (i18n)
|
||||
|
||||
- Translation files located in `src/i18n/locales/`
|
||||
- Using `react-i18next` for internationalization
|
||||
- Supported languages: ar, de, en, es, fa, fr, hi, hu, it, ja, ko, pl, pt-BR, pt-PT, ru, th, zh
|
||||
|
||||
#### Adding New Language
|
||||
|
||||
1. Create a new file in `src/i18n/locales/` with the language code (e.g., `th.ts` for Thai)
|
||||
2. According to `src/i18n/locales/en.ts`, add translation key-value pairs
|
||||
3. Update `src/i18n/index.ts` to include the new language resource
|
||||
4. Update `detectLanguage` function in `src/lib/utils.ts` to support detecting the new language
|
||||
|
||||
## Nostr Protocol Integration
|
||||
|
||||
### Core Concepts
|
||||
|
||||
- **Events**: Nostr events (notes, profile updates, etc.). All data in Nostr is represented as events. They have different kinds (kinds) to represent different types of data.
|
||||
- **Relays**: Relay servers, which are WebSocket servers that store and forward Nostr events.
|
||||
- **NIPs**: Nostr Implementation Proposals
|
||||
|
||||
### Supported Event Kinds
|
||||
|
||||
I mean kinds that are supported to be displayed in the feed.
|
||||
|
||||
- Kind 1: Short Text Note
|
||||
- Kind 6: Repost
|
||||
- Kind 20: Picture Note
|
||||
- Kind 21: Video Note
|
||||
- Kind 22: Short Video Note
|
||||
- Kind 1068: Poll
|
||||
- Kind 1111: Comment
|
||||
- Kind 1222: Voice Note
|
||||
- Kind 1244: Voice Comment
|
||||
- Kind 9802: Highlight
|
||||
- Kind 30023: Long-Form Article
|
||||
- Kind 31987: Relay Review
|
||||
- Kind 34550: Community Definition
|
||||
- Kind 30311: Live Event
|
||||
- Kind 39000: Group Metadata
|
||||
|
||||
More details you can find in `src/components/Note/`. If you want to add support for new kinds, you need to create new components under `src/components/Note/` and update `src/components/Note/index.tsx`.
|
||||
|
||||
Please avoid modifying the framework, such as avatars, usernames, timestamps, and action buttons in the `Note` component. Only add content rendering logic for new types.
|
||||
|
||||
## Common Modification Scenarios
|
||||
|
||||
### Adding a New Component
|
||||
|
||||
1. Create a component folder in `src/components/`
|
||||
2. Create `index.tsx` and necessary sub-components
|
||||
3. Write styles using Tailwind CSS
|
||||
4. If needed, add base UI components in `src/components/ui/`
|
||||
|
||||
### Adding a New Page
|
||||
|
||||
#### Adding a Primary Page (Left Column)
|
||||
|
||||
Primary pages are the main navigation pages that appear in the left column (or full screen on mobile).
|
||||
|
||||
1. **Create the page component**:
|
||||
|
||||
```bash
|
||||
# Create a new folder under src/pages/primary/
|
||||
mkdir src/pages/primary/YourNewPage
|
||||
```
|
||||
|
||||
2. **Implement the component** (`src/pages/primary/YourNewPage/index.tsx`):
|
||||
|
||||
```tsx
|
||||
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
|
||||
import { TPageRef } from '@/types'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const YourNewPage = forwardRef<TPageRef>((_, ref) => {
|
||||
return (
|
||||
<PrimaryPageLayout ref={ref} title="Your Page Title" icon={<YourIcon />}>
|
||||
{/* Your page content */}
|
||||
</PrimaryPageLayout>
|
||||
)
|
||||
})
|
||||
|
||||
export default YourNewPage
|
||||
```
|
||||
|
||||
**Important**:
|
||||
|
||||
- Primary pages MUST use `forwardRef<TPageRef>`
|
||||
- Wrap content with `PrimaryPageLayout`
|
||||
- The ref is used by PageManager for navigation control
|
||||
|
||||
3. **Register the route** in `src/routes/primary.tsx`:
|
||||
|
||||
```tsx
|
||||
import YourNewPage from '@/pages/primary/YourNewPage'
|
||||
|
||||
const PRIMARY_ROUTE_CONFIGS: RouteConfig[] = [
|
||||
// ... existing routes
|
||||
{ key: 'yourNewPage', component: YourNewPage }
|
||||
]
|
||||
```
|
||||
|
||||
4. **Navigate to the page** using the `usePrimaryPage` hook:
|
||||
|
||||
```tsx
|
||||
import { usePrimaryPage } from '@/PageManager'
|
||||
|
||||
const { navigate } = usePrimaryPage()
|
||||
navigate('yourNewPage')
|
||||
```
|
||||
|
||||
#### Adding a Secondary Page (Right Column)
|
||||
|
||||
Secondary pages appear in the right column (or full screen on mobile) and support stack-based navigation.
|
||||
|
||||
1. **Create the page component**:
|
||||
|
||||
```bash
|
||||
# Create a new folder under src/pages/secondary/
|
||||
mkdir src/pages/secondary/YourNewPage
|
||||
```
|
||||
|
||||
2. **Implement the component** (`src/pages/secondary/YourNewPage/index.tsx`):
|
||||
|
||||
```tsx
|
||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const YourNewPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
return (
|
||||
<SecondaryPageLayout ref={ref} index={index} title="Your Page Title">
|
||||
{/* Your page content */}
|
||||
</SecondaryPageLayout>
|
||||
)
|
||||
})
|
||||
|
||||
export default YourNewPage
|
||||
```
|
||||
|
||||
**Important**:
|
||||
|
||||
- Secondary pages receive an `index` prop for stack navigation
|
||||
- Use `SecondaryPageLayout` for consistent styling
|
||||
- The ref enables navigation control
|
||||
|
||||
3. **Register the route** in `src/routes/secondary.tsx`:
|
||||
|
||||
```tsx
|
||||
import YourNewPage from '@/pages/secondary/YourNewPage'
|
||||
|
||||
const SECONDARY_ROUTE_CONFIGS = [
|
||||
// ... existing routes
|
||||
{ path: '/your-path/:id', element: <YourNewPage /> }
|
||||
]
|
||||
```
|
||||
|
||||
Add the corresponding path generation function in `src/lib/link.ts` for the new route:
|
||||
|
||||
```tsx
|
||||
export const toYourNewPage = (id: string) => `/your-path/${id}`
|
||||
```
|
||||
|
||||
4. **Navigate to the page**:
|
||||
|
||||
```tsx
|
||||
import { useSecondaryPage } from '@/PageManager'
|
||||
import { toYourNewPage } from '@/lib/link'
|
||||
|
||||
const { push, pop } = useSecondaryPage()
|
||||
|
||||
// Navigate to new page
|
||||
push(toYourNewPage('some-id'))
|
||||
|
||||
// Navigate back
|
||||
pop()
|
||||
```
|
||||
|
||||
5. **Access route parameters**:
|
||||
|
||||
```tsx
|
||||
const YourNewPage = forwardRef(({ id, index }: { id?: string; index?: number }, ref) => {
|
||||
console.log('Route param id:', id)
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
#### Key Differences
|
||||
|
||||
| Aspect | Primary Pages | Secondary Pages |
|
||||
| -------------- | ----------------------------------- | ------------------------------- |
|
||||
| **Location** | Left column (main navigation) | Right column (detail view) |
|
||||
| **Navigation** | Replace-based (`navigate`) | Stack-based (`push`/`pop`) |
|
||||
| **Layout** | `PrimaryPageLayout` | `SecondaryPageLayout` |
|
||||
| **Routes** | Key-based (e.g., 'home', 'explore') | Path-based (e.g., '/notes/:id') |
|
||||
|
||||
On mobile devices or single-column layouts, primary pages occupy the full screen, while secondary pages are accessed via stack navigation. When navigating to another primary page, it will clear the secondary page stack.
|
||||
|
||||
### Adding New State Management
|
||||
|
||||
1. For global state, create a new Provider in `src/providers/`
|
||||
2. Add Provider in `App.tsx` in the correct dependency order
|
||||
|
||||
Or create a singleton service in `src/services/` and use Jotai atoms for state management.
|
||||
|
||||
### Adding New Business Logic
|
||||
|
||||
1. Create a new service file in `src/services/`
|
||||
2. Export singleton instance
|
||||
3. Import and use in anywhere needed
|
||||
|
||||
### Style Modifications
|
||||
|
||||
- Global styles: `src/index.css`
|
||||
- Tailwind configuration: `tailwind.config.js`
|
||||
- Component styles: Use Tailwind class names directly
|
||||
Reference in New Issue
Block a user