@prmichaelsen/acp-visualizer 0.1.0 → 0.1.2

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.
Files changed (159) hide show
  1. package/package.json +8 -10
  2. package/src/components/ExtraFieldsBadge.tsx +1 -1
  3. package/src/components/FilterBar.tsx +1 -1
  4. package/src/components/Header.tsx +1 -1
  5. package/src/components/MilestoneTable.tsx +1 -1
  6. package/src/components/MilestoneTree.tsx +2 -2
  7. package/src/components/StatusBadge.tsx +1 -1
  8. package/src/components/StatusDot.tsx +1 -1
  9. package/src/components/TaskList.tsx +1 -1
  10. package/src/routes/__root.tsx +5 -5
  11. package/src/routes/api/watch.ts +1 -1
  12. package/src/routes/index.tsx +2 -2
  13. package/src/routes/milestones.tsx +7 -7
  14. package/src/routes/search.tsx +4 -4
  15. package/src/routes/tasks.tsx +3 -3
  16. package/src/services/progress-database.service.ts +3 -3
  17. package/agent/commands/acp.clarification-address.md +0 -417
  18. package/agent/commands/acp.clarification-capture.md +0 -386
  19. package/agent/commands/acp.clarification-create.md +0 -437
  20. package/agent/commands/acp.clarifications-research.md +0 -326
  21. package/agent/commands/acp.command-create.md +0 -432
  22. package/agent/commands/acp.design-create.md +0 -286
  23. package/agent/commands/acp.design-reference.md +0 -355
  24. package/agent/commands/acp.handoff.md +0 -270
  25. package/agent/commands/acp.index.md +0 -423
  26. package/agent/commands/acp.init.md +0 -546
  27. package/agent/commands/acp.package-create.md +0 -895
  28. package/agent/commands/acp.package-info.md +0 -212
  29. package/agent/commands/acp.package-install.md +0 -539
  30. package/agent/commands/acp.package-list.md +0 -280
  31. package/agent/commands/acp.package-publish.md +0 -541
  32. package/agent/commands/acp.package-remove.md +0 -293
  33. package/agent/commands/acp.package-search.md +0 -307
  34. package/agent/commands/acp.package-update.md +0 -361
  35. package/agent/commands/acp.package-validate.md +0 -540
  36. package/agent/commands/acp.pattern-create.md +0 -386
  37. package/agent/commands/acp.plan.md +0 -587
  38. package/agent/commands/acp.proceed.md +0 -882
  39. package/agent/commands/acp.project-create.md +0 -675
  40. package/agent/commands/acp.project-info.md +0 -312
  41. package/agent/commands/acp.project-list.md +0 -226
  42. package/agent/commands/acp.project-remove.md +0 -379
  43. package/agent/commands/acp.project-set.md +0 -227
  44. package/agent/commands/acp.project-update.md +0 -307
  45. package/agent/commands/acp.projects-restore.md +0 -228
  46. package/agent/commands/acp.projects-sync.md +0 -347
  47. package/agent/commands/acp.report.md +0 -407
  48. package/agent/commands/acp.resume.md +0 -239
  49. package/agent/commands/acp.sessions.md +0 -301
  50. package/agent/commands/acp.status.md +0 -293
  51. package/agent/commands/acp.sync.md +0 -364
  52. package/agent/commands/acp.task-create.md +0 -500
  53. package/agent/commands/acp.update.md +0 -302
  54. package/agent/commands/acp.validate.md +0 -466
  55. package/agent/commands/acp.version-check-for-updates.md +0 -276
  56. package/agent/commands/acp.version-check.md +0 -191
  57. package/agent/commands/acp.version-update.md +0 -289
  58. package/agent/commands/command.template.md +0 -339
  59. package/agent/commands/git.commit.md +0 -526
  60. package/agent/commands/git.init.md +0 -514
  61. package/agent/commands/tanstack-cloudflare.deploy.md +0 -272
  62. package/agent/commands/tanstack-cloudflare.tail.md +0 -275
  63. package/agent/design/.gitkeep +0 -0
  64. package/agent/design/design.template.md +0 -154
  65. package/agent/design/local.dashboard-layout-routing.md +0 -288
  66. package/agent/design/local.data-model-yaml-parsing.md +0 -310
  67. package/agent/design/local.search-filtering.md +0 -331
  68. package/agent/design/local.server-api-auto-refresh.md +0 -235
  69. package/agent/design/local.table-tree-views.md +0 -299
  70. package/agent/design/local.visualizer-requirements.md +0 -349
  71. package/agent/design/requirements.template.md +0 -387
  72. package/agent/index/.gitkeep +0 -0
  73. package/agent/index/acp.core.yaml +0 -137
  74. package/agent/index/local.main.template.yaml +0 -37
  75. package/agent/manifest.template.yaml +0 -13
  76. package/agent/manifest.yaml +0 -302
  77. package/agent/milestones/.gitkeep +0 -0
  78. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +0 -67
  79. package/agent/milestones/milestone-1-{title}.template.md +0 -206
  80. package/agent/milestones/milestone-2-dashboard-views-interaction.md +0 -79
  81. package/agent/package.template.yaml +0 -86
  82. package/agent/patterns/.gitkeep +0 -0
  83. package/agent/patterns/bootstrap.template.md +0 -1237
  84. package/agent/patterns/pattern.template.md +0 -382
  85. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +0 -332
  86. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +0 -416
  87. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +0 -401
  88. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +0 -387
  89. package/agent/patterns/tanstack-cloudflare.card-and-list.md +0 -271
  90. package/agent/patterns/tanstack-cloudflare.chat-engine.md +0 -353
  91. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +0 -346
  92. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +0 -516
  93. package/agent/patterns/tanstack-cloudflare.email-service.md +0 -431
  94. package/agent/patterns/tanstack-cloudflare.expander.md +0 -98
  95. package/agent/patterns/tanstack-cloudflare.fcm-push.md +0 -115
  96. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +0 -441
  97. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +0 -348
  98. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +0 -550
  99. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +0 -369
  100. package/agent/patterns/tanstack-cloudflare.form-controls.md +0 -145
  101. package/agent/patterns/tanstack-cloudflare.global-search-context.md +0 -93
  102. package/agent/patterns/tanstack-cloudflare.image-carousel.md +0 -126
  103. package/agent/patterns/tanstack-cloudflare.library-services.md +0 -553
  104. package/agent/patterns/tanstack-cloudflare.lightbox.md +0 -169
  105. package/agent/patterns/tanstack-cloudflare.markdown-content.md +0 -115
  106. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +0 -98
  107. package/agent/patterns/tanstack-cloudflare.modal.md +0 -156
  108. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +0 -461
  109. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +0 -151
  110. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +0 -90
  111. package/agent/patterns/tanstack-cloudflare.og-metadata.md +0 -296
  112. package/agent/patterns/tanstack-cloudflare.pagination.md +0 -442
  113. package/agent/patterns/tanstack-cloudflare.pill-input.md +0 -220
  114. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +0 -401
  115. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +0 -323
  116. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +0 -338
  117. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +0 -375
  118. package/agent/patterns/tanstack-cloudflare.slide-over.md +0 -129
  119. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +0 -571
  120. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +0 -508
  121. package/agent/patterns/tanstack-cloudflare.toast-system.md +0 -142
  122. package/agent/patterns/tanstack-cloudflare.unified-header.md +0 -280
  123. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +0 -628
  124. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +0 -237
  125. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +0 -358
  126. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +0 -336
  127. package/agent/progress.template.yaml +0 -161
  128. package/agent/progress.yaml +0 -145
  129. package/agent/schemas/package.schema.yaml +0 -276
  130. package/agent/scripts/acp.common.sh +0 -1781
  131. package/agent/scripts/acp.install.sh +0 -333
  132. package/agent/scripts/acp.package-create.sh +0 -924
  133. package/agent/scripts/acp.package-info.sh +0 -288
  134. package/agent/scripts/acp.package-install.sh +0 -893
  135. package/agent/scripts/acp.package-list.sh +0 -311
  136. package/agent/scripts/acp.package-publish.sh +0 -420
  137. package/agent/scripts/acp.package-remove.sh +0 -348
  138. package/agent/scripts/acp.package-search.sh +0 -156
  139. package/agent/scripts/acp.package-update.sh +0 -517
  140. package/agent/scripts/acp.package-validate.sh +0 -1018
  141. package/agent/scripts/acp.uninstall.sh +0 -85
  142. package/agent/scripts/acp.version-check-for-updates.sh +0 -98
  143. package/agent/scripts/acp.version-check.sh +0 -47
  144. package/agent/scripts/acp.version-update.sh +0 -176
  145. package/agent/scripts/acp.yaml-parser.sh +0 -985
  146. package/agent/scripts/acp.yaml-validate.sh +0 -205
  147. package/agent/tasks/.gitkeep +0 -0
  148. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +0 -210
  149. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +0 -294
  150. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +0 -193
  151. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +0 -262
  152. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +0 -156
  153. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +0 -178
  154. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +0 -141
  155. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +0 -153
  156. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +0 -174
  157. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +0 -233
  158. package/agent/tasks/task-1-{title}.template.md +0 -244
  159. package/vitest.config.ts +0 -27
@@ -1,169 +0,0 @@
1
- # LightboxContainer & ImageLightbox
2
-
3
- **Category**: Design
4
- **Applicable To**: Full-screen image galleries, memory detail viewers, crop editors, and any swipeable full-screen overlay
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- LightboxContainer is a reusable full-screen shell (portal, z-55) with slide animation, keyboard/swipe navigation, and a counter badge. ImageLightbox extends it for image galleries with crop data, lazy preloading, and scaled previews. Other lightboxes (MemoryLightbox, ImageCropLightbox) also build on LightboxContainer.
12
-
13
- ---
14
-
15
- ## Implementation
16
-
17
- ### LightboxContainer (Shell)
18
-
19
- **File**: `src/components/LightboxContainer.tsx`
20
-
21
- ```typescript
22
- interface LightboxContainerProps {
23
- totalCount: number
24
- index: number
25
- onPrev: () => void
26
- onNext: () => void
27
- onClose: () => void
28
- navDisabled?: boolean // Disable keyboard/swipe nav (e.g., during crop edit)
29
- onEscapeWhileNavDisabled?: () => void // Escape exits sub-mode, not lightbox
30
- onBackdropClickWhileNavDisabled?: () => void
31
- children: ReactNode // The slide content
32
- overlay?: ReactNode // Non-animated toolbar/controls
33
- animatedClassName?: string // Extra classes on the animated content div
34
- }
35
- ```
36
-
37
- **Features**:
38
- - Portal to `document.body`, z-55, `bg-black/90 backdrop-blur-sm`
39
- - Body scroll lock + safe-area-inset-top
40
- - **Slide animation**: 200ms ease-out, scale(0.92) + translateX(±60px) on exit/enter
41
- - **Keyboard**: ArrowLeft/Right for prev/next, Escape to close
42
- - **Touch/swipe**: Horizontal >100px = nav, vertical up >80px from backdrop = dismiss
43
- - **Navigation UI**: Chevron buttons (hidden on mobile), counter badge at bottom ("3 / 10")
44
- - Close button (X) top-right with safe-area offset
45
-
46
- **Gesture Detection**:
47
-
48
- ```typescript
49
- // Horizontal swipe: navigate
50
- if (deltaX > 100 && absX > absY) onPrev()
51
- if (deltaX < -100 && absX > absY) onNext()
52
- // Vertical swipe up from backdrop: dismiss
53
- if (onBackdrop && deltaY < -80 && absY > absX) onClose()
54
- ```
55
-
56
- **Usage** (building a custom lightbox):
57
-
58
- ```typescript
59
- function MyLightbox({ items, startIndex, onClose }) {
60
- const [index, setIndex] = useState(startIndex)
61
- return (
62
- <LightboxContainer
63
- totalCount={items.length}
64
- index={index}
65
- onPrev={() => setIndex(i => Math.max(0, i - 1))}
66
- onNext={() => setIndex(i => Math.min(items.length - 1, i + 1))}
67
- onClose={onClose}
68
- >
69
- <MySlideContent item={items[index]} />
70
- </LightboxContainer>
71
- )
72
- }
73
- ```
74
-
75
- ---
76
-
77
- ### ImageLightbox (Gallery Viewer)
78
-
79
- **File**: `src/components/ImageLightbox.tsx`
80
-
81
- ```typescript
82
- interface ImageLightboxProps {
83
- images: Array<{ src: string; alt?: string; crop?: CropData | null }>
84
- startIndex: number
85
- onClose: () => void
86
- }
87
- ```
88
-
89
- **Features**:
90
- - Built on LightboxContainer
91
- - Lazy-loads crop data via HEAD request to image proxy (module-level cache)
92
- - Preloads adjacent images (current ± 1) to eliminate flash
93
- - ScaledCropPreview: uses CSS `background-position` + `background-size` for efficient cropped display
94
- - Max constraints: 95vw width, 85vh height
95
- - Click-stop propagation on images (prevents backdrop close)
96
-
97
- ---
98
-
99
- ### ImageCropLightbox (Crop Editor)
100
-
101
- **File**: `src/components/ImageCropLightbox.tsx`
102
-
103
- ```typescript
104
- interface ImageCropLightboxProps {
105
- images: CropImage[]
106
- startIndex: number
107
- onClose: () => void
108
- onCropChange?: (index: number, crop: CropData) => void
109
- }
110
- ```
111
-
112
- **Features**:
113
- - Built on LightboxContainer with `navDisabled` during active crop
114
- - Toggle between view mode and crop mode (Escape exits crop mode, not lightbox)
115
- - Overlay buttons: crop toggle, reset crop
116
- - Lazy-loads natural image dimensions for proper crop calculations
117
-
118
- ---
119
-
120
- ## Anti-Patterns
121
-
122
- ### Building Full-Screen Overlays Without LightboxContainer
123
-
124
- ```typescript
125
- // Bad: Reimplementing swipe, keyboard, animation, scroll lock
126
- <div className="fixed inset-0 z-50" onKeyDown={handleKey}>
127
- {/* Custom implementation */}
128
- </div>
129
-
130
- // Good: Use LightboxContainer for the shell
131
- <LightboxContainer totalCount={n} index={i} onPrev={prev} onNext={next} onClose={close}>
132
- {/* Just the slide content */}
133
- </LightboxContainer>
134
- ```
135
-
136
- ### Forgetting navDisabled for Sub-Modes
137
-
138
- ```typescript
139
- // Bad: User swipes during crop edit, navigates away and loses changes
140
- <LightboxContainer onPrev={prev} onNext={next}>
141
- <CropEditor />
142
- </LightboxContainer>
143
-
144
- // Good: Disable nav during sub-mode
145
- <LightboxContainer
146
- navDisabled={cropActive}
147
- onEscapeWhileNavDisabled={() => setCropActive(false)}
148
- onBackdropClickWhileNavDisabled={() => setCropActive(false)}
149
- >
150
- <CropEditor />
151
- </LightboxContainer>
152
- ```
153
-
154
- ---
155
-
156
- ## Checklist
157
-
158
- - [ ] Use LightboxContainer for any full-screen gallery or detail viewer
159
- - [ ] Set `navDisabled` when entering a sub-mode (crop, edit, etc.)
160
- - [ ] Provide `onEscapeWhileNavDisabled` to exit sub-mode on Escape
161
- - [ ] Preload adjacent slides to eliminate flash on navigation
162
- - [ ] Apply `e.stopPropagation()` on interactive content to prevent backdrop close
163
- - [ ] Safe-area-inset-top applied via inline style
164
-
165
- ---
166
-
167
- **Status**: Stable
168
- **Last Updated**: 2026-03-14
169
- **Contributors**: Community
@@ -1,115 +0,0 @@
1
- # Markdown Content Rendering
2
-
3
- **Category**: Design
4
- **Applicable To**: Rendering AI-generated or user-submitted markdown with XSS protection, @mention badges, code blocks, and font size preferences
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- `MarkdownContent` wraps ReactMarkdown with rehype-sanitize for XSS protection, custom mention preprocessing (`@agent`, `@uid:userId`), link validation (internal/external routing), syntax-highlighted code blocks, and user font size preferences. Safe for rendering AI-generated content that may contain arbitrary markdown.
12
-
13
- ---
14
-
15
- ## Implementation
16
-
17
- **File**: `src/components/chat/MarkdownContent.tsx`
18
-
19
- ```typescript
20
- interface MarkdownContentProps {
21
- content: string
22
- className?: string
23
- currentUserId?: string // For mention badge interactivity
24
- }
25
- ```
26
-
27
- ### Processing Pipeline
28
-
29
- ```
30
- Raw content
31
- → stripTimestampPrefix() // Remove <msg ts="..."/> prefixes
32
- → linkifyText() // Convert bare URLs to [url](url) markdown
33
- → preprocessMentions() // @agent → **@agent**, @uid:X → **@uid:X**
34
- → ReactMarkdown
35
- + rehype-sanitize // Strip XSS vectors
36
- + custom components // Links, code, strong (mentions)
37
- ```
38
-
39
- ### XSS Sanitization
40
-
41
- ```typescript
42
- const sanitizeSchema = {
43
- ...defaultSchema,
44
- attributes: {
45
- code: [...(defaultSchema.attributes?.code || []), 'className'],
46
- a: ['href', 'title'],
47
- },
48
- protocols: { href: ['http', 'https', 'mailto'] },
49
- tagNames: (defaultSchema.tagNames || []).filter(tag =>
50
- !['script', 'iframe', 'object', 'embed', 'style'].includes(tag)
51
- ),
52
- }
53
- ```
54
-
55
- ### Link Routing
56
-
57
- ```typescript
58
- // Internal links (/memory/abc): navigate within app
59
- // External links (https://...): target="_blank" rel="noopener noreferrer"
60
- // Invalid URLs: render as red [Invalid Link] span
61
-
62
- function isInternalUrl(url: string): boolean { return url.startsWith('/') }
63
- function isValidUrl(url: string): boolean {
64
- if (url.startsWith('/')) return true
65
- try { return ['http:', 'https:', 'mailto:'].includes(new URL(url).protocol) }
66
- catch { return false }
67
- }
68
- ```
69
-
70
- ### Code Blocks
71
-
72
- ```typescript
73
- // Multiline → CodeBlock component with syntax highlighting + copy button
74
- // Inline → gray background with font size preference
75
- const isCodeBlock = code.includes('\n') || startLine !== endLine
76
- if (isCodeBlock) return <CodeBlock code={code} language={language} />
77
- return <code className="bg-gray-700 px-1.5 py-0.5 rounded">{children}</code>
78
- ```
79
-
80
- ### Mention Badges
81
-
82
- `@agent` and `@uid:userId` are preprocessed to bold markdown, then the `strong` renderer detects them:
83
-
84
- ```typescript
85
- strong({ children }) {
86
- const text = extractText(children)
87
- if (text === '@agent') return <span className="bg-blue-500/20 text-blue-400 ...">@agent</span>
88
- if (text.startsWith('@uid:')) return <MentionBadge userId={text.slice(5)} />
89
- return <strong>{children}</strong>
90
- }
91
- ```
92
-
93
- ### Font Size Integration
94
-
95
- Uses `useUIPreferencesLocal()` context — heading sizes and prose classes scale with preference.
96
-
97
- ---
98
-
99
- ## Anti-Patterns
100
-
101
- ### Rendering Unsanitized HTML
102
-
103
- ```typescript
104
- // Bad: XSS vulnerability
105
- <div dangerouslySetInnerHTML={{ __html: aiResponse }} />
106
-
107
- // Good: ReactMarkdown + rehype-sanitize
108
- <MarkdownContent content={aiResponse} />
109
- ```
110
-
111
- ---
112
-
113
- **Status**: Stable
114
- **Last Updated**: 2026-03-14
115
- **Contributors**: Community
@@ -1,98 +0,0 @@
1
- # Mention Suggestion System
2
-
3
- **Category**: Design
4
- **Applicable To**: @mention autocomplete in chat inputs with instant context + async search tiers
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- A two-tier mention autocomplete: Tier 1 (instant) uses in-memory conversation participant profiles for sub-millisecond results. Tier 2 (async) searches the global people index via API when the context tier has no matches. Stale call detection prevents race conditions. Suggestions sorted by: agent first → prefix matches → substring matches.
12
-
13
- ---
14
-
15
- ## Implementation
16
-
17
- ### useMentionSuggestions Hook
18
-
19
- **File**: `src/hooks/useMentionSuggestions.ts`
20
-
21
- ```typescript
22
- interface MentionSuggestion {
23
- id: string // userId or 'agent'
24
- username: string
25
- type: 'agent' | 'user'
26
- avatarUrl?: string
27
- displayName?: string
28
- section?: 'context' | 'search'
29
- }
30
-
31
- function useMentionSuggestions(participantIds?: string[]) {
32
- const contextProfilesRef = useRef<Map<string, UserProfile>>(new Map())
33
- const callIdRef = useRef(0) // Stale call detection
34
-
35
- // Tier 1: Load participant profiles on mount
36
- useEffect(() => {
37
- if (!participantIds?.length) return
38
- ProfileService.getProfiles(participantIds).then(profiles => {
39
- contextProfilesRef.current = new Map(Object.entries(profiles))
40
- })
41
- }, [participantIds?.join(',')])
42
-
43
- const getSuggestions = useCallback(async (query: string) => {
44
- const thisCallId = ++callIdRef.current
45
-
46
- // Tier 1: Instant context matches
47
- const contextResults = matchFromContext(query, contextProfilesRef.current)
48
-
49
- // Tier 2: Async global search (if context insufficient)
50
- if (contextResults.length < 3 && query.length >= 1) {
51
- const searchResults = await PeopleService.search(query, 5)
52
- if (callIdRef.current !== thisCallId) return [] // Stale
53
- return [...contextResults, ...searchResults]
54
- }
55
-
56
- return contextResults
57
- }, [])
58
-
59
- return { getSuggestions }
60
- }
61
- ```
62
-
63
- ### MentionAutocomplete Component
64
-
65
- **File**: `src/components/chat/MentionAutocomplete.tsx`
66
-
67
- ```typescript
68
- interface MentionAutocompleteProps {
69
- inputValue: string
70
- textareaRef: RefObject<HTMLTextAreaElement | null>
71
- onSelect: (suggestion, startIndex, endIndex) => void
72
- getSuggestions?: (query: string) => MentionSuggestion[] | Promise<MentionSuggestion[]>
73
- maxResults?: number
74
- reverse?: boolean // Bottom-to-top rendering (closest to input = most relevant)
75
- }
76
- ```
77
-
78
- **Mention Detection**: Scans backwards from cursor for `@` preceded by whitespace or start-of-input.
79
-
80
- **Keyboard Navigation**: ArrowUp/Down (flipped in reverse mode), Enter/Tab to select, Escape to close.
81
-
82
- **Text Insertion**: `onSelect(suggestion, @position, endPosition)` — caller replaces the `@query` range with `@username `.
83
-
84
- ---
85
-
86
- ## Checklist
87
-
88
- - [ ] Tier 1 profiles loaded from conversation participants on mount
89
- - [ ] Tier 2 search triggered when context has < 3 matches
90
- - [ ] Stale call detection via incrementing callIdRef
91
- - [ ] Agent suggestion always appears first if query matches
92
- - [ ] `reverse` mode used when autocomplete renders above input
93
-
94
- ---
95
-
96
- **Status**: Stable
97
- **Last Updated**: 2026-03-14
98
- **Contributors**: Community
@@ -1,156 +0,0 @@
1
- # Modal & Confirmation Modal
2
-
3
- **Category**: Design
4
- **Applicable To**: All dialog overlays, confirmations, form modals, and persistent consent dialogs
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- The Modal system provides a portal-rendered overlay (z-55) with backdrop blur, escape/click-outside dismissal, body scroll lock, and safe-area-inset-top support. ConfirmationModal extends it with variant-colored icons and a two-button confirm/cancel footer. Use `persistent: true` to disable all dismissal paths for consent flows.
12
-
13
- ---
14
-
15
- ## Implementation
16
-
17
- ### Modal (Base)
18
-
19
- **File**: `src/components/modals/Modal.tsx`
20
-
21
- ```typescript
22
- interface ModalProps {
23
- isOpen: boolean
24
- onClose: () => void
25
- children: React.ReactNode
26
- title?: string
27
- style?: React.CSSProperties
28
- maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'
29
- persistent?: boolean // Disables Escape, backdrop click, and close button
30
- }
31
- ```
32
-
33
- **Behavior**:
34
- - `createPortal` to `document.body` at z-index 55
35
- - Backdrop: `bg-black/50 backdrop-blur-sm`, click-outside closes (unless persistent)
36
- - Escape key closes (unless persistent)
37
- - Body scroll lock: `document.body.style.overflow = 'hidden'` on mount, restored on unmount
38
- - Close button (X) top-right, hidden when persistent
39
- - Title rendered above children if provided
40
- - `paddingTop: env(safe-area-inset-top)` on the fixed container
41
- - Backdrop click uses `e.target === e.currentTarget` to avoid closing on content clicks
42
-
43
- **Usage**:
44
-
45
- ```typescript
46
- <Modal isOpen={showModal} onClose={() => setShowModal(false)} title="Edit Item" maxWidth="md">
47
- <form>{/* form content */}</form>
48
- </Modal>
49
- ```
50
-
51
- ---
52
-
53
- ### ConfirmationModal
54
-
55
- **File**: `src/components/modals/ConfirmationModal.tsx`
56
-
57
- ```typescript
58
- interface ConfirmationModalProps {
59
- isOpen: boolean
60
- onClose: () => void
61
- onConfirm: () => void
62
- title: string
63
- message: string | React.ReactNode
64
- confirmText?: string // default: "Confirm"
65
- cancelText?: string // default: "Cancel"
66
- variant?: 'danger' | 'warning' | 'info'
67
- isLoading?: boolean
68
- }
69
- ```
70
-
71
- **Behavior**:
72
- - Built on Modal (sm width)
73
- - Variant-colored gradient icon circle at top:
74
- - `danger`: purple-pink gradient
75
- - `warning`: yellow-orange gradient
76
- - `info`: blue-cyan gradient
77
- - Two-button footer: Cancel (gray) | Confirm (variant gradient)
78
- - Both buttons disabled during `isLoading`
79
- - Prevents modal dismiss during loading: passes `() => {}` as `onClose` to Modal
80
-
81
- **Usage**:
82
-
83
- ```typescript
84
- <ConfirmationModal
85
- isOpen={showDelete}
86
- onClose={() => setShowDelete(false)}
87
- onConfirm={handleDelete}
88
- title="Delete Memory"
89
- message="This action cannot be undone."
90
- confirmText="Delete"
91
- variant="danger"
92
- isLoading={deleting}
93
- />
94
- ```
95
-
96
- ---
97
-
98
- ### SuccessModal
99
-
100
- **File**: `src/components/modals/SuccessModal.tsx`
101
-
102
- ```typescript
103
- interface SuccessModalProps {
104
- isOpen: boolean
105
- onClose: () => void
106
- title: string
107
- message: React.ReactNode
108
- }
109
- ```
110
-
111
- Single "Close" button with blue-cyan gradient. Check icon in gradient circle.
112
-
113
- ---
114
-
115
- ## Anti-Patterns
116
-
117
- ### Rendering Modal Content Without Portal
118
-
119
- ```typescript
120
- // Bad: Modal renders in component tree, z-index conflicts with parents
121
- <div className="relative z-10">
122
- <div className="fixed inset-0 bg-black/50">{content}</div>
123
- </div>
124
-
125
- // Good: Use Modal component (portals to document.body)
126
- <Modal isOpen={open} onClose={close}>{content}</Modal>
127
- ```
128
-
129
- ### Forgetting isLoading Guard on Dismiss
130
-
131
- ```typescript
132
- // Bad: User can close modal while async confirm is running
133
- <Modal isOpen={open} onClose={() => setOpen(false)}>
134
- <button onClick={asyncConfirm}>Confirm</button>
135
- </Modal>
136
-
137
- // Good: Disable dismiss during loading
138
- <ConfirmationModal isLoading={loading} onClose={() => setOpen(false)} ... />
139
- // ConfirmationModal internally passes () => {} as onClose when loading
140
- ```
141
-
142
- ---
143
-
144
- ## Checklist
145
-
146
- - [ ] Use `Modal` base for custom dialogs, `ConfirmationModal` for confirm/cancel flows
147
- - [ ] Set `persistent: true` for consent/TOS dialogs that must not be dismissed
148
- - [ ] Set `maxWidth` appropriately (sm for confirms, md-lg for forms, xl-2xl for complex content)
149
- - [ ] Guard dismiss during async operations with `isLoading`
150
- - [ ] Content uses max-h-[90vh] with overflow-auto for long content
151
-
152
- ---
153
-
154
- **Status**: Stable
155
- **Last Updated**: 2026-03-14
156
- **Contributors**: Community