diff --git a/src/App.test.tsx b/src/App.test.tsx
index acdb016..efd9131 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -15,12 +15,30 @@ describe('App bilingual UI', () => {
expect(screen.getByLabelText('switch-ui-language-zh')).toHaveAttribute('aria-pressed', 'true');
expect(screen.getByText('字幕语言')).toBeInTheDocument();
- expect(screen.getByText('上传视频')).toBeInTheDocument();
+ expect(screen.getAllByText('上传视频').length).toBeGreaterThan(0);
fireEvent.click(screen.getByLabelText('switch-ui-language-en'));
expect(screen.getByLabelText('switch-ui-language-en')).toHaveAttribute('aria-pressed', 'true');
expect(screen.getByText('Subtitle Language')).toBeInTheDocument();
- expect(screen.getByText('Upload Video')).toBeInTheDocument();
+ expect(screen.getAllByText('Upload Video').length).toBeGreaterThan(0);
+ });
+
+ it('shows the upload workbench header and keeps the language switcher visible', () => {
+ render();
+
+ expect(screen.getByRole('banner')).toBeInTheDocument();
+ expect(screen.getByLabelText('switch-ui-language-zh')).toBeInTheDocument();
+ expect(screen.getByLabelText('switch-ui-language-en')).toBeInTheDocument();
+
+ 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();
+ expect(screen.getByText('Video Translate')).toBeInTheDocument();
});
});
diff --git a/src/App.tsx b/src/App.tsx
index c7e8b25..4c64240 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -38,51 +38,82 @@ function AppContent() {
setCurrentView('editor');
};
+ const languageSwitcher = (
+
+
+
+
+ );
+
return (
-
-
-
-
+
+ {currentView === 'upload' ? (
+
-
-
-
-
+
+
+
+ {m.upload.workbenchEyebrow}
+
+ {m.app.productName}
+
+
+
+ {m.upload.workbenchTitle}
+
+
+ {m.upload.workbenchDescription}
+
+
+
+
+
{languageSwitcher}
+
+ ) : (
+
{languageSwitcher}
+ )}
+
+
+
+ {currentView === 'upload' ? (
+
+ ) : (
+ setCurrentView('upload')}
+ />
+ )}
- {currentView === 'upload' ? (
-
- ) : (
-
setCurrentView('upload')}
- />
- )}
);
}
diff --git a/src/components/UploadScreen.test.tsx b/src/components/UploadScreen.test.tsx
index 7c55792..ba2f248 100644
--- a/src/components/UploadScreen.test.tsx
+++ b/src/components/UploadScreen.test.tsx
@@ -56,6 +56,17 @@ describe('UploadScreen', () => {
expect(preview).toHaveStyle({ fontSize: '32px', bottom: '18%' });
});
+ 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();
+ });
+
it('shows a fixed English subtitle language and the supported TTS languages', () => {
renderUploadScreen();
@@ -125,4 +136,12 @@ describe('UploadScreen', () => {
expect(screen.queryByRole('button', { name: /close trim/i })).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: /generate translated video/i })).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),
+ );
+ });
});
diff --git a/src/components/UploadScreen.tsx b/src/components/UploadScreen.tsx
index cd31dc9..4d9dadb 100644
--- a/src/components/UploadScreen.tsx
+++ b/src/components/UploadScreen.tsx
@@ -33,6 +33,10 @@ export default function UploadScreen({
const [tempFile, setTempFile] = useState
(null);
const [subtitleDefaults, setSubtitleDefaults] = useState(DEFAULT_SUBTITLE_DEFAULTS);
const fileInputRef = useRef(null);
+ const activeModeLabel = mode === 'editing' ? m.upload.editingMode : m.upload.simpleMode;
+ const activeModeDescription = mode === 'editing' ? m.upload.editingModeDesc : m.upload.simpleModeDesc;
+ const settingsCardClass =
+ 'app-surface rounded-[28px] border border-white/70 px-5 py-5 shadow-[0_18px_60px_-34px_rgba(15,23,42,0.3)] sm:px-6';
const clearPendingUpload = () => {
setTempFile(null);
@@ -55,91 +59,145 @@ export default function UploadScreen({
};
return (
-
- {/* Left: Upload Area */}
-
-
-
-
-
{m.upload.clickToUpload}
-
-
-
- {m.upload.supportedFormats}
-
-
-
- {/* Right: Settings */}
-
- {/* Mode Selection */}
-
-
setMode('editing')}
- >
-
- {mode === 'editing' ? (
-
- ) : (
-
- )}
- {m.upload.editingMode}
-
-
{m.upload.editingModeDesc}
+
+
+
+
+
+ {m.upload.uploadPanelTitle}
+
+
+ {m.upload.uploadPanelDescription}
+
-
setMode('simple')}
- >
-
- {mode === 'simple' ? (
-
- ) : (
-
- )}
- {m.upload.simpleMode}
-
-
{m.upload.simpleModeDesc}
+
+
+
+ {m.upload.modeWorkflowTitle}
+
+
{activeModeLabel}
+
{activeModeDescription}
-
-
-
-
{m.upload.subtitleDefaults}
-
- {m.upload.subtitleDefaultsDesc}
+
+
+
+
+
+
+
+
+
+
{m.upload.uploadVideo}
+
+ {m.upload.clickToUpload}
+
+
+
+
+
+
+
{m.upload.supportedFormats}
+
+ {activeModeLabel}
+
+
+
+
+