feat: improve ui components

This commit is contained in:
2024-01-04 21:46:10 -06:00
parent 0c74c0a0a9
commit 7d39bb3d89
14 changed files with 245 additions and 37 deletions
+3
View File
@@ -193,3 +193,6 @@ dist
# Panda Css # Panda Css
src/styled-system src/styled-system
# Vscode
.vscode
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -19,7 +19,7 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"appwrite": "^13.0.1", "appwrite": "^13.0.1",
"entgamers-database": "^0.0.5", "entgamers-database": "^0.0.5",
"entgamers-panda-preset": "0.1.0", "entgamers-panda-preset": "0.1.1",
"formik": "^2.4.5", "formik": "^2.4.5",
"framer-motion": "^10.16.16", "framer-motion": "^10.16.16",
"isomorphic-fetch": "^3.0.0", "isomorphic-fetch": "^3.0.0",
+21 -15
View File
@@ -1,35 +1,41 @@
import { cx } from '@/styled-system/css' import { cx } from '@/styled-system/css'
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert' import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
import { type MergeOmitting } from '@/types/utilities' import { type MergeOmitting } from '@/types/utilities'
import { faTimes } from '@fortawesome/free-solid-svg-icons' import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes'
import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react' import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
import IconButton, { type IconButtonProps } from './IconButton'
export type AlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps> type ComposedAlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
const Alert: FC<AlertProps> = ({ children, className, ...props }) => { const Alert: FC<ComposedAlertProps> = ({ className, children, ...props }) => {
const [alertArgs, allOtherProps] = alert.splitVariantProps(props) const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
return ( return (
<div <div
className={cx(alert(alertArgs).body, className)} className={cx(alert(alertRecipeArgs).body, className)}
{...allOtherProps} {...allOtherAlertProps}
> >
{children} {children}
</div> </div>
) )
} }
export type AlertCloseButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, AlertVariantProps> type ComposedAlertCloseButtonProps = MergeOmitting<IconButtonProps, AlertVariantProps> & {
children?: ReactNode
}
export const AlertCloseButton: FC<AlertCloseButtonProps> = ({ children, className, ...props }) => { export const AlertCloseButton: FC<ComposedAlertCloseButtonProps> = ({ children, className, ...props }) => {
const [alertArgs, allOtherProps] = alert.splitVariantProps(props) const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
return ( return (
<button <IconButton
className={cx(alert(alertArgs).closeButton, className)} className={cx(alert(alertRecipeArgs).closeButton, className)}
{...allOtherProps} {...allOtherAlertProps}
> >
{children !== undefined ? children : <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth />} {children === undefined
</button> ? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth size='sm' />
: children
}
</IconButton>
) )
} }
+20
View File
@@ -0,0 +1,20 @@
import { cx } from '@/styled-system/css'
import { buttonGroup, type ButtonGroupVariantProps } from '@/styled-system/recipes/button-group'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
export type ButtonGroupProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, ButtonGroupVariantProps>
const ButtonGroup: FC<ButtonGroupProps> = ({ children, className, ...rest }) => {
const [buttonGroupRecipeArgs, allOtherButtonGroupProps] = buttonGroup.splitVariantProps(rest)
return (
<div
className={cx(buttonGroup(buttonGroupRecipeArgs), className)}
{...allOtherButtonGroupProps}
>
{children}
</div>
)
}
export default ButtonGroup
+19
View File
@@ -0,0 +1,19 @@
import { cx } from '@/styled-system/css'
import { chip, type ChipVariantProps } from '@/styled-system/recipes/chip'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
export type ChipProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, ChipVariantProps>
const Chip: FC<ChipProps> = ({ children, className, ...rest }) => {
const [chipRecipeArgs, allOtherChipProps] = chip.splitVariantProps(rest)
return (
<span
className={cx(chip(chipRecipeArgs), className)}
{...allOtherChipProps}
>
{children}
</span>
)
}
export default Chip
+36
View File
@@ -0,0 +1,36 @@
import { cx } from '@/styled-system/css'
import { collapse, type CollapseVariantProps } from '@/styled-system/recipes/collapse'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type DetailsHTMLAttributes, type FC, type HTMLAttributes, type ReactNode } from 'react'
export type CollapseProps = MergeOmitting<DetailedHTMLProps<DetailsHTMLAttributes<HTMLDetailsElement>, HTMLDetailsElement>, CollapseVariantProps> & {
children?: ReactNode
contentProps?: HTMLAttributes<HTMLElement>
summary: ReactNode
summaryProps?: HTMLAttributes<HTMLElement>
}
const Collapse: FC<CollapseProps> = ({ children, className, summary, summaryProps, contentProps, ...rest }) => {
const [collapseRecipeArgs, allOtherCollapseProps] = collapse.splitVariantProps(rest)
return (
<details
className={cx(collapse(collapseRecipeArgs).root, className)}
{...allOtherCollapseProps}
>
<summary
{...summaryProps}
className={cx(collapse(collapseRecipeArgs).summary, summaryProps?.className)}
>
{summary}
</summary>
<div
{...contentProps}
className={cx(collapse(collapseRecipeArgs).content, contentProps?.className)}
>
{children}
</div>
</details>
)
}
export default Collapse
+2 -2
View File
@@ -1,9 +1,9 @@
import { cx } from '@/styled-system/css' import { cx } from '@/styled-system/css'
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button' import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
import { type MergeOmitting } from '@/types/utilities' import { type MergeOmitting } from '@/types/utilities'
import React, { type FC } from 'react' import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC } from 'react'
type ComposedIconButtonProps = MergeOmitting<React.HTMLAttributes<HTMLButtonElement>, IconButtonVariantProps> type ComposedIconButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, IconButtonVariantProps>
export interface IconButtonProps extends ComposedIconButtonProps {} export interface IconButtonProps extends ComposedIconButtonProps {}
+20
View File
@@ -0,0 +1,20 @@
import { cx } from '@/styled-system/css'
import { listGroup, type ListGroupVariantProps } from '@/styled-system/recipes/list-group'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>, ListGroupVariantProps>
const ListGroup: FC<ComposedInputProps> = ({ children, className, ...rest }) => {
const [listGroupRecipeArgs, allOtherListGroupProps] = listGroup.splitVariantProps(rest)
return (
<ul
className={cx(listGroup(listGroupRecipeArgs).root, className)}
{...allOtherListGroupProps}
>
{children}
</ul>
)
}
export default ListGroup
+19
View File
@@ -0,0 +1,19 @@
import { cx } from '@/styled-system/css'
import { listGroup, type ListGroupVariantProps } from '@/styled-system/recipes/list-group'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type LiHTMLAttributes } from 'react'
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, ListGroupVariantProps>
const ListGroupItem: FC<ComposedInputProps> = ({ children, className, ...rest }) => {
const [listGroupRecipeArgs, allOtherListGroupProps] = listGroup.splitVariantProps(rest)
return (
<li
className={cx(listGroup(listGroupRecipeArgs).item, className)}
{...allOtherListGroupProps}
>
{children}
</li>
)
}
export default ListGroupItem
+28
View File
@@ -0,0 +1,28 @@
import { cx } from '@/styled-system/css'
import { tooltip, type TooltipVariantProps } from '@/styled-system/recipes/tooltip'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
type ComposedTooltipProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, TooltipVariantProps> & {
title: ReactNode
}
const Tooltip: FC<ComposedTooltipProps> = ({ children, className, title, ...rest }) => {
const [tooltipRecipeArgs, allOtherTooltipProps] = tooltip.splitVariantProps(rest)
return (
<div
className={cx(tooltip(tooltipRecipeArgs), className)}
{...allOtherTooltipProps}
>
{children}
<span
className="tooltip__content"
aria-hidden="true"
>
{title}
</span>
</div>
)
}
export default Tooltip
+7 -12
View File
@@ -1,9 +1,9 @@
import { cx } from '@/styled-system/css' import { cx } from '@/styled-system/css'
import { typography, type TypographyVariantProps } from '@/styled-system/recipes' import { typography, type TypographyVariantProps } from '@/styled-system/recipes/typography'
import { type MergeOmitting } from '@/types/utilities' import { type MergeOmitting } from '@/types/utilities'
import React, { type ElementType, type FC } from 'react' import { type ElementType, type FC, type HTMLAttributes } from 'react'
type ComposedTypographyProps = MergeOmitting<React.HTMLAttributes<HTMLElement>, TypographyVariantProps> type ComposedTypographyProps = MergeOmitting<HTMLAttributes<HTMLElement>, TypographyVariantProps>
export interface TypographyProps extends ComposedTypographyProps { export interface TypographyProps extends ComposedTypographyProps {
component?: ElementType component?: ElementType
@@ -33,19 +33,14 @@ const variantToComponent = (variant: TypographyVariantProps['variant']): Element
} }
} }
const isHeading = (text: string): boolean => {
return text.startsWith('h')
}
const Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => { const Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest) const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
const Component = component ?? variantToComponent(typographyRecipeArgs.variant) const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
typographyRecipeArgs.color = typographyRecipeArgs.color !== undefined typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
? typographyRecipeArgs.color
: typeof typographyRecipeArgs.variant === 'string' && isHeading(typographyRecipeArgs.variant)
? 'primary' ? 'primary'
: undefined : 'inherit'
)
return ( return (
<Component <Component
className={cx(typography(typographyRecipeArgs), className)} className={cx(typography(typographyRecipeArgs), className)}
+11 -6
View File
@@ -3,15 +3,20 @@ import { input, type InputVariantProps } from '@/styled-system/recipes/input'
import { type MergeOmitting } from '@/types/utilities' import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react' import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react'
export type InputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps> type ComposedInputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
const Input: FC<InputProps> = ({ className, ...props }) => { export interface InputProps extends ComposedInputProps {}
const [inputCss, rest] = input.splitVariantProps(props)
const Input: FC<InputProps> = ({ children, className, ...rest }) => {
const [inputRecipeArgs, allOtherInputProps] = input.splitVariantProps(rest)
return ( return (
<input <input
className={cx(input(inputCss), className)} className={cx(input(inputRecipeArgs), className)}
{...rest} {...allOtherInputProps}
/> >
{children}
</input>
) )
} }
export default Input export default Input
+57
View File
@@ -0,0 +1,57 @@
import IconButton from '@/components/ui/IconButton'
import Tooltip from '@/components/ui/Tooltip'
import { css, cx } from '@/styled-system/css'
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
import { type MergeOmitting } from '@/types/utilities'
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useState, type FC, type InputHTMLAttributes } from 'react'
export type InputProps = MergeOmitting<Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>, InputVariantProps>
const PasswordInput: FC<InputProps> = ({ className, ...props }) => {
const [showPassword, setShowPassword] = useState(false)
const [inputCss, rest] = input.splitVariantProps(props)
return (
<div
className={css({
display: 'flex',
alignItems: 'center',
position: 'relative'
})}
>
<input
className={cx(
input(inputCss),
css({ fontSize: 'medium' }),
className
)}
{...rest}
type={showPassword ? 'text' : 'password'}
/>
<div
className={css({
position: 'absolute',
right: '16px',
top: '50%',
transform: 'translateY(-50%)'
})}
>
<Tooltip
title={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
position="top"
>
<IconButton
type="button"
color="primary"
size="small"
onClick={() => { setShowPassword(!showPassword) }}
>
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} fixedWidth/>
</IconButton>
</Tooltip>
</div>
</div>
)
}
export default PasswordInput