jivamai 0.1.4-dev.edce8f4 → 0.2.0-dev.03f9681
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index-CnH2DbfK.js +31 -0
- package/dist/assets/index-Dxv8YLOA.css +10 -0
- package/dist/index.html +2 -2
- package/dist-server/index.js +1 -292
- package/package.json +7 -2
- package/dist/assets/index-CisS1YJo.css +0 -10
- package/dist/assets/index-DftBqc_W.js +0 -510
- package/dist-server/index.js.map +0 -1
- package/docs/README.md +0 -55
- package/docs/architecture/cloud-mode.md +0 -204
- package/docs/architecture/code-agent-integration.md +0 -276
- package/docs/architecture/ipc-contract.md +0 -162
- package/docs/architecture/jiva-core-integration.md +0 -147
- package/docs/architecture/overview.md +0 -87
- package/docs/architecture/startup-flow.md +0 -108
- package/docs/architecture/state-management.md +0 -153
- package/docs/guides/adding-features.md +0 -196
- package/docs/guides/design-guide.md +0 -308
- package/docs/release_notes/.gitkeep +0 -0
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
# Adding Features
|
|
2
|
-
|
|
3
|
-
This guide walks through the full stack of changes required to add a new IPC-backed feature to Jivam. Every feature that requires main-process capabilities (file system, native APIs, jiva-core) follows this pattern.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
Adding a feature requires changes in four layers:
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
1. electron/ipc-handlers.ts ← Register the IPC handler (main process)
|
|
13
|
-
2. electron/preload.ts ← Expose it on window.electron (preload bridge)
|
|
14
|
-
3. src/types/electron.d.ts ← Type the new API (TypeScript)
|
|
15
|
-
4. src/store/*.store.ts ← Consume it in a Zustand store action
|
|
16
|
-
5. src/components/**/*.tsx ← Build the UI using store + primitives
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
If the feature only touches renderer state (no IPC needed), skip steps 1–3 and add directly to a store and component.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Worked Example: Word Count Panel
|
|
24
|
-
|
|
25
|
-
We'll add a panel that counts words in the currently open file.
|
|
26
|
-
|
|
27
|
-
### Step 1 — IPC Handler (`electron/ipc-handlers.ts`)
|
|
28
|
-
|
|
29
|
-
Add a new `ipcMain.handle` inside `setupIpcHandlers`:
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
ipcMain.handle('workspace:word-count', (_event, filePath: string) => {
|
|
33
|
-
try {
|
|
34
|
-
const homeDir = os.homedir()
|
|
35
|
-
const resolvedFile = path.resolve(filePath)
|
|
36
|
-
if (!resolvedFile.startsWith(path.resolve(homeDir))) return { success: false, error: 'Access denied' }
|
|
37
|
-
|
|
38
|
-
const content = fs.readFileSync(resolvedFile, 'utf-8')
|
|
39
|
-
const wordCount = content.trim().split(/\s+/).filter(Boolean).length
|
|
40
|
-
return { success: true, wordCount }
|
|
41
|
-
} catch (err) {
|
|
42
|
-
return { success: false, error: err instanceof Error ? err.message : String(err) }
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
**Convention:** Return `{ success: boolean; error?: string }` on failure. Return the data on success alongside `success: true`.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
### Step 2 — Preload Bridge (`electron/preload.ts`)
|
|
52
|
-
|
|
53
|
-
Add the new method inside the `contextBridge.exposeInMainWorld('electron', { ... })` call, in the appropriate namespace:
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
workspace: {
|
|
57
|
-
// ...existing methods...
|
|
58
|
-
wordCount: (filePath: string) =>
|
|
59
|
-
ipcRenderer.invoke('workspace:word-count', filePath),
|
|
60
|
-
},
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
### Step 3 — TypeScript Types (`src/types/electron.d.ts`)
|
|
66
|
-
|
|
67
|
-
Extend the `ElectronAPI` interface to include the new method:
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
workspace: {
|
|
71
|
-
// ...existing methods...
|
|
72
|
-
wordCount: (filePath: string) => Promise<{
|
|
73
|
-
success: boolean
|
|
74
|
-
wordCount?: number
|
|
75
|
-
error?: string
|
|
76
|
-
}>
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
After this, `window.electron.workspace.wordCount(path)` will be fully typed throughout the renderer.
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
### Step 4 — Store Action (`src/store/files.store.ts`)
|
|
85
|
-
|
|
86
|
-
Add state and an action to the relevant store:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
interface FilesState {
|
|
90
|
-
// ...existing state...
|
|
91
|
-
wordCount: number | null
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Inside the store:
|
|
95
|
-
wordCount: null,
|
|
96
|
-
|
|
97
|
-
countWords: async () => {
|
|
98
|
-
const { selectedFile } = get()
|
|
99
|
-
if (!selectedFile) return
|
|
100
|
-
const result = await window.electron.workspace.wordCount(selectedFile.path)
|
|
101
|
-
if (result.success && result.wordCount !== undefined) {
|
|
102
|
-
set({ wordCount: result.wordCount })
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
### Step 5 — Component (`src/components/files/WordCountBadge.tsx`)
|
|
110
|
-
|
|
111
|
-
Build the UI using store state and design system primitives:
|
|
112
|
-
|
|
113
|
-
```tsx
|
|
114
|
-
import { useFilesStore } from '../../store/files.store'
|
|
115
|
-
import { Badge } from '../ui/Badge'
|
|
116
|
-
|
|
117
|
-
export function WordCountBadge() {
|
|
118
|
-
const { wordCount, countWords, selectedFile } = useFilesStore()
|
|
119
|
-
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (selectedFile) countWords()
|
|
122
|
-
}, [selectedFile, countWords])
|
|
123
|
-
|
|
124
|
-
if (!wordCount) return null
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<Badge variant="default">
|
|
128
|
-
{wordCount.toLocaleString()} words
|
|
129
|
-
</Badge>
|
|
130
|
-
)
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
### Step 6 — Wire to AppShell or Feature Panel
|
|
137
|
-
|
|
138
|
-
Add the component where it belongs in the layout:
|
|
139
|
-
|
|
140
|
-
```tsx
|
|
141
|
-
// In src/components/files/FilesPanel.tsx (or wherever the file preview lives):
|
|
142
|
-
import { WordCountBadge } from './WordCountBadge'
|
|
143
|
-
|
|
144
|
-
// In the file preview header:
|
|
145
|
-
<div className="flex items-center gap-2">
|
|
146
|
-
<span className="text-sm text-[var(--text-muted)]">{selectedFile.name}</span>
|
|
147
|
-
<WordCountBadge />
|
|
148
|
-
</div>
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Checklist
|
|
154
|
-
|
|
155
|
-
Use this checklist for every new IPC-backed feature:
|
|
156
|
-
|
|
157
|
-
- [ ] `ipcMain.handle('namespace:action', handler)` added in `electron/ipc-handlers.ts`
|
|
158
|
-
- [ ] `namespace: { action: (...args) => ipcRenderer.invoke(...) }` added in `electron/preload.ts`
|
|
159
|
-
- [ ] Type added to `ElectronAPI` in `src/types/electron.d.ts`
|
|
160
|
-
- [ ] Store action added that calls `window.electron.namespace.action()`
|
|
161
|
-
- [ ] Component uses `useXxxStore()` — no direct `window.electron` calls in components
|
|
162
|
-
- [ ] UI uses `Button` / `Badge` primitives (no raw `<button>`)
|
|
163
|
-
- [ ] Colors use CSS custom properties (no hardcoded hex)
|
|
164
|
-
- [ ] Errors handled gracefully — store sets an error state or shows a toast
|
|
165
|
-
- [ ] `npx tsc --noEmit` passes with zero errors
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## File-Only Features (No IPC)
|
|
170
|
-
|
|
171
|
-
For purely UI features (e.g. a collapsible sidebar section, a new settings toggle):
|
|
172
|
-
|
|
173
|
-
1. Add state to the relevant store if needed
|
|
174
|
-
2. Build the component
|
|
175
|
-
3. Import and render it in the appropriate parent
|
|
176
|
-
|
|
177
|
-
No IPC or preload changes needed.
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## Adding a New Tab
|
|
182
|
-
|
|
183
|
-
To add a new top-level tab to the app:
|
|
184
|
-
|
|
185
|
-
1. Add the tab name to the `ActiveTab` union in `src/App.tsx`
|
|
186
|
-
2. Add a `TabButton` entry in `src/components/layout/AppShell.tsx` (sidebar nav)
|
|
187
|
-
3. Add a conditional render of the new panel in `AppShell`'s main content area
|
|
188
|
-
4. Create the panel component in `src/components/<feature>/`
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## Security Considerations
|
|
193
|
-
|
|
194
|
-
- **File system access:** All file paths passed to main-process handlers must be validated against `os.homedir()`. See the `workspace:list-files` and `workspace:read-file` handlers for the pattern.
|
|
195
|
-
- **No shell injection:** Never interpolate user input into `execSync` strings. Use argument arrays.
|
|
196
|
-
- **Config writes:** Always read the existing config with `readConfig()` before writing — never overwrite with a partial object.
|
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
# Design Guide
|
|
2
|
-
|
|
3
|
-
This guide documents Jivam's visual design system: color tokens, typography, spacing, component library, animation patterns, and special CSS utilities. Follow these conventions for all new UI work to maintain visual consistency.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Color System
|
|
8
|
-
|
|
9
|
-
Colors are defined as CSS custom properties in `src/index.css`. The theme is toggled by setting `data-theme="dark"` on `<html>` — controlled by `useSettingsStore`.
|
|
10
|
-
|
|
11
|
-
**Never hardcode color values.** Always use the tokens below.
|
|
12
|
-
|
|
13
|
-
### Design Tokens
|
|
14
|
-
|
|
15
|
-
| Token | Light | Dark | Usage |
|
|
16
|
-
|-------|-------|------|-------|
|
|
17
|
-
| `--bg` | `#F5F3FF` | `#0A0A0B` | Page background |
|
|
18
|
-
| `--bg-secondary` | `#EDE9FE` | `#111113` | Secondary background areas |
|
|
19
|
-
| `--card` | `#FFFFFF` | `rgba(28,28,33,0.85)` | Card and panel surfaces |
|
|
20
|
-
| `--card-border` | `rgba(139,92,246,0.15)` | `rgba(139,92,246,0.20)` | Card borders |
|
|
21
|
-
| `--card-shadow` | `0 4px 24px rgba(139,92,246,0.08)` | `0 4px 24px rgba(139,92,246,0.15)` | Card shadows |
|
|
22
|
-
| `--text` | `#1E1B4B` | `#F5F3FF` | Primary text |
|
|
23
|
-
| `--text-muted` | `#6B7280` | `#9CA3AF` | Secondary / supporting text |
|
|
24
|
-
| `--text-subtle` | `#9CA3AF` | `#6B7280` | Placeholder and hint text |
|
|
25
|
-
| `--accent` | `#8B5CF6` | `#A78BFA` | Primary brand accent |
|
|
26
|
-
| `--accent-blue` | `#3B82F6` | `#60A5FA` | Secondary accent |
|
|
27
|
-
| `--accent-indigo` | `#6366F1` | `#818CF8` | Tertiary accent |
|
|
28
|
-
| `--input-bg` | `rgba(255,255,255,0.9)` | `rgba(28,28,33,0.9)` | Input field backgrounds |
|
|
29
|
-
| `--input-border` | `rgba(139,92,246,0.25)` | `rgba(139,92,246,0.35)` | Input borders |
|
|
30
|
-
| `--user-bubble-bg` | `linear-gradient(135deg,#8B5CF6,#3B82F6)` | `linear-gradient(135deg,#7C3AED,#2563EB)` | User message bubbles |
|
|
31
|
-
| `--agent-bubble-bg` | `#FFFFFF` | `rgba(28,28,33,0.9)` | Assistant message bubbles |
|
|
32
|
-
| `--agent-bubble-border` | `rgba(139,92,246,0.12)` | `rgba(139,92,246,0.20)` | Assistant bubble borders |
|
|
33
|
-
| `--topbar-bg` | `rgba(245,243,255,0.85)` | `rgba(10,10,11,0.9)` | Top bar background |
|
|
34
|
-
| `--topbar-border` | `rgba(139,92,246,0.12)` | `rgba(139,92,246,0.15)` | Top bar bottom border |
|
|
35
|
-
| `--sidebar-bg` | `rgba(255,255,255,0.95)` | `rgba(17,17,19,0.98)` | Sidebar background |
|
|
36
|
-
| `--scrollbar-thumb` | `rgba(139,92,246,0.3)` | `rgba(139,92,246,0.4)` | Scrollbar handle |
|
|
37
|
-
| `--code-bg` | `#F8F5FF` | `rgba(28,28,33,0.8)` | Code block background |
|
|
38
|
-
| `--code-border` | `rgba(139,92,246,0.12)` | `rgba(139,92,246,0.20)` | Code block border |
|
|
39
|
-
|
|
40
|
-
### Brand Colors (Fixed, Theme-Independent)
|
|
41
|
-
|
|
42
|
-
These are in `tailwind.config.js` and can be used as Tailwind classes:
|
|
43
|
-
|
|
44
|
-
| Name | Hex | Tailwind class example |
|
|
45
|
-
|------|-----|----------------------|
|
|
46
|
-
| `jivam-purple` | `#8B5CF6` | `bg-jivam-purple`, `text-jivam-purple` |
|
|
47
|
-
| `jivam-blue` | `#3B82F6` | `bg-jivam-blue`, `text-jivam-blue` |
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Typography
|
|
52
|
-
|
|
53
|
-
**Font:** `Inter` — loaded from Google Fonts in `src/index.css`. Fallback: `system-ui, sans-serif`.
|
|
54
|
-
|
|
55
|
-
```css
|
|
56
|
-
font-family: 'Inter', system-ui, sans-serif;
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Weights used:** 300 (light), 400 (regular), 500 (medium), 600 (semibold), 700 (bold).
|
|
60
|
-
|
|
61
|
-
**Scale:** Tailwind defaults. Common usage:
|
|
62
|
-
|
|
63
|
-
| Class | Size | Use |
|
|
64
|
-
|-------|------|-----|
|
|
65
|
-
| `text-xs` | 12px | Badges, captions, metadata |
|
|
66
|
-
| `text-sm` | 14px | Body text, list items, labels |
|
|
67
|
-
| `text-base` | 16px | Default (rarely used explicitly) |
|
|
68
|
-
| `text-lg` | 18px | Section headings |
|
|
69
|
-
| `text-2xl` | 24px | Screen titles (h1 in setup/splash) |
|
|
70
|
-
|
|
71
|
-
**Gradient text** — for brand headings only:
|
|
72
|
-
|
|
73
|
-
```html
|
|
74
|
-
<h1 class="gradient-text">Jivam</h1>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
```css
|
|
78
|
-
.gradient-text {
|
|
79
|
-
background: linear-gradient(135deg, var(--accent), var(--accent-blue));
|
|
80
|
-
-webkit-background-clip: text;
|
|
81
|
-
-webkit-text-fill-color: transparent;
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Spacing & Layout
|
|
88
|
-
|
|
89
|
-
**App layout:** Fixed sidebar (240px) + `flex-1` main content area. Do not change these dimensions.
|
|
90
|
-
|
|
91
|
-
**Spacing scale:** Use Tailwind's scale. Preferred values:
|
|
92
|
-
|
|
93
|
-
| Use case | Class |
|
|
94
|
-
|----------|-------|
|
|
95
|
-
| Tight gap (icons, inline) | `gap-1`, `gap-2` |
|
|
96
|
-
| Standard gap (list items, cards) | `gap-3`, `gap-4` |
|
|
97
|
-
| Section spacing | `gap-6`, `gap-8` |
|
|
98
|
-
| Card padding | `p-4`, `px-4 py-3` |
|
|
99
|
-
| Panel padding | `p-6` |
|
|
100
|
-
|
|
101
|
-
**Border radius:** Prefer `rounded-xl` (12px) for cards and panels. Use `rounded-lg` for buttons and inputs. Use `rounded-full` only for avatars and dots.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Utility Classes
|
|
106
|
-
|
|
107
|
-
These are defined in `src/index.css` and must be used as intended.
|
|
108
|
-
|
|
109
|
-
### `.glass-card`
|
|
110
|
-
|
|
111
|
-
The standard card surface. Applied to all floating panels, settings cards, and sidebar sections.
|
|
112
|
-
|
|
113
|
-
```css
|
|
114
|
-
.glass-card {
|
|
115
|
-
background: var(--card);
|
|
116
|
-
backdrop-filter: blur(12px);
|
|
117
|
-
-webkit-backdrop-filter: blur(12px);
|
|
118
|
-
border: 1px solid var(--card-border);
|
|
119
|
-
box-shadow: var(--card-shadow);
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Usage: `<div className="glass-card rounded-xl p-4">`
|
|
124
|
-
|
|
125
|
-
### `.aurora-bg`
|
|
126
|
-
|
|
127
|
-
The animated purple-blue gradient orbs that appear behind all screens. **Always include on every top-level screen** — it is part of the brand identity.
|
|
128
|
-
|
|
129
|
-
```html
|
|
130
|
-
<div className="aurora-bg" />
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
It is `position: fixed; inset: 0; pointer-events: none; z-index: 0`. Content must have `position: relative; z-index: 10` (or higher) to appear above it.
|
|
134
|
-
|
|
135
|
-
### `.gradient-text`
|
|
136
|
-
|
|
137
|
-
See Typography section above.
|
|
138
|
-
|
|
139
|
-
### `.typing-dot`
|
|
140
|
-
|
|
141
|
-
Three animated dots used as a loading indicator:
|
|
142
|
-
|
|
143
|
-
```html
|
|
144
|
-
<div className="flex items-center gap-1.5">
|
|
145
|
-
<span className="typing-dot" />
|
|
146
|
-
<span className="typing-dot" />
|
|
147
|
-
<span className="typing-dot" />
|
|
148
|
-
</div>
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
Dots bounce with staggered delays. Color uses `var(--accent)`.
|
|
152
|
-
|
|
153
|
-
### `.drag-region` / `.no-drag`
|
|
154
|
-
|
|
155
|
-
Controls Electron window dragging. Apply `.drag-region` to the title bar area. Apply `.no-drag` to interactive elements within a drag region (buttons, inputs).
|
|
156
|
-
|
|
157
|
-
### `.markdown-body`
|
|
158
|
-
|
|
159
|
-
Applied to AI response content. Provides scoped prose styles for `h1-h4`, `p`, `ul/ol`, `code`, `pre`, `blockquote`, `table`, `a`, and `hr`. Uses `var(--code-bg)` and `var(--code-border)` for code blocks.
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
## Component Library
|
|
164
|
-
|
|
165
|
-
All interactive components live in `src/components/ui/`. **Always use these primitives — never write raw `<button>` or bare `<span>` elements in feature components.**
|
|
166
|
-
|
|
167
|
-
### `Button`
|
|
168
|
-
|
|
169
|
-
```tsx
|
|
170
|
-
import { Button } from '../ui/Button'
|
|
171
|
-
|
|
172
|
-
<Button variant="primary" size="md" onClick={handler}>
|
|
173
|
-
<Icon size={14} />
|
|
174
|
-
Label
|
|
175
|
-
</Button>
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
| Prop | Values | Default |
|
|
179
|
-
|------|--------|---------|
|
|
180
|
-
| `variant` | `primary` \| `secondary` \| `ghost` \| `danger` | `secondary` |
|
|
181
|
-
| `size` | `sm` \| `md` \| `lg` | `md` |
|
|
182
|
-
| `disabled` | `boolean` | `false` |
|
|
183
|
-
|
|
184
|
-
- `primary` — filled with `--accent` gradient, white text
|
|
185
|
-
- `secondary` — outlined with `--card-border`, `--text` text
|
|
186
|
-
- `ghost` — no border, transparent background, `--text-muted` text
|
|
187
|
-
- `danger` — red accent, used for destructive actions only
|
|
188
|
-
|
|
189
|
-
### `Badge`
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
import { Badge } from '../ui/Badge'
|
|
193
|
-
|
|
194
|
-
<Badge variant="success">Connected</Badge>
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
| Prop | Values |
|
|
198
|
-
|------|--------|
|
|
199
|
-
| `variant` | `default` \| `success` \| `warning` \| `danger` \| `accent` |
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## Animations (Framer Motion)
|
|
204
|
-
|
|
205
|
-
Jivam uses [Framer Motion](https://www.framer.com/motion/) for all transitions. Do not use CSS `transition` for enter/exit — use `AnimatePresence` + `motion.*`.
|
|
206
|
-
|
|
207
|
-
### Standard Page Entrance
|
|
208
|
-
|
|
209
|
-
```tsx
|
|
210
|
-
<motion.div
|
|
211
|
-
initial={{ opacity: 0, y: 16 }}
|
|
212
|
-
animate={{ opacity: 1, y: 0 }}
|
|
213
|
-
transition={{ duration: 0.4 }}
|
|
214
|
-
>
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Staggered List Items
|
|
218
|
-
|
|
219
|
-
```tsx
|
|
220
|
-
{items.map((item, index) => (
|
|
221
|
-
<motion.div
|
|
222
|
-
key={item.id}
|
|
223
|
-
initial={{ opacity: 0, y: 8 }}
|
|
224
|
-
animate={{ opacity: 1, y: 0 }}
|
|
225
|
-
transition={{ delay: index * 0.08 }}
|
|
226
|
-
>
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Collapse / Expand (Height Animation)
|
|
230
|
-
|
|
231
|
-
```tsx
|
|
232
|
-
<AnimatePresence>
|
|
233
|
-
{expanded && (
|
|
234
|
-
<motion.div
|
|
235
|
-
initial={{ height: 0, opacity: 0 }}
|
|
236
|
-
animate={{ height: 'auto', opacity: 1 }}
|
|
237
|
-
exit={{ height: 0, opacity: 0 }}
|
|
238
|
-
transition={{ duration: 0.2 }}
|
|
239
|
-
>
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Brand Pulse (Logo, Loading States)
|
|
243
|
-
|
|
244
|
-
```tsx
|
|
245
|
-
<motion.div
|
|
246
|
-
animate={{ scale: [1, 1.04, 1] }}
|
|
247
|
-
transition={{ duration: 2.5, repeat: Infinity, ease: 'easeInOut' }}
|
|
248
|
-
>
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Exit Transitions
|
|
252
|
-
|
|
253
|
-
Always wrap components that mount/unmount with `AnimatePresence` at the parent level:
|
|
254
|
-
|
|
255
|
-
```tsx
|
|
256
|
-
<AnimatePresence>
|
|
257
|
-
{showPanel && (
|
|
258
|
-
<motion.div
|
|
259
|
-
initial={{ opacity: 0 }}
|
|
260
|
-
animate={{ opacity: 1 }}
|
|
261
|
-
exit={{ opacity: 0 }}
|
|
262
|
-
>
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## Scrollbars
|
|
268
|
-
|
|
269
|
-
Scrollbars are globally styled in `src/index.css`:
|
|
270
|
-
|
|
271
|
-
- Width: 6px
|
|
272
|
-
- Thumb: `var(--scrollbar-thumb)` (accent purple at 30-40% opacity)
|
|
273
|
-
- Track: transparent
|
|
274
|
-
- Hover: accent at 50% opacity
|
|
275
|
-
|
|
276
|
-
No additional classes needed — all scrollable elements inherit this automatically.
|
|
277
|
-
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
## Syntax Highlighting
|
|
281
|
-
|
|
282
|
-
Code blocks in AI responses use [highlight.js](https://highlightjs.org/). Theme overrides are in `src/index.css` under `.hljs`. Dark mode applies custom token colors:
|
|
283
|
-
|
|
284
|
-
| Token | Dark color |
|
|
285
|
-
|-------|-----------|
|
|
286
|
-
| Keywords | `#C084FC` (purple) |
|
|
287
|
-
| Strings | `#86EFAC` (green) |
|
|
288
|
-
| Comments | `#6B7280` (gray) |
|
|
289
|
-
| Numbers | `#FCA5A5` (red) |
|
|
290
|
-
| Functions | `#93C5FD` (blue) |
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
## Do's and Don'ts
|
|
295
|
-
|
|
296
|
-
**Do:**
|
|
297
|
-
- Use CSS custom properties for all colors
|
|
298
|
-
- Use `.glass-card` for all card surfaces
|
|
299
|
-
- Use `Button` and `Badge` primitives for all interactive elements
|
|
300
|
-
- Include `<div className="aurora-bg" />` on every full-screen view
|
|
301
|
-
- Use Framer Motion for enter/exit animations
|
|
302
|
-
|
|
303
|
-
**Don't:**
|
|
304
|
-
- Hardcode hex colors (use tokens)
|
|
305
|
-
- Write raw `<button>` elements
|
|
306
|
-
- Use CSS `display: none` for hiding — use `AnimatePresence` + conditional rendering
|
|
307
|
-
- Skip the aurora background on new screens
|
|
308
|
-
- Add scrollbar styles to individual elements (global styles handle it)
|
|
File without changes
|