-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
852 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { FormHTMLAttributes, ReactNode } from 'react' | ||
|
||
type FormProps = { | ||
children: ReactNode | ||
} & FormHTMLAttributes<HTMLFormElement> | ||
|
||
export const FormContainer = ({ children, className, ...props }: FormProps) => { | ||
let localClassName = 'flex gap-6 flex-col' | ||
|
||
if (className) { | ||
localClassName += ` ${className}` | ||
} | ||
|
||
return <form className={localClassName} {...props}>{children}</form> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { InputProps } from '..' | ||
|
||
export const Checkbox = ({ options, name, label, value, ...props }: InputProps) => { | ||
return ( | ||
<div> | ||
{options?.map((opt) => ( | ||
<div className="flex items-center mt-4 pl-4"> | ||
<input | ||
id={`${name}-${opt.value}`} | ||
name={name} | ||
checked={Array.isArray(value) ? value.includes(opt.value) : opt.value === value} | ||
type="checkbox" | ||
value={opt.value} | ||
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded dark:ring-offset-gray-800 dark:bg-gray-700 dark:border-gray-600" | ||
{...props} | ||
/> | ||
<label htmlFor={`${name}-${opt.value}`} className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">{opt.label}</label> | ||
</div> | ||
))} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
|
||
import { Toggle } from './toggle' | ||
import { Checkbox } from './checkbox' | ||
import { Radio } from './radio' | ||
import { Select } from './select' | ||
import { Textarea } from './textarea' | ||
|
||
type AdapterType = { | ||
[key: string]: any | ||
} | ||
|
||
export const Adapters: AdapterType = { | ||
'checkbox': Checkbox, | ||
'select': Select, | ||
'radio': Radio, | ||
'textarea': Textarea, | ||
'toggle': Toggle, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { InputProps } from '..' | ||
|
||
export const Radio = ({ options, name, label, value, ...props }: InputProps) => { | ||
return ( | ||
<div> | ||
{options?.map((opt) => ( | ||
<div className="flex items-center mt-4 pl-4"> | ||
<input id={`${name}-${opt.value}`} checked={value === opt.value} type="radio" value={opt.value} className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded dark:ring-offset-gray-800 dark:bg-gray-700 dark:border-gray-600" {...props} /> | ||
<label htmlFor={`${name}-${opt.value}`} className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">{opt.label}</label> | ||
</div> | ||
))} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import ReactSelect, { Props } from 'react-select' | ||
import { InputProps } from '..' | ||
|
||
type SelectProps = InputProps & Props | ||
|
||
export const Select = ({ options, name, error, className, label, helpText, value, onChange, ...props }: SelectProps) => { | ||
return ( | ||
<> | ||
<ReactSelect | ||
id={name} | ||
options={options} | ||
value={options ? options?.filter((opt) => Array.isArray(value) ? value.includes(opt.value) : opt.value === value) : []} | ||
onChange={(e: any) => { | ||
if (Array.isArray(e) && onChange) { | ||
onChange({ target: { value: e.map((item: any) => item.value) } } as any) | ||
return | ||
} | ||
|
||
if (onChange) { | ||
onChange({ target: { value: e?.value } } as any) | ||
} | ||
}} | ||
isSearchable | ||
isClearable | ||
className={`react-select-container${error ? ' error' : ''}`} | ||
classNamePrefix="react-select" | ||
{...props} | ||
/> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { ReactNode, TextareaHTMLAttributes } from 'react' | ||
import { resolveClassName } from '../input-field' | ||
|
||
type TextareaProps = { | ||
children?: ReactNode | ||
rows?: number | ||
label?: string | ||
helpText?: ReactNode | ||
error?: boolean | ||
} & TextareaHTMLAttributes<HTMLTextAreaElement> | ||
|
||
export const Textarea = ({ children, rows, name, label, helpText, className, error, ...props }: TextareaProps) => { | ||
const localClassName = resolveClassName({ error, className }) | ||
|
||
return ( | ||
<div> | ||
<div className="flex items-center mt-4"> | ||
<textarea id={name} rows={rows} className={localClassName} {...props}>{children}</textarea> | ||
</div> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { InputProps } from '..' | ||
import { Toggle as ToggleComponent } from '../../toggle' | ||
|
||
export const Toggle = ({ options, value, onChange }: InputProps) => { | ||
return ( | ||
<div> | ||
{options?.map((opt) => ( | ||
<div className="flex items-center mt-4 pl-4"> | ||
<ToggleComponent | ||
checked={Array.isArray(value) ? value.includes(opt.value) : opt.value === value} | ||
onClick={() => onChange ? onChange({ target: { value: opt.value } } as any) : ''} | ||
> | ||
{opt.label} | ||
</ToggleComponent> | ||
</div> | ||
))} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { ReactNode, useEffect, useState } from 'react' | ||
import { InputField, InputFieldProps } from './input-field' | ||
import { Typography } from '../../Typography' | ||
import { Adapters } from './adapter' | ||
import { Label } from './label' | ||
|
||
export type Option = { | ||
value: any | ||
label: string | ||
} | ||
|
||
export type InputProps = InputFieldProps & { | ||
name: string | ||
label?: string | ||
helpText?: ReactNode | ||
options?: Option[] | ||
rows?: number | ||
isMulti?: boolean | ||
} | ||
|
||
export const Input = ({ label, helpText, type = 'text', options, onChange, ...props }: InputProps) => { | ||
const [hasAdapter, setHasAdapter] = useState<boolean>(false) | ||
|
||
useEffect(() => { | ||
setHasAdapter(!!Adapters[type]) | ||
}, [type]) | ||
|
||
let localHelpTextClassName = 'mt-2 !mb-0 text-sm text-gray-500 dark:text-gray-400' | ||
|
||
if (props?.error) { | ||
localHelpTextClassName += ' !text-red-500' | ||
} | ||
|
||
return ( | ||
<div> | ||
{label && <Label name={props.name} label={label} />} | ||
<InputField type={hasAdapter ? 'hidden' : type} id={props.name} onChange={onChange} {...props} /> | ||
{ | ||
hasAdapter && Adapters[type]({ label, helpText, type, options, onChange, ...props }) | ||
} | ||
{helpText && | ||
<Typography id="helper-text-explanation" className={localHelpTextClassName}>{helpText}</Typography> | ||
} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { HTMLInputTypeAttribute, InputHTMLAttributes } from 'react' | ||
|
||
export type InputFieldProps = { | ||
label?: string | ||
type?: HTMLInputTypeAttribute | ||
error?: boolean | ||
isLoading?: boolean | ||
} & InputHTMLAttributes<HTMLInputElement> | ||
|
||
const classNameTemplate = 'bg-gray-50 border-2 border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white' | ||
const classNameErrorTemplate = '!border-red-500 !outline-red-500' | ||
|
||
export const resolveClassName = ({ className, error }: Partial<InputFieldProps>): string => { | ||
let localClassName = classNameTemplate | ||
|
||
if (className) { | ||
localClassName = `${localClassName} ${className}` | ||
} | ||
|
||
if (error) { | ||
localClassName = `${localClassName} ${classNameErrorTemplate}` | ||
} | ||
|
||
return localClassName | ||
} | ||
|
||
export const InputField = ({ type, error, className, ...props }: InputFieldProps) => { | ||
const localClassName = resolveClassName({ error, className }) | ||
|
||
return ( | ||
<input | ||
type={type ?? 'text'} | ||
className={localClassName} | ||
{...props} | ||
/> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type LabelProps = { | ||
label: string | ||
name?: string | ||
} | ||
|
||
export const Label = ({ name, label }: LabelProps) => | ||
<label htmlFor={name} className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{label}</label> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/components/menu/index.tsx → ...layouts/default/components/menu/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { FormEvent, useCallback } from 'react' | ||
import { useDarkMode } from '../../contexts/dark-mode' | ||
import { Typography } from '../../components/Typography' | ||
import { Toggle } from '../../components/form/toggle' | ||
import { Rounded } from '../../components/rounded' | ||
import { Img } from '../../components/img' | ||
import { Card, CardBackground } from '../../components/card' | ||
import { FormContainer } from '../../components/form/form-container' | ||
import { Input } from '../../components/form/input' | ||
import { Button } from '../../components/button' | ||
import { useNavigate } from 'react-router-dom' | ||
|
||
export const LoginLayout = () => { | ||
const { isDarkMode, toggleDarkMode } = useDarkMode() | ||
const navigate = useNavigate() | ||
|
||
const darkModeHandler = useCallback(() => { | ||
toggleDarkMode() | ||
}, [isDarkMode]) | ||
|
||
const submit = (e: FormEvent<HTMLFormElement>) => { | ||
e.preventDefault() | ||
navigate('/') | ||
} | ||
|
||
return ( | ||
<div className={isDarkMode ? 'dark' : ''}> | ||
<div className="grid grid-cols-2 h-screen"> | ||
|
||
<div className="flex justify-center items-center bg-gray-300 relative"> | ||
<CardBackground src="/programmer.jpeg" className="bg-dark/80 rounded-full text-white flex flex-col gap-16 items-center justify-around"> | ||
<div className="flex items-center gap-3"> | ||
<Rounded><Img src="/logo.png" width={50} height={50} /></Rounded> | ||
{' '} | ||
<span>Erik <span className='text-primary'>Dashboard</span></span> | ||
</div> | ||
</CardBackground> | ||
</div> | ||
|
||
<div className="flex justify-center items-center bg-gray-200 dark:text-white dark:bg-gray-800 p-4"> | ||
<FormContainer style={{ maxWidth: 400, width: '100%' }} onSubmit={submit}> | ||
<Card className='flex gap-6 flex-col'> | ||
<Typography type="h2" className="flex items-center gap-3"> | ||
<Rounded><Img src="/logo.png" width={50} height={50} /></Rounded> | ||
Sign in to your account | ||
</Typography> | ||
|
||
<Input | ||
name="email" | ||
label="Email" | ||
type="email" | ||
placeholder='Field with HTML props support' | ||
/> | ||
|
||
<Input | ||
name="password" | ||
label="Field text" | ||
type="password" | ||
placeholder='Field with HTML props support' | ||
/> | ||
|
||
<Input | ||
name="input-text-checkbox" | ||
type='checkbox' | ||
options={[ | ||
{ label: 'Remember-me', value: 'remember' }, | ||
]} | ||
/> | ||
|
||
<Button>Login</Button> | ||
</Card> | ||
</FormContainer> | ||
</div> | ||
|
||
</div> | ||
|
||
<Typography type="display" className='absolute bottom-4 right-1 flex items-center gap-6 dark:text-white'> | ||
<Toggle checked={isDarkMode} onClick={darkModeHandler}> | ||
<span className="material-symbols-outlined">{isDarkMode ? 'brightness_4' : 'brightness_7'}</span> Dark Mode | ||
</Toggle> | ||
</Typography> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.