mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-16 14:06:49 +01:00
108 lines
2.9 KiB
TypeScript
108 lines
2.9 KiB
TypeScript
import { open } from '@tauri-apps/plugin-dialog';
|
|
import classNames from 'classnames';
|
|
import mime from 'mime';
|
|
import type { ReactNode } from 'react';
|
|
import type { ButtonProps } from './core/Button';
|
|
import { Button } from './core/Button';
|
|
import { IconButton } from './core/IconButton';
|
|
import { IconTooltip } from './core/IconTooltip';
|
|
import { Label } from './core/Label';
|
|
import { HStack } from './core/Stacks';
|
|
|
|
type Props = Omit<ButtonProps, 'type'> & {
|
|
onChange: (value: { filePath: string | null; contentType: string | null }) => void;
|
|
filePath: string | null;
|
|
directory?: boolean;
|
|
inline?: boolean;
|
|
noun?: string;
|
|
help?: ReactNode;
|
|
label?: ReactNode;
|
|
};
|
|
|
|
// Special character to insert ltr text in rtl element
|
|
const rtlEscapeChar = <>‎</>;
|
|
|
|
export function SelectFile({
|
|
onChange,
|
|
filePath,
|
|
inline,
|
|
className,
|
|
directory,
|
|
noun,
|
|
size = 'sm',
|
|
label,
|
|
help,
|
|
...props
|
|
}: Props) {
|
|
const handleClick = async () => {
|
|
const filePath = await open({
|
|
title: directory ? 'Select Folder' : 'Select File',
|
|
multiple: false,
|
|
directory,
|
|
});
|
|
if (filePath == null) return;
|
|
const contentType = filePath ? mime.getType(filePath) : null;
|
|
onChange({ filePath, contentType });
|
|
};
|
|
|
|
const handleClear = async () => {
|
|
onChange({ filePath: null, contentType: null });
|
|
};
|
|
|
|
const itemLabel = noun ?? (directory ? 'Folder' : 'File');
|
|
const selectOrChange = (filePath ? 'Change ' : 'Select ') + itemLabel;
|
|
|
|
return (
|
|
<div>
|
|
{label && (
|
|
<Label htmlFor={null} help={help}>
|
|
{label}
|
|
</Label>
|
|
)}
|
|
<HStack className="relative justify-stretch overflow-hidden">
|
|
<Button
|
|
className={classNames(
|
|
className,
|
|
'rtl mr-1.5',
|
|
inline && 'w-full',
|
|
filePath && inline && 'font-mono text-xs',
|
|
)}
|
|
color="secondary"
|
|
onClick={handleClick}
|
|
size={size}
|
|
{...props}
|
|
>
|
|
{rtlEscapeChar}
|
|
{inline ? filePath || selectOrChange : selectOrChange}
|
|
</Button>
|
|
|
|
{!inline && (
|
|
<>
|
|
{filePath && (
|
|
<IconButton
|
|
size={size === 'auto' ? 'md' : size}
|
|
variant="border"
|
|
icon="x"
|
|
title={'Unset ' + itemLabel}
|
|
onClick={handleClear}
|
|
/>
|
|
)}
|
|
<div
|
|
className={classNames(
|
|
'truncate rtl pl-1.5 pr-3 text-text',
|
|
filePath && 'font-mono',
|
|
size === 'xs' && filePath && 'text-xs',
|
|
size === 'sm' && filePath && 'text-sm',
|
|
)}
|
|
>
|
|
{rtlEscapeChar}
|
|
{filePath ?? `No ${itemLabel.toLowerCase()} selected`}
|
|
</div>
|
|
{filePath == null && help && !label && <IconTooltip content={help} />}
|
|
</>
|
|
)}
|
|
</HStack>
|
|
</div>
|
|
);
|
|
}
|