From c0e32b060d84e0730b232085f9e1c77e7520fdac Mon Sep 17 00:00:00 2001 From: 0xaudacity <147813840+Bighero0122@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:15:01 -0500 Subject: [PATCH 1/2] Revert "Revert "Rob 53 extending robot capabilities"" --- src/pages/Teleop.css | 239 ++++++++++++++++++++++++++++++++++++++++ src/pages/Teleop.tsx | 100 ++++++++++++++++- src/pages/UserSetup.css | 50 +++++++-- src/pages/UserSetup.tsx | 2 + tsconfig.tsbuildinfo | 1 - 5 files changed, 383 insertions(+), 9 deletions(-) delete mode 100644 tsconfig.tsbuildinfo diff --git a/src/pages/Teleop.css b/src/pages/Teleop.css index 177af59..9dbf7f3 100644 --- a/src/pages/Teleop.css +++ b/src/pages/Teleop.css @@ -618,6 +618,232 @@ html { font-size: 1rem; } +/* Camera Control Section */ + +.camera-controls-section { + background: rgba(255, 255, 255, 0.03); + border-radius: 12px; + padding: 1rem; + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.camera-controls-section .section-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1rem; +} + +.camera-controls-section .section-header h4 { + margin: 0; + color: #fff; + font-size: 0.95rem; + font-weight: 600; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.camera-controls-section .section-header h4 svg { + color: #ffc107; +} + +.camera-mode-toggle { + display: flex; + gap: 0.25rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 6px; + padding: 0.2rem; +} + +.mini-btn { + padding: 0.35rem 0.6rem; + font-size: 0.7rem; + font-weight: 600; + border: none; + border-radius: 4px; + background: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: pointer; + transition: all 0.2s; +} + +.mini-btn:hover { + color: rgba(255, 255, 255, 0.8); +} + +.mini-btn.active { + background: rgba(255, 193, 7, 0.2); + color: #ffc107; +} + +/* Camera D-Pad */ +.camera-manual-controls { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +.camera-dpad { + display: grid; + grid-template-areas: + ". up ." + "left center right" + ". down ."; + grid-template-columns: 48px 48px 48px; + grid-template-rows: 48px 48px 48px; + gap: 4px; +} + +.dpad-btn { + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 8px; + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: all 0.15s; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; +} + +.dpad-btn:hover { + background: rgba(255, 193, 7, 0.15); + border-color: rgba(255, 193, 7, 0.3); + color: #ffc107; +} + +.dpad-btn:active { + background: rgba(255, 193, 7, 0.3); + transform: scale(0.95); +} + +.dpad-btn.up { grid-area: up; } +.dpad-btn.down { grid-area: down; } +.dpad-btn.left { grid-area: left; } +.dpad-btn.right { grid-area: right; } + +.dpad-center { + grid-area: center; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 193, 7, 0.1); + border-radius: 50%; + color: rgba(255, 193, 7, 0.5); + font-size: 1rem; +} + +/* Zoom Controls */ +.zoom-controls { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 1rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 24px; +} + +.zoom-btn { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid rgba(255, 255, 255, 0.15); + background: rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.85rem; +} + +.zoom-btn:hover:not(:disabled) { + background: rgba(255, 193, 7, 0.15); + border-color: rgba(255, 193, 7, 0.3); + color: #ffc107; +} + +.zoom-btn:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.zoom-indicator { + min-width: 50px; + text-align: center; + font-weight: 700; + font-size: 0.95rem; + color: #ffc107; +} + +/* Camera Position Display */ +.camera-position { + display: flex; + gap: 1.5rem; +} + +.position-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.2rem; +} + +.pos-label { + font-size: 0.7rem; + color: rgba(255, 255, 255, 0.5); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.pos-value { + font-size: 0.85rem; + font-weight: 600; + color: #fff; +} + +/* Camera Reset Button */ +.camera-reset-btn { + padding: 0.5rem 1rem; + font-size: 0.8rem; + font-weight: 600; + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 6px; + background: rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.camera-reset-btn:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + color: #fff; +} + +/* Auto-Follow Mode Info */ +.camera-follow-info { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + padding: 1.5rem; + color: rgba(255, 255, 255, 0.6); + font-size: 0.85rem; +} + +.camera-follow-info svg { + color: #ffc107; + font-size: 1.2rem; +} + /* Responsive */ @media (max-width: 768px) { .security-indicator-banner { @@ -690,4 +916,17 @@ html { justify-content: center; } } + +@media (max-width: 768px) { + .camera-controls-section .section-header { + flex-direction: column; + gap: 0.75rem; + align-items: flex-start; + } + + .camera-dpad { + grid-template-columns: 44px 44px 44px; + grid-template-rows: 44px 44px 44px; + } +} \ No newline at end of file diff --git a/src/pages/Teleop.tsx b/src/pages/Teleop.tsx index fc40b67..7b9a410 100644 --- a/src/pages/Teleop.tsx +++ b/src/pages/Teleop.tsx @@ -14,7 +14,12 @@ import { faGamepad, faRightFromBracket, faCheckCircle, - faLock + faLock, + faCamera, + faSearchPlus, + faSearchMinus, + faExpand, + faRotate as faRotateBack } from '@fortawesome/free-solid-svg-icons'; import "./Teleop.css"; import { usePageTitle } from "../hooks/usePageTitle"; @@ -33,6 +38,11 @@ export default function Teleop() { const [gamepadDetected, setGamepadDetected] = useState(false); const sendIntervalMs = 100; // 10 Hz + const [cameraMode, setCameraMode] = useState<'manual' | 'follow'>('manual'); + const [cameraPan, setCameraPan] = useState(0); // -100 to 100 + const [cameraTilt, setCameraTilt] = useState(0); // -100 to 100 + const [cameraZoom, setCameraZoom] = useState(1); // 1x to 5x + // Read WebSocket URL from amplify_outputs.json (AWS signaling server) // Falls back to local WebSocket for development const wsUrl = outputs?.custom?.signaling?.websocketUrl @@ -410,6 +420,94 @@ export default function Teleop() { +