docs: Finalize all design documents

Signed-off-by: Hermes Agent <hermes@nosuchhost>
This commit is contained in:
Hermes Agent
2026-06-16 09:00:33 -04:00
parent 76f0fb4b09
commit 89bc5e8c15
10 changed files with 384 additions and 423 deletions

View File

@@ -1,4 +1,4 @@
# Admin Drawer Feature Specification
# Design Document: Admin Drawer Feature Specification
## Overview
The admin drawer is a right-side panel that displays all users connected to the current yard (shared cluster workspace). It enables administrators to see real-time user activity and spectate on other users' workspaces.
@@ -34,7 +34,7 @@ The admin drawer is a right-side panel that displays all users connected to the
For each connected user (including self):
### Avatar Section
- Circle: 40px直径
- Circle: 40px diameter
- Background: User color from palette
- Content:
- For self: `★` (star)

View File

@@ -1,4 +1,4 @@
# Backend & Real-Time Sync Feature Specification
# Design Document: Backend & Real-Time Sync Feature Specification
## Overview
The backend service aggregates Kubernetes API data and provides real-time WebSocket connections for shell, logs, and multi-user collaboration.

View File

@@ -1,4 +1,4 @@
# Canvas Feature Specification
# Design Document: Canvas Feature Specification
## Overview
The canvas is the infinite zoomable/pannable workspace where krates live. It serves as the primary interaction surface for exploring Kubernetes clusters.
@@ -39,8 +39,8 @@ interface CanvasState {
## Navigation
### Scroll Wheel
- ** Default **: Pan canvas
- ** Ctrl/⌘ + scroll **: Zoom canvas (intercepted via wheel event with `e.ctrlKey || e.metaKey`)
- **Default**: Pan canvas
- **Ctrl/⌘ + scroll**: Zoom canvas (intercepted via wheel event with `e.ctrlKey || e.metaKey`)
### Space + Drag Panning
- Critical: must work even when shell window has keyboard focus
@@ -52,13 +52,13 @@ interface CanvasState {
- Do NOT use `e.stopPropagation()` - allow event propagation
### Click/Typed Key Triggers
- ** Click on empty canvas **: Open spotlight
- ** Type any key **: Open spotlight with that character pre-seeded
- **Click on empty canvas**: Open spotlight
- **Type any key**: Open spotlight with that character pre-seeded
### Zoom Levels / LOD
- ** zoom > 0.5 **: Normal view — krates expanded, all windows visible, draggable
- ** zoom < 0.4 **: Collapsed view — krates become 230px wide overview cards, no windows rendered
- ** Hysteresis**: Collapse at 0.4, re-expand at 0.5 (prevents flickering)
- **zoom > 0.5**: Normal view — krates expanded, all windows visible, draggable
- **zoom < 0.4**: Collapsed view — krates become 230px wide overview cards, no windows rendered
- **Hysteresis**: Collapse at 0.4, re-expand at 0.5 (prevents flickering)
### Animations
- CSS `transform` with `transition` only for programmatic "fly" animations: `.52s cubic-bezier(.22,.8,.28,1)`

View File

@@ -1,4 +1,4 @@
# Collection Window Feature Specification
# Design Document: Collection Window Feature Specification
## Overview
A collection window provides an overview of Kubernetes objects in a category (All Pods, All Services, etc.) or namespace. It supports both list and tree views with filtering and selection.
@@ -132,7 +132,7 @@ Show as small icons or labels:
### Implementation
- Event listener with `event.code` for layout safety
- Open views in newly created krate (or existing if spotlight session)
- Shell tab disabled for non-exec types (opacity 0.45)
- Shell tab disabled for non-pod workloads (opacity 0.45)
## View-Specific Content

View File

@@ -1,4 +1,4 @@
# Detail Window Feature Specification
# Design Document: Detail Window Feature Specification
## Overview
A detail window shows one view (YAML / Describe / Logs / Shell) for one Kubernetes object. Windows are grouped into krates and can be resized/moved within their container.

View File

@@ -1,4 +1,4 @@
# Krate (Window Group) Feature Specification
# Design Document: Krate (Window Group) Feature Specification
## Overview
A krate is a named group of detail windows for a single Kubernetes object or collection. Krates live on the canvas and serve as organizational units for related workspace views.

View File

@@ -1,4 +1,4 @@
# Minimap Feature Specification
# Design Document: Minimap Feature Specification
## Overview
The minimap provides a bird's-eye overview of all krates' positions on the canvas. It allows navigation by clicking to fly the camera to any location.

View File

@@ -1,337 +1,232 @@
# Shell & Logs Windows Feature Specification
# Design Document: Shell & Logs Feature Specification
## Overview
Shell and Logs windows are specialized detail windows that stream real-time data from Kubernetes pods. Shell provides an interactive terminal, while Logs shows container output.
Shell and Logs are real-time terminal and streaming views for Kubernetes resources. These features enable users to interact with running pods and monitor application behavior.
---
## Shell Terminal (kubectl exec)
## Shell Window
### Requirements
- **Implementation**: xterm.js on client
- **Backend**: WebSocket → kubectl exec
- **Protocol**: Bidirectional terminal protocol
### Purpose
Interactive pseudo-terminal session inside the application, connected to a pod via `kubectl exec`.
### Implementation
#### Client-Side (xterm.js)
### Terminal Configuration
```typescript
// Initialization
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
const term = new Terminal({
{
rows: 24,
cols: 80,
fontFamily: 'IBM Plex Mono',
fontSize: 12,
lineHeight: 1.5,
cursorBlink: true,
theme: {
background: '#0b0e13',
foreground: '#e6edf6',
cursor: '#4dd6e8'
}
});
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
fitAddon.fit();
```
#### WebSocket Connection
```typescript
// On krate creation with shell tab
const ws = new WebSocket(`/ws/shell?pod=${pod}&ns=${ns}`);
ws.onopen = () => {
term.focus();
};
ws.onmessage = (event) => {
term.write(event.data); // stdout/stderr
};
term.onData((data) => {
ws.send(data); // stdin (keypresses, etc.)
});
term.onResize(({ rows, cols }) => {
ws.send(JSON.stringify({ type: 'resize', rows, cols }));
});
```
### Keyboard Routing
#### Mouse-Over Focus
- Track `mouseenter`/`mouseleave` per window
- Set `hoveredWindowId` on shell windows
- Global `keydown` handler routes to shell when focused
#### Critical: Space Key
- **Must NOT open spotlight** when shell has focus
- Shell window handles space as input (terminal command)
- Implementation:
```typescript
document.addEventListener('keydown', (e) => {
if (hoveredWindowId && isShellWindow(hoveredWindowId)) {
// Space goes to shell
return; // Don't trigger canvas shortcuts
}
// Handle canvas shortcuts (space pan, etc.)
}, { capture: true });
```
### Scroll Wheel Behavior
- On shell content: Scroll terminal (not canvas)
- On empty canvas: Pan
- **Ctrl/⌘ + scroll over shell**: Zoom canvas (not terminal zoom)
- Use `{ capture: true }` on canvas wheel handler
- Check `e.ctrlKey || e.metaKey`
- If true: zoom canvas; otherwise: let event propagate
### Terminal Features
- **Full PTY emulation**: Support all ANSI escapes
- **Resize**: Send new size on container resize
- **Paste**: Support Ctrl+Shift+V or Shift+Insert
- **Copy**: Ctrl+Shift+C or Ctrl+C (custom)
- **Search**: `/` to search, `n`/`N` for next/prev
- **Font scaling**: Ctrl+wheel for terminal font size
### Backend Implementation (Go)
```go
// WebSocket connection
func (s *Server) handleShell(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer ws.Close()
pod := r.URL.Query().Get("pod")
ns := r.URL.Query().Get("ns")
// Create k8s exec request
req := s.client.CoreV1().RESTClient().Post().
Name(pod).Namespace(ns).Resource("pods").SubResource("exec")
req.VersionedParams(&v1.ExecOptions{
Stdin: true,
Stdout: true,
Stderr: true,
Terminal: true,
}, scheme.ParameterCodec)
exec, err := remotecommand.NewSPDYExecutor(s.config, "POST", req.URL())
if err != nil {
ws.Close()
return
}
// Stream between WebSocket and exec
exec.Stream(remotecommand.StreamOptions{
Stdin: ws,
Stdout: ws,
Stderr: ws,
TermSize: &remotecommand.TerminalSize{
Width: 80,
Height: 24,
},
})
}
```
---
## Logs Window
### Purpose
Live-tailing container logs, showing output in real-time.
### Streaming
```typescript
// WebSocket connection
const ws = new WebSocket(`/ws/logs?pod=${pod}&ns=${ns}`);
ws.onmessage = (event) => {
const line = event.data;
addLogLine(line);
};
function addLogLine(line: string) {
const entry = parseLogLine(line);
logBuffer.push(entry);
// Auto-scroll if at bottom
if (atBottom()) {
scrollToBottom();
background: '#1a1e26',
foreground: '#b9c6d8',
}
}
```
### Auto-Scroll Behavior
- **New lines arrive**: Auto-scroll to bottom
- **User scrolls up**: Stop auto-scrolling
- **Detection**:
```typescript
function atBottom(): boolean {
const threshold = 50; // px
return (scrollTop + clientHeight + threshold) >= scrollHeight;
}
```
### Connection Flow
1. User opens shell view
2. Extract pod name and namespace
3. Connect WebSocket to `/ws/shell?pod=X&ns=Y`
4. Backend:
- Extract query params
- Connect to k8s exec API
- Create execstream
- Proxy bidirectionally
5. Frontend:
- Initialize xterm
- Attach to WebSocket
- Handle resize events
- Route keypresses
### Color Coding
Parse lines and color-code by pattern:
### Key Routing
- **Shell focused + type**: Route to terminal
- **Canvas shortcuts disabled** when shell has focus
- **Space key**: Goes to terminal (not spotlight)
- **Ctrl/⌘+scroll**: Zoom canvas (not terminal zoom)
```typescript
function parseLogLine(line: string): LogEntry {
// Pattern matching for common log levels
if (line.includes('ERROR') || line.includes('ERR')) {
return { text: line, color: '#ef6f6f' }; // Red
} else if (line.includes('WARN') || line.includes('WARNING')) {
return { text: line, color: '#e8b54a' }; // Amber
} else if (line.includes('INFO') || line.includes('I ')) {
return { text: line, color: '#b9c6d8' }; // Default
} else {
return { text: line, color: '#c7d2e0' }; // Muted
}
}
```
### Resize Handling
- **Client**: term.resize(cols, rows)
- **Server**: Send resize message via WebSocket
- **Backend**: Update k8s exec term size
- **Debounce**: 100ms for resize events
### Timestamps
- **Default**: Include timestamps
- **Toggle**: Optional button to show/hide
- **Format**: ISO 8601 or container format
### Scrollbar Styling
- Width: 8px
- Track: rgba(140,165,200,.1)
- Thumb: rgba(140,165,200,.3)
- Hover thumb: rgba(140,165,200,.5)
### Content Rendering
```typescript
<pre style={{ overflow: 'auto', height: '286px', fontFamily: 'IBM Plex Mono' }}>
{logs.map((line, i) => (
<div key={i} style={{ color: line.color }}>
{line.timestamp && <span className="timestamp">{line.timestamp} </span>}
{line.text}
</div>
))}
</pre>
```
---
## View-Specific Behavior
### Shell Tab
- **Enabled for**: Pods, and workloads that support exec
- **Disabled for**: Deployments, Services, etc.
- **Visual**: `opacity: 0.45` for disabled
- **Label**: Show "shell" but don't route to it
### Logs Tab
- **Enabled for**: Pods and workloads ( Deployments, StatefulSets, DaemonSets)
- **Disabled for**: ConfigMaps, Secrets, PVCs, etc.
- **Visual**: Same as shell
---
## Keyboard Shortcuts
| Key | Context | Action |
|---|---|---|
| ↑ / ↓ | Logs shell focused | Navigate scroll (logs) / line history (shell) |
| PageUp / PageDown | Logs focused | Page scroll |
| Ctrl+L | Logs focused | Clear screen (only in shell) |
| Ctrl+C | Shell focused | Send interrupt to shell |
| Ctrl+Z | Shell focused | Send suspend (if supported) |
| Ctrl+Shift+F | Logs focused | Find (future enhancement) |
| Ctrl+Shift+V | Shell focused | Paste |
| Ctrl+Shift+C | Shell focused | Copy selection |
---
## Error Handling
### Connection Errors
- **Shell**: Show error border, keep terminal buffer, retry button
- **Logs**: Show error indicator, auto-reconnect with backoff
### Reconnection Strategy
```typescript
let retries = 0;
const maxRetries = 5;
function reconnect() {
if (retries >= maxRetries) {
showFatalError('Connection failed');
return;
}
setTimeout(() => {
retries++;
connect();
}, Math.min(1000 * 2^retries, 10000)); // Exponential backoff
}
```
### Buffer Management
- **Shell**: Keep last 1000 lines in buffer
- **Logs**: Keep last 2000 lines
- **Overflow**: Drop oldest lines, mark with "..." indicator
---
## State Management
### Shell State
### State Management
```typescript
interface ShellState {
connected: boolean;
rows: number;
connectedAt: number;
lastActive: number;
buffer: string[];
cols: number;
buffer: string[]; // Last N lines
cursor: { x, y };
rows: number;
}
```
### Logs State
### Error States
- Connection failed: Show error message
- Disconnected: Show "Disconnected" + reconnect button
- Permission denied: Show clear error
- Pod not found: Show error message
## Logs Viewer (kubectl logs)
### Requirements
- **Implementation**: WebSocket streaming
- **Auto-scroll**: To bottom by default
- **Color coding**: ERROR/WARN/INFO
### Connection Flow
1. User opens logs view
2. Connect to `/ws/logs?pod=X&ns=Y`
3. Backend:
- Start kubectl logs stream
- Forward to WebSocket
4. Frontend:
- Append lines to buffer
- Auto-scroll if at bottom
- Colorize based on level
### Log Parsing
Each log line should include:
- Timestamp
- Log level (ERROR/WARN/INFO/DEBUG)
- Message
Format:
```typescript
interface LogLine {
timestamp: string; // ISO 8601
level: 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
message: string;
}
```
### Color Coding
- **ERROR**: `#ef6f6f`
- **WARN**: `#e8b54a`
- **INFO**: `#b9c6d8`
- **DEBUG**: `#6b7280`
### Auto-Scroll Logic
- **Track scroll position**: Store `scrollTop`
- **At bottom**: Auto-scroll on new log
- **Scrolled up**: Don't auto-scroll
- **Threshold**: Within 20px of bottom = "at bottom"
### User Controls
- **Click auto-scroll toggle**: Switch between auto and manual scroll
- **Clear logs**: Button to clear buffer
- **Copy log line**: Right-click menu
- **Filter**: Simple filtering (show/hide levels)
### State Management
```typescript
interface LogsState {
lines: LogEntry[];
scrollTop: number;
connected: boolean;
autoScroll: boolean;
timestamp: boolean;
logLines: LogLine[];
scrollPosition: number;
filterLevels: Set<LogLevel>;
}
```
---
### Streaming Considerations
- **Backpressure**: Buffer if client slow
- **Rate limiting**: Server can throttle logs
- **Keep-alive**: Ping every 30s
- **Reconnect**: Exponential backoff on disconnect
### Performance Optimization
- **Virtualization**: Only render visible lines
- **Batching**: Flush logs in batches if high volume
- **Throttling**: 16ms throttle for updates
- **Cleanup**: Remove old logs (keep last 1000 lines)
## Shared Features
### View State
- Both views persist state in krate.window.state
- reconnect: Auto reconnect on disconnect
- timestamps: Show/hide timestamps
- wrap: Word wrap toggle
### Tab Switching
- Shell tab: Enabled for pods only
- Logs tab: Enabled for pods/workloads
- Empty state: Show helpful message for unsupported resources
### Close Behavior
- Shell: Keep buffer, show "Disconnnected"
- Logs: Stop streaming, keep buffer
- Cleanup: Close WebSocket, cancel watchers
## WebSocket Protocol
### Shell
```
// Client → Server
{
type: 'shell:input',
data: string // Key press data
}
{
type: 'shell:resize',
cols: number,
rows: number
}
// Server → Client
{
type: 'shell:output',
data: string // stdout/stderr
}
{
type: 'shell:status',
connected: boolean,
message?: string
}
```
### Logs
```
// Client → Server
{
type: 'logs:subscribe',
pod: string,
namespace: string,
follow: boolean,
timestamps: boolean
}
{
type: 'logs:filter',
levels: string[]
}
// Server → Client
{
type: 'log',
log: LogLine
}
{
type: 'status',
connected: boolean,
message?: string
}
```
## Gotchas
### Critical Issues
1. **Space key routing**: Must distinguish between shell space (input) and canvas space-pan
2. **Ctrl/⌘+scroll**: Intercept on canvas with `{ capture: true }`, check modifier
3. **Terminal resize**: Send `TermSize` on window resize events
4. **Paste security**: Sanitize pasted content, avoid escape sequences
5. **Cursor position**: xterm.js tracks cursor; keep in sync with server
6. **Buffer overflow**: Implement LRU buffer, don't memory leak
### Performance
1. **Throttle updates**: Don't render on every log line, batch
2. **Virtual scrolling**: For logs with many lines
3. **Web Worker**: Offload parsing to worker for large logs
### Animation
1. **Blinking cursor**: CSS animation or xterm.js built-in
2. **Auto-scroll indicator**: Small arrow when scrolled up
3. **Connection status**: Green/amber/red dot
## Testing Checklist
- [ ] Shell key press → terminal receives it
- [ ] Terminal output → WebSocket → UI
- [ ] Resize → terminal resizes correctly
- [ ] Space in shell ≠ spotlight open
- [ ] Ctrl+scroll over shell ≠ zoom canvas
- [ ] Logs auto-scroll works (and stops on manual scroll)
- [ ] Connection loss → retry with backoff
- [ ] Buffer overflow → old lines dropped
- [ ] Shell interrupt (Ctrl+C) handled
- [ ] Paste works (Ctrl+Shift+V)
1. **Space key**: Must distinguish between canvas pan and shell input
2. **Focus routing**: Route keys based on hovered window
3. **Scroll management**: Track scroll position for logs
4. **Terminal resize**: Debounce resize events
5. **Reconnection**: Handle WebSocket disconnects gracefully
6. **Memory**: Clean up old logs/shell buffers
7. **Authentication**: Validate user on WebSocket upgrade
8. **Permissions**: Enforce namespace RBAC on backend

View File

@@ -1,137 +1,203 @@
# Spotlight Search Feature Specification
# Design Document: Spotlight Feature Specification
## Overview
The spotlight is the global search overlay that allows users to find any Kubernetes object or existing krate. It provides fuzzy-ranked search results with quick view shortcuts.
Spotlight is the universal search and discovery interface that allows users to quickly find and create krates for Kubernetes resources. It's triggered by clicking the canvas or typing any character.
## Core Responsibilities
- Display search results ranked by fuzzy matching
- Support typed filters (Tab to cycle through types)
- Provide view shortcuts (Logs, Shell, Describe, YAML)
- Auto-close after keyboard idle and open selected object
- Handle universal search across Kubernetes resources
- Support fuzzy matching of names, namespaces, labels
- Allow quick creation of krates from search results
- Support filtering by resource type
## UI Components
## Trigger
- **Click on empty canvas**: Open spotlight
- **Type any key**: Open spotlight with that character pre-seeded
- **Esc key**: Close spotlight
- **Spotlight open**: Prevent canvas shortcuts from triggering
### Layout
- Full-screen backdrop: `rgba(7,9,13,.55)`, `backdrop-filter: blur(2px)`
- Search panel: `width: min(660px, 93vw)`, `top: 15%`, centered horizontally
- Panel: `background: rgba(16,20,28,.97)`, `border: 1px solid rgba(140,165,200,.26)`, `border-radius: 14px`
## Spotlight Anatomy
### Sections (top→bottom)
1. **Input row** (~52px):
- `⌕` glyph (accent color)
- Optional type-filter pill
- Input field (`font-size: 18px`, IBM Plex Sans)
- Optional Tab ghost hint
### Search Input
- Position: Top of spotlight panel
- Auto-focused on open
- Placeholder: `Search...`
- Clear on Esc
- Debounced: 16ms for fuzzy search
2. **Type chips row** (scrollable):
- All / deploy / svc / pods / secrets / config / sts / crd / namespace / ns
- Scrollable horizontally on small screens
- Shows selected filter as pill
### Filter Bar
- Location: Below search input
- Filter chips: All, Krates, Namespaces, Pods, Deployments, Services
- Click filter: Apply filter
- Click active filter: Clear filter
3. **Results list** (`max-height: 48vh, overflow: auto`):
- Each row: shape glyph + name + subtext (type · ns/namespace) + CRD badge + type badge
- Selected row highlight: accent background
- Scrollbar styled (8px, rgba(140,165,200,.18))
### Results List
- Position: Below filter bar
- Max height: ~400px
- Scrollable
- Results: Search results + quick actions
- Keyboard navigation: ↑↓ to navigate, Enter to select, Esc to close
4. **View chips** (expanded on selected row only):
- `⌥L logs · ⌥S shell · ⌥D describe · ⌥Y yaml`
- Only available views shown (YAML and Describe always shown; Logs and Shell for pods/deployments/daemonsets/statefulsets)
- Click to open that view for selected result
### Results Item
Content per item:
- Shape glyph (8px, color-coded by type)
- Name (primary text)
- Type badge (muted color)
- Namespace (muted, optional)
- View shortcuts: `L`, `S`, `D`, `Y`
- Hover: Highlight, show view shortcut tooltips
5. **Footer**:
- `↑↓ pick · ⌥L/S/D/Y open views · ⏎ open default · ⇥ filter type · esc done`
## Search Implementation
## Fuzzy Search Algorithm
### Scoring Formula
```
Score = character-match score × 10 + type boost
### Fuzzy Algorithm
```typescript
function fuzzy(query: string, text: string): number {
// Prefer starts-with matches
if (text.toLowerCase().startsWith(query.toLowerCase())) {
return 1 - query.length / text.length
}
// Then scoring based on character matching
let score = 0
let queryIndex = 0
for (let i = 0; i < text.length && queryIndex < query.length; i++) {
if (text[i].toLowerCase() === query[queryIndex].toLowerCase()) {
score++
queryIndex++
}
}
return score / query.length
}
```
### Type Boosts
- CRD: 60
- Deployment: 50
- StatefulSet: 48
- Service: 46
- DaemonSet: 44
- Ingress: 42
- Secret: 24
- ConfigMap: 22
- PVC: 18
- Pod: 16
### Search Scope
- Namespaces
- Pods
- Deployments
- Services
- ConfigMaps
- Secrets
- Krates (created by user)
### Character Matching
- Sequential character match
- Bonus for consecutive matches: +3
- Bonus for word-boundary starts: +5
### Resource Discovery
1. Initial load: Fetch all resources from `/api/resources`
2. Real-time updates: WebSocket `/ws/watch` for changes
3. Local cache: Store in Zustand krateStore
4. Filtering: Apply fuzzy search + type filter
### Results
- Capped at 8 results
- Debounce: 16ms (one animation frame) for performance with large datasets
## Results Organization
## Type Filter
### Search vs Quick Actions
- Search results: Resource matches (top section)
- Quick actions: Create new krate, open specific view (bottom section)
### Tab Quick-Filter
- Typing type alias (e.g., `pod`, `svc`) shows ghost hint: `⇥ Pods`
- Tab locks filter as pill
- Backspace removes filter (only when empty query and filter active)
- Tab cycles through type filters (most-recently-opened first)
## View Shortcuts
### Key Mapping
All use **⌥ (Alt/Option)**, NOT Ctrl (reserved for terminal):
- `⌥L` = logs
- `⌥S` = shell
- `⌥D` = describe
- `⌥Y` = yaml
### Implementation
- Use `event.code` (layout-safe, e.g., `KeyL`), not `event.key`
- Multiple views can be opened before closing spotlight
- Views stack as windows in one krate
### Quick Actions
- `Create krate for ns/{namespace}`
- `All pods`
- `All services`
- `All deployments`
- `Search again for...`
## Keyboard Navigation
| Key | Context | Action |
|---|---|---|
| ↑ / ↓ | Spotlight | Navigate results |
| Tab | Spotlight | Apply type filter / cycle filters |
| Backspace | Spotlight (empty query, filter active) | Clear type filter |
| Enter | Spotlight (result selected) | Open default view + close |
| ⌥L/S/D/Y | Spotlight | Open that view for selected result |
| Esc | Spotlight | Close spotlight |
| ↑ / ↓ | Spotlight open | Move selection |
| PageUp / PageDown | Spotlight open | Page navigation |
| Home / End | Spotlight open | First / last item |
| Enter | Item selected | Create krate / open resource |
| Esc | Spotlight open | Close spotlight |
| Space | Input focused | Search space character |
| Ctrl+K | Anywhere | Open spotlight |
| / | Anywhere | Open spotlight |
## Auto-Close Behavior
- After 500ms of keyboard idle (no more keypresses)
- Spotlight closes automatically
- Camera flies to the newly created krate
- Debounce timer resets on each keypress
## View Shortcuts
All use **Option/Alt** key:
- `⌥L`: Open logs view (if supported)
- `⌥S`: Open shell view (if supported)
- `⌥D`: Open describe view
- `⌥Y`: Open YAML view
## Search Results Include
- **Existing krates** (jump to working set, camera flies there)
- **Namespace results** (`ns/payments`) → opens collection window
- **Category results** (`All Pods`, `All Services`) → opens collection window
- **Kubernetes objects**: pods, deployments, services, secrets, configmaps, etc.
## Krate Creation Flow
1. User selects resource from spotlight
2. Create new krate with:
- Title: Resource name
- Color: Namespace color palette
- Position: Find non-overlapping location
- Windows: Create detail windows for selected views
3. Fly camera to new krate
4. Zoom to 0.92
## State
## State Management
### Spotlight State
```typescript
interface SpotlightState {
open: boolean;
query: string;
filterType: string | null;
sel: number; // selected result index
navigated: boolean; // true after ↑/↓ press
session: { // tracks views opened before closing
kid: string;
objId: string;
views: string[];
} | null;
sel: number;
navigated: boolean;
}
type FilterType = 'all' | 'krate' | 'namespace' | 'pod' | 'deployment' | 'service'
```
### Search State
```typescript
interface SearchState {
results: SearchResult[];
loading: boolean;
error: string | null;
}
interface SearchResult {
id: string;
type: string;
name: string;
namespace?: string;
score: number;
icon: string;
}
```
## Visual Design
### Spotlight Panel
- Position: Fixed, centered horizontally at top of canvas
- Width: 600px
- Max height: 500px
- Background: `#1a1e26`
- Border: `1px solid rgba(140,165,200,0.18)`
- Border-radius: 12px
- Shadow: `0 10px 40px rgba(0,0,0,0.5)`
### Results Item
- Hover background: `rgba(255,255,255,0.04)`
- Selected: `accentDim` (subtle accent color)
- Left border: 2px solid accent when selected
- Padding: 8px 12px
- Font-size: 14px
### Color Palette (by namespace)
- `default`: `#6fb1ff`
- `kube-system`: `#9c88ff`
- `kube-public`: `#4dd6e8`
- Custom namespaces: Pick from palette
## Gotchas
1. **Fuzzy search speed**: For real clusters with thousands of objects, debounce by 16ms or run in Web Worker
2. **View shortcuts**: Must use `event.code` for layout safety across OS/keyboard layouts
3. **Auto-close timer**: Reset on each keypress, don't close during active typing
4. **Pre-seeding**: All printable characters (not just letters) should pre-seed spotlight
1. **Space character**: When spotlight open, space goes to search (not canvas pan)
2. **Esc handling**: Must be handled in spotlight, not propagate to canvas
3. **Fuzzy search**: Use debounced search for large datasets
4. **Keyboard routing**: When spotlight open, route keys to spotlight, not canvas
5. **Focus management**: Auto-focus input, trap Tab cycle when open
6. **Selection reset**: Reset selection on query change
## Future Enhancements
- Quick pick recent resources
- Star/favorite resources
- Saved searches
- Search history
- Resource previews
- Multi-resource selection

View File

@@ -1,4 +1,4 @@
# Top Bar Feature Specification
# Design Document: Top Bar Feature Specification
## Overview
The top bar is the primary navigation and status bar for the application. It provides quick access to cluster information, user presence, and global actions.