feat: add app and config
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
export { KeyParse, keysTips } from './pages/file/modules/key-parse';
|
||||
export { PermissionManager } from './pages/file/modules/PermissionManager.tsx';
|
||||
export { PermissionModal, usePermissionModal } from './pages/file/modules/PermissionModal.tsx';
|
||||
export { iText } from './i-text/index.ts';
|
||||
export * from './pages/upload/app';
|
||||
export * from './pages/upload/app';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import ReactDatePicker from 'antd/es/date-picker';
|
||||
import { styled, useTheme } from '@mui/material';
|
||||
import 'antd/es/date-picker/style/index';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
interface DatePickerProps {
|
||||
value?: Date | null;
|
||||
onChange?: (date: Date | null) => void;
|
||||
@@ -8,13 +9,14 @@ interface DatePickerProps {
|
||||
}
|
||||
|
||||
export const DatePickerCom = ({ value, onChange, className }: DatePickerProps) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const primaryColor = theme.palette.primary.main;
|
||||
return (
|
||||
<div className={className}>
|
||||
<ReactDatePicker
|
||||
placement='topLeft'
|
||||
placeholder='请选择日期'
|
||||
placeholder={t('Select Date')}
|
||||
value={value}
|
||||
showNow={false}
|
||||
// showTime={true}
|
||||
|
||||
@@ -7,10 +7,10 @@ import { toast } from 'react-toastify';
|
||||
import { create } from 'zustand';
|
||||
import { uniq } from 'lodash-es';
|
||||
import { DatePicker } from './DatePicker';
|
||||
import { SelectPicker } from './SelectPicker';
|
||||
import { DialogKey } from './DialogKey';
|
||||
import { keysTips, KeyParse } from '../../modules/key-parse';
|
||||
import { KeyShareSelect, KeyTextField } from '../../modules/PermissionManager';
|
||||
import { TagsInput } from '@kevisual/center-components/select/TagsInput.tsx';
|
||||
export const setShareKeysOperate = (value: 'public' | 'protected' | 'private') => {
|
||||
const keys = ['password', 'usernames', 'expiration-time'];
|
||||
const deleteKeys = keys.map((item) => {
|
||||
@@ -187,7 +187,7 @@ export const MetaForm = () => {
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
<form>
|
||||
<form className='flex flex-col gap-1 pb-4'>
|
||||
{keys.map((key) => {
|
||||
let control: React.ReactNode | null = null;
|
||||
if (key === 'share') {
|
||||
@@ -195,7 +195,7 @@ export const MetaForm = () => {
|
||||
} else if (key === 'expiration-time') {
|
||||
control = <DatePicker value={formData[key]} onChange={(date) => handleFormDataChange(key, date)} />;
|
||||
} else if (key === 'usernames') {
|
||||
control = <SelectPicker value={formData[key] || []} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||
control = <TagsInput value={formData[key] || []} showLabel={false} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||
} else {
|
||||
control = <KeyTextField name={key} value={formData[key] || ''} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||
}
|
||||
@@ -226,23 +226,7 @@ export const MetaForm = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div key={key} className='flex flex-col gap-2'>
|
||||
<FormControlLabel
|
||||
key={key}
|
||||
label={<Label />}
|
||||
labelPlacement='top'
|
||||
control={control}
|
||||
sx={{
|
||||
alignItems: 'flex-start',
|
||||
'& .MuiFormControlLabel-label': {
|
||||
textAlign: 'left',
|
||||
width: '100%',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
return <FormControlLabel key={key} labelPlacement={'top'} label={<Label />} control={control} />;
|
||||
})}
|
||||
</form>
|
||||
<DialogKey onAdd={addMetaKey} />
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { styled } from '@mui/material';
|
||||
import Select from 'antd/es/select';
|
||||
import 'antd/es/select/style/index';
|
||||
|
||||
interface SelectPickerProps {
|
||||
value: string[];
|
||||
onChange: (value: string[]) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const SelectPickerCom = ({ value, onChange, className }: SelectPickerProps) => {
|
||||
return <Select className={className} style={{ width: '100%' }} popupClassName='hidden' showSearch={false} mode='tags' value={value} onChange={onChange} />;
|
||||
};
|
||||
export const SelectPicker = styled(SelectPickerCom)(({ theme }) => ({
|
||||
|
||||
'& .ant-select-selection-item': {
|
||||
backgroundColor: 'var(--color-primary) !important',
|
||||
color: 'white !important',
|
||||
},
|
||||
'& svg': {
|
||||
color: 'white !important',
|
||||
},
|
||||
'& svg:hover': {
|
||||
color: '#ccc !important',
|
||||
},
|
||||
'& .ant-select-arrow': {
|
||||
// color: 'var(--color-primary) !important',
|
||||
display: 'none !important',
|
||||
},
|
||||
}));
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { KeyParse, getTips } from './key-parse';
|
||||
import { FormControlLabel, TextField, Select, MenuItem, FormGroup, Tooltip } from '@mui/material';
|
||||
import { FormControlLabel, TextField, Select, MenuItem, Tooltip } from '@mui/material';
|
||||
import { DatePicker } from '../draw/modules/DatePicker';
|
||||
import { SelectPicker } from '../draw/modules/SelectPicker';
|
||||
import { TagsInput } from '@kevisual/center-components/select/TagsInput.tsx';
|
||||
import { HelpCircle } from 'lucide-react';
|
||||
import clsx from 'clsx';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const KeyShareSelect = ({ name, value, onChange }: { name: string; value: string; onChange?: (value: string) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Select
|
||||
variant='outlined'
|
||||
@@ -18,14 +19,14 @@ export const KeyShareSelect = ({ name, value, onChange }: { name: string; value:
|
||||
width: '100%',
|
||||
marginBottom: '16px',
|
||||
}}>
|
||||
<MenuItem value='public' title='公开'>
|
||||
公开
|
||||
<MenuItem value='public' title={t('Public')}>
|
||||
{t('Public')}
|
||||
</MenuItem>
|
||||
<MenuItem value='protected' title='受保护'>
|
||||
受保护
|
||||
<MenuItem value='protected' title={t('Protected')}>
|
||||
{t('Protected')}
|
||||
</MenuItem>
|
||||
<MenuItem value='private' title='私有'>
|
||||
私有
|
||||
<MenuItem value='private' title={t('Private')}>
|
||||
{t('Private')}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
);
|
||||
@@ -85,8 +86,9 @@ export const PermissionManager = ({ value, onChange, className }: PermissionMana
|
||||
};
|
||||
const tips = getTips('share', i18n.language);
|
||||
return (
|
||||
<form className={clsx('flex flex-col gap-2', className)}>
|
||||
<form className={clsx('flex flex-col w-full gap-2', className)}>
|
||||
<FormControlLabel
|
||||
labelPlacement='top'
|
||||
control={<KeyShareSelect name='share' value={formData?.share} onChange={(value) => onChangeValue('share', value)} />}
|
||||
label={
|
||||
<div className='flex items-center gap-1'>
|
||||
@@ -99,38 +101,26 @@ export const PermissionManager = ({ value, onChange, className }: PermissionMana
|
||||
/>
|
||||
{keys.map((item: any) => {
|
||||
let control: React.ReactNode | null = null;
|
||||
const tips = getTips(item);
|
||||
|
||||
const label = (
|
||||
<div className='flex items-center gap-1'>
|
||||
{t(item)}
|
||||
{tips && (
|
||||
<Tooltip title={tips}>
|
||||
<HelpCircle size={16} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
if (item === 'expiration-time') {
|
||||
control = <DatePicker value={formData[item] || ''} onChange={(date) => onChangeValue(item, date)} />;
|
||||
control = <DatePicker className='mt-1' value={formData[item] || ''} onChange={(date) => onChangeValue(item, date)} />;
|
||||
} else if (item === 'usernames') {
|
||||
control = <SelectPicker value={formData[item] || []} onChange={(value) => onChangeValue(item, value)} />;
|
||||
control = <TagsInput value={formData[item] || []} onChange={(value) => onChangeValue(item, value)} />;
|
||||
} else {
|
||||
control = <KeyTextField name={item} value={formData[item] || ''} onChange={(value) => onChangeValue(item, value)} />;
|
||||
}
|
||||
const tips = getTips(item);
|
||||
return (
|
||||
<FormControlLabel
|
||||
labelPlacement='top'
|
||||
key={item}
|
||||
control={control}
|
||||
label={
|
||||
<div className='flex items-center gap-1'>
|
||||
{item}
|
||||
{tips && (
|
||||
<Tooltip title={tips}>
|
||||
<HelpCircle size={16} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
sx={{
|
||||
alignItems: 'flex-start',
|
||||
'& .MuiFormControlLabel-label': {
|
||||
textAlign: 'left',
|
||||
width: '100%',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return <FormControlLabel key={item} labelPlacement='top' control={control} label={label} />;
|
||||
})}
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PermissionManager } from './PermissionManager';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
type PermissionModalProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
value: Record<string, any>;
|
||||
onChange: (value: Record<string, any>) => void;
|
||||
onSave: () => void;
|
||||
};
|
||||
export const PermissionModal = ({ open, onClose, value, onChange, onSave }: PermissionModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>{t('app.share')}</DialogTitle>
|
||||
<DialogContent sx={{ width: '400px' }}>
|
||||
<PermissionManager value={value} onChange={onChange} />
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>{t('Cancel')}</Button>
|
||||
<Button color='primary' onClick={onSave}>
|
||||
{t('Submit')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
type UsePermissionModalProps = {
|
||||
/**
|
||||
* 保存回调
|
||||
*/
|
||||
onSave: (values: Record<string, any>) => Promise<boolean>;
|
||||
};
|
||||
export const usePermissionModal = ({ onSave }: UsePermissionModalProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||
const onChange = (value: Record<string, any>) => {
|
||||
setFormData(value);
|
||||
};
|
||||
const _onSave = async () => {
|
||||
const res = await onSave(formData);
|
||||
if (res) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
const contextHolder = <PermissionModal open={open} onClose={() => setOpen(false)} value={formData} onChange={onChange} onSave={_onSave} />;
|
||||
return {
|
||||
open,
|
||||
setOpen: (open: boolean, fromData?: any) => {
|
||||
setOpen(open);
|
||||
if (open) {
|
||||
setFormData(fromData ?? {});
|
||||
}
|
||||
},
|
||||
setFormData: (values: any) => {
|
||||
setFormData({ ...formData, ...values });
|
||||
},
|
||||
contextHolder,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user