-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Labels
featureNew feature implementationNew feature implementationpriority: criticalMust be done immediatelyMust be done immediatelyreadyReady to be worked onReady to be worked onuiUser interface and componentsUser interface and components
Description
Description
Implement the MultiFileEditor component that manages multiple FileEditor instances in a vertical layout, following GitHub Gist's UX pattern.
Requirements
- Vertical layout: All files displayed vertically on one page (NO TABS)
- Each file editor is stacked below the previous one
- Add new file button at the bottom of all files
- Auto-scroll to newly added files with smooth animation
- Delete file functionality with inline remove button
- Minimum 1 file, maximum 20 files
- Generate default filenames (file1.txt, file2.txt, etc.)
- Prevent duplicate filenames across all files
- Total size validation (5MB limit for entire gist)
- Individual file size validation (500KB per file)
- Responsive design for mobile
- Proper focus management when adding/removing files
Acceptance Criteria
- Files are displayed vertically, all visible at once
- Can add new files up to 20 file limit
- New files appear at the bottom with auto-scroll
- Focus moves to new file's filename input
- Can delete files (except when only 1 remains)
- Remove button hidden when only 1 file exists
- Confirmation dialog for non-empty file deletion
- Default filenames are auto-generated sequentially
- Duplicate filenames are prevented with error message
- Total size limit is enforced (5MB) with clear indicator
- Individual file warnings at 400KB, errors at 500KB
- Component is fully typed with TypeScript
- Works well on mobile devices
- Keyboard shortcuts work (Ctrl+Enter for new file)
- Accessible with screen readers
State Interface
interface FileData {
id: string; // nanoid for React keys
name: string;
content: string;
language?: string;
}
interface MultiFileEditorProps {
initialFiles?: FileData[];
onChange: (files: FileData[]) => void;
readOnly?: boolean;
maxFiles?: number; // Default 20
maxTotalSize?: number; // Default 5MB
maxFileSize?: number; // Default 500KB
}UI Layout
┌─ MultiFileEditor Container ─────────────┐
│ │
│ Total: 3 files, 126 KB / 5 MB │
│ │
│ [FileEditor 1] │
│ filename.js | JavaScript ▼ | ✕ │
│ // code... │
│ │
│ [FileEditor 2] │
│ styles.css | CSS ▼ | ✕ │
│ /* code... */ │
│ │
│ [FileEditor 3] │
│ data.json | JSON ▼ │
│ { "data": "..." } │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ ➕ Add another file │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
File Management Logic
// Generate unique default filename
function generateFilename(existingFiles: FileData[]): string {
let counter = 1;
let filename = `file${counter}.txt`;
while (existingFiles.some(f => f.name === filename)) {
counter++;
filename = `file${counter}.txt`;
}
return filename;
}
// Calculate total size
function calculateTotalSize(files: FileData[]): number {
return files.reduce((sum, file) =>
sum + new Blob([file.content]).size, 0
);
}Technical Notes
- Follow the design in docs/MULTI_FILE_EDITOR_DESIGN.md
- Use array state management for files
- Each file needs unique ID (use nanoid)
- Implement proper memoization to prevent unnecessary re-renders
- Use React.memo for FileEditor components
- Consider virtualization for many files (future enhancement)
- File operations should update state immutably
- Use requestAnimationFrame for smooth scrolling
- Debounce size calculations for performance
Keyboard Shortcuts
- Ctrl/Cmd + Enter: Add new file
- Delete/Backspace: Remove file (when focused on remove button)
- Tab: Navigate between file editors
- Shift + Tab: Navigate backwards
Related
- Depends on Implement FileEditor component for single file editing #55 (FileEditor component)
- Uses design from docs/MULTI_FILE_EDITOR_DESIGN.md
- Part of Phase 4 UI Components
- Core component for create page functionality
Metadata
Metadata
Assignees
Labels
featureNew feature implementationNew feature implementationpriority: criticalMust be done immediatelyMust be done immediatelyreadyReady to be worked onReady to be worked onuiUser interface and componentsUser interface and components