264 lines
7.6 KiB
Markdown
264 lines
7.6 KiB
Markdown
# Upload First-Fold Layout Implementation Plan
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Compress the upload workbench so the complete upload workflow remains visible in the first desktop viewport without forcing users to scroll to discover mode, subtitle, and dubbing options.
|
|
|
|
**Architecture:** Keep the existing upload screen state and action flow intact, but reduce the upload page's vertical footprint. Most of the work stays inside `src/App.tsx` and `src/components/UploadScreen.tsx`, with supporting text updates in `src/i18n.tsx`, one small surface helper in `src/index.css`, and test updates in the existing app/upload test files. The tall TTS list will be replaced with a compact grid so all supported language choices are immediately visible.
|
|
|
|
**Tech Stack:** React 19, TypeScript, Tailwind CSS v4 utilities, Vitest, React Testing Library
|
|
|
|
---
|
|
|
|
### Task 1: Lock the compact first-fold language layout with failing tests
|
|
|
|
**Files:**
|
|
- Modify: `src/components/UploadScreen.test.tsx`
|
|
- Reference: `src/components/UploadScreen.tsx`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
Add a test that describes the compact language section and rejects the old tabbed list structure:
|
|
|
|
```tsx
|
|
it('shows all supported tts languages in a compact always-visible grid', () => {
|
|
renderUploadScreen();
|
|
|
|
expect(screen.getByTestId('tts-language-grid')).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'Chinese' })).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'Cantonese' })).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'English' })).toBeInTheDocument();
|
|
expect(screen.queryByText('ABC')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('GHI')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('DEF')).not.toBeInTheDocument();
|
|
});
|
|
```
|
|
|
|
**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 upload page still renders the alphabet tabs and has no compact grid marker.
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Update `src/components/UploadScreen.tsx` just enough to:
|
|
|
|
- remove the old alphabet tabs
|
|
- expose a compact language grid container with `data-testid="tts-language-grid"`
|
|
- keep the existing language buttons and selection behavior
|
|
|
|
**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 new compact-language assertion.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add src/components/UploadScreen.tsx src/components/UploadScreen.test.tsx
|
|
git commit -m "test: lock compact tts language layout"
|
|
```
|
|
|
|
### Task 2: Compress the upload page shell and card heights
|
|
|
|
**Files:**
|
|
- Modify: `src/App.tsx`
|
|
- Modify: `src/components/UploadScreen.tsx`
|
|
- Modify: `src/i18n.tsx`
|
|
- Modify: `src/index.css`
|
|
- Test: `src/App.test.tsx`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
Add an app-level test that captures the compact first-fold shell:
|
|
|
|
```tsx
|
|
it('renders the upload shell with compact first-fold copy', () => {
|
|
render(<App />);
|
|
|
|
fireEvent.click(screen.getByLabelText('switch-ui-language-en'));
|
|
|
|
expect(screen.getByRole('heading', { name: 'Upload & prepare' })).toBeInTheDocument();
|
|
expect(screen.getByText('Everything you need to start translation is visible right away.')).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 compact shell copy does not exist yet.
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Update the upload shell and localized copy to reduce the first-fold height budget:
|
|
|
|
- shrink upload-header padding and margins
|
|
- reduce title and description footprint
|
|
- tighten workbench spacing
|
|
- keep the language switcher visible
|
|
|
|
Localized copy example:
|
|
|
|
```tsx
|
|
workbenchDescription: 'Everything you need to start translation is visible right away.'
|
|
```
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
node ./node_modules/vitest/vitest.mjs run src/App.test.tsx
|
|
```
|
|
|
|
Expected: PASS for the compact-header assertion.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add src/App.tsx src/App.test.tsx src/i18n.tsx src/index.css
|
|
git commit -m "feat: compress upload shell for first-fold visibility"
|
|
```
|
|
|
|
### Task 3: Tighten the upload card and settings cards to fit the first fold
|
|
|
|
**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 targeted structure checks for the compact card composition:
|
|
|
|
```tsx
|
|
it('keeps the compact upload controls and primary action visible together', () => {
|
|
renderUploadScreen();
|
|
|
|
expect(screen.getByTestId('upload-dropzone-card')).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'Upload Video' })).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'Generate Translated Video' })).toBeInTheDocument();
|
|
});
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
node ./node_modules/vitest/vitest.mjs run src/components/UploadScreen.test.tsx
|
|
```
|
|
|
|
Expected: FAIL until the compact layout and new language grid are fully in place.
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Refactor `src/components/UploadScreen.tsx` to reclaim vertical space:
|
|
|
|
- reduce upload-card header spacing
|
|
- shorten the dropzone min height
|
|
- reduce top and bottom padding on all cards
|
|
- tighten card gaps
|
|
- shrink subtitle preview height
|
|
- compress mode buttons
|
|
- render the TTS language options in a multi-column grid instead of a scrolling letter list
|
|
- keep the generate button at the bottom of the visible settings stack
|
|
|
|
Representative shape:
|
|
|
|
```tsx
|
|
<aside className="grid gap-4">
|
|
<section className="...compact-mode-card..." />
|
|
<section className="...compact-subtitle-card..." />
|
|
<section className="...compact-language-card...">
|
|
<div data-testid="tts-language-grid" className="grid grid-cols-2 gap-2">
|
|
...
|
|
</div>
|
|
</section>
|
|
</aside>
|
|
```
|
|
|
|
**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 compact-card and compact-language assertions while preserving existing upload behavior tests.
|
|
|
|
**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: fit upload workbench into first fold"
|
|
```
|
|
|
|
### Task 4: Full verification
|
|
|
|
**Files:**
|
|
- Modify: `src/App.tsx`
|
|
- Modify: `src/App.test.tsx`
|
|
- Modify: `src/components/UploadScreen.tsx`
|
|
- Modify: `src/components/UploadScreen.test.tsx`
|
|
- Modify: `src/i18n.tsx`
|
|
- Modify: `src/index.css`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
If any final localized copy or structure assertions remain missing after Tasks 1-3, add the smallest regression test needed before the last polish.
|
|
|
|
**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 only if the final regression gap is real.
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Apply only the last polish needed to satisfy the failing regression test, without broadening scope.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm.cmd test
|
|
npm.cmd run lint
|
|
npm.cmd run build
|
|
```
|
|
|
|
Expected:
|
|
|
|
- all tests PASS
|
|
- typecheck PASS
|
|
- build PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add src/App.tsx src/App.test.tsx src/components/UploadScreen.tsx src/components/UploadScreen.test.tsx src/i18n.tsx src/index.css
|
|
git commit -m "test: verify first-fold upload layout"
|
|
```
|