restore: recover deleted documentation, CI/CD, and infrastructure files
Restored from origin/main (b4663fb): - .github/ workflows and issue templates - .gitignore (proper exclusions) - .opencode/agent/web_developer.md - AGENTS.md, BUILD.md, PROGRESS.md - dev-docs/ (9 architecture/implementation docs) - docs/screenshots/ (4 UI screenshots) - images/ (CodeNomad icons) - package-lock.json (dependency lockfile) - tasks/ (25+ project task files) Also restored original source files that were modified: - packages/ui/src/App.tsx - packages/ui/src/lib/logger.ts - packages/ui/src/stores/instances.ts - packages/server/src/server/routes/workspaces.ts - packages/server/src/workspaces/manager.ts - packages/server/src/workspaces/runtime.ts - packages/server/package.json Kept new additions: - Install-*.bat/.sh (enhanced installers) - Launch-*.bat/.sh (new launchers) - README.md (SEO optimized with GLM 4.7)
This commit is contained in:
280
tasks/done/002-empty-state-ui.md
Normal file
280
tasks/done/002-empty-state-ui.md
Normal file
@@ -0,0 +1,280 @@
|
||||
# Task 002: Empty State UI & Folder Selection
|
||||
|
||||
## Goal
|
||||
|
||||
Create the initial empty state interface that appears when no instances are running, with folder selection capability.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Task 001 completed (project setup)
|
||||
- Basic understanding of SolidJS components
|
||||
- Electron IPC understanding
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Empty state displays when no instances exist
|
||||
- [ ] "Select Folder" button visible and styled
|
||||
- [ ] Clicking button triggers Electron dialog
|
||||
- [ ] Selected folder path displays temporarily
|
||||
- [ ] UI matches design spec (centered, clean)
|
||||
- [ ] Keyboard shortcut Cmd/Ctrl+N works
|
||||
- [ ] Error handling for cancelled selection
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Create Empty State Component
|
||||
|
||||
**src/components/empty-state.tsx:**
|
||||
|
||||
**Structure:**
|
||||
|
||||
- Centered container
|
||||
- Large folder icon (from lucide-solid)
|
||||
- Subheading: "Select a folder to start coding with AI"
|
||||
- Primary button: "Select Folder"
|
||||
- Helper text: "Keyboard shortcut: Cmd/Ctrl+N"
|
||||
|
||||
**Styling:**
|
||||
|
||||
- Use TailwindCSS utilities
|
||||
- Center vertically and horizontally
|
||||
- Max width: 500px
|
||||
- Padding: 32px
|
||||
- Icon size: 64px
|
||||
- Text sizes: Heading 24px, body 16px, helper 14px
|
||||
- Colors: Follow design spec (light/dark mode)
|
||||
|
||||
**Props:**
|
||||
|
||||
- `onSelectFolder: () => void` - Callback when button clicked
|
||||
|
||||
### 2. Create UI Store
|
||||
|
||||
**src/stores/ui.ts:**
|
||||
|
||||
**State:**
|
||||
|
||||
```typescript
|
||||
interface UIStore {
|
||||
hasInstances: boolean
|
||||
selectedFolder: string | null
|
||||
isSelectingFolder: boolean
|
||||
}
|
||||
```
|
||||
|
||||
**Signals:**
|
||||
|
||||
- `hasInstances` - Reactive boolean
|
||||
- `selectedFolder` - Reactive string or null
|
||||
- `isSelectingFolder` - Reactive boolean (loading state)
|
||||
|
||||
**Actions:**
|
||||
|
||||
- `setHasInstances(value: boolean)`
|
||||
- `setSelectedFolder(path: string | null)`
|
||||
- `setIsSelectingFolder(value: boolean)`
|
||||
|
||||
### 3. Implement IPC for Folder Selection
|
||||
|
||||
**electron/main/main.ts additions:**
|
||||
|
||||
**IPC Handler:**
|
||||
|
||||
- Register handler for 'dialog:selectFolder'
|
||||
- Use `dialog.showOpenDialog()` with:
|
||||
- `properties: ['openDirectory']`
|
||||
- Title: "Select Project Folder"
|
||||
- Button label: "Select"
|
||||
- Return selected folder path or null if cancelled
|
||||
- Handle errors gracefully
|
||||
|
||||
**electron/preload/index.ts additions:**
|
||||
|
||||
**Expose method:**
|
||||
|
||||
```typescript
|
||||
electronAPI: {
|
||||
selectFolder: () => Promise<string | null>
|
||||
}
|
||||
```
|
||||
|
||||
**Type definitions:**
|
||||
|
||||
```typescript
|
||||
interface ElectronAPI {
|
||||
selectFolder: () => Promise<string | null>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: ElectronAPI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Update App Component
|
||||
|
||||
**src/App.tsx:**
|
||||
|
||||
**Logic:**
|
||||
|
||||
- Import UI store
|
||||
- Import EmptyState component
|
||||
- Check if `hasInstances` is false
|
||||
- If false, render EmptyState
|
||||
- If true, render placeholder for instance UI (future)
|
||||
|
||||
**Folder selection handler:**
|
||||
|
||||
```typescript
|
||||
async function handleSelectFolder() {
|
||||
setIsSelectingFolder(true)
|
||||
try {
|
||||
const folder = await window.electronAPI.selectFolder()
|
||||
if (folder) {
|
||||
setSelectedFolder(folder)
|
||||
// TODO: Will trigger instance creation in Task 003
|
||||
console.log("Selected folder:", folder)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Folder selection failed:", error)
|
||||
// TODO: Show error toast (Task 010)
|
||||
} finally {
|
||||
setIsSelectingFolder(false)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Add Keyboard Shortcut
|
||||
|
||||
**electron/main/menu.ts (new file):**
|
||||
|
||||
**Create application menu:**
|
||||
|
||||
- File menu:
|
||||
- New Instance (Cmd/Ctrl+N)
|
||||
- Click: Send 'menu:newInstance' to renderer
|
||||
- Separator
|
||||
- Quit (Cmd/Ctrl+Q)
|
||||
|
||||
**Platform-specific menu:**
|
||||
|
||||
- macOS: Include app menu with About, Hide, etc.
|
||||
- Windows/Linux: Standard File menu
|
||||
|
||||
**Register menu in main.ts:**
|
||||
|
||||
- Import Menu, buildFromTemplate
|
||||
- Create menu structure
|
||||
- Set as application menu
|
||||
|
||||
**electron/preload/index.ts additions:**
|
||||
|
||||
```typescript
|
||||
electronAPI: {
|
||||
onNewInstance: (callback: () => void) => void
|
||||
}
|
||||
```
|
||||
|
||||
**src/App.tsx additions:**
|
||||
|
||||
- Listen for 'newInstance' event
|
||||
- Trigger handleSelectFolder when received
|
||||
|
||||
### 6. Add Loading State
|
||||
|
||||
**Button states:**
|
||||
|
||||
- Default: "Select Folder"
|
||||
- Loading: "Selecting..." with spinner icon
|
||||
- Disabled when isSelectingFolder is true
|
||||
|
||||
**Spinner component:**
|
||||
|
||||
- Use lucide-solid Loader2 icon
|
||||
- Add spin animation class
|
||||
- Size: 16px
|
||||
|
||||
### 7. Add Validation
|
||||
|
||||
**Folder validation (in handler):**
|
||||
|
||||
- Check if folder exists
|
||||
- Check if readable
|
||||
- Check if it's actually a directory
|
||||
- Show appropriate error if invalid
|
||||
|
||||
**Error messages:**
|
||||
|
||||
- "Folder does not exist"
|
||||
- "Cannot access folder (permission denied)"
|
||||
- "Please select a directory, not a file"
|
||||
|
||||
### 8. Style Refinements
|
||||
|
||||
**Responsive behavior:**
|
||||
|
||||
- Works at minimum window size (800x600)
|
||||
- Maintains centering
|
||||
- Text remains readable
|
||||
|
||||
**Accessibility:**
|
||||
|
||||
- Button has proper ARIA labels
|
||||
- Keyboard focus visible
|
||||
- Screen reader friendly text
|
||||
|
||||
**Theme support:**
|
||||
|
||||
- Test in light mode
|
||||
- Test in dark mode (use prefers-color-scheme)
|
||||
- Icons and text have proper contrast
|
||||
|
||||
### 9. Add Helpful Context
|
||||
|
||||
**Additional helper text:**
|
||||
|
||||
- "Examples: ~/projects/my-app"
|
||||
- "You can have multiple instances of the same folder"
|
||||
|
||||
**Icon improvements:**
|
||||
|
||||
- Use animated folder icon (optional)
|
||||
- Add subtle entrance animation (fade in)
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
**Manual Tests:**
|
||||
|
||||
1. Launch app → Empty state appears
|
||||
2. Click "Select Folder" → Dialog opens
|
||||
3. Select folder → Path logged to console
|
||||
4. Cancel dialog → No error, back to empty state
|
||||
5. Press Cmd/Ctrl+N → Dialog opens
|
||||
6. Select non-directory → Error shown
|
||||
7. Select restricted folder → Permission error shown
|
||||
8. Resize window → Layout stays centered
|
||||
|
||||
**Edge Cases:**
|
||||
|
||||
- Very long folder paths (ellipsis)
|
||||
- Special characters in folder name
|
||||
- Folder on network drive
|
||||
- Folder that gets deleted while selected
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Blocks:** Task 003 (needs folder path to create instance)
|
||||
- **Blocked by:** Task 001 (needs project setup)
|
||||
|
||||
## Estimated Time
|
||||
|
||||
2-3 hours
|
||||
|
||||
## Notes
|
||||
|
||||
- Keep UI simple and clean
|
||||
- Focus on UX - clear messaging
|
||||
- Don't implement instance creation yet (that's Task 003)
|
||||
- Log selected folder to console for verification
|
||||
- Prepare for state management patterns used in later tasks
|
||||
Reference in New Issue
Block a user