Refactor login functionality and enhance MobileCallPage positioning

- Update LoginPage to initialize username state as an empty string for improved user experience.
- Introduce floatingVideoRef in MobileCallVisualWorkspace to dynamically manage video panel positioning.
- Adjust position calculations for the floating video panel to account for its dimensions, enhancing drag-and-drop functionality and ensuring proper placement within the viewport.
This commit is contained in:
Xin Wang
2026-07-13 08:08:00 +08:00
parent 313387778a
commit bd2f156cca
2 changed files with 27 additions and 8 deletions

View File

@@ -18,7 +18,7 @@ import { Input } from "@/components/ui/input";
export default function LoginPage() { export default function LoginPage() {
const router = useRouter(); const router = useRouter();
const { user, loading, login } = useAuth(); const { user, loading, login } = useAuth();
const [username, setUsername] = useState("admin"); const [username, setUsername] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState(""); const [error, setError] = useState("");

View File

@@ -150,6 +150,7 @@ function MobileCallVisualWorkspace({
cameraError: string | null; cameraError: string | null;
}) { }) {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const floatingVideoRef = useRef<HTMLButtonElement>(null);
const [position, setPosition] = useState({ x: 16, y: 72 }); const [position, setPosition] = useState({ x: 16, y: 72 });
const positionedRef = useRef(false); const positionedRef = useRef(false);
const dragRef = useRef<{ const dragRef = useRef<{
@@ -166,16 +167,25 @@ function MobileCallVisualWorkspace({
useEffect(() => { useEffect(() => {
const container = containerRef.current; const container = containerRef.current;
if (!container) return; const floatingVideo = floatingVideoRef.current;
if (!container || !floatingVideo) return;
const rect = container.getBoundingClientRect(); const rect = container.getBoundingClientRect();
const floatWidth = floatingVideo.offsetWidth;
const floatHeight = floatingVideo.offsetHeight;
if (!positionedRef.current) { if (!positionedRef.current) {
positionedRef.current = true; positionedRef.current = true;
setPosition({ x: Math.max(16, rect.width - 168), y: 72 }); setPosition({ x: Math.max(16, rect.width - floatWidth - 16), y: 72 });
return; return;
} }
setPosition((current) => ({ setPosition((current) => ({
x: Math.min(Math.max(16, current.x), Math.max(16, rect.width - 168)), x: Math.min(
y: Math.min(Math.max(72, current.y), Math.max(72, rect.height - 200)), Math.max(16, current.x),
Math.max(16, rect.width - floatWidth - 16),
),
y: Math.min(
Math.max(72, current.y),
Math.max(72, rect.height - floatHeight - 104),
),
})); }));
}, [view]); }, [view]);
@@ -187,9 +197,17 @@ function MobileCallVisualWorkspace({
const dy = event.clientY - drag.startY; const dy = event.clientY - drag.startY;
if (Math.abs(dx) + Math.abs(dy) > 4) drag.moved = true; if (Math.abs(dx) + Math.abs(dy) > 4) drag.moved = true;
const rect = container.getBoundingClientRect(); const rect = container.getBoundingClientRect();
const floatWidth = event.currentTarget.offsetWidth;
const floatHeight = event.currentTarget.offsetHeight;
setPosition({ setPosition({
x: Math.min(Math.max(16, drag.originX + dx), Math.max(16, rect.width - 168)), x: Math.min(
y: Math.min(Math.max(72, drag.originY + dy), Math.max(72, rect.height - 200)), Math.max(16, drag.originX + dx),
Math.max(16, rect.width - floatWidth - 16),
),
y: Math.min(
Math.max(72, drag.originY + dy),
Math.max(72, rect.height - floatHeight - 104),
),
}); });
}, []); }, []);
@@ -199,9 +217,10 @@ function MobileCallVisualWorkspace({
<> <>
<MobileCallTranscript messages={messages} /> <MobileCallTranscript messages={messages} />
<button <button
ref={floatingVideoRef}
type="button" type="button"
style={{ left: position.x, top: position.y }} style={{ left: position.x, top: position.y }}
className="absolute z-10 h-24 w-38 touch-none overflow-hidden rounded-2xl border border-white/20 bg-black shadow-2xl ring-1 ring-black/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/50" className="absolute z-10 aspect-video w-[clamp(7.5rem,38vw,10rem)] touch-none overflow-hidden rounded-2xl border border-white/20 bg-black shadow-2xl ring-1 ring-black/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/50"
aria-label="拖动摄像头浮窗,点击切换到视频流" aria-label="拖动摄像头浮窗,点击切换到视频流"
onPointerDown={(event) => { onPointerDown={(event) => {
event.currentTarget.setPointerCapture(event.pointerId); event.currentTarget.setPointerCapture(event.pointerId);