补全 html → body → #root 的高度链,使用 dvh 动态视口单位 适配 iOS Safari 地址栏动态收起/展开,添加 overscroll-contain 防止滚动穿透
34 lines
1.1 KiB
TypeScript
34 lines
1.1 KiB
TypeScript
import { Toaster } from "sonner";
|
|
import { HistoryList } from "./components/HistoryList";
|
|
import { MicButton } from "./components/MicButton";
|
|
import { PreviewBox } from "./components/PreviewBox";
|
|
import { StatusBadge } from "./components/StatusBadge";
|
|
import { useRecorder } from "./hooks/useRecorder";
|
|
import { useWebSocket } from "./hooks/useWebSocket";
|
|
|
|
export function App() {
|
|
const { sendJSON, sendBinary } = useWebSocket();
|
|
const { startRecording, stopRecording } = useRecorder({
|
|
sendJSON,
|
|
sendBinary,
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<div className="relative z-1 mx-auto flex h-dvh max-w-[480px] flex-col px-5 pt-[calc(16px+env(safe-area-inset-top,0px))] pb-[calc(16px+env(safe-area-inset-bottom,0px))]">
|
|
<header className="flex shrink-0 items-center justify-between pt-2 pb-5">
|
|
<h1 className="font-bold text-[22px] tracking-[-0.03em]">
|
|
VoicePaste
|
|
</h1>
|
|
<StatusBadge />
|
|
</header>
|
|
|
|
<PreviewBox />
|
|
<MicButton onStart={startRecording} onStop={stopRecording} />
|
|
<HistoryList sendJSON={sendJSON} />
|
|
</div>
|
|
<Toaster theme="dark" position="bottom-center" />
|
|
</>
|
|
);
|
|
}
|