This commit is contained in:
2026-02-06 04:36:06 +08:00
parent 3635fbd256
commit 12eb5c412a
12 changed files with 530 additions and 411 deletions

View File

@@ -6,6 +6,8 @@ import { Letter, SupportedAlphabets } from "@/lib/interfaces";
import { IconClick, CircleToggleButton, CircleButton } from "@/components/ui/buttons";
import { IMAGES } from "@/config/images";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { PageLayout } from "@/components/ui/PageLayout";
import { Card } from "@/components/ui/Card";
interface AlphabetCardProps {
alphabet: Letter[];
@@ -97,124 +99,122 @@ export function AlphabetCard({ alphabet, alphabetType, onBack }: AlphabetCardPro
};
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center px-4 py-8">
<div className="w-full max-w-2xl">
{/* 右上角返回按钮 */}
<div className="flex justify-end mb-4">
<IconClick
size={32}
alt="close"
src={IMAGES.close}
onClick={onBack}
className="bg-white rounded-full shadow-md"
/>
<PageLayout className="relative">
{/* 右上角返回按钮 - outside the white card */}
<div className="flex justify-end mb-4">
<IconClick
size={32}
alt="close"
src={IMAGES.close}
onClick={onBack}
className="bg-white rounded-full shadow-md"
/>
</div>
{/* 白色主卡片容器 */}
<Card padding="xl">
{/* 顶部进度指示器和显示选项按钮 */}
<div className="flex justify-between items-center mb-6">
{/* 当前字母进度 */}
<span className="text-sm text-gray-500">
{currentIndex + 1} / {alphabet.length}
</span>
{/* 显示选项切换按钮组 */}
<div className="flex gap-2 flex-wrap">
<CircleToggleButton
selected={showLetter}
onClick={() => setShowLetter(!showLetter)}
>
{t("letter")}
</CircleToggleButton>
{/* IPA 音标显示切换 */}
<CircleToggleButton
selected={showIPA}
onClick={() => setShowIPA(!showIPA)}
>
IPA
</CircleToggleButton>
{/* 罗马音显示切换(仅日语显示) */}
{hasRomanization && (
<CircleToggleButton
selected={showRoman}
onClick={() => setShowRoman(!showRoman)}
>
{t("roman")}
</CircleToggleButton>
)}
{/* 随机模式切换 */}
<CircleToggleButton
selected={isRandomMode}
onClick={() => setIsRandomMode(!isRandomMode)}
>
{t("random")}
</CircleToggleButton>
</div>
</div>
{/* 白色主卡片容器 */}
<div className="bg-white rounded-2xl shadow-xl p-8 md:p-12">
{/* 顶部进度指示器和显示选项按钮 */}
<div className="flex justify-between items-center mb-6">
{/* 当前字母进度 */}
<span className="text-sm text-gray-500">
{currentIndex + 1} / {alphabet.length}
</span>
{/* 显示选项切换按钮组 */}
<div className="flex gap-2 flex-wrap">
<CircleToggleButton
selected={showLetter}
onClick={() => setShowLetter(!showLetter)}
>
{t("letter")}
</CircleToggleButton>
{/* IPA 音标显示切换 */}
<CircleToggleButton
selected={showIPA}
onClick={() => setShowIPA(!showIPA)}
>
IPA
</CircleToggleButton>
{/* 罗马音显示切换(仅日语显示) */}
{hasRomanization && (
<CircleToggleButton
selected={showRoman}
onClick={() => setShowRoman(!showRoman)}
>
{t("roman")}
</CircleToggleButton>
)}
{/* 随机模式切换 */}
<CircleToggleButton
selected={isRandomMode}
onClick={() => setIsRandomMode(!isRandomMode)}
>
{t("random")}
</CircleToggleButton>
{/* 字母主要内容显示区域 */}
<div className="text-center mb-8">
{/* 字母本身(可隐藏) */}
{showLetter ? (
<div className="text-6xl md:text-8xl font-bold text-gray-800 mb-4">
{currentLetter.letter}
</div>
</div>
{/* 字母主要内容显示区域 */}
<div className="text-center mb-8">
{/* 字母本身(可隐藏) */}
{showLetter ? (
<div className="text-6xl md:text-8xl font-bold text-gray-800 mb-4">
{currentLetter.letter}
</div>
) : (
<div className="text-6xl md:text-8xl font-bold text-gray-300 mb-4 h-20 md:h-24 flex items-center justify-center">
<span className="text-2xl md:text-3xl text-gray-400">?</span>
</div>
)}
{/* IPA 音标显示 */}
{showIPA && (
<div className="text-2xl md:text-3xl text-gray-600 mb-2">
{currentLetter.letter_sound_ipa}
</div>
)}
{/* 罗马音显示(日语) */}
{showRoman && hasRomanization && currentLetter.roman_letter && (
<div className="text-lg md:text-xl text-gray-500">
{currentLetter.roman_letter}
</div>
)}
</div>
{/* 底部导航控制区域 */}
<div className="flex justify-between items-center">
{/* 上一个按钮 */}
<CircleButton onClick={goToPrevious} aria-label="上一个字母">
<ChevronLeft size={24} />
</CircleButton>
{/* 中间区域:随机按钮 */}
<div className="flex gap-2 items-center">
{isRandomMode && (
<button
onClick={goToRandom}
className="px-4 py-2 rounded-full bg-[#35786f] text-white text-sm font-medium hover:bg-[#2d5f58] transition-colors"
>
{t("randomNext")}
</button>
)}
) : (
<div className="text-6xl md:text-8xl font-bold text-gray-300 mb-4 h-20 md:h-24 flex items-center justify-center">
<span className="text-2xl md:text-3xl text-gray-400">?</span>
</div>
)}
{/* 下一个按钮 */}
<CircleButton onClick={goToNext} aria-label="下一个字母">
<ChevronRight size={24} />
</CircleButton>
{/* IPA 音标显示 */}
{showIPA && (
<div className="text-2xl md:text-3xl text-gray-600 mb-2">
{currentLetter.letter_sound_ipa}
</div>
)}
{/* 罗马音显示(日语) */}
{showRoman && hasRomanization && currentLetter.roman_letter && (
<div className="text-lg md:text-xl text-gray-500">
{currentLetter.roman_letter}
</div>
)}
</div>
{/* 底部导航控制区域 */}
<div className="flex justify-between items-center">
{/* 上一个按钮 */}
<CircleButton onClick={goToPrevious} aria-label="上一个字母">
<ChevronLeft size={24} />
</CircleButton>
{/* 中间区域:随机按钮 */}
<div className="flex gap-2 items-center">
{isRandomMode && (
<button
onClick={goToRandom}
className="px-4 py-2 rounded-full bg-[#35786f] text-white text-sm font-medium hover:bg-[#2d5f58] transition-colors"
>
{t("randomNext")}
</button>
)}
</div>
</div>
{/* 底部操作提示文字 */}
<div className="text-center mt-6 text-white text-sm">
<p>
{isRandomMode
? "使用左右箭头键或空格键随机切换字母ESC键返回"
: "使用左右箭头键或滑动切换字母ESC键返回"
}
</p>
{/* 下一个按钮 */}
<CircleButton onClick={goToNext} aria-label="下一个字母">
<ChevronRight size={24} />
</CircleButton>
</div>
</Card>
{/* 底部操作提示文字 */}
<div className="text-center mt-6 text-white text-sm">
<p>
{isRandomMode
? "使用左右箭头键或空格键随机切换字母ESC键返回"
: "使用左右箭头键或滑动切换字母ESC键返回"
}
</p>
</div>
{/* 全屏触摸事件监听层(用于滑动切换) */}
@@ -224,6 +224,6 @@ export function AlphabetCard({ alphabet, alphabetType, onBack }: AlphabetCardPro
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}
/>
</div>
</PageLayout>
);
}

View File

@@ -3,7 +3,7 @@
import { useState, useEffect } from "react";
import { useTranslations } from "next-intl";
import { Letter, SupportedAlphabets } from "@/lib/interfaces";
import { Container } from "@/components/ui/Container";
import { PageLayout } from "@/components/ui/PageLayout";
import { LightButton } from "@/components/ui/buttons";
import { AlphabetCard } from "./AlphabetCard";
@@ -48,87 +48,81 @@ export default function Alphabet() {
// 语言选择界面
if (!chosenAlphabet) {
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex flex-col items-center justify-center px-4">
<Container className="p-8 max-w-2xl w-full text-center">
{/* 页面标题 */}
<h1 className="text-4xl md:text-5xl font-bold text-gray-800 mb-4">
{t("chooseCharacters")}
</h1>
{/* 副标题说明 */}
<p className="text-gray-600 mb-8 text-lg">
</p>
<PageLayout>
{/* 页面标题 */}
<h1 className="text-4xl md:text-5xl font-bold text-gray-800 mb-4">
{t("chooseCharacters")}
</h1>
{/* 副标题说明 */}
<p className="text-gray-600 mb-8 text-lg">
</p>
{/* 语言选择按钮网格 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* 日语假名选项 */}
<LightButton
onClick={() => setChosenAlphabet("japanese")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2"></span>
<span>{t("japanese")}</span>
</div>
</LightButton>
{/* 语言选择按钮网格 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* 日语假名选项 */}
<LightButton
onClick={() => setChosenAlphabet("japanese")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2"></span>
<span>{t("japanese")}</span>
</div>
</LightButton>
{/* 英语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("english")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABC</span>
<span>{t("english")}</span>
</div>
</LightButton>
{/* 英语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("english")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABC</span>
<span>{t("english")}</span>
</div>
</LightButton>
{/* 维吾尔语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("uyghur")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ئۇيغۇر</span>
<span>{t("uyghur")}</span>
</div>
</LightButton>
{/* 维吾尔语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("uyghur")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ئۇيغۇر</span>
<span>{t("uyghur")}</span>
</div>
</LightButton>
{/* 世界语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("esperanto")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABCĜĤ</span>
<span>{t("esperanto")}</span>
</div>
</LightButton>
</div>
</Container>
</div>
{/* 世界语字母选项 */}
<LightButton
onClick={() => setChosenAlphabet("esperanto")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABCĜĤ</span>
<span>{t("esperanto")}</span>
</div>
</LightButton>
</div>
</PageLayout>
);
}
// 加载状态
if (loadingState === "loading") {
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center">
<Container className="p-8 text-center">
<div className="text-2xl text-gray-600">{t("loading")}</div>
</Container>
</div>
<PageLayout>
<div className="text-2xl text-gray-600 text-center">{t("loading")}</div>
</PageLayout>
);
}
// 错误状态
if (loadingState === "error") {
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center">
<Container className="p-8 text-center">
<div className="text-2xl text-red-600">{t("loadFailed")}</div>
</Container>
</div>
<PageLayout>
<div className="text-2xl text-red-600 text-center">{t("loadFailed")}</div>
</PageLayout>
);
}

View File

@@ -1,4 +1,4 @@
import { Container } from "@/components/ui/Container";
import { PageLayout } from "@/components/ui/PageLayout";
import { SearchForm } from "./SearchForm";
import { SearchResult } from "./SearchResult";
import { getTranslations } from "next-intl/server";
@@ -43,37 +43,33 @@ export default async function DictionaryPage({ searchParams }: DictionaryPagePro
}
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f]">
<PageLayout>
{/* 搜索区域 */}
<div className="flex items-center justify-center px-4 py-12">
<Container className="max-w-3xl w-full p-4">
<SearchForm
defaultQueryLang={queryLang}
defaultDefinitionLang={definitionLang}
/>
</Container>
<div className="mb-8">
<SearchForm
defaultQueryLang={queryLang}
defaultDefinitionLang={definitionLang}
/>
</div>
{/* 搜索结果区域 */}
<div className="flex-1 px-4 pb-12">
<Container className="max-w-3xl w-full p-4">
{searchQuery && (
<SearchResult
searchResult={searchResult}
searchQuery={searchQuery}
queryLang={queryLang}
definitionLang={definitionLang}
/>
)}
{!searchQuery && (
<div className="text-center py-12 bg-white/20 rounded-lg">
<div className="text-6xl mb-4">📚</div>
<p className="text-gray-800 text-xl mb-2">{t("welcomeTitle")}</p>
<p className="text-gray-600">{t("welcomeHint")}</p>
</div>
)}
</Container>
<div>
{searchQuery && (
<SearchResult
searchResult={searchResult}
searchQuery={searchQuery}
queryLang={queryLang}
definitionLang={definitionLang}
/>
)}
{!searchQuery && (
<div className="text-center py-12">
<div className="text-6xl mb-4">📚</div>
<p className="text-gray-800 text-xl mb-2">{t("welcomeTitle")}</p>
<p className="text-gray-600">{t("welcomeHint")}</p>
</div>
)}
</div>
</div>
</PageLayout>
);
}

View File

@@ -5,6 +5,7 @@ import { useTranslations } from "next-intl";
import Link from "next/link";
import { Folder as Fd } from "lucide-react";
import { TSharedFolderWithTotalPairs } from "@/shared/folder-type";
import { PageLayout } from "@/components/ui/PageLayout";
interface FolderSelectorProps {
folders: TSharedFolderWithTotalPairs[];
@@ -15,81 +16,77 @@ const FolderSelector: React.FC<FolderSelectorProps> = ({ folders }) => {
const router = useRouter();
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center px-4 py-8">
<div className="w-full max-w-2xl">
<div className="bg-white rounded-2xl shadow-xl p-6 md:p-8">
{folders.length === 0 ? (
// 空状态 - 显示提示和跳转按钮
<div className="text-center">
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 mb-4">
{t("noFolders")}
</h1>
<Link
className="inline-block px-6 py-2 bg-[#35786f] text-white rounded-full hover:bg-[#2d5f58] transition-colors"
href="/folders"
>
Go to Folders
</Link>
</div>
) : (
<>
{/* 页面标题 */}
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 mb-6">
{t("selectFolder")}
</h1>
{/* 文件夹列表 */}
<div className="border border-gray-200 rounded-2xl max-h-96 overflow-y-auto">
{folders
.toSorted((a, b) => a.id - b.id)
.map((folder) => (
<div
key={folder.id}
onClick={() =>
router.push(`/memorize?folder_id=${folder.id}`)
}
className="flex flex-row items-center p-4 gap-3 hover:cursor-pointer hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-b-0"
>
{/* 文件夹图标 */}
<div className="shrink-0">
<Fd className="text-gray-600" size={24} />
</div>
{/* 文件夹信息 */}
<div className="flex-1">
<div className="font-medium text-gray-900">
{folder.name}
</div>
<div className="text-sm text-gray-500">
{t("folderInfo", {
id: folder.id,
name: folder.name,
count: folder.total,
})}
</div>
</div>
{/* 右箭头 */}
<div className="text-gray-400">
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</div>
</div>
))}
</div>
</>
)}
<PageLayout>
{folders.length === 0 ? (
// 空状态 - 显示提示和跳转按钮
<div className="text-center">
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 mb-4">
{t("noFolders")}
</h1>
<Link
className="inline-block px-6 py-2 bg-[#35786f] text-white rounded-full hover:bg-[#2d5f58] transition-colors"
href="/folders"
>
Go to Folders
</Link>
</div>
</div>
</div>
) : (
<>
{/* 页面标题 */}
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 mb-6">
{t("selectFolder")}
</h1>
{/* 文件夹列表 */}
<div className="border border-gray-200 rounded-2xl max-h-96 overflow-y-auto">
{folders
.toSorted((a, b) => a.id - b.id)
.map((folder) => (
<div
key={folder.id}
onClick={() =>
router.push(`/memorize?folder_id=${folder.id}`)
}
className="flex flex-row items-center p-4 gap-3 hover:cursor-pointer hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-b-0"
>
{/* 文件夹图标 */}
<div className="shrink-0">
<Fd className="text-gray-600" size={24} />
</div>
{/* 文件夹信息 */}
<div className="flex-1">
<div className="font-medium text-gray-900">
{folder.name}
</div>
<div className="text-sm text-gray-500">
{t("folderInfo", {
id: folder.id,
name: folder.name,
count: folder.total,
})}
</div>
</div>
{/* 右箭头 */}
<div className="text-gray-400">
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</div>
</div>
))}
</div>
</>
)}
</PageLayout>
);
};

View File

@@ -8,6 +8,7 @@ import { useTranslations } from "next-intl";
import localFont from "next/font/local";
import { isNonNegativeInteger, SeededRandom } from "@/utils/random";
import { TSharedPair } from "@/shared/folder-type";
import { PageLayout } from "@/components/ui/PageLayout";
const myFont = localFont({
src: "../../../../public/fonts/NotoNaskhArabic-VariableFont_wght.ttf",
@@ -28,11 +29,9 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
if (textPairs.length === 0) {
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center px-4">
<div className="bg-white rounded-2xl shadow-xl p-8 max-w-md w-full text-center">
<p className="text-gray-700">{t("noTextPairs")}</p>
</div>
</div>
<PageLayout maxWidth="md">
<p className="text-gray-700 text-center">{t("noTextPairs")}</p>
</PageLayout>
);
}
@@ -113,87 +112,83 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
: [getTextPairs()[index].text1, getTextPairs()[index].text2];
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center px-4 py-8">
<div className="w-full max-w-2xl">
<div className="bg-white rounded-2xl shadow-xl p-6 md:p-8">
{/* 进度指示器 */}
<div className="flex justify-center mb-4">
<LinkButton onClick={handleIndexClick} className="text-sm">
{index + 1} / {getTextPairs().length}
</LinkButton>
</div>
{/* 文本显示区域 */}
<div className={`h-[40dvh] ${myFont.className} mb-4`}>
{(() => {
if (dictation) {
if (show === "question") {
return (
<div className="h-full flex items-center justify-center">
<div className="text-gray-400 text-4xl">?</div>
</div>
);
} else {
return (
<div className="space-y-2">
{createText(text1)}
<div className="border-t border-gray-200"></div>
{createText(text2)}
</div>
);
}
} else {
if (show === "question") {
return createText(text1);
} else {
return (
<div className="space-y-2">
{createText(text1)}
<div className="border-t border-gray-200"></div>
{createText(text2)}
</div>
);
}
}
})()}
</div>
{/* 底部按钮 */}
<div className="flex flex-row gap-2 items-center justify-center flex-wrap">
<LightButton
onClick={handleNext}
className="px-4 py-2 rounded-full text-sm"
>
{show === "question" ? t("answer") : t("next")}
</LightButton>
<LightButton
onClick={handlePrevious}
className="px-4 py-2 rounded-full text-sm"
>
{t("previous")}
</LightButton>
<CircleToggleButton
selected={reverse}
onClick={toggleReverse}
>
{t("reverse")}
</CircleToggleButton>
<CircleToggleButton
selected={dictation}
onClick={toggleDictation}
>
{t("dictation")}
</CircleToggleButton>
<CircleToggleButton
selected={disorder}
onClick={toggleDisorder}
>
{t("disorder")}
</CircleToggleButton>
</div>
</div>
<PageLayout>
{/* 进度指示器 */}
<div className="flex justify-center mb-4">
<LinkButton onClick={handleIndexClick} className="text-sm">
{index + 1} / {getTextPairs().length}
</LinkButton>
</div>
</div>
{/* 文本显示区域 */}
<div className={`h-[40dvh] ${myFont.className} mb-4`}>
{(() => {
if (dictation) {
if (show === "question") {
return (
<div className="h-full flex items-center justify-center">
<div className="text-gray-400 text-4xl">?</div>
</div>
);
} else {
return (
<div className="space-y-2">
{createText(text1)}
<div className="border-t border-gray-200"></div>
{createText(text2)}
</div>
);
}
} else {
if (show === "question") {
return createText(text1);
} else {
return (
<div className="space-y-2">
{createText(text1)}
<div className="border-t border-gray-200"></div>
{createText(text2)}
</div>
);
}
}
})()}
</div>
{/* 底部按钮 */}
<div className="flex flex-row gap-2 items-center justify-center flex-wrap">
<LightButton
onClick={handleNext}
className="px-4 py-2 rounded-full text-sm"
>
{show === "question" ? t("answer") : t("next")}
</LightButton>
<LightButton
onClick={handlePrevious}
className="px-4 py-2 rounded-full text-sm"
>
{t("previous")}
</LightButton>
<CircleToggleButton
selected={reverse}
onClick={toggleReverse}
>
{t("reverse")}
</CircleToggleButton>
<CircleToggleButton
selected={dictation}
onClick={toggleDictation}
>
{t("dictation")}
</CircleToggleButton>
<CircleToggleButton
selected={disorder}
onClick={toggleDisorder}
>
{t("disorder")}
</CircleToggleButton>
</div>
</PageLayout>
);
};

View File

@@ -4,6 +4,7 @@ import React from "react";
import { useTranslations } from "next-intl";
import { toast } from "sonner";
import { Video, FileText } from "lucide-react";
import { PageLayout } from "@/components/ui/PageLayout";
import { useSrtPlayer } from "./hooks/useSrtPlayer";
import { useSubtitleSync } from "./hooks/useSubtitleSync";
import { useKeyboardShortcuts, createSrtPlayerShortcuts } from "./hooks/useKeyboardShortcuts";
@@ -106,23 +107,19 @@ export default function SrtPlayerPage() {
const canPlay = state.video.url && state.subtitle.url && state.subtitle.data.length > 0;
return (
<div className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4 py-8">
<div className="max-w-6xl mx-auto">
{/* 标题区域 */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-gray-800 mb-2">
{t("srtPlayer.name")}
</h1>
<p className="text-lg text-gray-600">
{t("srtPlayer.description")}
</p>
</div>
<PageLayout>
{/* 标题区域 */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-gray-800 mb-2">
{t("srtPlayer.name")}
</h1>
<p className="text-lg text-gray-600">
{t("srtPlayer.description")}
</p>
</div>
{/* 主要内容区域 */}
<div className="bg-white rounded-xl shadow-lg overflow-hidden">
{/* 视频播放器区域 */}
<div className="aspect-video bg-black relative">
{/* 视频播放器区域 */}
<div className="aspect-video bg-black relative rounded-xl overflow-hidden">
{(!state.video.url || !state.subtitle.url || state.subtitle.data.length === 0) && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-900 bg-opacity-75 z-10">
<div className="text-center text-white">
@@ -163,10 +160,10 @@ export default function SrtPlayerPage() {
)}
</div>
{/* 控制面板 */}
<div className="p-3 bg-gray-50 border-t">
{/* 上传区域和状态指示器 */}
<div className="mb-3">
{/* 控制面板 */}
<div className="p-3 bg-gray-50 border-t rounded-b-xl">
{/* 上传区域和状态指示器 */}
<div className="mb-3">
<div className="flex gap-3">
<div className={`flex-1 p-2 rounded-lg border-2 transition-all ${state.video.url
? 'border-gray-800 bg-gray-100'
@@ -269,12 +266,9 @@ export default function SrtPlayerPage() {
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</PageLayout>
);
}

View File

@@ -95,7 +95,7 @@ export default function TranslatorPage() {
};
return (
<>
<div className="min-h-[calc(100vh-64px)] bg-white">
{/* TCard Component */}
<div className="w-screen flex flex-col md:flex-row md:justify-between gap-2 p-2">
{/* Card Component - Left Side */}
@@ -218,6 +218,6 @@ export default function TranslatorPage() {
{t("translate")}
</PrimaryButton>
</div>
</>
</div>
);
}