init
This commit is contained in:
commit
717730eed7
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "@kevisual/components",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "center components",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.14.0",
|
||||||
|
"@emotion/styled": "^11.14.0",
|
||||||
|
"@mui/material": "^6.4.7",
|
||||||
|
"react": "19.0.0",
|
||||||
|
"react-dom": "19.0.0",
|
||||||
|
"react-hook-form": "^7.54.2"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./src/index.tsx",
|
||||||
|
"./*": "./src/*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"tailwind-merge": "^3.0.2"
|
||||||
|
}
|
||||||
|
}
|
25
src/button/index.tsx
Normal file
25
src/button/index.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import MuiButton, { ButtonProps } from '@mui/material/Button';
|
||||||
|
|
||||||
|
export const Button = (props: ButtonProps) => {
|
||||||
|
return <MuiButton {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IconButton = (props: ButtonProps) => {
|
||||||
|
const { variant = 'contained', color = 'primary', sx, children, ...rest } = props;
|
||||||
|
return (
|
||||||
|
<MuiButton variant={variant} color={color} {...rest} sx={{ color: 'white', minWidth: '32px', padding: '8px', ...sx }}>
|
||||||
|
{children}
|
||||||
|
</MuiButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IconButtonItem = (props: ButtonProps) => {
|
||||||
|
const { variant = 'contained', size = 'small', color = 'primary', sx, children, ...rest } = props;
|
||||||
|
return (
|
||||||
|
<MuiButton {...props} >
|
||||||
|
{/* <MuiButton variant={'contained'} size={size} color={color} {...rest} sx={{ color: 'white', ...sx }}> */}
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</MuiButton>
|
||||||
|
);
|
||||||
|
};
|
17
src/card/CardBlank.tsx
Normal file
17
src/card/CardBlank.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import clsx from 'clsx';
|
||||||
|
import twMerge from 'tailwind-merge';
|
||||||
|
|
||||||
|
type CardBlankProps = {
|
||||||
|
number?: number;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
export const CardBlank = (props: CardBlankProps) => {
|
||||||
|
const { number = 4, className } = props;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{new Array(number).fill(0).map((_, index) => {
|
||||||
|
return <div key={index} className={clsx('w-[300px] shark-0', className)}></div>;
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
7
src/clsx/index.ts
Normal file
7
src/clsx/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import clsx, { ClassValue } from 'clsx';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
export const clsxMerge = (...args: ClassValue[]) => {
|
||||||
|
return twMerge(clsx(...args));
|
||||||
|
};
|
||||||
|
export { clsx };
|
6
src/index.tsx
Normal file
6
src/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export * from './theme';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入组件, 使用theme的defaultProps
|
||||||
|
*/
|
||||||
|
export * from './input/TextField';
|
23
src/input/TextField.tsx
Normal file
23
src/input/TextField.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { TextField as MuiTextField, TextFieldProps, Tooltip } from '@mui/material';
|
||||||
|
import { useTheme } from '../theme';
|
||||||
|
import { HelpCircle } from 'lucide-react';
|
||||||
|
|
||||||
|
export const TextField = (props: TextFieldProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const defaultProps = theme.components?.MuiTextField?.defaultProps;
|
||||||
|
return <MuiTextField {...defaultProps} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TextFieldLabel = ({ children, tips, label }: { children?: React.ReactNode; tips?: string; label?: any }) => {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center gap-1'>
|
||||||
|
{label}
|
||||||
|
{children}
|
||||||
|
{tips && (
|
||||||
|
<Tooltip title={tips}>
|
||||||
|
<HelpCircle size={16} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
47
src/input/index.tsx
Normal file
47
src/input/index.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { FormControlLabel, TextField } from '@mui/material';
|
||||||
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
|
export const InputControl = ({ name, value, onChange }: { name: string; value: string; onChange?: (value: string) => void }) => {
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
variant='outlined'
|
||||||
|
size='small'
|
||||||
|
name={name}
|
||||||
|
value={value || ''}
|
||||||
|
onChange={(e) => onChange?.(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: '16px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
type FormProps = {
|
||||||
|
onSubmit?: (data: any) => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
export const FormDemo = (props: FormProps) => {
|
||||||
|
const { control, handleSubmit } = useForm();
|
||||||
|
const { onSubmit = () => {}, children } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Controller
|
||||||
|
name='name'
|
||||||
|
control={control}
|
||||||
|
defaultValue=''
|
||||||
|
rules={{ required: 'Name is required' }}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<TextField
|
||||||
|
{...field}
|
||||||
|
label='Name'
|
||||||
|
variant='outlined'
|
||||||
|
margin='normal'
|
||||||
|
fullWidth //
|
||||||
|
error={!!error}
|
||||||
|
helperText={<>{error?.message}</>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
99
src/modal/Confirm.tsx
Normal file
99
src/modal/Confirm.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button } from '@mui/material';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import type { ModalFuncProps } from 'antd';
|
||||||
|
export const Confirm = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
onConfirm,
|
||||||
|
okText = '确认',
|
||||||
|
cancelText = '取消',
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
onConfirm?: () => void;
|
||||||
|
okText?: string;
|
||||||
|
cancelText?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
aria-labelledby='alert-dialog-title'
|
||||||
|
aria-describedby='alert-dialog-description'>
|
||||||
|
<DialogTitle id='alert-dialog-title' className='text-secondary min-w-[300px]'>
|
||||||
|
{title}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText id='alert-dialog-description'>{content}</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose} color='primary'>
|
||||||
|
{cancelText || '取消'}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={onConfirm} variant='contained' color='primary' autoFocus>
|
||||||
|
{okText || '确认'}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type Fn = () => void;
|
||||||
|
export const useModal = () => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
const [content, setContent] = useState('');
|
||||||
|
const fns = useRef<{
|
||||||
|
onConfirm: Fn;
|
||||||
|
onCancel: Fn;
|
||||||
|
okText: string;
|
||||||
|
cancelText: string;
|
||||||
|
}>({
|
||||||
|
onConfirm: () => {},
|
||||||
|
onCancel: () => {},
|
||||||
|
okText: '确认',
|
||||||
|
cancelText: '取消',
|
||||||
|
});
|
||||||
|
const modal = {
|
||||||
|
confirm: (props: ModalFuncProps) => {
|
||||||
|
setOpen(true);
|
||||||
|
setTitle(props.title as string);
|
||||||
|
setContent(props.content as string);
|
||||||
|
fns.current.onConfirm = async () => {
|
||||||
|
const isClose = await props.onOk?.();
|
||||||
|
if (!isClose) {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fns.current.onCancel = async () => {
|
||||||
|
await props.onCancel?.();
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
fns.current.okText = props.okText as string;
|
||||||
|
fns.current.cancelText = props.cancelText as string;
|
||||||
|
},
|
||||||
|
cancel: () => {
|
||||||
|
setOpen(false);
|
||||||
|
fns.current.onCancel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const contextHolder = (
|
||||||
|
<Confirm
|
||||||
|
open={open}
|
||||||
|
okText={fns.current.okText}
|
||||||
|
cancelText={fns.current.cancelText}
|
||||||
|
onClose={() => {
|
||||||
|
setOpen(false);
|
||||||
|
fns.current.onCancel();
|
||||||
|
}}
|
||||||
|
title={title}
|
||||||
|
content={content}
|
||||||
|
onConfirm={fns.current.onConfirm}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return [modal, contextHolder] as [typeof modal, React.ReactNode];
|
||||||
|
};
|
58
src/select/TagsInput.tsx
Normal file
58
src/select/TagsInput.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { Fragment, useEffect, useState } from 'react';
|
||||||
|
import Autocomplete from '@mui/material/Autocomplete';
|
||||||
|
import { TextField, Chip } from '@mui/material';
|
||||||
|
|
||||||
|
type TagsInputProps = {
|
||||||
|
value: string[];
|
||||||
|
onChange: (value: string[]) => void;
|
||||||
|
placeholder?: string;
|
||||||
|
label?: any;
|
||||||
|
showLabel?: boolean;
|
||||||
|
};
|
||||||
|
export const TagsInput = ({ value, onChange, placeholder = '', label = '', showLabel = false }: TagsInputProps) => {
|
||||||
|
const [tags, setTags] = useState<string[]>(value);
|
||||||
|
useEffect(() => {
|
||||||
|
setTags(value);
|
||||||
|
}, [value]);
|
||||||
|
const randomid = () => {
|
||||||
|
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
multiple
|
||||||
|
freeSolo
|
||||||
|
options={[]}
|
||||||
|
value={tags}
|
||||||
|
onChange={(event, newValue) => {
|
||||||
|
// setTags(newValue as string[]);
|
||||||
|
onChange(newValue as string[]);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
renderTags={(value: string[], getTagProps) => {
|
||||||
|
const id = randomid();
|
||||||
|
const com = value.map((option: string, index: number) => (
|
||||||
|
<Chip
|
||||||
|
variant='outlined'
|
||||||
|
sx={{
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
borderRadius: '4px',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
},
|
||||||
|
'& .MuiChip-deleteIcon': {
|
||||||
|
color: 'secondary.main',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label={option}
|
||||||
|
{...getTagProps({ index })}
|
||||||
|
key={`${id}-${index}`}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
return <Fragment key={id}>{com}</Fragment>;
|
||||||
|
}}
|
||||||
|
renderInput={(params) => <TextField {...params} label={showLabel ? label : ''} placeholder={placeholder} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
20
src/select/index.tsx
Normal file
20
src/select/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { MenuItem, Select as MuiSelect, SelectProps as MuiSelectProps } from '@mui/material';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type SelectProps = {
|
||||||
|
options?: { label: string; value: string }[];
|
||||||
|
} & MuiSelectProps;
|
||||||
|
|
||||||
|
export const Select = React.forwardRef((props: SelectProps, ref) => {
|
||||||
|
const { options, ...rest } = props;
|
||||||
|
console.log(props, 'props');
|
||||||
|
return (
|
||||||
|
<MuiSelect {...rest} ref={ref}>
|
||||||
|
{options?.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</MuiSelect>
|
||||||
|
);
|
||||||
|
});
|
226
src/theme/index.tsx
Normal file
226
src/theme/index.tsx
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
import { createTheme, Shadows, ThemeOptions } from '@mui/material/styles';
|
||||||
|
import { useTheme as useMuiTheme, Theme } from '@mui/material/styles';
|
||||||
|
import { amber, red } from '@mui/material/colors';
|
||||||
|
import { ThemeProvider } from '@mui/material/styles';
|
||||||
|
const generateShadows = (color: string): Shadows => {
|
||||||
|
return [
|
||||||
|
'none',
|
||||||
|
`0px 2px 1px -1px ${color}`,
|
||||||
|
`0px 1px 1px 0px ${color}`,
|
||||||
|
`0px 1px 3px 0px ${color}`,
|
||||||
|
`0px 2px 4px -1px ${color}`,
|
||||||
|
|
||||||
|
`0px 3px 5px -1px ${color}`,
|
||||||
|
`0px 3px 5px -1px ${color}`,
|
||||||
|
`0px 4px 5px -2px ${color}`,
|
||||||
|
`0px 5px 5px -3px ${color}`,
|
||||||
|
`0px 5px 6px -3px ${color}`,
|
||||||
|
|
||||||
|
`0px 6px 6px -3px ${color}`,
|
||||||
|
`0px 6px 7px -4px ${color}`,
|
||||||
|
`0px 7px 8px -4px ${color}`,
|
||||||
|
`0px 7px 8px -4px ${color}`,
|
||||||
|
`0px 8px 9px -5px ${color}`,
|
||||||
|
|
||||||
|
`0px 8px 9px -5px ${color}`,
|
||||||
|
`0px 9px 10px -5px ${color}`,
|
||||||
|
`0px 9px 11px -6px ${color}`,
|
||||||
|
`0px 10px 12px -6px ${color}`,
|
||||||
|
`0px 10px 13px -6px ${color}`,
|
||||||
|
|
||||||
|
`0px 11px 13px -7px ${color}`,
|
||||||
|
`0px 11px 14px -7px ${color}`,
|
||||||
|
`0px 12px 15px -7px ${color}`,
|
||||||
|
`0px 12px 16px -8px ${color}`,
|
||||||
|
`0px 13px 17px -8px ${color}`,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
const primaryMain = amber[300]; // #ffc107
|
||||||
|
const secondaryMain = amber[500]; // #ffa000
|
||||||
|
export const themeOptions: ThemeOptions = {
|
||||||
|
// @ts-ignore
|
||||||
|
// cssVariables: true,
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: primaryMain, // amber[300]
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: secondaryMain, // amber[500]
|
||||||
|
},
|
||||||
|
divider: amber[200],
|
||||||
|
common: {
|
||||||
|
white: secondaryMain,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: amber[600],
|
||||||
|
secondary: amber[600],
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: '#ffffff', // 设置默认背景颜色
|
||||||
|
// paper: '#f5f5f5', // 设置纸张背景颜色
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
main: red[500], // 设置错误颜色 "#f44336"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shadows: generateShadows('rgba(255, 193, 7, 0.2)'),
|
||||||
|
typography: {
|
||||||
|
// fontFamily: 'Roboto, sans-serif',
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiButtonBase: {
|
||||||
|
defaultProps: {
|
||||||
|
disableRipple: true,
|
||||||
|
},
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: amber[100],
|
||||||
|
},
|
||||||
|
'&.MuiButton-contained': {
|
||||||
|
color: '#ffffff',
|
||||||
|
':hover': {
|
||||||
|
color: secondaryMain,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiButtonGroup: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& .MuiButton-root': {
|
||||||
|
borderColor: amber[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTextField: {
|
||||||
|
defaultProps: {
|
||||||
|
fullWidth: true,
|
||||||
|
size: 'small',
|
||||||
|
slotProps: {
|
||||||
|
inputLabel: {
|
||||||
|
shrink: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'& fieldset': {
|
||||||
|
borderColor: amber[300],
|
||||||
|
},
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: amber[500],
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input': {
|
||||||
|
color: amber[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiInputLabel-root': {
|
||||||
|
color: amber[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAutocomplete: {
|
||||||
|
defaultProps: {
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiSelect: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[300],
|
||||||
|
},
|
||||||
|
'&:hover .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[500],
|
||||||
|
},
|
||||||
|
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[500],
|
||||||
|
},
|
||||||
|
'& .MuiSelect-icon': {
|
||||||
|
color: amber[500], // Set arrow icon color to primary
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiCard: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
// border: `1px solid ${amber[300]}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#ffffff', // Set default font color to white
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiFormControlLabel: {
|
||||||
|
defaultProps: {
|
||||||
|
labelPlacement: 'top',
|
||||||
|
},
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: amber[600],
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
'& .MuiFormControlLabel-label': {
|
||||||
|
textAlign: 'left',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
'& .MuiFormControlLabel-root': {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-root': {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiMenuItem: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'&.Mui-selected': {
|
||||||
|
backgroundColor: amber[500],
|
||||||
|
color: '#ffffff',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: amber[600],
|
||||||
|
color: '#ffffff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://bareynol.github.io/mui-theme-creator/
|
||||||
|
*/
|
||||||
|
export const theme = createTheme(themeOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useTheme = () => {
|
||||||
|
return useMuiTheme<Theme>();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义主题设置。
|
||||||
|
* @param param0
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const CustomThemeProvider = ({ children, themeOptions: customThemeOptions }: { children: React.ReactNode; themeOptions?: ThemeOptions }) => {
|
||||||
|
const theme = createTheme(customThemeOptions || themeOptions);
|
||||||
|
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: think
|
||||||
|
export const getComponentProps = () => {};
|
76
src/theme/wind-theme.css
Normal file
76
src/theme/wind-theme.css
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: #ffc107;
|
||||||
|
--color-secondary: #ffa000;
|
||||||
|
--color-success: #28a745;
|
||||||
|
--color-scrollbar-thumb: #999999;
|
||||||
|
--color-scrollbar-track: rgba(0, 0, 0, 0.1);
|
||||||
|
--color-scrollbar-thumb-hover: #666666;
|
||||||
|
--scrollbar-color: #ffc107; /* 滚动条颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
}
|
||||||
|
/* font-family */
|
||||||
|
@utility font-family-mon {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
}
|
||||||
|
@utility font-family-rob {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
}
|
||||||
|
@utility font-family-int {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
@utility font-family-orb {
|
||||||
|
font-family: 'Orbitron', sans-serif;
|
||||||
|
}
|
||||||
|
@utility font-family-din {
|
||||||
|
font-family: 'DIN', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility flex-row-center {
|
||||||
|
@apply flex flex-row items-center justify-center;
|
||||||
|
}
|
||||||
|
@utility flex-col-center {
|
||||||
|
@apply flex flex-col items-center justify-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility scrollbar {
|
||||||
|
overflow: auto;
|
||||||
|
/* 整个滚动条 */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background-color: var(--color-scrollbar-track);
|
||||||
|
}
|
||||||
|
/* 滚动条有滑块的轨道部分 */
|
||||||
|
&::-webkit-scrollbar-track-piece {
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条滑块(竖向:vertical 横向:horizontal) */
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--color-scrollbar-thumb);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条滑块hover */
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: var(--color-scrollbar-thumb-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 同时有垂直和水平滚动条时交汇的部分 */
|
||||||
|
&::-webkit-scrollbar-corner {
|
||||||
|
display: block; /* 修复交汇时出现的白块 */
|
||||||
|
}
|
||||||
|
}
|
40
tsconfig.json
Normal file
40
tsconfig.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": [
|
||||||
|
"ES2020",
|
||||||
|
"DOM",
|
||||||
|
"DOM.Iterable"
|
||||||
|
],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"baseUrl": "./",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
"node_modules/@kevisual/types",
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@kevisual/components/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src",
|
||||||
|
"typings.d.ts",
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user