@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,375 +0,0 @@
1
- # Searchable Settings Page
2
-
3
- **Category**: Design
4
- **Applicable To**: Settings pages with grouped sections, search-to-scroll, hash-based navigation, and a registry of searchable items
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- The Settings page uses a registry-based architecture: all settings are defined in a central `SettingsItem[]` array with name, description, category, hidden keywords, and a hash-fragment path. A search input filters the registry using AND-logic word matching, and selecting a result navigates to the route + scrolls to the section via its `id` attribute. This makes settings discoverable without browsing every section.
12
-
13
- ---
14
-
15
- ## When to Use This Pattern
16
-
17
- **Use this pattern when:**
18
- - Building a settings page with many sections that benefit from search
19
- - Any page with hash-based scroll-to-section navigation
20
- - Settings that span multiple sub-pages (main settings, ghost settings, delete account)
21
-
22
- **Don't use this pattern when:**
23
- - The page has fewer than 5 settings (just list them, no search needed)
24
- - Settings are entirely form-based with no sections (use a simple form)
25
-
26
- ---
27
-
28
- ## Core Principles
29
-
30
- 1. **Registry as Source of Truth**: All searchable settings defined in one `SettingsItem[]` array
31
- 2. **Hidden Keywords**: Extra search terms (`keywords[]`) improve discoverability without cluttering the UI
32
- 3. **AND-Logic Search**: All query words must match in the concatenated haystack
33
- 4. **Hash-Fragment Navigation**: Search results link to `path#section-id`, scrolling to the section
34
- 5. **Optimistic Updates**: Toggle/slider changes apply immediately, revert on API failure
35
-
36
- ---
37
-
38
- ## Implementation
39
-
40
- ### Settings Registry
41
-
42
- **File**: `src/constant/settings-registry.ts`
43
-
44
- ```typescript
45
- export interface SettingsItem {
46
- /** Unique identifier, also used as Algolia objectID */
47
- id: string
48
- /** Display name shown in search results */
49
- name: string
50
- /** Short description shown under the name */
51
- description: string
52
- /** Category grouping (e.g. "Ghost Mode", "Privacy", "Display") */
53
- category: string
54
- /** Extra search terms not visible in UI (e.g. "telemetry" for analytics) */
55
- keywords: string[]
56
- /** Route path + optional hash fragment (e.g. "/settings#privacy") */
57
- path: string
58
- /** Sub-items listed for context in search results */
59
- sub_items: string[]
60
- }
61
-
62
- export const SETTINGS_REGISTRY: SettingsItem[] = [
63
- {
64
- id: 'ghost-mode',
65
- name: 'Ghost Mode',
66
- description: 'Configure your ghost persona and conversation behavior',
67
- category: 'Ghost Mode',
68
- keywords: ['persona', 'alter ego', 'anonymous', 'identity'],
69
- path: '/settings/ghost#ghost-mode',
70
- sub_items: ['Enable ghost mode', 'Ghost name', 'Ghost persona'],
71
- },
72
- {
73
- id: 'privacy-analytics',
74
- name: 'Analytics',
75
- description: 'Control whether usage data is collected',
76
- category: 'Privacy',
77
- keywords: ['tracking', 'telemetry', 'data collection', 'opt out'],
78
- path: '/settings#privacy',
79
- sub_items: ['Toggle analytics on/off'],
80
- },
81
- // ... 25 total items
82
- ]
83
- ```
84
-
85
- ### Search Algorithm
86
-
87
- **File**: `src/routes/settings/index.tsx`
88
-
89
- ```typescript
90
- function searchSettings(query: string): SettingsItem[] {
91
- if (!query.trim()) return []
92
- const q = query.toLowerCase()
93
- return SETTINGS_REGISTRY.filter((item) => {
94
- const haystack = [
95
- item.name,
96
- item.description,
97
- item.category,
98
- ...item.sub_items,
99
- ...item.keywords,
100
- ].join(' ').toLowerCase()
101
- return q.split(/\s+/).every((word) => haystack.includes(word))
102
- })
103
- }
104
- ```
105
-
106
- **How it works**:
107
- - Concatenates all searchable fields into one string ("haystack")
108
- - Splits query into words
109
- - Every word must appear in the haystack (AND logic)
110
- - Example: `"toggle privacy"` matches items containing both "toggle" AND "privacy"
111
-
112
- ### Search UI
113
-
114
- ```typescript
115
- const [searchQuery, setSearchQuery] = useState('')
116
- const [searchFocused, setSearchFocused] = useState(false)
117
- const searchRef = useRef<HTMLDivElement>(null)
118
-
119
- const searchResults = useMemo(() => searchSettings(searchQuery), [searchQuery])
120
- const showResults = searchFocused && searchQuery.trim().length > 0
121
- ```
122
-
123
- **Rendered structure**:
124
-
125
- ```
126
- ┌─ Search Input ────────────────────────────────┐
127
- │ 🔍 Search settings... ✕ │
128
- ├───────────────────────────────────────────────┤
129
- │ Ghost Mode [Ghost Mode] │ ← category badge
130
- │ Configure your ghost persona... │
131
- │ • Enable ghost mode • Ghost name │ ← sub_items
132
- ├───────────────────────────────────────────────┤
133
- │ Analytics [Privacy] │
134
- │ Control whether usage data is collected │
135
- │ • Toggle analytics on/off │
136
- └───────────────────────────────────────────────┘
137
- ```
138
-
139
- **Result click handler**:
140
-
141
- ```typescript
142
- onClick={() => {
143
- setSearchQuery('')
144
- setSearchFocused(false)
145
- const [to, hash] = item.path.split('#')
146
- navigate({ to, hash })
147
- if (hash) {
148
- setTimeout(() => {
149
- document.getElementById(hash)?.scrollIntoView({
150
- behavior: 'smooth',
151
- block: 'start',
152
- })
153
- }, 300) // Delay allows DOM to settle after navigation
154
- }
155
- }
156
- ```
157
-
158
- ### Section Anchors
159
-
160
- Each settings section uses an `id` attribute matching the hash fragment:
161
-
162
- ```typescript
163
- <div id="privacy" className="bg-gray-900/50 backdrop-blur-sm border border-gray-800 rounded-xl p-6">
164
- <div className="flex items-center gap-3 mb-4">
165
- <Shield className="w-5 h-5 text-blue-400" />
166
- <h2 className="text-lg font-semibold text-white">Privacy</h2>
167
- </div>
168
- {/* Setting controls */}
169
- </div>
170
- ```
171
-
172
- ### Hash Scroll on Page Load
173
-
174
- ```typescript
175
- useEffect(() => {
176
- const hash = window.location.hash.slice(1)
177
- if (!hash) return
178
- const timer = setTimeout(() => {
179
- document.getElementById(hash)?.scrollIntoView({
180
- behavior: 'smooth',
181
- block: 'start',
182
- })
183
- }, 300)
184
- return () => clearTimeout(timer)
185
- }, [])
186
- ```
187
-
188
- This handles both direct links (`/settings#privacy`) and search-driven navigation.
189
-
190
- ### Settings Controls Within Sections
191
-
192
- **Toggle setting**:
193
-
194
- ```typescript
195
- <div className="flex items-center justify-between py-3">
196
- <div>
197
- <p className="text-sm font-medium text-white">Analytics</p>
198
- <p className="text-xs text-gray-500">Help improve the app by sharing usage data</p>
199
- </div>
200
- <ToggleSwitch
201
- checked={analyticsEnabled}
202
- onChange={handleAnalyticsToggle}
203
- disabled={toggling}
204
- />
205
- </div>
206
- ```
207
-
208
- **Slider setting**:
209
-
210
- ```typescript
211
- <div className="py-3">
212
- <p className="text-sm font-medium text-white mb-2">Search Relevance</p>
213
- <p className="text-xs text-gray-500 mb-3">Higher values return fewer but more relevant results</p>
214
- <Slider min={0} max={0.8} step={0.05} value={threshold} onChange={handleChange} />
215
- </div>
216
- ```
217
-
218
- **Link to sub-page**:
219
-
220
- ```typescript
221
- <Link to="/settings/ghost"
222
- className="flex items-center justify-between p-4 bg-gray-900/50 border border-gray-800 rounded-xl hover:border-purple-500/50 transition-colors">
223
- <div className="flex items-center gap-3">
224
- <Ghost className="w-5 h-5 text-purple-400" />
225
- <div>
226
- <p className="text-sm font-medium text-white">Ghost Mode</p>
227
- <p className="text-xs text-gray-500">Configure persona and trust levels</p>
228
- </div>
229
- </div>
230
- <ChevronRight className="w-4 h-4 text-gray-500" />
231
- </Link>
232
- ```
233
-
234
- ### State Management
235
-
236
- **Server-synced preferences** (UIPreferencesContext):
237
- ```typescript
238
- const { preferences, updatePreference } = useUIPreferences()
239
-
240
- // Optimistic update + API call
241
- const handleToggle = async (value: boolean) => {
242
- const success = await updatePreference({ memory_card_overflow: value ? 'scroll' : 'clip' })
243
- if (!success) toast.error({ title: 'Failed to save' })
244
- }
245
- ```
246
-
247
- **Device-local preferences** (UIPreferencesLocalContext):
248
- ```typescript
249
- const { contentFontSize, setContentFontSize } = useUIPreferencesLocal()
250
- // Stored in localStorage, varies per device (mobile vs desktop)
251
- ```
252
-
253
- ---
254
-
255
- ## Examples
256
-
257
- ### Adding a New Setting
258
-
259
- 1. **Add to registry** (`src/constant/settings-registry.ts`):
260
- ```typescript
261
- {
262
- id: 'theme-mode',
263
- name: 'Theme',
264
- description: 'Choose light or dark color scheme',
265
- category: 'Display',
266
- keywords: ['dark mode', 'light mode', 'appearance', 'color'],
267
- path: '/settings#ui-preferences',
268
- sub_items: ['Light', 'Dark', 'System'],
269
- }
270
- ```
271
-
272
- 2. **Add section anchor** (in settings page):
273
- ```typescript
274
- <div id="ui-preferences" className="bg-gray-900/50 ...">
275
- {/* existing controls + new theme toggle */}
276
- </div>
277
- ```
278
-
279
- 3. **Done** — the new setting is immediately searchable.
280
-
281
- ### Adding a New Sub-Page
282
-
283
- 1. Create route: `src/routes/settings/new-page.tsx`
284
- 2. Add registry entries with `path: '/settings/new-page#section-id'`
285
- 3. Add link in main settings page with ChevronRight arrow
286
-
287
- ---
288
-
289
- ## Anti-Patterns
290
-
291
- ### Hardcoding Settings Without Registry
292
-
293
- ```typescript
294
- // Bad: Settings not searchable, no central definition
295
- <div>
296
- <h2>Privacy</h2>
297
- <ToggleSwitch checked={analytics} onChange={toggleAnalytics} />
298
- </div>
299
-
300
- // Good: Define in registry, render from section id, searchable automatically
301
- // settings-registry.ts:
302
- { id: 'privacy-analytics', name: 'Analytics', path: '/settings#privacy', ... }
303
- // settings page:
304
- <div id="privacy">...</div>
305
- ```
306
-
307
- ### OR-Logic Search
308
-
309
- ```typescript
310
- // Bad: Returns too many results (any word matches)
311
- return q.split(/\s+/).some((word) => haystack.includes(word))
312
-
313
- // Good: AND logic — all words must match
314
- return q.split(/\s+/).every((word) => haystack.includes(word))
315
- ```
316
-
317
- ### Scrolling Without Delay
318
-
319
- ```typescript
320
- // Bad: Element might not be in DOM yet after navigation
321
- document.getElementById(hash)?.scrollIntoView({ behavior: 'smooth' })
322
-
323
- // Good: Wait for DOM to settle
324
- setTimeout(() => {
325
- document.getElementById(hash)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
326
- }, 300)
327
- ```
328
-
329
- ---
330
-
331
- ## Key Design Decisions
332
-
333
- ### Search Architecture
334
-
335
- | Decision | Choice | Rationale |
336
- |---|---|---|
337
- | Search data source | Static registry array | Fast, no API call, works offline |
338
- | Search algorithm | AND-logic word matching | More precise than OR; reduces noise |
339
- | Hidden keywords | `keywords[]` field | Improves discoverability without UI clutter |
340
- | Result navigation | Route + hash scroll | Deep-links to exact section |
341
- | Scroll delay | 300ms setTimeout | Allows DOM render after route navigation |
342
-
343
- ### State Management
344
-
345
- | Decision | Choice | Rationale |
346
- |---|---|---|
347
- | Server preferences | UIPreferencesContext with optimistic update | Syncs across devices; instant UI response |
348
- | Device preferences | localStorage via UIPreferencesLocalContext | Font size varies per device (mobile vs desktop) |
349
- | Update pattern | Optimistic + rollback on failure | Feels instant; reverts if API fails |
350
-
351
- ---
352
-
353
- ## Checklist
354
-
355
- - [ ] New settings added to `SETTINGS_REGISTRY` with id, name, description, category, keywords, path, sub_items
356
- - [ ] Section div has `id` attribute matching the hash fragment in the registry path
357
- - [ ] Keywords include synonyms users might search for (e.g., "telemetry" for analytics)
358
- - [ ] Sub-items list the specific controls within the section
359
- - [ ] Path uses hash fragment for same-page sections, full route for sub-pages
360
- - [ ] Settings controls use ToggleSwitch, Slider, or link-with-chevron patterns
361
- - [ ] Server-synced settings use optimistic update via UIPreferencesContext
362
- - [ ] Device-local settings use localStorage via UIPreferencesLocalContext
363
-
364
- ---
365
-
366
- ## Related Patterns
367
-
368
- - **[Form Controls](./tanstack-cloudflare.form-controls.md)**: ToggleSwitch and Slider used within settings sections
369
- - **[Unified Header](./tanstack-cloudflare.unified-header.md)**: Settings page uses UnifiedHeader with back navigation
370
-
371
- ---
372
-
373
- **Status**: Stable
374
- **Last Updated**: 2026-03-14
375
- **Contributors**: Community
@@ -1,129 +0,0 @@
1
- # SlideOverPanel & MessageSearchSlideover
2
-
3
- **Category**: Design
4
- **Applicable To**: Right-side slide panels, search slideouts, and configuration drawers
5
- **Status**: Stable
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- SlideOverPanel is a lightweight right-side drawer (w-72) that slides in with a translate-x animation and backdrop. MessageSearchSlideover is a specialized full-width search panel with debounced API search and result navigation. Both render inline (not portaled) with fixed positioning.
12
-
13
- ---
14
-
15
- ## Implementation
16
-
17
- ### SlideOverPanel (Generic Drawer)
18
-
19
- **File**: `src/components/SlideOverPanel.tsx`
20
-
21
- ```typescript
22
- interface SlideOverPanelProps {
23
- open: boolean
24
- onClose: () => void
25
- children: ReactNode
26
- }
27
- ```
28
-
29
- **Behavior**:
30
- - Fixed positioning: `top-14` (below header), `right-0`, `bottom-0`
31
- - Width: `w-72` (288px)
32
- - **Not** a portal — renders inline from parent component
33
- - **Animation** (200ms):
34
- - Backdrop: `opacity-0` → `opacity-100`
35
- - Panel: `translate-x-full` → `translate-x-0`
36
- - Mounted/visible state tracking for exit animation before unmount
37
- - Backdrop click closes
38
- - z-index: backdrop 20, panel 30
39
- - Dark theme: `bg-gray-900` with `border-l border-gray-800`
40
-
41
- **Usage**:
42
-
43
- ```typescript
44
- <SlideOverPanel open={panelOpen} onClose={() => setPanelOpen(false)}>
45
- <div className="p-4">
46
- <h3>Panel Content</h3>
47
- {/* configuration, details, etc. */}
48
- </div>
49
- </SlideOverPanel>
50
- ```
51
-
52
- ---
53
-
54
- ### MessageSearchSlideover (Search Panel)
55
-
56
- **File**: `src/components/chat/MessageSearchSlideover.tsx`
57
-
58
- ```typescript
59
- interface MessageSearchSlideoverProps {
60
- conversationId: string
61
- isOpen: boolean
62
- onClose: () => void
63
- onSelectMessage: (messageId: string) => void
64
- }
65
- ```
66
-
67
- **Behavior**:
68
- - Full-screen fixed panel (not constrained to right side)
69
- - Max-width: `md` on desktop
70
- - **Header**: Search icon + auto-focused input + X close button
71
- - **Debounced search**: 300ms delay, calls `/api/search/messages`
72
- - **Results**: Message snippet with fade mask, role label, relative time
73
- - Click result → calls `onSelectMessage(messageId)` and closes panel
74
- - Escape key closes
75
- - Backdrop click closes
76
- - Safe-area-inset-top handling
77
-
78
- **Usage**:
79
-
80
- ```typescript
81
- <MessageSearchSlideover
82
- conversationId={conversationId}
83
- isOpen={searchOpen}
84
- onClose={() => setSearchOpen(false)}
85
- onSelectMessage={(id) => scrollToMessage(id)}
86
- />
87
- ```
88
-
89
- ---
90
-
91
- ## Anti-Patterns
92
-
93
- ### Using Portal for Simple Slide Panels
94
-
95
- ```typescript
96
- // Bad: Unnecessary portal when parent layout supports fixed children
97
- {createPortal(<div className="fixed right-0">...</div>, document.body)}
98
-
99
- // Good: Render inline — simpler and avoids portal context issues
100
- <SlideOverPanel open={open} onClose={close}>{content}</SlideOverPanel>
101
- ```
102
-
103
- ### Not Auto-Focusing Search Input
104
-
105
- ```typescript
106
- // Bad: User must click into input after opening
107
- <input type="text" />
108
-
109
- // Good: Auto-focus on open
110
- const inputRef = useRef<HTMLInputElement>(null)
111
- useEffect(() => { if (isOpen) inputRef.current?.focus() }, [isOpen])
112
- ```
113
-
114
- ---
115
-
116
- ## Checklist
117
-
118
- - [ ] Use `SlideOverPanel` for generic right-side drawers
119
- - [ ] Use `MessageSearchSlideover` for search-within-conversation
120
- - [ ] Auto-focus input when panel opens
121
- - [ ] Debounce search input (300ms)
122
- - [ ] Panel renders below header (`top-14`) to avoid overlapping
123
- - [ ] Exit animation completes before unmount (mounted/visible state tracking)
124
-
125
- ---
126
-
127
- **Status**: Stable
128
- **Last Updated**: 2026-03-14
129
- **Contributors**: Community