@vybestack/llxprt-ui 0.7.0-nightly.251211.5750c518a
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/PLAN-messages.md +681 -0
- package/PLAN.md +47 -0
- package/README.md +25 -0
- package/bun.lock +1024 -0
- package/dev-docs/ARCHITECTURE.md +178 -0
- package/dev-docs/CODE_ORGANIZATION.md +232 -0
- package/dev-docs/STANDARDS.md +235 -0
- package/dev-docs/UI_DESIGN.md +425 -0
- package/eslint.config.cjs +194 -0
- package/images/nui.png +0 -0
- package/llxprt.png +0 -0
- package/llxprt.svg +128 -0
- package/package.json +66 -0
- package/scripts/check-limits.ts +177 -0
- package/scripts/start.js +71 -0
- package/src/app.tsx +599 -0
- package/src/bootstrap.tsx +23 -0
- package/src/commands/AuthCommand.tsx +80 -0
- package/src/commands/ModelCommand.tsx +102 -0
- package/src/commands/ProviderCommand.tsx +103 -0
- package/src/commands/ThemeCommand.tsx +71 -0
- package/src/features/chat/history.ts +178 -0
- package/src/features/chat/index.ts +3 -0
- package/src/features/chat/persistentHistory.ts +102 -0
- package/src/features/chat/responder.ts +217 -0
- package/src/features/completion/completions.ts +161 -0
- package/src/features/completion/index.ts +3 -0
- package/src/features/completion/slash.test.ts +82 -0
- package/src/features/completion/slash.ts +248 -0
- package/src/features/completion/suggestions.test.ts +51 -0
- package/src/features/completion/suggestions.ts +112 -0
- package/src/features/config/configSession.test.ts +189 -0
- package/src/features/config/configSession.ts +179 -0
- package/src/features/config/index.ts +4 -0
- package/src/features/config/llxprtAdapter.integration.test.ts +202 -0
- package/src/features/config/llxprtAdapter.test.ts +139 -0
- package/src/features/config/llxprtAdapter.ts +257 -0
- package/src/features/config/llxprtCommands.test.ts +40 -0
- package/src/features/config/llxprtCommands.ts +35 -0
- package/src/features/config/llxprtConfig.test.ts +261 -0
- package/src/features/config/llxprtConfig.ts +418 -0
- package/src/features/theme/index.ts +2 -0
- package/src/features/theme/theme.test.ts +51 -0
- package/src/features/theme/theme.ts +105 -0
- package/src/features/theme/themeManager.ts +84 -0
- package/src/hooks/useAppCommands.ts +129 -0
- package/src/hooks/useApprovalKeyboard.ts +156 -0
- package/src/hooks/useChatStore.test.ts +112 -0
- package/src/hooks/useChatStore.ts +252 -0
- package/src/hooks/useInputManager.ts +99 -0
- package/src/hooks/useKeyboardHandlers.ts +130 -0
- package/src/hooks/useListNavigation.test.ts +166 -0
- package/src/hooks/useListNavigation.ts +62 -0
- package/src/hooks/usePersistentHistory.ts +94 -0
- package/src/hooks/useScrollManagement.ts +107 -0
- package/src/hooks/useSelectionClipboard.ts +48 -0
- package/src/hooks/useSessionManager.test.ts +85 -0
- package/src/hooks/useSessionManager.ts +101 -0
- package/src/hooks/useStreamingLifecycle.ts +71 -0
- package/src/hooks/useStreamingResponder.ts +401 -0
- package/src/hooks/useSuggestionSetup.ts +23 -0
- package/src/hooks/useToolApproval.test.ts +140 -0
- package/src/hooks/useToolApproval.ts +264 -0
- package/src/hooks/useToolScheduler.ts +432 -0
- package/src/index.ts +3 -0
- package/src/jsx.d.ts +11 -0
- package/src/lib/clipboard.ts +18 -0
- package/src/lib/logger.ts +107 -0
- package/src/lib/random.ts +5 -0
- package/src/main.tsx +13 -0
- package/src/test/mockTheme.ts +51 -0
- package/src/types/events.ts +87 -0
- package/src/types.ts +13 -0
- package/src/ui/components/ChatLayout.tsx +694 -0
- package/src/ui/components/CommandComponents.tsx +74 -0
- package/src/ui/components/DiffViewer.tsx +306 -0
- package/src/ui/components/FilterInput.test.ts +69 -0
- package/src/ui/components/FilterInput.tsx +62 -0
- package/src/ui/components/HeaderBar.tsx +137 -0
- package/src/ui/components/RadioSelect.test.ts +140 -0
- package/src/ui/components/RadioSelect.tsx +88 -0
- package/src/ui/components/SelectableList.test.ts +83 -0
- package/src/ui/components/SelectableList.tsx +35 -0
- package/src/ui/components/StatusBar.tsx +45 -0
- package/src/ui/components/SuggestionPanel.tsx +102 -0
- package/src/ui/components/messages/ModelMessage.tsx +14 -0
- package/src/ui/components/messages/SystemMessage.tsx +29 -0
- package/src/ui/components/messages/ThinkingMessage.tsx +14 -0
- package/src/ui/components/messages/UserMessage.tsx +26 -0
- package/src/ui/components/messages/index.ts +15 -0
- package/src/ui/components/messages/renderMessage.test.ts +49 -0
- package/src/ui/components/messages/renderMessage.tsx +43 -0
- package/src/ui/components/messages/types.test.ts +24 -0
- package/src/ui/components/messages/types.ts +36 -0
- package/src/ui/modals/AuthModal.tsx +106 -0
- package/src/ui/modals/ModalShell.tsx +60 -0
- package/src/ui/modals/SearchSelectModal.tsx +236 -0
- package/src/ui/modals/ThemeModal.tsx +204 -0
- package/src/ui/modals/ToolApprovalModal.test.ts +206 -0
- package/src/ui/modals/ToolApprovalModal.tsx +282 -0
- package/src/ui/modals/index.ts +20 -0
- package/src/ui/modals/modals.test.ts +26 -0
- package/src/ui/modals/types.ts +19 -0
- package/src/uicontext/Command.tsx +102 -0
- package/src/uicontext/Dialog.tsx +65 -0
- package/src/uicontext/index.ts +2 -0
- package/themes/ansi-light.json +59 -0
- package/themes/ansi.json +59 -0
- package/themes/atom-one-dark.json +59 -0
- package/themes/ayu-light.json +59 -0
- package/themes/ayu.json +59 -0
- package/themes/default-light.json +59 -0
- package/themes/default.json +59 -0
- package/themes/dracula.json +59 -0
- package/themes/github-dark.json +59 -0
- package/themes/github-light.json +59 -0
- package/themes/googlecode.json +59 -0
- package/themes/green-screen.json +59 -0
- package/themes/no-color.json +59 -0
- package/themes/shades-of-purple.json +59 -0
- package/themes/xcode.json +59 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# UI Design for nui
|
|
2
|
+
|
|
3
|
+
## Current UI Design
|
|
4
|
+
|
|
5
|
+
The nui project implements a terminal-based chat interface using OpenTUI and React. The UI is structured into four primary regions that create a cohesive chat experience in the terminal environment.
|
|
6
|
+
|
|
7
|
+
### Layout Architecture
|
|
8
|
+
|
|
9
|
+
The UI consists of a vertical layout with four distinct bands:
|
|
10
|
+
|
|
11
|
+
1. **Header** (1-5 lines): Displays application title and branding
|
|
12
|
+
2. **Scrollback** (flexible height): Main conversation area with message history
|
|
13
|
+
3. **Input** (1-10 lines): Multi-line text input area with submission controls
|
|
14
|
+
4. **Status Bar** (1-3 lines): Shows stream state, word count, and scroll indicators
|
|
15
|
+
|
|
16
|
+
### Core Components
|
|
17
|
+
|
|
18
|
+
#### ChatLayout
|
|
19
|
+
|
|
20
|
+
The main layout orchestrates all UI components and manages:
|
|
21
|
+
|
|
22
|
+
- Overall component arrangement
|
|
23
|
+
- Input height constraints (1-10 lines with automatic adjustment)
|
|
24
|
+
- Theme application and color management
|
|
25
|
+
- Mouse interaction handling for clipboard selection
|
|
26
|
+
|
|
27
|
+
#### Message Rendering System
|
|
28
|
+
|
|
29
|
+
Messages are rendered by role-specific components:
|
|
30
|
+
|
|
31
|
+
- **UserMessage**: Left border (┃) with user color scheme
|
|
32
|
+
- **ModelMessage**: Standard appearance with responder color
|
|
33
|
+
- **SystemMessage**: Left border (│) with distinct background and text color
|
|
34
|
+
- **ThinkingMessage**: Special formatting for AI reasoning content
|
|
35
|
+
|
|
36
|
+
Each message component receives:
|
|
37
|
+
|
|
38
|
+
- Unique ID
|
|
39
|
+
- Text content
|
|
40
|
+
- Theme definition for colors and styling
|
|
41
|
+
- Consistent spacing and border treatment
|
|
42
|
+
|
|
43
|
+
#### Tool Display
|
|
44
|
+
|
|
45
|
+
Tool calls have dedicated rendering with:
|
|
46
|
+
|
|
47
|
+
- Status indicators (○, ◎, [OK], , ?, -)
|
|
48
|
+
- Parameter formatting with line truncation for long values
|
|
49
|
+
- Output display with scrollable regions for large results
|
|
50
|
+
- Border styling based on execution status (success, error, warning)
|
|
51
|
+
- Streaming indicators for active tool calls
|
|
52
|
+
|
|
53
|
+
#### Input Management
|
|
54
|
+
|
|
55
|
+
The input component provides:
|
|
56
|
+
|
|
57
|
+
- Multi-line text input (1-10 lines)
|
|
58
|
+
- Custom key bindings (Enter to submit, Shift+Enter/Option+Enter for newline)
|
|
59
|
+
- Placeholder text with theme-appropriate styling
|
|
60
|
+
- Automatic height adjustment as content grows
|
|
61
|
+
|
|
62
|
+
#### Autocomplete/Suggestion System
|
|
63
|
+
|
|
64
|
+
The suggestion panel displays:
|
|
65
|
+
|
|
66
|
+
- Command and file path completions
|
|
67
|
+
- Paging for large suggestion sets
|
|
68
|
+
- Selection indicators with highlighting
|
|
69
|
+
- Context-aware filtering based on current input
|
|
70
|
+
|
|
71
|
+
### Visual Design Language
|
|
72
|
+
|
|
73
|
+
#### Color System
|
|
74
|
+
|
|
75
|
+
All colors are defined in JSON themes with the following structure:
|
|
76
|
+
|
|
77
|
+
- Background and panel colors
|
|
78
|
+
- Text colors by role (user,Responder, system, thinking, tool)
|
|
79
|
+
- Input colors (background, text, placeholder, border)
|
|
80
|
+
- Status colors for different states
|
|
81
|
+
- Accent colors for visual emphasis
|
|
82
|
+
- Selection colors for highlighted items
|
|
83
|
+
|
|
84
|
+
#### Border Styles
|
|
85
|
+
|
|
86
|
+
Different message types use distinct border characters:
|
|
87
|
+
|
|
88
|
+
- User messages: Custom vertical borders (┃, ╹, ╻)
|
|
89
|
+
- System messages: Standard vertical borders (│, ╵, ╷)
|
|
90
|
+
- Tool blocks: Rounded or single borders based on type
|
|
91
|
+
|
|
92
|
+
### Interaction Patterns
|
|
93
|
+
|
|
94
|
+
#### Keyboard Navigation
|
|
95
|
+
|
|
96
|
+
- **Enter**: Submit input
|
|
97
|
+
- **Shift+Enter/Option+Enter**: Insert newline
|
|
98
|
+
- **Escape**: Cancel streaming or clear input
|
|
99
|
+
- **Arrow keys**: Navigation through suggestions and scrollback
|
|
100
|
+
- **Tab**: Accept suggestion
|
|
101
|
+
|
|
102
|
+
#### Visual Feedback
|
|
103
|
+
|
|
104
|
+
- Streaming content appears incrementally
|
|
105
|
+
- Status indicators show current operation state
|
|
106
|
+
- Tool execution progress with status changes
|
|
107
|
+
- Selection highlighting in suggestion panels
|
|
108
|
+
|
|
109
|
+
### Context Management
|
|
110
|
+
|
|
111
|
+
#### Dialog System
|
|
112
|
+
|
|
113
|
+
Modal dialogs use a stack-based approach:
|
|
114
|
+
|
|
115
|
+
- Single dialog at a time
|
|
116
|
+
- Escape key dismissal
|
|
117
|
+
- Context providers for dialog state
|
|
118
|
+
- Command triggering from dialogs
|
|
119
|
+
|
|
120
|
+
#### Command System
|
|
121
|
+
|
|
122
|
+
Commands are registered components that:
|
|
123
|
+
|
|
124
|
+
- Connect to the dialog system
|
|
125
|
+
- Provide consistent execution patterns
|
|
126
|
+
- Support async operations
|
|
127
|
+
- Handle configuration changes
|
|
128
|
+
|
|
129
|
+
## Future UI Design Standards
|
|
130
|
+
|
|
131
|
+
While the current implementation provides a solid foundation, the following standards should guide UI evolution:
|
|
132
|
+
|
|
133
|
+
### Component Design Principles
|
|
134
|
+
|
|
135
|
+
1. **Minimalism Over Density**
|
|
136
|
+
- Terminal UI benefits from clear separation
|
|
137
|
+
- Use whitespace deliberately to guide attention
|
|
138
|
+
- Avoid visual noise and unnecessary embellishments
|
|
139
|
+
- Allow content to breathe with appropriate padding
|
|
140
|
+
|
|
141
|
+
2. **Terminal-Appropriate Interactions**
|
|
142
|
+
- Leverage terminal strengths: text precision, keyboard shortcuts
|
|
143
|
+
- Avoid emulating GUI patterns that don't translate well
|
|
144
|
+
- Design for efficient, keyboard-first navigation
|
|
145
|
+
- Consider accessibility with contrast and readability
|
|
146
|
+
|
|
147
|
+
3. **Responsive to Content**
|
|
148
|
+
- UI should adapt to content rather than forcing content into rigid containers
|
|
149
|
+
- Components should expand/contract based on their content's needs
|
|
150
|
+
- Prioritize content visibility over chrome
|
|
151
|
+
- Implement content-aware resizing that respects terminal constraints
|
|
152
|
+
|
|
153
|
+
4. **Progressive Enhancement**
|
|
154
|
+
- Basic structure must be functional without advanced features
|
|
155
|
+
- Advanced interactions should enhance, not replace core functionality
|
|
156
|
+
- Fallback options for environments with limited capabilities
|
|
157
|
+
- Graceful degradation in constrained environments
|
|
158
|
+
|
|
159
|
+
5. **Size-Aware Components**
|
|
160
|
+
- Components should be aware of available space
|
|
161
|
+
- Implement adaptive layouts that respond to size changes
|
|
162
|
+
- Provide alternative representations when space is limited
|
|
163
|
+
- Ensure core functionality remains accessible at any reasonable terminal size
|
|
164
|
+
|
|
165
|
+
### Visual Standards
|
|
166
|
+
|
|
167
|
+
#### Color Usage
|
|
168
|
+
|
|
169
|
+
1. **Semantic Color Mapping**
|
|
170
|
+
- Use colors consistently for semantic meaning
|
|
171
|
+
- Status colors indicate state, not aesthetics
|
|
172
|
+
- Maintain theme consistency across components
|
|
173
|
+
|
|
174
|
+
2. **Contrast and Readability**
|
|
175
|
+
- Ensure sufficient contrast for all text elements
|
|
176
|
+
- Test readability across all supported themes
|
|
177
|
+
- Prioritize legibility over creative color choices
|
|
178
|
+
|
|
179
|
+
#### Layout Standards
|
|
180
|
+
|
|
181
|
+
1. **Hierarchical Grouping**
|
|
182
|
+
- Use visual grouping to indicate relationships
|
|
183
|
+
- Maintain consistent spacing patterns
|
|
184
|
+
- Implement clear content hierarchy
|
|
185
|
+
- Use whitespace strategically to improve scannability
|
|
186
|
+
|
|
187
|
+
2. **Responsive Dimensions**
|
|
188
|
+
- Design for various terminal sizes (minimum 80x24 characters)
|
|
189
|
+
- Implement minimum/maximum constraints for components
|
|
190
|
+
- Prioritize content over UI chrome when space is limited
|
|
191
|
+
- Provide alternative content layouts as size changes
|
|
192
|
+
- Maintain component relationships during resize operations
|
|
193
|
+
|
|
194
|
+
3. **Consistent Spacing System**
|
|
195
|
+
- Use standardized spacing units (characters/lines)
|
|
196
|
+
- Apply consistent padding and margins across components
|
|
197
|
+
- Define spacing scale similar to CSS frameworks
|
|
198
|
+
- Ensure spacing is proportional to terminal size
|
|
199
|
+
|
|
200
|
+
### Interaction Standards
|
|
201
|
+
|
|
202
|
+
#### Input Patterns
|
|
203
|
+
|
|
204
|
+
1. **Predictable Behavior**
|
|
205
|
+
- Standard text operations should work as expected
|
|
206
|
+
- Provide visible feedback for all interactions
|
|
207
|
+
- Use familiar keyboard shortcuts where possible
|
|
208
|
+
|
|
209
|
+
2. **Error Prevention**
|
|
210
|
+
- Prevent invalid input where possible
|
|
211
|
+
- Provide clear validation feedback
|
|
212
|
+
- Offer recovery paths from error states
|
|
213
|
+
|
|
214
|
+
#### State Communication
|
|
215
|
+
|
|
216
|
+
1. **Clear Status Indicators**
|
|
217
|
+
- Always communicate current state
|
|
218
|
+
- Use universally understood symbols
|
|
219
|
+
- Provide context for status changes
|
|
220
|
+
|
|
221
|
+
2. **Progressive Disclosure**
|
|
222
|
+
- Show relevant information first
|
|
223
|
+
- Allow access to details when needed
|
|
224
|
+
- Use progressive disclosure to manage complexity
|
|
225
|
+
|
|
226
|
+
### Architectural Patterns
|
|
227
|
+
|
|
228
|
+
#### Component Structure
|
|
229
|
+
|
|
230
|
+
1. **Single Responsibility**
|
|
231
|
+
- Each component should have one clear purpose
|
|
232
|
+
- Avoid components that try to do too much
|
|
233
|
+
- Keep component interfaces minimal and focused
|
|
234
|
+
|
|
235
|
+
2. **Composition Over Inheritance**
|
|
236
|
+
- Build complex UI through composition
|
|
237
|
+
- Use composition to extend functionality
|
|
238
|
+
- Avoid deep inheritance hierarchies
|
|
239
|
+
|
|
240
|
+
#### State Management
|
|
241
|
+
|
|
242
|
+
1. **Isolated State**
|
|
243
|
+
- State should be as close to its usage as possible
|
|
244
|
+
- Avoid global state except for truly global concerns
|
|
245
|
+
- Use clear state propagation patterns
|
|
246
|
+
|
|
247
|
+
2. **Immutable Updates**
|
|
248
|
+
- All state updates should be immutable
|
|
249
|
+
- Use functional update patterns
|
|
250
|
+
- Minimize state mutation to prevent subtle bugs
|
|
251
|
+
|
|
252
|
+
### Responsive Design Standards
|
|
253
|
+
|
|
254
|
+
#### Terminal Size Adaptability
|
|
255
|
+
|
|
256
|
+
1. **Minimum Terminal Size Support**
|
|
257
|
+
- Ensure core functionality works at 80x24 characters minimum
|
|
258
|
+
- Provide graceful degradation at smaller sizes
|
|
259
|
+
- Implement strategic content collapsing when necessary
|
|
260
|
+
- Maintain readability as the primary concern
|
|
261
|
+
|
|
262
|
+
2. **Dynamic Component Scaling**
|
|
263
|
+
- Layout should adapt both horizontally and vertically
|
|
264
|
+
- Implement fluid or elastic sizing where appropriate
|
|
265
|
+
- Use flexible containers that redistribute content
|
|
266
|
+
- Preserve component relationships during resize operations
|
|
267
|
+
|
|
268
|
+
3. **Content Prioritization**
|
|
269
|
+
- Critical content should remain visible at all sizes
|
|
270
|
+
- Non-essential UI elements can be hidden at smaller sizes
|
|
271
|
+
- Implement progressive disclosure based on available space
|
|
272
|
+
- Maintain access to core functionality regardless of terminal size
|
|
273
|
+
|
|
274
|
+
#### Boundary Conditions
|
|
275
|
+
|
|
276
|
+
1. **Size Thresholds**
|
|
277
|
+
- Define clear breakpoints for UI reorganization
|
|
278
|
+
- Smooth transitions between size categories
|
|
279
|
+
- Component behavior should be predictable at boundary conditions
|
|
280
|
+
- No content should become permanently inaccessible
|
|
281
|
+
|
|
282
|
+
2. **Aspect Ratio Considerations**
|
|
283
|
+
- Account for both tall and wide terminal configurations
|
|
284
|
+
- Optimize for common aspect ratios while supporting extremes
|
|
285
|
+
- Ensure UI remains usable in non-standard proportions
|
|
286
|
+
- Test with both portrait and landscape terminal layouts
|
|
287
|
+
|
|
288
|
+
### Performance Standards
|
|
289
|
+
|
|
290
|
+
#### Rendering Efficiency
|
|
291
|
+
|
|
292
|
+
1. **Minimize Re-renders**
|
|
293
|
+
- Optimize components to prevent unnecessary re-renders
|
|
294
|
+
- Use memoization strategically
|
|
295
|
+
- Profile and optimize critical paths
|
|
296
|
+
|
|
297
|
+
2. **Progressive Loading**
|
|
298
|
+
- Load and render content progressively
|
|
299
|
+
- Provide immediate feedback for user actions
|
|
300
|
+
- Use placeholders for loading states
|
|
301
|
+
|
|
302
|
+
3. **Resize Performance**
|
|
303
|
+
- Optimize for smooth terminal resize operations
|
|
304
|
+
- Implement debouncing for resize event handling
|
|
305
|
+
- Avoid expensive recalculations during intermediate resize states
|
|
306
|
+
- Maintain responsiveness during size transitions
|
|
307
|
+
|
|
308
|
+
### Accessibility Standards
|
|
309
|
+
|
|
310
|
+
1. **Keyboard Navigation**
|
|
311
|
+
- Ensure full functionality is available via keyboard
|
|
312
|
+
- Provide clear focus indicators
|
|
313
|
+
- Implement logical tab order
|
|
314
|
+
|
|
315
|
+
2. **Screen Reader Compatibility**
|
|
316
|
+
- Use semantic HTML elements where applicable
|
|
317
|
+
- Provide meaningful labeling for interactive elements
|
|
318
|
+
- Test with screen readers when possible
|
|
319
|
+
|
|
320
|
+
### Testing Standards
|
|
321
|
+
|
|
322
|
+
1. **Visual Testing**
|
|
323
|
+
- Implement visual regression tests for UI components
|
|
324
|
+
- Test across different terminal sizes
|
|
325
|
+
- Verify theme consistency
|
|
326
|
+
|
|
327
|
+
2. **Interaction Testing**
|
|
328
|
+
- Test all user interaction paths
|
|
329
|
+
- Verify keyboard navigation
|
|
330
|
+
- Test component state transitions
|
|
331
|
+
|
|
332
|
+
## Implementation Guidelines
|
|
333
|
+
|
|
334
|
+
### Adding New Components
|
|
335
|
+
|
|
336
|
+
1. Follow the established component structure:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
export function ComponentName(props: ComponentProps): JSX.Element {
|
|
340
|
+
// Implementation
|
|
341
|
+
}
|
|
342
|
+
ComponentName.displayName = 'ComponentName';
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
2. Use the ThemeDefinition prop for all styling:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
const Component = ({ theme, ...props }: ComponentProps) => {
|
|
349
|
+
return (
|
|
350
|
+
<box style={{ color: theme.colors.text.primary }}>
|
|
351
|
+
{/* content */}
|
|
352
|
+
</box>
|
|
353
|
+
);
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
3. Implement keyboard navigation with useKeyboard when needed
|
|
358
|
+
|
|
359
|
+
4. Add responsive behavior for new components:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const Component = ({ theme, isSmall, ...props }: ComponentProps) => {
|
|
363
|
+
// Use isSmall flag to adapt rendering for terminals below size threshold
|
|
364
|
+
if (isSmall) {
|
|
365
|
+
return <SimplifiedLayout />;
|
|
366
|
+
}
|
|
367
|
+
return <StandardLayout />;
|
|
368
|
+
};
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
5. Follow minimum size requirements:
|
|
372
|
+
- Ensure critical content remains visible at 80x24 characters
|
|
373
|
+
- Test components in both narrow and tall terminal configurations
|
|
374
|
+
- Implement graceful degradation when space is limited
|
|
375
|
+
|
|
376
|
+
### Theme Development
|
|
377
|
+
|
|
378
|
+
1. Include all required color properties
|
|
379
|
+
2. Ensure sufficient contrast ratios
|
|
380
|
+
3. Test with all components for compatibility
|
|
381
|
+
4. Provide both light and dark variants when appropriate
|
|
382
|
+
5. Consider how colors might need to adapt for different terminal sizes:
|
|
383
|
+
- Ensure critical elements remain distinguishable in cramped layouts
|
|
384
|
+
- Maintain readability across all supported terminal dimensions
|
|
385
|
+
- Test at both minimum and maximum expected terminal sizes
|
|
386
|
+
|
|
387
|
+
### State Management
|
|
388
|
+
|
|
389
|
+
1. Keep component state local when possible
|
|
390
|
+
2. Use centralized state only when necessary
|
|
391
|
+
3. Follow immutable update patterns
|
|
392
|
+
4. Provide clear interfaces between components
|
|
393
|
+
|
|
394
|
+
5. Implement size-aware state management:
|
|
395
|
+
```typescript
|
|
396
|
+
const [terminalSize, setTerminalSize] = useState({ width: 80, height: 24 });
|
|
397
|
+
const isAboveMinimum = terminalSize.width >= 80 && terminalSize.height >= 24;
|
|
398
|
+
```
|
|
399
|
+
6. Consider terminal resize in state effects
|
|
400
|
+
7. Store size-dependent preferences that persist across resize operations
|
|
401
|
+
|
|
402
|
+
### Responsive Implementation Practices
|
|
403
|
+
|
|
404
|
+
1. **Size Detection**
|
|
405
|
+
- Implement reliable terminal size detection
|
|
406
|
+
- Set up event listeners for resize operations
|
|
407
|
+
- Debounce resize events to prevent excessive re-renders
|
|
408
|
+
|
|
409
|
+
2. **Layout Adaptation**
|
|
410
|
+
- Use flexible boxes and containers with constraints
|
|
411
|
+
- Implement content priorities for different sizes
|
|
412
|
+
- Design components to be "size-aware" and adapt accordingly
|
|
413
|
+
|
|
414
|
+
3. **Content Strategies**
|
|
415
|
+
- Implement summarization for large content in small terminals
|
|
416
|
+
- Use paging or scrolling for content that exceeds available space
|
|
417
|
+
- Provide alternative views for complex components when space is limited
|
|
418
|
+
|
|
419
|
+
4. **Testing Considerations**
|
|
420
|
+
- Test components at minimum supported size (80x24)
|
|
421
|
+
- Test with common terminal sizes (120x40, 160x50, etc.)
|
|
422
|
+
- Verify content remains readable and accessible at extreme ratios
|
|
423
|
+
- Check smooth transitions during resize operations
|
|
424
|
+
|
|
425
|
+
These standards should guide UI development decisions as nui evolves, ensuring a consistent, efficient, and pleasant user experience in the terminal environment.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const eslintJs = require('@eslint/js');
|
|
2
|
+
const globals = require('globals');
|
|
3
|
+
const tsParser = require('@typescript-eslint/parser');
|
|
4
|
+
const tsPlugin = require('@typescript-eslint/eslint-plugin');
|
|
5
|
+
const eslintComments = require('eslint-plugin-eslint-comments');
|
|
6
|
+
const sonarjs = require('eslint-plugin-sonarjs');
|
|
7
|
+
const reactPlugin = require('eslint-plugin-react');
|
|
8
|
+
const reactHooks = require('eslint-plugin-react-hooks');
|
|
9
|
+
const vitest = require('@vitest/eslint-plugin');
|
|
10
|
+
|
|
11
|
+
const tsTypeCheckedRules = tsPlugin.configs['recommended-type-checked'].rules;
|
|
12
|
+
const tsStylisticRules = tsPlugin.configs['stylistic-type-checked'].rules;
|
|
13
|
+
|
|
14
|
+
module.exports = [
|
|
15
|
+
{
|
|
16
|
+
ignores: ['dist', 'node_modules'],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
files: ['**/*.{ts,tsx}'],
|
|
20
|
+
languageOptions: {
|
|
21
|
+
parser: tsParser,
|
|
22
|
+
parserOptions: {
|
|
23
|
+
project: './tsconfig.json',
|
|
24
|
+
tsconfigRootDir: __dirname,
|
|
25
|
+
sourceType: 'module',
|
|
26
|
+
ecmaVersion: 'latest',
|
|
27
|
+
ecmaFeatures: {
|
|
28
|
+
jsx: true,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
globals: { ...globals.node },
|
|
32
|
+
},
|
|
33
|
+
plugins: {
|
|
34
|
+
'@typescript-eslint': tsPlugin,
|
|
35
|
+
'eslint-comments': eslintComments,
|
|
36
|
+
sonarjs,
|
|
37
|
+
react: reactPlugin,
|
|
38
|
+
'react-hooks': reactHooks,
|
|
39
|
+
},
|
|
40
|
+
settings: {
|
|
41
|
+
react: {
|
|
42
|
+
version: 'detect',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
rules: {
|
|
46
|
+
...eslintJs.configs.recommended.rules,
|
|
47
|
+
...tsTypeCheckedRules,
|
|
48
|
+
...tsStylisticRules,
|
|
49
|
+
...eslintComments.configs.recommended.rules,
|
|
50
|
+
...sonarjs.configs.recommended.rules,
|
|
51
|
+
|
|
52
|
+
// TypeScript strict rules
|
|
53
|
+
'@typescript-eslint/ban-ts-comment': [
|
|
54
|
+
'error',
|
|
55
|
+
{
|
|
56
|
+
'ts-expect-error': true,
|
|
57
|
+
'ts-ignore': true,
|
|
58
|
+
'ts-nocheck': true,
|
|
59
|
+
'ts-check': false,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
63
|
+
'error',
|
|
64
|
+
{ prefer: 'type-imports' },
|
|
65
|
+
],
|
|
66
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
67
|
+
'@typescript-eslint/no-floating-promises': 'error',
|
|
68
|
+
'@typescript-eslint/no-misused-promises': 'error',
|
|
69
|
+
|
|
70
|
+
// Type-checked rules to catch LLM sloppiness
|
|
71
|
+
'@typescript-eslint/no-unnecessary-condition': 'error',
|
|
72
|
+
'@typescript-eslint/no-redundant-type-constituents': 'error',
|
|
73
|
+
'@typescript-eslint/strict-boolean-expressions': [
|
|
74
|
+
'error',
|
|
75
|
+
{
|
|
76
|
+
allowString: true,
|
|
77
|
+
allowNumber: false,
|
|
78
|
+
allowNullableObject: true,
|
|
79
|
+
allowNullableBoolean: false,
|
|
80
|
+
allowNullableString: true,
|
|
81
|
+
allowNullableNumber: false,
|
|
82
|
+
allowAny: false,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
'@typescript-eslint/switch-exhaustiveness-check': 'error',
|
|
86
|
+
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
|
87
|
+
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
|
88
|
+
'@typescript-eslint/prefer-optional-chain': 'error',
|
|
89
|
+
'@typescript-eslint/no-useless-constructor': 'error',
|
|
90
|
+
'@typescript-eslint/no-empty-function': 'error',
|
|
91
|
+
|
|
92
|
+
// General code quality
|
|
93
|
+
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
|
94
|
+
curly: ['error', 'multi-line'],
|
|
95
|
+
'no-var': 'error',
|
|
96
|
+
'prefer-const': ['error', { destructuring: 'all' }],
|
|
97
|
+
'object-shorthand': 'error',
|
|
98
|
+
'prefer-arrow-callback': 'error',
|
|
99
|
+
'no-else-return': 'error',
|
|
100
|
+
'no-lonely-if': 'error',
|
|
101
|
+
'no-unneeded-ternary': 'error',
|
|
102
|
+
'no-console': 'warn',
|
|
103
|
+
|
|
104
|
+
// Disable sonarjs/function-return-type for React components - returning ReactNode is valid
|
|
105
|
+
'sonarjs/function-return-type': 'off',
|
|
106
|
+
|
|
107
|
+
// Complexity limits
|
|
108
|
+
complexity: ['warn', 15],
|
|
109
|
+
'max-lines': [
|
|
110
|
+
'warn',
|
|
111
|
+
{ max: 800, skipBlankLines: false, skipComments: false },
|
|
112
|
+
],
|
|
113
|
+
'max-lines-per-function': [
|
|
114
|
+
'warn',
|
|
115
|
+
{ max: 80, skipBlankLines: false, skipComments: false },
|
|
116
|
+
],
|
|
117
|
+
'sonarjs/cognitive-complexity': ['error', 30],
|
|
118
|
+
|
|
119
|
+
// ESLint comments
|
|
120
|
+
'eslint-comments/no-use': 'error',
|
|
121
|
+
|
|
122
|
+
// React rules
|
|
123
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
124
|
+
'react-hooks/exhaustive-deps': 'error',
|
|
125
|
+
'react/jsx-no-bind': [
|
|
126
|
+
'warn',
|
|
127
|
+
{
|
|
128
|
+
ignoreDOMComponents: false,
|
|
129
|
+
ignoreRefs: true,
|
|
130
|
+
allowArrowFunctions: false,
|
|
131
|
+
allowFunctions: false,
|
|
132
|
+
allowBind: false,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
'react/jsx-no-constructed-context-values': 'error',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
// Vitest test file rules - prevent mock theater and shallow tests
|
|
139
|
+
{
|
|
140
|
+
files: [
|
|
141
|
+
'**/*.test.{ts,tsx}',
|
|
142
|
+
'**/*.spec.{ts,tsx}',
|
|
143
|
+
'**/__tests__/**/*.{ts,tsx}',
|
|
144
|
+
],
|
|
145
|
+
plugins: {
|
|
146
|
+
vitest,
|
|
147
|
+
},
|
|
148
|
+
rules: {
|
|
149
|
+
...vitest.configs.recommended.rules,
|
|
150
|
+
|
|
151
|
+
// Prevent tests without real assertions
|
|
152
|
+
'vitest/expect-expect': 'error',
|
|
153
|
+
'vitest/no-standalone-expect': 'error',
|
|
154
|
+
'vitest/valid-expect': 'error',
|
|
155
|
+
|
|
156
|
+
// Prevent conditional/unreliable tests
|
|
157
|
+
'vitest/no-conditional-expect': 'error',
|
|
158
|
+
'vitest/no-conditional-in-test': 'error',
|
|
159
|
+
'vitest/no-conditional-tests': 'error',
|
|
160
|
+
|
|
161
|
+
// Require meaningful error checking
|
|
162
|
+
'vitest/require-to-throw-message': 'error',
|
|
163
|
+
|
|
164
|
+
// Prevent test pollution
|
|
165
|
+
'vitest/no-focused-tests': 'error',
|
|
166
|
+
'vitest/no-disabled-tests': 'warn',
|
|
167
|
+
'vitest/no-commented-out-tests': 'warn',
|
|
168
|
+
'vitest/no-identical-title': 'error',
|
|
169
|
+
'vitest/no-duplicate-hooks': 'error',
|
|
170
|
+
|
|
171
|
+
// Force stricter assertions
|
|
172
|
+
'vitest/prefer-strict-equal': 'error',
|
|
173
|
+
'vitest/prefer-to-be': 'error',
|
|
174
|
+
'vitest/prefer-to-have-length': 'error',
|
|
175
|
+
'vitest/prefer-comparison-matcher': 'error',
|
|
176
|
+
'vitest/prefer-equality-matcher': 'error',
|
|
177
|
+
|
|
178
|
+
// Prevent dynamic snapshots that always pass
|
|
179
|
+
'vitest/no-interpolation-in-snapshots': 'error',
|
|
180
|
+
|
|
181
|
+
// Structural rules
|
|
182
|
+
'vitest/max-nested-describe': ['error', { max: 3 }],
|
|
183
|
+
'vitest/require-top-level-describe': 'error',
|
|
184
|
+
'vitest/prefer-hooks-on-top': 'error',
|
|
185
|
+
|
|
186
|
+
// Discourage excessive mocking
|
|
187
|
+
'vitest/no-mocks-import': 'warn',
|
|
188
|
+
|
|
189
|
+
// Relax some rules that conflict with test patterns
|
|
190
|
+
'@typescript-eslint/no-empty-function': 'off',
|
|
191
|
+
'max-lines-per-function': 'off',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
];
|
package/images/nui.png
ADDED
|
Binary file
|
package/llxprt.png
ADDED
|
Binary file
|