@@ -2,12 +2,13 @@ import * as React from 'react';
22import { keyframes } from '@emotion/react' ;
33import type { FileWithHandle } from 'browser-fs-access' ;
44
5- import { Box , Button , Checkbox , ColorPaletteProp , Divider , Dropdown , IconButton , ListItem , ListItemDecorator , Menu , MenuButton , MenuItem } from '@mui/joy' ;
5+ import { Box , Button , Checkbox , ColorPaletteProp , Dropdown , IconButton , ListDivider , ListItem , ListItemDecorator , Menu , MenuButton , MenuItem } from '@mui/joy' ;
66import AddRoundedIcon from '@mui/icons-material/AddRounded' ;
77import AddToDriveRoundedIcon from '@mui/icons-material/AddToDriveRounded' ;
88import AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded' ;
99import CameraAltOutlinedIcon from '@mui/icons-material/CameraAltOutlined' ;
1010import ContentPasteGoIcon from '@mui/icons-material/ContentPasteGo' ;
11+ import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord' ;
1112import LanguageRoundedIcon from '@mui/icons-material/LanguageRounded' ;
1213import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor' ;
1314
@@ -35,10 +36,11 @@ const animationMenuItem = keyframes` from {opacity: 0;transform: translateY(-6px
3536
3637const _style = {
3738 menuItem : {
38- py : 1 ,
3939 // pl: 3,
4040 // pr: 2,
41+ py : 0.5 , // was 1
4142 minHeight : 60 ,
43+ // minHeight: '3.25rem', // now 52, was 60
4244 } as const ,
4345 menuItemContent : {
4446 display : 'flex' ,
@@ -58,6 +60,24 @@ const _style = {
5860} ;
5961
6062
63+ // Live feed record button - returns null if onClick is undefined
64+ function LiveFeedButton ( props : { isActive : boolean , onClick : ( ) => void } ) {
65+ return (
66+ < IconButton
67+ size = 'sm'
68+ variant = { props . isActive ? 'solid' : 'soft' }
69+ color = 'danger'
70+ onClick = { ( e ) => {
71+ e . stopPropagation ( ) ;
72+ props . onClick ( ) ;
73+ } }
74+ >
75+ < FiberManualRecordIcon sx = { { fontSize : 16 } } />
76+ </ IconButton >
77+ ) ;
78+ }
79+
80+
6181// Rich menu item (used in menu-rich mode)
6282function RichMenuItem ( props : {
6383 name : React . ReactNode ;
@@ -67,6 +87,7 @@ function RichMenuItem(props: {
6787 delay ?: number ;
6888 disabled ?: boolean ;
6989 color ?: ColorPaletteProp ;
90+ endAction ?: React . ReactNode ;
7091} ) {
7192 return (
7293 < MenuItem
@@ -89,6 +110,11 @@ function RichMenuItem(props: {
89110 { props . description }
90111 </ Box >
91112 </ Box >
113+ { props . endAction && (
114+ < Box sx = { { ml : 'auto' , display : 'flex' , alignItems : 'center' } } >
115+ { props . endAction }
116+ </ Box >
117+ ) }
92118 </ MenuItem >
93119 ) ;
94120}
@@ -107,7 +133,7 @@ function AutoDownloadToggle(props: { delay?: number }) {
107133
108134 return < >
109135
110- < Divider sx = { { my : 0.5 } } />
136+ < ListDivider inset = 'gutter' sx = { { my : 1 } } />
111137
112138 < ListItem
113139 sx = { {
@@ -165,6 +191,11 @@ function AttachmentSources(props: {
165191 hasScreenCapture : boolean ,
166192 // configuration
167193 onlyImages ?: boolean , // makes clipboard/drive/web unavailable
194+ // live feeds - end action buttons (presence if the callback is set, active state if the boolean is true)
195+ hasActiveCameraFeed ?: boolean ,
196+ hasActiveScreenFeed ?: boolean ,
197+ onStartLiveCameraFeed ?: ( ) => void ,
198+ onStartLiveScreenFeed ?: ( ) => void ,
168199 // callbacks
169200 onAttachClipboard : ( ) => void ,
170201 onAttachFiles : ( files : FileWithHandle [ ] , errorMessage : string | null ) => void ,
@@ -299,7 +330,15 @@ function AttachmentSources(props: {
299330 // <ListItemDecorator><ScreenshotMonitorIcon /></ListItemDecorator>
300331 // Screen
301332 // </MenuItem>
302- < RichMenuItem name = 'Screen' description = { screenCaptureError ? `Error: ${ screenCaptureError } ` : 'Capture windows, tabs, or screens' } color = { screenCaptureError ? 'danger' : props . color } icon = { < ScreenshotMonitorIcon /> } onClick = { handleTakeScreenCapture } disabled = { capturingScreen } />
333+ < RichMenuItem
334+ name = 'Screen'
335+ color = { screenCaptureError ? 'danger' : props . color }
336+ description = { screenCaptureError ? `Error: ${ screenCaptureError } ` : 'Capture tabs, apps, and screens' }
337+ icon = { < ScreenshotMonitorIcon /> }
338+ disabled = { capturingScreen }
339+ onClick = { handleTakeScreenCapture }
340+ endAction = { ! isMessage && props . onStartLiveScreenFeed && < LiveFeedButton isActive = { ! ! props . hasActiveScreenFeed } onClick = { props . onStartLiveScreenFeed } /> }
341+ />
303342 ) }
304343
305344 { /* Camera */ }
@@ -308,7 +347,14 @@ function AttachmentSources(props: {
308347 // <ListItemDecorator><CameraAltOutlinedIcon /></ListItemDecorator>
309348 // Camera
310349 // </MenuItem>
311- < RichMenuItem name = 'Camera' description = 'Capture photos and optional OCR' color = { props . color } icon = { < CameraAltOutlinedIcon /> } onClick = { props . onOpenCamera } />
350+ < RichMenuItem
351+ name = 'Camera'
352+ color = { props . color }
353+ icon = { < CameraAltOutlinedIcon /> }
354+ description = 'Capture photos with optional OCR'
355+ onClick = { props . onOpenCamera }
356+ endAction = { ! isMessage && props . onStartLiveCameraFeed && < LiveFeedButton isActive = { ! ! props . hasActiveCameraFeed } onClick = { props . onStartLiveCameraFeed } /> }
357+ />
312358 ) }
313359
314360 </ Menu >
@@ -412,25 +458,51 @@ function AttachmentSources(props: {
412458 < RichMenuItem
413459 name = 'Clipboard'
414460 icon = { < ContentPasteGoIcon /> }
415- description = 'Auto-converts images and text to the best format'
461+ // description='Auto-converts images and text to the best format'
462+ description = 'Auto-adapts images and text'
416463 onClick = { props . onAttachClipboard }
417464 delay = { 0.06 }
418465 />
419466 ) }
420467
468+ { /*{!props.onlyImages && props.canBrowse && (*/ }
469+ { /* <ListItem>*/ }
470+ { /* <ListItemDecorator />*/ }
471+ { /* <Checkbox*/ }
472+ { /* size='sm'*/ }
473+ { /* color='neutral'*/ }
474+ { /* // checked={enableComposerAttach}*/ }
475+ { /* // onChange={handleToggle}*/ }
476+ { /* onClick={(event) => event.stopPropagation()}*/ }
477+ { /* sx={{ ml: 0.375 }}*/ }
478+ { /* slotProps={{*/ }
479+ { /* label: {*/ }
480+ { /* sx: {*/ }
481+ { /* fontSize: 'sm',*/ }
482+ { /* fontWeight: 'md',*/ }
483+ { /* },*/ }
484+ { /* },*/ }
485+ { /* }}*/ }
486+ { /* label='Download and attach links'*/ }
487+ { /* />*/ }
488+ { /* </ListItem>*/ }
489+ { /*)}*/ }
490+
491+
421492 { /* Divider before labs features */ }
422- { ( props . hasScreenCapture || props . hasCamera ) && < Divider sx = { { my : 0.5 } } /> }
493+ { ( props . hasScreenCapture || props . hasCamera ) && < ListDivider inset = 'gutter' sx = { { my : 1 } } /> }
423494
424495 { /* Screen Capture */ }
425496 { props . hasScreenCapture && (
426497 < RichMenuItem
427498 name = 'Screen'
428499 icon = { < ScreenshotMonitorIcon /> }
429- description = { screenCaptureError ? `Error: ${ screenCaptureError } ` : 'Capture windows, tabs, or screens' }
500+ description = { screenCaptureError ? `Error: ${ screenCaptureError } ` : 'Capture tabs, apps, and screens' }
430501 onClick = { handleTakeScreenCapture }
431502 disabled = { capturingScreen }
432503 color = { screenCaptureError ? 'danger' : undefined }
433504 delay = { 0.08 }
505+ endAction = { props . onStartLiveScreenFeed && < LiveFeedButton isActive = { ! ! props . hasActiveScreenFeed } onClick = { props . onStartLiveScreenFeed } /> }
434506 />
435507 ) }
436508
@@ -439,9 +511,10 @@ function AttachmentSources(props: {
439511 < RichMenuItem
440512 name = 'Camera'
441513 icon = { < CameraAltOutlinedIcon /> }
442- description = 'Capture photos with optional text recognition '
514+ description = 'Capture photos with optional OCR '
443515 onClick = { props . onOpenCamera }
444516 delay = { 0.1 }
517+ endAction = { props . onStartLiveCameraFeed && < LiveFeedButton isActive = { ! ! props . hasActiveCameraFeed } onClick = { props . onStartLiveCameraFeed } /> }
445518 />
446519 ) }
447520
0 commit comments