Skip to content

Commit

Permalink
Merge pull request #3 from liuhuapiaoyuan/feature/mobile
Browse files Browse the repository at this point in the history
feat: 移动端兼容
  • Loading branch information
YOYZHANG authored Oct 25, 2024
2 parents 1528868 + 0bf6e2c commit 01318c7
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 39 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@madzadev/audio-player": "^2.1.14",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-select": "^2.1.2",
Expand Down
38 changes: 38 additions & 0 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Menu from "./components/menu";
import { useJsonData } from "./hooks/useJsonData";
import { useStreamText } from './hooks/useStreamText';
import { BASE_URL } from "./lib/constant";
import MobileMenu from "./components/mobile-menu";

function App() {
const [isGenerating, setIsGenerating] = useState(false);
Expand All @@ -23,7 +24,7 @@ function App() {
data: podInfoData,
error: podInfoError,
isLoading: isPodInfoLoading,
fetchJsonData: fetchPodInfo,
fetchJsonData: fetchPodInfo,
} = useJsonData();


Expand All @@ -37,13 +38,13 @@ function App() {
return (
<div className="h-screen flex flex-col overflow-hidden">
<main className="flex-grow flex bg-[rgb(245,245,245)] h-full">
<Menu
<Menu className="hidden md:flex "
handleGenerate={handleGenerate}
isGenerating={isGenerating}
/>
/>
<Content
summaryTextChunks={summaryTextChunks}
summaryFinalResult={summaryFinalResult}
summaryFinalResult={summaryFinalResult}
isSummaryLoading={isSummaryLoading}
summaryError={summaryError}
isSummaryDone={isSummaryDone}
Expand All @@ -55,6 +56,10 @@ function App() {
formData={formData!}
activeTab={activeTab}
setActiveTab={setActiveTab}
mobileMenu={<MobileMenu
handleGenerate={handleGenerate}
isGenerating={isGenerating}
/>}
/>
</main>
</div>
Expand Down
30 changes: 21 additions & 9 deletions frontend/src/components/audio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,36 @@ export default function Audio({ audioUrl, isAudioLoading, audioError }: { audioU
}
};

const MOBILE_TEMPLATE_AREA = {
"trackInfo": "row1-1",
"playButton": "row2-1",
"repeatType": "row2-2",
"playList": "row2-3",
"progress": "row3-1",
"trackTimeDuration": "row1-3",
"trackTimeCurrent": "row1-2",
};
return (
<div className="p-2 px-12">
<div className="md:p-2 md:px-12">
<Card>
<CardContent className="p-2 bg-[rgb(249,249,249)] rounded-xl">
<CardContent className="p-2 bg-[rgb(249,249,249)] md:rounded-xl">
{isAudioLoading ? (
<div className="rounded-lg p-4 flex items-center">
<div className="bg-blue-100 rounded-full p-2 mr-4">
<Loader2 className="w-6 h-6 text-blue-500 animate-spin" />
</div>
<div>
<div className="rounded-lg p-4 flex items-center">
<div className="bg-blue-100 rounded-full p-2 mr-4">
<Loader2 className="w-6 h-6 text-blue-500 animate-spin" />
</div>
<div>
<p className="text-gray-800 font-medium">Generating conversation...</p>
<p className="text-gray-500 text-sm">This may take a few minutes. No need to stick around!</p>
</div>
</div>
</div>
) : audioError ? (
<div className="flex items-center justify-center text-red-500">
<AlertCircle className="mr-2" />
<p>音频生成失败: {audioError}</p>
</div>
) : audioUrl ? (
<div className="flex justify-between items-center">
<div className="flex md:justify-between md:items-center">
<AudioPlayer
playList={playList}
activeUI={{
Expand All @@ -63,6 +72,9 @@ export default function Audio({ audioUrl, isAudioLoading, audioError }: { audioU
placement={{
player: "static",
playList: "top",
interface: {
templateArea: MOBILE_TEMPLATE_AREA as any,
}
}}
rootContainerProps={{
colorScheme: "light",
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/components/content.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Episode from "./episode";
import Audio from "./audio";
import Transcript from "./transcript";
import { useEffect } from "react";
import React, { PropsWithChildren, useEffect } from "react";
import { BASE_URL } from "@/lib/constant";
import { useStreamText } from "@/hooks/useStreamText";
import { useAudioGeneration } from "@/hooks/useTaskData";
Expand All @@ -22,6 +22,7 @@ interface ContentProps {
formData: FormData
activeTab: string;
setActiveTab: (activeTab: string) => void;
mobileMenu?:React.ReactNode;
}
export default function Content({
formData,
Expand All @@ -35,7 +36,8 @@ export default function Content({
setIsGenerating,
activeTab,
setActiveTab,
}: ContentProps) {
mobileMenu
}:ContentProps ) {
const {
error: audioError,
isLoading: isAudioLoading,
Expand Down Expand Up @@ -93,9 +95,10 @@ export default function Content({
isPodInfoLoading={isPodInfoLoading}
podInfoError={podInfoError}
podInfoData={podInfoData}
mobileMenu={mobileMenu}
/>
</div>
<div className="flex-grow overflow-hidden">
<div className="flex-1 overflow-hidden h-1">
<Transcript
isSummaryLoading={isSummaryLoading}
summaryError={summaryError}
Expand Down
22 changes: 13 additions & 9 deletions frontend/src/components/episode.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Skeleton } from "@/components/ui/skeleton"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { AlertCircle } from "lucide-react"
import MobileMenu from "./mobile-menu";
import { ReactNode } from "react";

interface EpisodeProps {
mobileMenu?:ReactNode
isPodInfoLoading: boolean;
podInfoError: string | null;
podInfoData: {
Expand All @@ -11,13 +14,13 @@ interface EpisodeProps {
};
}

export default function Episode({ isPodInfoLoading, podInfoError, podInfoData }: EpisodeProps) {
export default function Episode({mobileMenu, isPodInfoLoading, podInfoError, podInfoData }: EpisodeProps) {

return (
<div className="flex items-start bg-gradient-to-br from-blue-100 via-purple-50 to-pink-50 p-4 rounded-2xl shadow-xl shadow-gray-200/50 mx-12 mb-2 mt-4">
<img
src="/cover1.png"
alt={podInfoData?.title || "Episode thumbnail"}
<div className="flex items-start bg-gradient-to-br from-blue-100 via-purple-50 to-pink-50 p-4 md:rounded-2xl shadow-xl shadow-gray-200/50 md:mx-12 mb-2 md:mt-4">
<img
src="/cover1.png"
alt={podInfoData?.title || "Episode thumbnail"}
className="w-14 h-14 m-2 bg-gray-300 rounded-2xl object-cover"
/>
{
Expand All @@ -34,7 +37,7 @@ export default function Episode({ isPodInfoLoading, podInfoError, podInfoData }:
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
{podInfoError || "An error occurred while loading the episode data."}
{podInfoError || "An error occurred while loading the episode data."}
</AlertDescription>
</Alert>
)
Expand All @@ -43,9 +46,10 @@ export default function Episode({ isPodInfoLoading, podInfoError, podInfoData }:
!isPodInfoLoading && !podInfoError && (
<div className="flex-1 flex flex-col">
<h2 className="text-xl font-bold my-2">{podInfoData?.title || "播客标题"}</h2>
<p className="text-sm text-gray-600">主讲人: {podInfoData?.host_name || "未知"}</p>
</div>
)}
<p className="text-sm text-gray-600">主讲人: {podInfoData?.host_name || "未知"}</p>
</div>
)}
{mobileMenu}
</div>
)
}
4 changes: 2 additions & 2 deletions frontend/src/components/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useSpeeker } from '@/hooks/useSpeeker';
const MAX_FILE_SIZE = 1 * 1024 * 1024; // 5MB in bytes
const DEMO_PDF_URL = '/demo.pdf'; // 替换为你的演示 PDF 文件的实际路径

export default function Menu({ handleGenerate, isGenerating }: { handleGenerate: (formData: FormData) => void, isGenerating: boolean }) {
export default function Menu({ handleGenerate,className, isGenerating }: { className?:string,handleGenerate: (formData: FormData) => void, isGenerating: boolean }) {
const [pdfFile, setPdfFile] = useState<File | null>(null);
const [textInput, setTextInput] = useState('');
const [tone, setTone] = useState('neutral');
Expand Down Expand Up @@ -69,7 +69,7 @@ export default function Menu({ handleGenerate, isGenerating }: { handleGenerate:
};

return (
<div className="w-full md:w-1/5 p-6 border-r rounded-2xl m-3 border-gray-200 bg-white flex flex-col text-gray-800 hidden md:flex shadow-lg shadow-gray-300/50">
<div className={`w-full md:w-1/5 p-6 border-r rounded-2xl m-3 h-full border-gray-200 bg-white flex flex-col text-gray-800 flex shadow-lg shadow-gray-300/50 ${className??''}`}>
<div className="flex-grow flex-1 h-1 overflow-y-auto space-y-8">
<div className="transition-all duration-300">
<h2 className="text-sm font-semibold mb-3 flex items-center"><Upload className="mr-2 text-gray-600" size={20} /> 上传 PDF *</h2>
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/components/mobile-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet"
import Menu from "./menu"
import { Button } from "./ui/button"
import { Sparkles } from "lucide-react"
import { useState } from "react"

/**
* smallest component possible for mobile menu
* @param props
* @returns
*/
export default function MobileMenu(
{ handleGenerate,
isGenerating }: { handleGenerate: (formData: FormData) => void, isGenerating: boolean }) {
const [open,setOpen] = useState(false)
return <Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger>
<Button
className={`md:hidden
w-full rounded-xl transition-all duration-300 transform hover:scale-105
flex items-center justify-center space-x-2
text-white font-semibold shadow-lg hover:shadow-xl
`}
>
<Sparkles className="size-5" />
<span>立即制作</span>
</Button>
</SheetTrigger>
<SheetContent className="flex flex-col h-screen">
<SheetHeader>
<SheetTitle>开始制作</SheetTitle>
</SheetHeader>
<div className="flex-1 h-1">
<Menu
isGenerating={isGenerating}
handleGenerate={data => {
setOpen(false)
return handleGenerate(data)
}}
className="!border-none p-0 m-0 !shadow-none" />
</div>
</SheetContent>
</Sheet>

}
18 changes: 8 additions & 10 deletions frontend/src/components/transcript.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export default function Transcript({
}, [transcriptTextChunks]);

return (
<div className="w-full px-12 py-6 overflow-hidden">
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<div className="w-full p-2 md:px-12 md:py-6 overflow-hidden h-full ">
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full h-full flex flex-col">
<div className="flex justify-center mb-4">
<TabsList className="inline-flex bg-gray-200 rounded-xl p-1">
<TabsTrigger
Expand All @@ -63,11 +63,9 @@ export default function Transcript({
</TabsTrigger>
</TabsList>
</div>
<TabsContent value="summary">
<Card className="p-8 bg-[rgb(249,249,249)]">
<CardContent
className={`h-[calc(100vh-400px)] overflow-y-auto`}
ref={summaryContentRef}
<TabsContent className="flex-1 h-1" value="summary">
<Card ref={summaryContentRef} className="p-2 h-full md:p-8 bg-[rgb(249,249,249)] overflow-y-auto">
<CardContent
>
{
renderContent(
Expand All @@ -78,9 +76,9 @@ export default function Transcript({
</CardContent>
</Card>
</TabsContent>
<TabsContent value="transcript">
<Card className="p-8 bg-[rgb(249,249,249)]">
<CardContent className={`h-[calc(100vh-400px)] overflow-y-auto`} ref={transcriptContentRef}>
<TabsContent className="flex-1 h-1" value="transcript">
<Card ref={transcriptContentRef} className="p-2 h-full md:p-8 bg-[rgb(249,249,249)] overflow-y-auto" >
<CardContent >
<DialogueList
textChunks={transcriptTextChunks}
transcriptError={transcriptError}
Expand Down
Loading

0 comments on commit 01318c7

Please sign in to comment.