From 7e42164c5c19d9d7699c09c389836af90a1b67e7 Mon Sep 17 00:00:00 2001 From: Benoit Date: Sat, 23 May 2026 10:17:29 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20int=C3=A9gration=20VU-m=C3=A8tre=20circ?= =?UTF-8?q?ulaire=20autour=20du=20bouton=20PTT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NOUVEAU DESIGN : - VU-mètre transformé en anneau SVG autour du bouton PTT - Cercle progressif (0-360°) selon le niveau audio - Couleurs dynamiques selon le niveau : - Vert (0-75%) : audio normal - Orange (75-90%) : niveau élevé - Rouge (90-100%) : saturation/danger avec effet glow - Bleu : mode talking (micro actif) AVANTAGES : - Beaucoup plus discret et élégant - Intégré visuellement au bouton principal - Pas d'encombrement UI supplémentaire - Contextuellement pertinent (niveau autour du contrôle) TECHNIQUE : - SVG avec stroke-dasharray pour l'arc progressif - Transition fluide 0.1s sur le niveau - Drop-shadow dynamique selon couleur - Responsive (adapté mobile/paysage) - z-index stratifié (anneau derrière, bouton devant) SUPPRESSION : - Ancien composant AudioIndicator.jsx retiré de App.jsx - Garde plus d'espace pour UserList et GroupSelector 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- client/src/App.jsx | 7 +-- client/src/components/PTTButton.css | 29 +++++++++++ client/src/components/PTTButton.jsx | 79 +++++++++++++++++++++++++---- 3 files changed, 100 insertions(+), 15 deletions(-) diff --git a/client/src/App.jsx b/client/src/App.jsx index 54be3a2..2e64284 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -2,7 +2,6 @@ import { useState, useEffect } from 'react'; import useLiveKit from './hooks/useLiveKit'; import PTTButton from './components/PTTButton'; import UserList from './components/UserList'; -import AudioIndicator from './components/AudioIndicator'; import GroupSelector from './components/GroupSelector'; import './App.css'; @@ -241,14 +240,12 @@ function App() { {/* Liste des participants */} - {/* Indicateur audio */} - - - {/* Bouton PTT principal */} + {/* Bouton PTT principal avec VU-mètre intégré */} diff --git a/client/src/components/PTTButton.css b/client/src/components/PTTButton.css index b550045..6bd0525 100644 --- a/client/src/components/PTTButton.css +++ b/client/src/components/PTTButton.css @@ -11,6 +11,24 @@ position: relative; } +/* Wrapper bouton + anneau VU-mètre */ +.ptt-button-wrapper { + position: relative; + display: flex; + align-items: center; + justify-content: center; +} + +/* Anneau VU-mètre (SVG) */ +.audio-ring { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 0; +} + .ptt-button { width: 240px; height: 240px; @@ -27,6 +45,7 @@ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); position: relative; overflow: hidden; + z-index: 1; /* Au-dessus de l'anneau */ /* Mobile touch optimizations */ touch-action: none; @@ -189,6 +208,11 @@ height: 200px; } + .audio-ring { + width: 240px; + height: 240px; + } + .ptt-icon { width: 56px; height: 56px; @@ -210,6 +234,11 @@ height: 160px; } + .audio-ring { + width: 200px; + height: 200px; + } + .ptt-icon { width: 48px; height: 48px; diff --git a/client/src/components/PTTButton.jsx b/client/src/components/PTTButton.jsx index bf977c9..2d1e5b8 100644 --- a/client/src/components/PTTButton.jsx +++ b/client/src/components/PTTButton.jsx @@ -7,8 +7,9 @@ import './PTTButton.css'; * Modes : * - PTT classique : maintenir pour parler * - Mode continu (lock) : glisser vers le haut pendant qu'on parle + * Inclut VU-mètre intégré (anneau autour du bouton) */ -export default function PTTButton({ isTalking, onPressStart, onPressEnd }) { +export default function PTTButton({ isTalking, onPressStart, onPressEnd, audioLevel = 0 }) { const buttonRef = useRef(null); const isPressingRef = useRef(false); const [isLockMode, setIsLockMode] = useState(false); @@ -241,6 +242,25 @@ export default function PTTButton({ isTalking, onPressStart, onPressEnd }) { } }; + // Calculer le niveau audio normalisé (0-100) + const normalizedLevel = Math.min(100, Math.max(0, audioLevel)); + + // Convertir le niveau en angle pour le cercle SVG (0-360°) + const levelAngle = (normalizedLevel / 100) * 360; + + // Calculer le dasharray pour l'arc SVG + const radius = 130; // Rayon du cercle VU-mètre + const circumference = 2 * Math.PI * radius; + const dashOffset = circumference - (levelAngle / 360) * circumference; + + // Déterminer la couleur selon le niveau + const getAudioColor = () => { + if (normalizedLevel > 90) return '#ef4444'; // Danger (rouge) + if (normalizedLevel > 75) return '#f59e0b'; // Warning (orange) + if (isTalking) return '#3b82f6'; // Talking (bleu) + return '#10b981'; // Normal (vert) + }; + return (
{/* Zone de drag vers le haut (indicateur visuel) */} @@ -253,15 +273,53 @@ export default function PTTButton({ isTalking, onPressStart, onPressEnd }) {
)} - {/* Bouton PTT principal */} - +

{isLockMode