Compare commits

..

No commits in common. "3e0276d6c078e863064845f58675be210ba26a30" and "1f0365e7165fabd0401282c17058287c73609d49" have entirely different histories.

4 changed files with 41 additions and 81 deletions

View File

@ -84,41 +84,30 @@ export function PhoneSimulator({
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const dragOffset = useRef({ x: 0, y: 0 }); const dragOffset = useRef({ x: 0, y: 0 });
const handleDragStart = (e: React.MouseEvent | React.TouchEvent) => { const handleDragStart = (e: React.MouseEvent) => {
e.preventDefault();
setIsDragging(true); setIsDragging(true);
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
dragOffset.current = { dragOffset.current = {
x: clientX - visualizerPosition.x, x: e.clientX - visualizerPosition.x,
y: clientY - visualizerPosition.y, y: e.clientY - visualizerPosition.y,
}; };
}; };
const handleDragMove = (e: MouseEvent | TouchEvent) => { const handleDragMove = (e: MouseEvent) => {
if (!isDragging || !phoneContainerRef.current || !visualizerRef.current) return; if (!isDragging || !phoneContainerRef.current || !visualizerRef.current) return;
e.preventDefault();
const containerRect = phoneContainerRef.current.getBoundingClientRect(); const containerRect = phoneContainerRef.current.getBoundingClientRect();
const visualizerRect = visualizerRef.current.getBoundingClientRect(); const visualizerRect = visualizerRef.current.getBoundingClientRect();
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX; let newX = e.clientX - dragOffset.current.x;
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY; let newY = e.clientY - dragOffset.current.y;
let newX = clientX - dragOffset.current.x;
let newY = clientY - dragOffset.current.y;
// Constrain within container // Constrain within container
const maxX = containerRect.width - visualizerRect.width; const maxX = containerRect.width - visualizerRect.width;
const maxY = containerRect.height - visualizerRect.height; const maxY = containerRect.height - visualizerRect.height;
// On mobile (width < 768px), status bar is hidden, so allow dragging to top (y=0) const statusBarHeight = 48; // h-12 = 48px
// On desktop, keep status bar height constraint (48px)
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
const minY = isMobile ? 0 : 48; // statusBarHeight = 48px
newX = Math.max(0, Math.min(newX, maxX)); newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(minY, Math.min(newY, maxY)); newY = Math.max(statusBarHeight, Math.min(newY, maxY));
setVisualizerPosition({ setVisualizerPosition({
x: newX, x: newX,
@ -134,14 +123,10 @@ export function PhoneSimulator({
if (isDragging) { if (isDragging) {
window.addEventListener("mouseup", handleDragEnd); window.addEventListener("mouseup", handleDragEnd);
window.addEventListener("mousemove", handleDragMove); window.addEventListener("mousemove", handleDragMove);
window.addEventListener("touchend", handleDragEnd);
window.addEventListener("touchmove", handleDragMove, { passive: false });
} }
return () => { return () => {
window.removeEventListener("mouseup", handleDragEnd); window.removeEventListener("mouseup", handleDragEnd);
window.removeEventListener("mousemove", handleDragMove); window.removeEventListener("mousemove", handleDragMove);
window.removeEventListener("touchend", handleDragEnd);
window.removeEventListener("touchmove", handleDragMove);
}; };
}, [isDragging]); }, [isDragging]);
@ -807,7 +792,7 @@ export function PhoneSimulator({
})(); })();
return ( return (
<div className="absolute inset-0 w-full h-full bg-black rounded-none border-0 overflow-hidden flex flex-col shrink-0 md:relative md:w-auto md:max-w-full md:h-full md:aspect-[9/19.5] md:max-h-full md:rounded-[40px] md:border-[12px] md:border-gray-900 md:shadow-2xl"> <div className="w-auto max-w-full h-full aspect-[9/19.5] max-h-full bg-black rounded-[40px] border-[12px] border-gray-900 overflow-hidden relative shadow-2xl flex flex-col shrink-0">
<style jsx global>{` <style jsx global>{`
.mirror-video video { .mirror-video video {
transform: scaleX(-1); transform: scaleX(-1);
@ -839,12 +824,7 @@ export function PhoneSimulator({
} }
`}</style> `}</style>
{/* Status Bar */} {/* Status Bar */}
<div className="hidden md:flex w-full bg-black/20 backdrop-blur-sm absolute top-0 left-0 z-50 items-center justify-between px-6 text-white text-xs font-medium" <div className="h-12 w-full bg-black/20 backdrop-blur-sm absolute top-0 left-0 z-50 flex items-center justify-between px-6 text-white text-xs font-medium">
style={{
paddingTop: 'max(env(safe-area-inset-top, 0px), 0.5rem)',
paddingBottom: '0.75rem',
minHeight: '3rem',
}}>
<span>{currentTime}</span> <span>{currentTime}</span>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<WifiIcon className="w-4 h-4" /> <WifiIcon className="w-4 h-4" />
@ -853,10 +833,7 @@ export function PhoneSimulator({
</div> </div>
{/* Main Content */} {/* Main Content */}
<div ref={phoneContainerRef} className="flex-grow relative bg-gray-950 w-full h-full overflow-hidden" <div ref={phoneContainerRef} className="flex-grow relative bg-gray-950 w-full h-full overflow-hidden">
style={{
paddingBottom: 'env(safe-area-inset-bottom, 0px)',
}}>
<div className={`h-full w-full transition-all duration-500 ease-in-out transform ${ <div className={`h-full w-full transition-all duration-500 ease-in-out transform ${
phoneMode === "hand_off" && roomState === ConnectionState.Connected phoneMode === "hand_off" && roomState === ConnectionState.Connected
? "blur-md scale-105" ? "blur-md scale-105"
@ -983,13 +960,12 @@ export function PhoneSimulator({
{roomState === ConnectionState.Connected && voiceAssistant.audioTrack && phoneMode !== "hand_off" && ( {roomState === ConnectionState.Connected && voiceAssistant.audioTrack && phoneMode !== "hand_off" && (
<div <div
ref={visualizerRef} ref={visualizerRef}
className="absolute z-50 p-2 bg-black/40 backdrop-blur-md rounded-lg border border-white/10 shadow-lg cursor-move select-none touch-none" className="absolute z-50 p-2 bg-black/40 backdrop-blur-md rounded-lg border border-white/10 shadow-lg cursor-move select-none"
style={{ style={{
left: visualizerPosition.x, left: visualizerPosition.x,
top: visualizerPosition.y, top: visualizerPosition.y,
}} }}
onMouseDown={handleDragStart} onMouseDown={handleDragStart}
onTouchStart={handleDragStart}
> >
<div className="h-8 w-24 flex items-center justify-center [--lk-va-bar-width:3px] [--lk-va-bar-gap:2px] [--lk-fg:white]"> <div className="h-8 w-24 flex items-center justify-center [--lk-va-bar-width:3px] [--lk-va-bar-gap:2px] [--lk-fg:white]">
<BarVisualizer <BarVisualizer
@ -1005,10 +981,7 @@ export function PhoneSimulator({
{/* Call Controls Overlay */} {/* Call Controls Overlay */}
{roomState === ConnectionState.Connected && ( {roomState === ConnectionState.Connected && (
phoneMode === "capture" ? ( phoneMode === "capture" ? (
<div className="absolute top-0 left-0 w-full h-full flex flex-col justify-end px-[8%] z-40" <div className="absolute top-0 left-0 w-full h-full flex flex-col justify-end pb-[5%] px-[8%] z-40">
style={{
paddingBottom: 'calc(5% + env(safe-area-inset-bottom, 0px))',
}}>
{/* Camera Controls Row */} {/* Camera Controls Row */}
<div className="w-full flex items-center justify-evenly mb-8"> <div className="w-full flex items-center justify-evenly mb-8">
{/* Left: Upload */} {/* Left: Upload */}
@ -1085,11 +1058,7 @@ export function PhoneSimulator({
</div> </div>
</div> </div>
) : ( ) : (
<div className="absolute bottom-[5%] left-0 w-full px-[8%] z-40" <div className="absolute bottom-[5%] left-0 w-full px-[8%] z-40">
style={{
paddingBottom: 'max(env(safe-area-inset-bottom, 0px), 0px)',
bottom: 'calc(5% + env(safe-area-inset-bottom, 0px))',
}}>
<div className="w-full flex flex-col items-center justify-center gap-4"> <div className="w-full flex flex-col items-center justify-center gap-4">
{/* Mode Toggle Switch */} {/* Mode Toggle Switch */}
{phoneMode !== "important_message" && phoneMode !== "hand_off" && voiceAssistant.agent && ( {phoneMode !== "important_message" && phoneMode !== "hand_off" && voiceAssistant.agent && (
@ -1157,7 +1126,7 @@ export function PhoneSimulator({
{phoneMode !== "important_message" && ( {phoneMode !== "important_message" && (
<button <button
ref={pushToTalkButtonRef} ref={pushToTalkButtonRef}
className={`w-24 h-24 rounded-full backdrop-blur-md transition-all flex flex-col items-center justify-center gap-2 aspect-square select-none ${ className={`w-24 h-24 rounded-full backdrop-blur-md transition-all flex flex-col items-center justify-center gap-2 aspect-square ${
interruptRejected interruptRejected
? "bg-red-500/70 text-white" ? "bg-red-500/70 text-white"
: isPushToTalkActive : isPushToTalkActive

View File

@ -45,7 +45,7 @@ export const PlaygroundTile: React.FC<PlaygroundTileProps> = ({
</div> </div>
)} )}
<div <div
className={`flex flex-col items-center grow w-full relative ${childrenClassName}`} className={`flex flex-col items-center grow w-full ${childrenClassName}`}
style={{ style={{
height: `calc(100% - ${title ? titleHeight + "px" : "0px"})`, height: `calc(100% - ${title ? titleHeight + "px" : "0px"})`,
padding: `${contentPadding * 4}px`, padding: `${contentPadding * 4}px`,
@ -74,7 +74,7 @@ export const PlaygroundTabbedTile: React.FC<PlaygroundTabbedTileProps> = ({
className={`flex flex-col h-full border rounded-sm border-gray-800 text-gray-500 bg-${backgroundColor} ${className}`} className={`flex flex-col h-full border rounded-sm border-gray-800 text-gray-500 bg-${backgroundColor} ${className}`}
> >
<div <div
className="flex items-center justify-start text-xs uppercase border-b border-b-gray-800 tracking-wider relative z-[100] bg-gray-950" className="flex items-center justify-start text-xs uppercase border-b border-b-gray-800 tracking-wider"
style={{ style={{
height: `${titleHeight}px`, height: `${titleHeight}px`,
}} }}

View File

@ -51,12 +51,3 @@ body {
opacity: 1; opacity: 1;
} }
} }
/* Hide Next.js floating dev indicator */
nextjs-portal,
#__next-build-watcher,
[data-nextjs-dialog],
[data-nextjs-toast],
div[style*="position: fixed"][style*="bottom"][style*="right"] {
display: none !important;
}