feat: 增强弱网与断线场景下的移动端交互反馈
This commit is contained in:
@@ -8,19 +8,19 @@ function formatTime(ts: number): string {
|
||||
}
|
||||
|
||||
interface HistoryListProps {
|
||||
sendJSON: (obj: Record<string, unknown>) => void;
|
||||
sendPaste: (text: string) => void;
|
||||
}
|
||||
|
||||
export function HistoryList({ sendJSON }: HistoryListProps) {
|
||||
export function HistoryList({ sendPaste }: HistoryListProps) {
|
||||
const history = useAppStore((s) => s.history);
|
||||
const clearHistory = useAppStore((s) => s.clearHistory);
|
||||
|
||||
const handleItemClick = useCallback(
|
||||
(text: string) => {
|
||||
sendJSON({ type: "paste", text });
|
||||
sendPaste(text);
|
||||
toast.info("发送粘贴…");
|
||||
},
|
||||
[sendJSON],
|
||||
[sendPaste],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -8,9 +8,13 @@ interface MicButtonProps {
|
||||
|
||||
export function MicButton({ onStart, onStop }: MicButtonProps) {
|
||||
const connected = useAppStore((s) => s.connectionStatus === "connected");
|
||||
const micReady = useAppStore((s) => s.micReady);
|
||||
const recording = useAppStore((s) => s.recording);
|
||||
const pendingStart = useAppStore((s) => s.pendingStart);
|
||||
const isActive = recording || pendingStart;
|
||||
const stopping = useAppStore((s) => s.stopping);
|
||||
const weakNetwork = useAppStore((s) => s.weakNetwork);
|
||||
const isActive = recording || pendingStart || stopping;
|
||||
const disabled = !connected || !micReady || stopping;
|
||||
|
||||
const handlePointerDown = useCallback(
|
||||
(e: React.PointerEvent<HTMLButtonElement>) => {
|
||||
@@ -46,6 +50,8 @@ export function MicButton({ onStart, onStop }: MicButtonProps) {
|
||||
"cursor-not-allowed border-edge bg-linear-to-br from-surface-hover to-surface text-fg-secondary opacity-30 shadow-[0_2px_12px_rgba(0,0,0,0.3),inset_0_1px_0_rgba(255,255,255,0.04)]";
|
||||
const activeClasses =
|
||||
"animate-mic-breathe scale-[1.06] border-accent-hover bg-accent text-white shadow-[0_0_32px_rgba(99,102,241,0.35),0_0_80px_rgba(99,102,241,0.2)]";
|
||||
const weakClasses =
|
||||
"border-amber-400 bg-linear-to-br from-amber-400/15 to-surface text-amber-200 shadow-[0_0_22px_rgba(251,191,36,0.28)]";
|
||||
const idleClasses =
|
||||
"border-edge bg-linear-to-br from-surface-hover to-surface text-fg-secondary shadow-[0_2px_12px_rgba(0,0,0,0.3),inset_0_1px_0_rgba(255,255,255,0.04)]";
|
||||
|
||||
@@ -54,13 +60,15 @@ export function MicButton({ onStart, onStop }: MicButtonProps) {
|
||||
<div className="relative flex touch-none items-center justify-center">
|
||||
<button
|
||||
type="button"
|
||||
disabled={!connected}
|
||||
disabled={disabled}
|
||||
className={`relative z-1 flex size-24 cursor-pointer touch-none select-none items-center justify-center rounded-full border-2 transition-all duration-[250ms] ease-[cubic-bezier(0.4,0,0.2,1)] ${
|
||||
!connected
|
||||
disabled
|
||||
? disabledClasses
|
||||
: isActive
|
||||
? activeClasses
|
||||
: idleClasses
|
||||
: weakNetwork
|
||||
? weakClasses
|
||||
: isActive
|
||||
? activeClasses
|
||||
: idleClasses
|
||||
}`}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerUp={handlePointerUp}
|
||||
@@ -98,7 +106,17 @@ export function MicButton({ onStart, onStop }: MicButtonProps) {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="font-medium text-fg-dim text-sm">{"按住说话"}</p>
|
||||
<p className="font-medium text-fg-dim text-sm">
|
||||
{!micReady
|
||||
? "请先准备麦克风"
|
||||
: !connected
|
||||
? "连接中断,等待重连"
|
||||
: stopping
|
||||
? "收尾中…"
|
||||
: weakNetwork
|
||||
? "网络波动,已启用缓冲"
|
||||
: "按住说话"}
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@ import { useAppStore } from "../stores/app-store";
|
||||
export function PreviewBox() {
|
||||
const text = useAppStore((s) => s.previewText);
|
||||
const active = useAppStore((s) => s.previewActive);
|
||||
const weakNetwork = useAppStore((s) => s.weakNetwork);
|
||||
const recording = useAppStore((s) => s.recording);
|
||||
const hasText = text.length > 0;
|
||||
const placeholder =
|
||||
weakNetwork && recording ? "网络波动中,音频缓冲后发送…" : "按住说话…";
|
||||
|
||||
return (
|
||||
<section className="shrink-0 pb-3">
|
||||
@@ -17,7 +21,7 @@ export function PreviewBox() {
|
||||
<p
|
||||
className={`break-words text-base leading-relaxed ${hasText ? "" : "text-fg-dim"}`}
|
||||
>
|
||||
{hasText ? text : "按住说话…"}
|
||||
{hasText ? text : placeholder}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -20,7 +20,12 @@ const statusConfig = {
|
||||
|
||||
export function StatusBadge() {
|
||||
const status = useAppStore((s) => s.connectionStatus);
|
||||
const { text, dotClass, borderClass } = statusConfig[status];
|
||||
const weakNetwork = useAppStore((s) => s.weakNetwork);
|
||||
const { dotClass, borderClass } = statusConfig[status];
|
||||
const text =
|
||||
status === "connected" && weakNetwork
|
||||
? "网络波动"
|
||||
: statusConfig[status].text;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user