LiveFile: message

This commit is contained in:
Enrico Ros
2024-07-22 16:19:26 -07:00
parent 7639eaa942
commit c2cd098003
6 changed files with 106 additions and 32 deletions
@@ -19,7 +19,8 @@ import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import { RenderImageURL } from '~/modules/blocks/image/RenderImageURL';
import { GoodTooltip } from '~/common/components/GoodTooltip';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcon';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcons';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
import { ellipsizeFront, ellipsizeMiddle } from '~/common/util/textUtils';
import { liveFileInAttachmentFragment } from '~/common/livefile/liveFile';
@@ -139,9 +140,13 @@ function attachmentIcons(attachmentDraft: AttachmentDraft): React.ReactNode {
{/*))}*/}
{/*{activeConterters.some(c => c.id.startsWith('url-page-')) ? <LanguageIcon sx={{ opacity: 0.2, ml: -2.5 }} /> : null}*/}
{activeConterters.map(c => {
const Icon = converterTypeToIconMap[c.id] ?? null;
return Icon ? <Icon key={c.id} sx={{ width: 20, height: 20 }} /> : null;
{activeConterters.map((_converter, idx) => {
const Icon = converterTypeToIconMap[_converter.id] ?? null;
return !Icon ? null : (
<TooltipOutlined key={`${_converter.id}-${idx}`} title={`Attached as ${_converter.name}`} placement='top-start'>
<Icon sx={{ width: 20, height: 20 }} />
</TooltipOutlined>
);
})}
</Typography>;
}
@@ -264,7 +269,11 @@ export function LLMAttachmentButton(props: {
{isOutputLoading && <CircularProgress color='success' size='sm' />}
{/* Live file icon */}
{hasLiveFile && <LiveFileIcon />}
{hasLiveFile && (
<TooltipOutlined title='LiveFile is supported' placement='top-end'>
<LiveFileIcon />
</TooltipOutlined>
)}
</>}
</Button>
)}
@@ -14,7 +14,7 @@ import { showImageDataRefInNewTab } from '~/modules/blocks/image/RenderImageRefD
import { CloseableMenu } from '~/common/components/CloseableMenu';
import { DMessageAttachmentFragment, isDocPart, isImageRefPart } from '~/common/stores/chat/chat.fragments';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcon';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcons';
import { copyToClipboard } from '~/common/util/clipboardUtils';
import { liveFileInAttachmentFragment } from '~/common/livefile/liveFile';
import { showImageDataURLInNewTab } from '~/common/util/imageUtils';
@@ -184,12 +184,6 @@ export function LLMAttachmentMenu(props: {
</Typography>
) : (
<Box sx={{ my: 0.5 }}>
{/* LiveFile notice */}
{hasLiveFile && !!draftInput && (
<Typography level='body-sm' sx={{ mb: 1 }} startDecorator={<LiveFileIcon sx={{ width: 16, height: 16 }} />}>
LiveFile is supported
</Typography>
)}
{/* <- inputs */}
{!!draftInput && (
@@ -271,6 +265,14 @@ export function LLMAttachmentMenu(props: {
</Typography>
)}
</Box>
{/* LiveFile notice */}
{hasLiveFile && !!draftInput && (
<Typography level='body-sm' sx={{ mt: 1 }} startDecorator={<LiveFileIcon sx={{ width: 16, height: 16 }} />}>
LiveFile is supported
</Typography>
)}
</Box>
)}
</MenuItem>
@@ -1,7 +1,7 @@
import * as React from 'react';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, Button, ColorPaletteProp, Tooltip } from '@mui/joy';
import { Box, Button, ColorPaletteProp } from '@mui/joy';
import AbcIcon from '@mui/icons-material/Abc';
import CodeIcon from '@mui/icons-material/Code';
import ExpandCircleDownIcon from '@mui/icons-material/ExpandCircleDown';
@@ -13,7 +13,8 @@ import TextureIcon from '@mui/icons-material/Texture';
import { ContentScaling, themeScalingMap } from '~/common/app.theme';
import { DMessageAttachmentFragment, DMessageFragmentId, isDocPart } from '~/common/stores/chat/chat.fragments';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcon';
import { LiveFileIcon } from '~/common/livefile/LiveFileIcons';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
import { ellipsizeMiddle } from '~/common/util/textUtils';
import { liveFileInAttachmentFragment } from '~/common/livefile/liveFile';
@@ -124,9 +125,9 @@ export function DocAttachmentFragmentButton(props: {
{/*</Box>*/}
</Box>
{liveFileInAttachmentFragment(fragment) && (
<Tooltip color='success' disableInteractive title='Supports LiveFile' placement='top-end' arrow>
<TooltipOutlined title='LiveFile is supported' color='success' placement='top-end'>
<LiveFileIcon color={isSelected ? undefined : 'success'} sx={{ mr: '0.5rem' }} />
</Tooltip>
</TooltipOutlined>
)}
</Button>
);
@@ -2,12 +2,13 @@ import * as React from 'react';
import { fileOpen } from 'browser-fs-access';
import { cleanupEfficiency, makeDiff } from '@sanity/diff-match-patch';
import { Alert, Box, Button, CircularProgress, ColorPaletteProp, IconButton, Tooltip } from '@mui/joy';
import { Alert, Box, Button, CircularProgress, ColorPaletteProp, IconButton } from '@mui/joy';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import type { DMessageAttachmentFragment } from '~/common/stores/chat/chat.fragments';
import { LiveFileIcon, LiveFileReloadIcon, LiveFileSaveIcon } from '~/common/livefile/LiveFileIcon';
import { LiveFileChooseIcon, LiveFileIcon, LiveFileReloadIcon, LiveFileSaveIcon } from '~/common/livefile/LiveFileIcons';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
import { liveFileCreate } from '~/common/livefile/liveFile';
@@ -155,19 +156,37 @@ export function useLiveFile(
const liveFileSyncButton = React.useMemo(() => (
<Tooltip disableInteractive enterDelay={600} arrow color={isPreviewMode ? 'primary' : 'success'} placement='top-end' title={!fileSystemFileHandle ? 'Setup LiveFile file association' : <>LiveFile connected.<br />Click to compare with file content.</>}>
<TooltipOutlined
title={
isPreviewMode ? 'Click to update the comparison.'
: fileSystemFileHandle ? 'Click compare with the File contents.'
: 'Setup LiveFile association.'
}
color={isPreviewMode ? 'primary' : 'success'}
variant={isPreviewMode ? undefined : 'solid'}
placement='top-end'
>
<Button
variant='soft'
color={isPreviewMode ? 'primary' : 'success'}
size='sm'
disabled={isWorking}
onClick={handleSyncButtonClick}
startDecorator={isPreviewMode ? <LiveFileIcon /> : (isWorking ? <CircularProgress sx={{ '--CircularProgress-size': '16px' }} /> : <LiveFileIcon />)}
startDecorator={
isPreviewMode ? <LiveFileIcon />
: (isWorking ? <CircularProgress sx={{ '--CircularProgress-size': '16px' }} />
: fileSystemFileHandle ? <LiveFileIcon />
: <LiveFileChooseIcon />)
}
aria-label={fileSystemFileHandle ? 'Sync File' : 'Choose File'}
>
{isPreviewMode ? 'Refresh' : (fileSystemFileHandle ? 'Sync File' : 'Choose File')}
{
isPreviewMode ? 'Refresh'
: fileSystemFileHandle ? 'Sync File'
: 'Pair File'
}
</Button>
</Tooltip>
</TooltipOutlined>
), [fileSystemFileHandle, handleSyncButtonClick, isPreviewMode, isWorking]);
@@ -195,7 +214,7 @@ export function useLiveFile(
>
<Box sx={{ display: 'flex', gap: 0.5, alignItems: 'center' }}>
{isPreviewMode && !!fileSystemFileHandle && (
<IconButton size='sm' color={statusColor} onClick={handleSyncButtonClick}>
<IconButton size='sm' onClick={handleSyncButtonClick}>
<LiveFileIcon />
</IconButton>
)}
@@ -204,9 +223,10 @@ export function useLiveFile(
<Box sx={{ ml: 'auto', display: 'flex', gap: 1 }}>
{/* Load from File */}
{(diffSummary && (diffSummary.insertions > 0 || diffSummary.deletions > 0)) && (
<Button
variant='plain'
variant={isMobile ? 'outlined' : 'plain'}
color='primary'
size='sm'
disabled={isWorking}
@@ -214,12 +234,14 @@ export function useLiveFile(
startDecorator={<LiveFileReloadIcon />}
aria-label='Load content from disk'
>
{isMobile ? 'Load File' : 'Load from File'}
{isMobile ? 'Update' : 'Load from File'}
</Button>
)}
{/* Save to File */}
{(diffSummary && (diffSummary.insertions > 0 || diffSummary.deletions > 0)) && (
<Button
variant='plain'
variant={isMobile ? 'outlined' : 'plain'}
color='danger'
size='sm'
disabled={isWorking}
@@ -227,14 +249,23 @@ export function useLiveFile(
startDecorator={<LiveFileSaveIcon />}
aria-label='Save content to disk'
>
{isMobile ? 'Save File' : 'Save to File'}
{isMobile ? 'Save' : 'Save to File'}
</Button>
)}
{/* Reassign File button */}
<TooltipOutlined title='Pair a different File.' placement='top-end'>
<IconButton size='sm' onClick={associateAndPreviewFile}>
<LiveFileChooseIcon />
</IconButton>
</TooltipOutlined>
{/* Close button */}
<IconButton size='sm' color={statusColor} onClick={resetState}>
<CloseRoundedIcon />
</IconButton>
<TooltipOutlined title='Close LiveFile.' placement='top-end'>
<IconButton size='sm' onClick={resetState}>
<CloseRoundedIcon />
</IconButton>
</TooltipOutlined>
</Box>
</Alert>
);
+25
View File
@@ -0,0 +1,25 @@
import * as React from 'react';
import { Tooltip, TooltipProps } from '@mui/joy';
export function TooltipOutlined(props: {
title: React.ReactNode;
color?: TooltipProps['color'];
variant?: TooltipProps['variant'];
placement?: TooltipProps['placement'];
children: React.JSX.Element;
}) {
return (
<Tooltip
title={props.title}
color={props.color}
variant={props.variant ?? 'outlined'}
arrow
disableInteractive
placement={props.placement ?? 'top'}
>
{props.children}
</Tooltip>
);
}
@@ -1,7 +1,13 @@
import { styled } from '@mui/joy';
import FileOpenOutlinedIcon from '@mui/icons-material/FileOpenOutlined';
import MultipleStopIcon from '@mui/icons-material/MultipleStop';
import SystemUpdateAltIcon from '@mui/icons-material/SystemUpdateAlt';
import UploadFileIcon from '@mui/icons-material/UploadFile';
export { MultipleStopIcon as LiveFileIcon };
export { UploadFileIcon as LiveFileSaveIcon };
export const LiveFileIcon = styled(MultipleStopIcon)({
rotate: '90deg',
});
export { FileOpenOutlinedIcon as LiveFileChooseIcon };
export { SystemUpdateAltIcon as LiveFileReloadIcon };
export { UploadFileIcon as LiveFileSaveIcon };