EnhancedRenderCode x LiveFileSync: extract WorkspaceLiveFilePicker

This commit is contained in:
Enrico Ros
2024-08-13 01:46:24 -07:00
parent f99c266255
commit 04938c80f2
2 changed files with 117 additions and 70 deletions
@@ -0,0 +1,106 @@
import * as React from 'react';
import { Box, Dropdown, IconButton, ListDivider, ListItemDecorator, Menu, MenuButton, MenuItem } from '@mui/joy';
import CodeIcon from '@mui/icons-material/Code';
import type { LiveFileId, LiveFileMetadata } from '~/common/livefile/liveFile.types';
import { LiveFilePatchIcon } from '~/common/components/icons/LiveFilePatchIcon';
import { useContextWorkspaceId } from '~/common/stores/workspace/WorkspaceIdProvider';
import { useWorkspaceContentsMetadata } from '~/common/stores/workspace/useWorkspaceContentsMetadata';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
/**
* Allows selection of LiveFiles in the current Workspace
*/
export function WorkspaceLiveFilePicker(props: {
enabled: boolean;
autoSelectName: string | null;
liveFileId: LiveFileId | null;
onSelectLiveFile: (id: LiveFileId | null) => void;
}) {
// external state
const workspaceId = useContextWorkspaceId();
const { liveFilesMetadata: wLiveFiles } = useWorkspaceContentsMetadata(props.enabled ? workspaceId : null);
// set as disabled when empty
const enabled = wLiveFiles.length > 0;
const { autoSelectName, liveFileId, onSelectLiveFile } = props;
// [effect] auto-select a LiveFileId
React.useEffect(() => {
if (!enabled || !wLiveFiles.length)
return;
if (wLiveFiles.length === 1) {
// auto-select the only LiveFile
onSelectLiveFile(wLiveFiles[0].id);
} else {
// auto-select by name
const lfm = wLiveFiles.find(lfm => lfm.name === autoSelectName);
if (lfm)
onSelectLiveFile(lfm.id);
}
}, [enabled, wLiveFiles, autoSelectName, onSelectLiveFile]);
return (
<Dropdown>
{/* Activation button */}
<TooltipOutlined color='success' title='Select a LiveFile to patch' placement='top-end'>
<MenuButton
aria-label='Pair File'
slots={{ root: IconButton }}
slotProps={{
root: {
color: liveFileId ? 'success' : undefined,
// variant: liveFileId ? undefined : undefined,
size: 'sm',
},
}}
sx={{
ml: 'auto',
}}
>
<LiveFilePatchIcon />
</MenuButton>
</TooltipOutlined>
{/* List of the Workspace LiveFiles to pair */}
<Menu
placement='bottom-start'
sx={{
minWidth: 200,
zIndex: 'var(--joy-zIndex-modal)', /* on top of its own modal in FS */
}}
>
{/*<ListItem>*/}
{/* <Typography level='body-sm'>Recent Workspace Files</Typography>*/}
{/*</ListItem>*/}
{wLiveFiles.map((lfm: LiveFileMetadata) => (
<MenuItem key={lfm.id} onClick={() => onSelectLiveFile(lfm.id)}>
<ListItemDecorator><CodeIcon sx={{ fontSize: 'lg' }} /></ListItemDecorator>
<Box sx={{ mr: 1 }}>
{lfm.name}
<Box component='span' sx={{ fontSize: 'xs', display: 'block' }}>
{lfm.size?.toLocaleString() || '(unknown)'} bytes {lfm.type ? `· ${lfm.type}` : ''}
</Box>
</Box>
</MenuItem>
))}
<ListDivider />
<MenuItem disabled={!liveFileId} onClick={() => onSelectLiveFile(null)}>
<ListItemDecorator />
Remove Pairing
</MenuItem>
</Menu>
</Dropdown>
);
}
@@ -1,16 +1,16 @@
import * as React from 'react';
import { Box, Dropdown, IconButton, ListDivider, ListItemDecorator, Menu, MenuButton, MenuItem, Typography } from '@mui/joy';
import CodeIcon from '@mui/icons-material/Code';
import { Typography } from '@mui/joy';
import { useContextWorkspaceId } from '~/common/stores/workspace/WorkspaceIdProvider';
import { useWorkspaceContentsMetadata } from '~/common/stores/workspace/useWorkspaceContentsMetadata';
import type { LiveFileId, LiveFileMetadata } from '~/common/livefile/liveFile.types';
import { LiveFilePatchIcon } from '~/common/components/icons/LiveFilePatchIcon';
import type { LiveFileId } from '~/common/livefile/liveFile.types';
import { isLiveFileSupported } from '~/common/livefile/store-live-file';
import { useUXLabsStore } from '~/common/state/store-ux-labs';
import { WorkspaceLiveFilePicker } from './WorkspaceLiveFilePicker';
export function useLiveFilePatch(title: string, code: string, isPartial: boolean, isMobile: boolean) {
@@ -25,19 +25,6 @@ export function useLiveFilePatch(title: string, code: string, isPartial: boolean
const workspaceId = useContextWorkspaceId();
const { liveFilesMetadata } = useWorkspaceContentsMetadata(isEnabled ? workspaceId : null);
// [effect] auto-select a LiveFileId
React.useEffect(() => {
if (liveFilesMetadata.length === 1) {
// auto-select the only LiveFile
setLiveFileId(liveFilesMetadata[0].id);
} else {
// auto-select matching the title
const lfm = liveFilesMetadata.find(lfm => lfm.name === title);
if (lfm)
setLiveFileId(lfm.id);
}
}, [isEnabled, liveFilesMetadata, title]);
// reset enablement if no live files
if (!liveFilesMetadata?.length)
@@ -51,60 +38,14 @@ export function useLiveFilePatch(title: string, code: string, isPartial: boolean
const button = React.useMemo(() => !isEnabled ? null : <>
<WorkspaceLiveFilePicker
autoSelectName={title}
enabled={isEnabled}
liveFileId={liveFileId}
onSelectLiveFile={setLiveFileId}
/>
{/* LiveFile selector */}
<Dropdown>
{/*<TooltipOutlined color='success' title='Select a LiveFile to patch'>*/}
<MenuButton
aria-label='Pair File'
slots={{ root: IconButton }}
slotProps={{
root: {
color: liveFileId ? 'success' : undefined,
variant: liveFileId ? undefined : undefined,
size: 'sm',
},
}}
sx={{
ml: 'auto',
}}
>
<LiveFilePatchIcon />
</MenuButton>
{/*</TooltipOutlined>*/}
<Menu
placement='bottom-start'
sx={{
minWidth: 200,
zIndex: 'var(--joy-zIndex-modal)', /* on top of its own modal in FS */
}}
>
{/*<ListItem>*/}
{/* <Typography level='body-sm'>Recent Workspace Files</Typography>*/}
{/*</ListItem>*/}
{liveFilesMetadata.map((lfm: LiveFileMetadata) => (
<MenuItem key={lfm.id} onClick={() => setLiveFileId(lfm.id)}>
<ListItemDecorator><CodeIcon sx={{ fontSize: 'lg' }} /></ListItemDecorator>
<Box>
{lfm.name}
<Typography level='body-xs'>{lfm.size?.toLocaleString() || '(unknown)'} bytes {lfm.type ? `· ${lfm.type}` : ''}</Typography>
</Box>
</MenuItem>
))}
<ListDivider />
<MenuItem disabled={!liveFileId} onClick={() => setLiveFileId(null)}>
<ListItemDecorator />
Remove Pairing
</MenuItem>
</Menu>
</Dropdown>
</>, [isEnabled, liveFileId, liveFilesMetadata]);
</>, [isEnabled, liveFileId, title]);
const actionBar = React.useMemo(() => (!isEnabled || !liveFilesMetadata || true) ? null : (