feat: export/import functionality (backup/restore/share with friends) + a new input component (#433)
* feat: export schedule function to be added to handler * feat: use UserScheduleStore and return json * feat: download functionality * feat: oh wow we already have a blob download util that is very very nice * feat: return empty json if none found * feat: import function completion * feat: file uploading done * feat: new input component-stories made-settings input replaced with component * feat: attempt 1 to hook settings.tsx to importSchedule * feat: it works horray aka using right Course constructor it works * chore: fix jsdoc * chore: comments and debug style * docs: extra comment * feat: name of schedule more user friendly * feat: reworked how schedule is passed and check for file being schedule * feat: color is kept on import * fix: add sendResponse to exportSchedule --------- Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
This commit is contained in:
74
src/views/components/common/InputButton.tsx
Normal file
74
src/views/components/common/InputButton.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import type { ThemeColor } from '@shared/types/ThemeColors';
|
||||
import { getThemeColorHexByName, getThemeColorRgbByName } from '@shared/util/themeColors';
|
||||
import Text from '@views/components/common/Text/Text';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import type IconComponent from '~icons/material-symbols';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
variant: 'filled' | 'outline' | 'single';
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
icon?: typeof IconComponent;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
color: ThemeColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reusable input button component that follows the Button.tsx consistency
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export default function InputButton({
|
||||
className,
|
||||
style,
|
||||
variant,
|
||||
onChange,
|
||||
icon,
|
||||
disabled,
|
||||
title,
|
||||
color,
|
||||
children,
|
||||
}: React.PropsWithChildren<Props>): JSX.Element {
|
||||
const Icon = icon;
|
||||
const isIconOnly = !children && !!icon;
|
||||
const colorHex = getThemeColorHexByName(color);
|
||||
const colorRgb = getThemeColorRgbByName(color)?.join(' ');
|
||||
|
||||
return (
|
||||
<label
|
||||
style={
|
||||
{
|
||||
...style,
|
||||
color: disabled ? 'ut-gray' : colorHex,
|
||||
backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity)`,
|
||||
} satisfies React.CSSProperties
|
||||
}
|
||||
className={clsx(
|
||||
'btn',
|
||||
{
|
||||
'text-white! bg-opacity-100 hover:enabled:shadow-md active:enabled:shadow-sm shadow-black/20':
|
||||
variant === 'filled',
|
||||
'bg-opacity-0 border-current hover:enabled:bg-opacity-8 border': variant === 'outline',
|
||||
'bg-opacity-0 border-none hover:enabled:bg-opacity-8': variant === 'single', // settings is the only "single"
|
||||
'px-2 py-1.25': isIconOnly && variant !== 'outline',
|
||||
'px-1.75 py-1.25': isIconOnly && variant === 'outline',
|
||||
'px-3.75': variant === 'outline' && !isIconOnly,
|
||||
},
|
||||
className
|
||||
)}
|
||||
title={title}
|
||||
>
|
||||
{Icon && <Icon className='h-6 w-6' />}
|
||||
{!isIconOnly && (
|
||||
<Text variant='h4' className='inline-flex translate-y-0.08 items-center gap-2'>
|
||||
{children}
|
||||
</Text>
|
||||
)}
|
||||
<input type='file' className='hidden' disabled={disabled} onChange={disabled ? undefined : onChange} />
|
||||
</label>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user