video_translate/docs/plans/2026-03-21-upload-first-fold-layout.md
2026-03-21 13:56:16 +08:00

7.6 KiB

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:

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:

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:

node ./node_modules/vitest/vitest.mjs run src/components/UploadScreen.test.tsx

Expected: PASS for the new compact-language assertion.

Step 5: Commit

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:

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:

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:

workbenchDescription: 'Everything you need to start translation is visible right away.'

Step 4: Run test to verify it passes

Run:

node ./node_modules/vitest/vitest.mjs run src/App.test.tsx

Expected: PASS for the compact-header assertion.

Step 5: Commit

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:

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:

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:

<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:

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

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:

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:

npm.cmd test
npm.cmd run lint
npm.cmd run build

Expected:

  • all tests PASS
  • typecheck PASS
  • build PASS

Step 5: Commit

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"