This commit is contained in:
Sacha Weatherstone
2021-08-15 18:27:33 +10:00
parent 2940791b9e
commit 29fcc8051c
46 changed files with 1143 additions and 1531 deletions
+33
View File
@@ -0,0 +1,33 @@
import React from 'react';
type DefaultDivProps = JSX.IntrinsicElements['div'];
interface LocalBlurProps {
disableOnMd?: boolean;
}
export type BlurProps = LocalBlurProps & DefaultDivProps;
export const Blur = ({
disableOnMd,
className,
onClick,
...props
}: BlurProps): JSX.Element => {
return (
<div
className={`absolute inset-0 z-10 w-full h-full transition-opacity ${
disableOnMd ? 'md:hidden' : 'test'
} ${className}`}
{...props}
>
<div
onClick={onClick}
className={`absolute inset-0 w-full h-full backdrop-filter backdrop-blur-sm ${
disableOnMd ? 'md:hidden' : 'test'
}`}
tabIndex={0}
></div>
</div>
);
};
+37 -15
View File
@@ -1,28 +1,50 @@
import React from 'react';
import MaterialButton from '@material-ui/core/Button';
import type { ButtonProps as MaterialButtonProps } from '@material-ui/core/Button/Button';
type DefaultButtonProps = JSX.IntrinsicElements['button'];
interface LocalButtonProps {
text: string;
icon?: JSX.Element;
circle?: boolean;
active?: boolean;
border?: boolean;
}
export type ButtonProps = MaterialButtonProps & LocalButtonProps;
export type ButtonProps = LocalButtonProps & DefaultButtonProps;
export const Button = ({ text, icon, ...props }: ButtonProps): JSX.Element => {
export const Button = ({
icon,
circle,
className,
active,
border,
disabled,
children,
...props
}: ButtonProps): JSX.Element => {
return (
<MaterialButton
<button
className={`items-center select-none flex dark:text-white ${
active && !disabled ? 'bg-gray-100 dark:bg-gray-700' : ''
} ${
circle ? 'rounded-full h-10 w-10' : 'rounded-md p-3 space-x-3 text-sm'
} ${
disabled
? 'cursor-not-allowed dark:bg-primaryDark bg-white'
: 'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 hover:shadow-md'
} ${border ? 'border dark:border-gray-600' : ''} ${className}`}
{...props}
className="dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700"
>
<div className="flex p-3">
{icon &&
React.cloneElement(icon, {
className: 'h-6 w-6 mr-3 text-gray-500 dark:text-gray-400',
})}
<span>{text}</span>
</div>
</MaterialButton>
{icon && (
<div
className={`text-gray-500 dark:text-gray-400 ${
circle ? 'mx-auto' : ''
}`}
>
{icon}
</div>
)}
<span>{children}</span>
</button>
);
};
+35
View File
@@ -0,0 +1,35 @@
import React from 'react';
import { Blur } from '@components/generic/Blur';
type DefaultAsideProps = JSX.IntrinsicElements['aside'];
interface LocalDrawerProps {
open: boolean;
permenant?: boolean;
onClose: () => void;
}
export type DrawerProps = LocalDrawerProps & DefaultAsideProps;
export const Drawer = ({
open,
permenant,
onClose,
children,
...props
}: DrawerProps): JSX.Element => {
return (
<>
{open && <Blur disableOnMd={true} onClick={onClose} />}
<aside
className={`transform top-0 left-0 bg-white dark:bg-secondaryDark shadow-md max-w-xs w-full border-r dark:border-gray-600 h-full overflow-auto ease-in-out transition-all duration-300 z-30 ${
permenant ? '' : 'absolute'
} ${open ? 'translate-x-0' : '-translate-x-full'}`}
{...props}
>
{children}
</aside>
</>
);
};
-15
View File
@@ -1,15 +0,0 @@
import React from 'react';
import MaterialIconButton from '@material-ui/core/IconButton';
import type { IconButtonProps } from '@material-ui/core/IconButton/IconButton';
export const IconButton = ({
children,
...props
}: IconButtonProps): JSX.Element => {
return (
<MaterialIconButton {...props} className="text-gray-500 dark:text-gray-400">
{children}
</MaterialIconButton>
);
};
+50
View File
@@ -0,0 +1,50 @@
import React from 'react';
type DefaultInputProps = JSX.IntrinsicElements['input'];
interface LocalInputProps {
icon?: JSX.Element;
label?: string;
valid?: boolean;
validationMessage?: string;
}
export type InputProps = LocalInputProps & DefaultInputProps;
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
function Input(
{ icon, label, valid, validationMessage, id, ...props }: InputProps,
ref,
) {
return (
<div className="w-full">
<label
htmlFor={id}
className="block text-sm font-medium dark:text-white"
>
{label}
</label>
<div className="relative">
{icon && (
<div className="absolute inset-y-0 left-0 flex items-center px-3 pointer-events-none">
{React.cloneElement(icon, {
className: 'w-5 h-5 text-gray-500 dark:text-gray-600',
})}
</div>
)}
<input
id={id}
ref={ref}
{...props}
className={`block w-full h-11 rounded-md border shadow-sm focus:outline-none focus:border-primary dark:focus:border-primary bg-white dark:bg-secondaryDark dark:border-gray-600 dark:text-white ${
icon ? 'pl-9' : 'pl-2'
}`}
/>
</div>
{!valid && (
<div className="text-sm text-gray-600">{validationMessage}</div>
)}
</div>
);
},
);
+82
View File
@@ -0,0 +1,82 @@
import React from 'react';
import { Listbox } from '@headlessui/react';
import { CheckIcon, SelectorIcon } from '@heroicons/react/solid';
export interface SelectProps {
label: string;
options: {
name: string;
value: string;
icon: JSX.Element;
}[];
id: string;
value: string;
onChange: (value: string) => void;
}
export const Select = ({
label,
options,
id,
value,
onChange,
}: SelectProps): JSX.Element => {
return (
<div className="w-full">
<label htmlFor={id} className="block text-sm font-medium dark:text-white">
{label}
</label>
<Listbox value={value} onChange={onChange}>
<div className="relative mt-1">
<Listbox.Button className="relative w-full text-left bg-white border rounded-md shadow-sm h-11 focus:outline-none focus:border-primary dark:focus:border-primary dark:bg-secondaryDark dark:border-gray-600 dark:text-white">
<span className="block truncate">{value}</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<SelectorIcon
className="w-5 h-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<Listbox.Options className="absolute w-full bg-white border rounded-md shadow-sm focus:outline-none dark:bg-secondaryDark dark:border-gray-600 dark:text-white">
{options.map((option) => (
<Listbox.Option
key={option.value}
className={({ active }): string =>
`cursor-default select-none relative py-2 pl-10 pr-4 first:rounded-t-md last:rounded-b-md dark:text-white ${
active ? 'bg-gray-200 dark:bg-primaryDark' : 'text-gray-900'
}`
}
value={option.value}
>
{({ selected, active }): JSX.Element => (
<>
<span
className={`${
selected ? 'font-medium' : 'font-normal'
} block truncate`}
>
{option.name}
</span>
{selected ? (
<span
className={`${
active ? 'text-amber-600' : 'text-amber-600'
}
absolute inset-y-0 left-0 flex items-center pl-3`}
>
<CheckIcon className="w-5 h-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</Listbox>
</div>
);
};
+33
View File
@@ -0,0 +1,33 @@
import React from 'react';
type DefaultDivProps = JSX.IntrinsicElements['div'];
interface LocalSidebarItemProps {
title: string;
description: string;
selected: boolean;
icon: JSX.Element;
}
export type SidebarItemProps = LocalSidebarItemProps & DefaultDivProps;
export const SidebarItem = ({
title,
description,
selected,
icon,
}: SidebarItemProps): JSX.Element => {
return (
<div
className={`flex p-5 cursor-pointer select-none dark:hover:bg-primaryDark ${
selected ? 'bg-gray-200 dark:bg-primaryDark' : 'dark:bg-secondaryDark'
}`}
>
<div className="text-gray-500 dark:text-gray-400">{icon}</div>
<div className="ml-3 text-left">
<div className="font-medium text-left">{title}</div>
<div className="mt-0.5 text-gray-400 text-sm">{description}</div>
</div>
</div>
);
};