docs: add first-fold upload layout design
This commit is contained in:
parent
5234f5b5db
commit
5c750ae34f
189
docs/plans/2026-03-21-upload-first-fold-layout-design.md
Normal file
189
docs/plans/2026-03-21-upload-first-fold-layout-design.md
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
# Upload First-Fold Layout Design
|
||||||
|
|
||||||
|
**Goal:** Make the upload page fit the primary workflow into the first visible desktop viewport so users can immediately see upload, mode selection, subtitle defaults, and dubbing choices without needing to scroll to discover more options.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The current upload workbench fixed the horizontal clipping problem, but the vertical footprint is still too tall. The page header, large upload surface, generous card spacing, subtitle preview height, and long TTS list combine to push the language card below the fold on common desktop windows.
|
||||||
|
|
||||||
|
That creates a discovery problem: users may not realize the page continues below, so important settings can be missed entirely even though the layout is technically responsive.
|
||||||
|
|
||||||
|
## User-Approved Direction
|
||||||
|
|
||||||
|
The approved direction is:
|
||||||
|
|
||||||
|
- keep everything on a single page
|
||||||
|
- prioritize first-fold visibility on common desktop screens
|
||||||
|
- avoid making users scroll to discover key settings
|
||||||
|
- compress the current layout rather than changing the product flow
|
||||||
|
|
||||||
|
## Approaches Considered
|
||||||
|
|
||||||
|
### Option A: Compact first-fold workbench
|
||||||
|
|
||||||
|
Reduce vertical whitespace, shorten the upload card, tighten the right-side cards, and replace the tall language list with a compact always-visible button grid.
|
||||||
|
|
||||||
|
**Pros**
|
||||||
|
|
||||||
|
- Preserves the current workflow and layout logic
|
||||||
|
- Directly addresses the "hidden options below the fold" problem
|
||||||
|
- Keeps all major choices visible at once
|
||||||
|
|
||||||
|
**Cons**
|
||||||
|
|
||||||
|
- Requires denser spacing and more careful visual balance
|
||||||
|
|
||||||
|
### Option B: Merge the settings cards
|
||||||
|
|
||||||
|
Combine multiple settings sections into one large card to reduce stack height.
|
||||||
|
|
||||||
|
**Pros**
|
||||||
|
|
||||||
|
- Fewer visual blocks
|
||||||
|
- Lower total vertical gap
|
||||||
|
|
||||||
|
**Cons**
|
||||||
|
|
||||||
|
- Weakens hierarchy
|
||||||
|
- Makes scanning and editing harder
|
||||||
|
|
||||||
|
### Option C: Move one settings section into the upload card
|
||||||
|
|
||||||
|
Embed mode selection or language selection into the left upload card.
|
||||||
|
|
||||||
|
**Pros**
|
||||||
|
|
||||||
|
- Reduces right-column height quickly
|
||||||
|
|
||||||
|
**Cons**
|
||||||
|
|
||||||
|
- Creates mixed responsibilities inside the upload card
|
||||||
|
- Makes the composition feel less structured
|
||||||
|
|
||||||
|
### Recommendation
|
||||||
|
|
||||||
|
Use **Option A**. It preserves a clear workbench layout while making all key actions visible in the first fold.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Header Compression
|
||||||
|
|
||||||
|
The upload-page header should become a slimmer top strip:
|
||||||
|
|
||||||
|
- smaller vertical padding
|
||||||
|
- smaller title scale
|
||||||
|
- reduced bottom margin
|
||||||
|
- language switcher remains visible but no longer consumes hero-card space
|
||||||
|
|
||||||
|
The header still provides context, but it should stop competing with the main workspace for height.
|
||||||
|
|
||||||
|
### Upload Card Compression
|
||||||
|
|
||||||
|
The left upload card should remain the primary visual anchor, but it no longer needs a tall poster-like dropzone.
|
||||||
|
|
||||||
|
Adjustments:
|
||||||
|
|
||||||
|
- reduce top summary spacing
|
||||||
|
- shorten the dropzone height substantially
|
||||||
|
- tighten the button and support-copy spacing
|
||||||
|
- keep mode summary compact
|
||||||
|
|
||||||
|
The upload action should still read as primary, just not oversized.
|
||||||
|
|
||||||
|
### Right Column Compression
|
||||||
|
|
||||||
|
Keep the three semantic cards:
|
||||||
|
|
||||||
|
1. mode and workflow
|
||||||
|
2. subtitle defaults
|
||||||
|
3. language and dubbing
|
||||||
|
|
||||||
|
But each card should be tightened:
|
||||||
|
|
||||||
|
- smaller paddings
|
||||||
|
- smaller inter-card gaps
|
||||||
|
- smaller preview panel
|
||||||
|
- less decorative empty space
|
||||||
|
|
||||||
|
### TTS Language Visibility
|
||||||
|
|
||||||
|
The biggest vertical cost comes from the current alphabet-tab + scrolling list treatment. Replace it with an always-visible compact grid of language buttons.
|
||||||
|
|
||||||
|
For the current supported languages, a compact grid is sufficient and preferable because:
|
||||||
|
|
||||||
|
- all options are visible immediately
|
||||||
|
- there is no hidden overflow area
|
||||||
|
- the user does not need to infer that more settings exist below
|
||||||
|
|
||||||
|
This is a visibility optimization, not a data-model change.
|
||||||
|
|
||||||
|
## Layout Rules
|
||||||
|
|
||||||
|
### Desktop-First Height Budget
|
||||||
|
|
||||||
|
Target the upload page body to sit comfortably within the first fold on common desktop heights. The implementation may use:
|
||||||
|
|
||||||
|
- tighter shell spacing
|
||||||
|
- a more compact upload-card min height
|
||||||
|
- reduced card gaps
|
||||||
|
- right-column sections that size to content without scroll regions
|
||||||
|
|
||||||
|
### No Discovery Scroll for Core Options
|
||||||
|
|
||||||
|
Core settings that must be visible without scrolling:
|
||||||
|
|
||||||
|
- upload entry point
|
||||||
|
- mode selection
|
||||||
|
- subtitle default preview and sliders
|
||||||
|
- subtitle language context
|
||||||
|
- all supported TTS language options
|
||||||
|
- primary "Generate Translated Video" button
|
||||||
|
|
||||||
|
### Fallback Behavior
|
||||||
|
|
||||||
|
If the viewport is unusually short, the page may still scroll slightly. But normal desktop usage should not require scrolling to discover additional settings.
|
||||||
|
|
||||||
|
## Interaction Details
|
||||||
|
|
||||||
|
### Mode Selection
|
||||||
|
|
||||||
|
Mode options should become denser selection blocks. Keep both options visible at once, but reduce their height and spacing.
|
||||||
|
|
||||||
|
### Subtitle Defaults
|
||||||
|
|
||||||
|
Keep:
|
||||||
|
|
||||||
|
- reset action
|
||||||
|
- preview
|
||||||
|
- position slider
|
||||||
|
- size slider
|
||||||
|
|
||||||
|
Reduce the preview height enough to preserve usefulness while reclaiming space.
|
||||||
|
|
||||||
|
### TTS Languages
|
||||||
|
|
||||||
|
Present the current supported languages as a compact grid, using the existing localized labels and current selection styling. Remove the alphabet tabs and long per-letter sections because they optimize for a larger catalog than this page currently has.
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
Add or update tests to cover:
|
||||||
|
|
||||||
|
- the compact upload layout still renders all major cards
|
||||||
|
- all TTS language buttons remain visible without the old tabbed list structure
|
||||||
|
- existing subtitle default interactions still work
|
||||||
|
- upload behavior and trim flow are unchanged
|
||||||
|
|
||||||
|
Manual verification should focus on a common desktop viewport to confirm that the bottom card no longer drops below the fold.
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
This revision does not:
|
||||||
|
|
||||||
|
- change the upload workflow
|
||||||
|
- add or remove supported languages
|
||||||
|
- redesign the editor screen
|
||||||
|
- change backend contracts
|
||||||
|
|
||||||
|
## Rollout Notes
|
||||||
|
|
||||||
|
Success means a user can land on the upload page and immediately understand every major choice without needing to notice or guess that the page continues below the fold.
|
||||||
263
docs/plans/2026-03-21-upload-first-fold-layout.md
Normal file
263
docs/plans/2026-03-21-upload-first-fold-layout.md
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
# 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"
|
||||||
|
```
|
||||||
Loading…
x
Reference in New Issue
Block a user