update ui
1 changed file+149−19
src/App.tsxmodified+149−19View file
@@ -39,21 +39,109 @@ const disabledStyle: React.CSSProperties = {
3939 cursor: 'not-allowed'
4040 }
4141
42-// A mute/cam-off button while its mute is engaged.
43-const engagedBtn: React.CSSProperties = {
42+// Square icon-only buttons for the in-call bar. Their meaning is carried by
43+// the icon plus a title tooltip and aria-label.
44+const iconBtn: React.CSSProperties = {
4445 ...btn,
46+ padding: '0.45rem',
47+ display: 'inline-flex',
48+ alignItems: 'center',
49+ justifyContent: 'center'
50+}
51+
52+// An icon button whose state is engaged (muted / sharing).
53+const engagedIconBtn: React.CSSProperties = {
54+ ...iconBtn,
4555 background: '#555',
4656 borderColor: '#555',
4757 color: '#fff'
4858 }
4959
60+const dangerIconBtn: React.CSSProperties = {
61+ ...iconBtn,
62+ background: '#c62828',
63+ borderColor: '#c62828',
64+ color: '#fff'
65+}
66+
5067 // Badge overlaid on the remote video reporting the other party's mute state.
5168 const muteChip: React.CSSProperties = {
5269 background: 'rgba(0, 0, 0, 0.65)',
5370 color: '#fff',
5471 borderRadius: 999,
55- padding: '0.15rem 0.6rem',
56- fontSize: '0.8rem'
72+ padding: '0.3rem',
73+ display: 'inline-flex',
74+ alignItems: 'center'
75+}
76+
77+// Stroke-style icon paths (Feather icons, MIT), drawn with currentColor.
78+const ICONS = {
79+ mic: (
80+ <>
81+ <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
82+ <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
83+ <path d="M12 19v4" />
84+ <path d="M8 23h8" />
85+ </>
86+ ),
87+ micOff: (
88+ <>
89+ <path d="M1 1l22 22" />
90+ <path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6" />
91+ <path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23" />
92+ <path d="M12 19v4" />
93+ <path d="M8 23h8" />
94+ </>
95+ ),
96+ video: (
97+ <>
98+ <path d="M23 7l-7 5 7 5V7z" />
99+ <rect x="1" y="5" width="15" height="14" rx="2" />
100+ </>
101+ ),
102+ videoOff: (
103+ <>
104+ <path d="M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10" />
105+ <path d="M1 1l22 22" />
106+ </>
107+ ),
108+ monitor: (
109+ <>
110+ <rect x="2" y="3" width="20" height="14" rx="2" />
111+ <path d="M8 21h8" />
112+ <path d="M12 17v4" />
113+ </>
114+ ),
115+ phone: (
116+ <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" />
117+ )
118+} as const
119+
120+function Icon({
121+ name,
122+ size = 18,
123+ style
124+}: {
125+ name: keyof typeof ICONS
126+ size?: number
127+ style?: React.CSSProperties
128+}) {
129+ return (
130+ <svg
131+ width={size}
132+ height={size}
133+ viewBox="0 0 24 24"
134+ fill="none"
135+ stroke="currentColor"
136+ strokeWidth={2}
137+ strokeLinecap="round"
138+ strokeLinejoin="round"
139+ style={{display: 'block', ...style}}
140+ aria-hidden
141+ >
142+ {ICONS[name]}
143+ </svg>
144+ )
57145 }
58146
59147 function VideoView({
@@ -234,8 +322,22 @@ export default function App() {
234322 gap: '0.4rem'
235323 }}
236324 >
237- {call.peerAudioMuted && <span style={muteChip}>mic muted</span>}
238- {call.peerVideoMuted && <span style={muteChip}>camera off</span>}
325+ {call.peerAudioMuted && (
326+ <span
327+ style={muteChip}
328+ title={`${call.peerName} muted their microphone`}
329+ >
330+ <Icon name="micOff" size={14} />
331+ </span>
332+ )}
333+ {call.peerVideoMuted && (
334+ <span
335+ style={muteChip}
336+ title={`${call.peerName} turned their camera off`}
337+ >
338+ <Icon name="videoOff" size={14} />
339+ </span>
340+ )}
239341 </div>
240342 )}
241343 <VideoView
@@ -273,18 +375,27 @@ export default function App() {
273375 </span>
274376 <button
275377 style={{
276- ...(call.audioMuted ? engagedBtn : btn),
378+ ...(call.audioMuted ? engagedIconBtn : iconBtn),
277379 ...(call.localStream ? null : disabledStyle)
278380 }}
279381 disabled={!call.localStream}
280- title={call.audioMuted ? 'Unmute your microphone' : 'Mute your microphone'}
382+ title={
383+ call.audioMuted
384+ ? 'Unmute your microphone'
385+ : 'Mute your microphone'
386+ }
387+ aria-label={
388+ call.audioMuted
389+ ? 'Unmute your microphone'
390+ : 'Mute your microphone'
391+ }
281392 onClick={() => network.setAudioMuted(!call.audioMuted)}
282393 >
283- {call.audioMuted ? 'Unmute' : 'Mute'}
394+ <Icon name={call.audioMuted ? 'micOff' : 'mic'} />
284395 </button>
285396 <button
286397 style={{
287- ...(call.videoMuted ? engagedBtn : btn),
398+ ...(call.videoMuted ? engagedIconBtn : iconBtn),
288399 ...(call.localStream ? null : disabledStyle)
289400 }}
290401 disabled={!call.localStream}
@@ -293,9 +404,14 @@ export default function App() {
293404 ? 'Turn your camera back on'
294405 : 'Turn your camera off'
295406 }
407+ aria-label={
408+ call.videoMuted
409+ ? 'Turn your camera back on'
410+ : 'Turn your camera off'
411+ }
296412 onClick={() => network.setVideoMuted(!call.videoMuted)}
297413 >
298- {call.videoMuted ? 'Cam on' : 'Cam off'}
414+ <Icon name={call.videoMuted ? 'videoOff' : 'video'} />
299415 </button>
300416 <label
301417 title="Video quality for both directions — either of you can change it"
@@ -331,23 +447,37 @@ export default function App() {
331447 </label>
332448 {canShareScreen && (
333449 <button
334- style={
335- call.phase === 'connected'
336- ? btn
337- : {...btn, ...disabledStyle}
338- }
450+ style={{
451+ ...(call.screenStream ? engagedIconBtn : iconBtn),
452+ ...(call.phase === 'connected' ? null : disabledStyle)
453+ }}
339454 disabled={call.phase !== 'connected'}
455+ title={
456+ call.screenStream
457+ ? 'Stop sharing your screen'
458+ : 'Share your screen'
459+ }
460+ aria-label={
461+ call.screenStream
462+ ? 'Stop sharing your screen'
463+ : 'Share your screen'
464+ }
340465 onClick={() =>
341466 call.screenStream
342467 ? void network.stopScreenShare()
343468 : void network.startScreenShare()
344469 }
345470 >
346- {call.screenStream ? 'Stop sharing' : 'Share screen'}
471+ <Icon name="monitor" />
347472 </button>
348473 )}
349- <button style={dangerBtn} onClick={() => network.endCall()}>
350- Hang up
474+ <button
475+ style={dangerIconBtn}
476+ title="Hang up"
477+ aria-label="Hang up"
478+ onClick={() => network.endCall()}
479+ >
480+ <Icon name="phone" style={{transform: 'rotate(135deg)'}} />
351481 </button>
352482 </div>
353483 </section>