# Upload Workbench Redesign Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Rebuild the upload page into a responsive workbench layout that keeps the settings panel fully accessible while preserving the current upload, trim, subtitle-default, and TTS selection behavior.
**Architecture:** Keep the existing upload-page workflow and state model, but replace the rigid centered flex layout with a top-aligned page shell and responsive grid. Most of the work lives in `src/components/UploadScreen.tsx`, with a smaller shell adjustment in `src/App.tsx` and assertion updates in the upload-page tests. The implementation should stay behavior-compatible and lean on CSS/Tailwind layout changes instead of introducing new product state.
**Tech Stack:** React 19, TypeScript, Vite, Tailwind CSS v4 utilities, Lucide React icons, Vitest, React Testing Library
---
### Task 1: Lock the redesigned upload-page structure with failing tests
**Files:**
- Modify: `src/App.test.tsx`
- Modify: `src/components/UploadScreen.test.tsx`
- Reference: `src/App.tsx`
- Reference: `src/components/UploadScreen.tsx`
**Step 1: Write the failing test**
Add assertions that describe the redesigned shell and card structure before implementation:
```tsx
it('shows the upload workbench header and keeps the language switcher visible', () => {
render();
expect(screen.getByText('Video Translate')).toBeInTheDocument();
expect(
screen.getByText('Upload a source video, tune subtitle defaults, and choose dubbing settings before generation.'),
).toBeInTheDocument();
expect(screen.getByLabelText('switch-ui-language-zh')).toBeInTheDocument();
expect(screen.getByLabelText('switch-ui-language-en')).toBeInTheDocument();
});
it('renders upload, mode, subtitle defaults, and language cards inside the responsive workbench', () => {
renderUploadScreen();
expect(screen.getByTestId('upload-workbench')).toBeInTheDocument();
expect(screen.getByTestId('upload-dropzone-card')).toBeInTheDocument();
expect(screen.getByTestId('upload-settings-column')).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Mode & Workflow' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Subtitle Defaults' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Language & Dubbing' })).toBeInTheDocument();
});
```
**Step 2: Run test to verify it fails**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx src/components/UploadScreen.test.tsx
```
Expected: FAIL because the new header copy, section headings, and test ids do not exist yet.
**Step 3: Write minimal implementation**
Do not redesign everything yet. Add only the smallest missing semantic hooks and copy needed to satisfy the new tests:
- app-shell heading and intro copy in `src/App.tsx`
- stable `data-testid` markers and section headings in `src/components/UploadScreen.tsx`
Use copy aligned with the approved design:
```tsx
Video Translate
{m.upload.workbenchTitle}
{m.upload.workbenchDescription}
```
**Step 4: Run test to verify it passes**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx src/components/UploadScreen.test.tsx
```
Expected: PASS for the new structure assertions, with no unrelated failures in those files.
**Step 5: Commit**
```bash
git add src/App.test.tsx src/components/UploadScreen.test.tsx src/App.tsx src/components/UploadScreen.tsx src/i18n.tsx
git commit -m "test: lock upload workbench shell structure"
```
### Task 2: Rebuild the page shell and header layout
**Files:**
- Modify: `src/App.tsx`
- Modify: `src/i18n.tsx`
- Test: `src/App.test.tsx`
**Step 1: Write the failing test**
Extend the app test to assert the header content is grouped into a page shell and remains bilingual:
```tsx
expect(screen.getByRole('banner')).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Upload & prepare' })).toBeInTheDocument();
expect(screen.getByText('Keep subtitle defaults visible and avoid clipped settings panels.')).toBeInTheDocument();
```
**Step 2: Run test to verify it fails**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx
```
Expected: FAIL because the new banner structure and localized hero text are not present yet.
**Step 3: Write minimal implementation**
Update `src/App.tsx` and `src/i18n.tsx` to:
- wrap the upload page in a proper shell with `min-h-screen`
- add a responsive header above the view content
- move the language switcher into the header
- add localized upload-page title and description strings for both Chinese and English
Implementation sketch:
```tsx
```
**Step 4: Run test to verify it passes**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx
```
Expected: PASS, showing the new header shell in the upload view and preserving the language toggle behavior.
**Step 5: Commit**
```bash
git add src/App.tsx src/i18n.tsx src/App.test.tsx
git commit -m "feat: add upload page workbench shell"
```
### Task 3: Replace the rigid upload-page flex layout with a responsive workbench grid
**Files:**
- Modify: `src/components/UploadScreen.tsx`
- Modify: `src/components/UploadScreen.test.tsx`
- Modify: `src/index.css`
- Reference: `src/types.ts`
**Step 1: Write the failing test**
Add tests that lock in the redesigned composition while preserving behavior:
```tsx
it('keeps subtitle preview behavior after the layout redesign', () => {
renderUploadScreen();
fireEvent.change(screen.getByLabelText(/subtitle initial size/i), {
target: { value: '32' },
});
expect(screen.getByTestId('upload-subtitle-preview')).toHaveStyle({ fontSize: '32px' });
expect(screen.getByRole('button', { name: 'Generate Translated Video' })).toBeDisabled();
});
it('keeps the upload interaction wired through the redesigned dropzone card', () => {
renderUploadScreen();
expect(screen.getByTestId('upload-dropzone-card')).toContainElement(
screen.getByLabelText(/upload video file/i),
);
});
```
**Step 2: Run test to verify it fails**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/components/UploadScreen.test.tsx
```
Expected: FAIL because the current layout does not expose the new workbench structure markers and updated headings yet.
**Step 3: Write minimal implementation**
Refactor `src/components/UploadScreen.tsx` to:
- replace the outer `flex ... h-screen items-center` shell with a responsive grid container
- use a wide primary upload card plus a flexible sidebar column
- remove the fixed `w-[400px]` sidebar
- add `min-w-0` to shrinkable containers
- convert the settings area into three distinct cards:
- mode and workflow
- subtitle defaults
- language and dubbing
- reduce the preview height and tighten card spacing
- keep the language list internally scrollable
- keep the primary generation button prominent at the bottom of the settings flow
Representative JSX shape:
```tsx
...
```
If a small amount of shared CSS improves consistency, keep it narrowly scoped in `src/index.css`:
```css
.app-surface {
background: rgba(255, 255, 255, 0.86);
backdrop-filter: blur(14px);
}
```
**Step 4: Run test to verify it passes**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/components/UploadScreen.test.tsx
```
Expected: PASS for the upload-screen interaction tests, including subtitle-preview updates and upload confirmation behavior.
**Step 5: Commit**
```bash
git add src/components/UploadScreen.tsx src/components/UploadScreen.test.tsx src/index.css src/i18n.tsx
git commit -m "feat: redesign upload page workbench layout"
```
### Task 4: Full verification and cleanup
**Files:**
- Modify: `src/App.tsx`
- Modify: `src/components/UploadScreen.tsx`
- Modify: `src/i18n.tsx`
- Modify: `src/index.css`
- Test: `src/App.test.tsx`
- Test: `src/components/UploadScreen.test.tsx`
**Step 1: Write the failing test**
Add one final regression assertion for the bilingual header text to ensure the redesigned shell still switches languages correctly:
```tsx
fireEvent.click(screen.getByLabelText('switch-ui-language-en'));
expect(screen.getByRole('heading', { name: 'Upload & prepare' })).toBeInTheDocument();
expect(screen.getByText('Upload a source video, tune subtitle defaults, and choose dubbing settings before generation.')).toBeInTheDocument();
```
**Step 2: Run test to verify it fails**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx
```
Expected: FAIL until the new localized header copy is fully wired.
**Step 3: Write minimal implementation**
Complete any remaining polish needed to satisfy the regression coverage:
- finalize localized header and section labels
- ensure the upload page stays visually coherent in both locales
- remove unused classes or stale layout wrappers from the old design
**Step 4: Run test to verify it passes**
Run:
```bash
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx src/components/UploadScreen.test.tsx
npm run lint
npm run build
```
Expected:
- targeted tests PASS
- typecheck PASS
- production build PASS
**Step 5: Commit**
```bash
git add src/App.tsx src/components/UploadScreen.tsx src/i18n.tsx src/index.css src/App.test.tsx src/components/UploadScreen.test.tsx
git commit -m "test: verify upload workbench redesign"
```