types: improved component typing

This commit is contained in:
wonderlandpark 2021-05-18 11:16:48 +09:00
parent 74fa828189
commit 3b52e4c386
43 changed files with 236 additions and 235 deletions

View File

@ -1,7 +1,7 @@
import { useEffect } from 'react'
import Logger from '@utils/Logger'
const Advertisement = ({ size = 'short' }: AdvertisementProps): JSX.Element => {
const Advertisement: React.FC<AdvertisementProps> = ({ size = 'short' }) => {
useEffect(() => {
if (process.env.NODE_ENV === 'production') {
window.adsbygoogle = window.adsbygoogle || []

View File

@ -3,15 +3,14 @@ import Link from 'next/link'
const DiscordAvatar = dynamic(() => import('@components/DiscordAvatar'))
const Application = ({ type, id, name }: ApplicationProps): JSX.Element => {
return (
<Link href={`/developers/applications/${type + 's'}/${id}`}>
<div className='relative px-2 py-4 text-center dark:bg-discord-black bg-little-white rounded-lg cursor-pointer transform hover:-translate-y-1 transition duration-100 ease-in'>
<DiscordAvatar userID={id} className='px-2 w-full rounded-xl' />
<h2 className='pt-2 whitespace-nowrap text-xl font-medium truncate'>{name}</h2>
</div>
</Link>
)
const Application: React.FC<ApplicationProps> = ({ type, id, name }) => {
return <Link href={`/developers/applications/${type + 's'}/${id}`}>
<div className='relative px-2 py-4 text-center dark:bg-discord-black bg-little-white rounded-lg cursor-pointer transform hover:-translate-y-1 transition duration-100 ease-in'>
<DiscordAvatar userID={id} className='px-2 w-full rounded-xl' />
<h2 className='pt-2 whitespace-nowrap text-xl font-medium truncate'>{name}</h2>
</div>
</Link>
}
interface ApplicationProps {

View File

@ -9,115 +9,114 @@ const Divider = dynamic(() => import('@components/Divider'))
const Tag = dynamic(() => import('@components/Tag'))
const DiscordAvatar = dynamic(() => import('@components/DiscordAvatar'))
const BotCard = ({ manage = false, bot }: BotProps): JSX.Element => {
return (
<div className='container mb-16 transform hover:-translate-y-1 transition duration-100 ease-in cursor-pointer'>
<div className='relative'>
<div className='container mx-auto'>
<div className='h-full'>
<div
className='relative mx-auto h-full text-black dark:text-white dark:bg-discord-black bg-little-white rounded-2xl shadow-xl'
style={
checkBotFlag(bot.flags, 'trusted') && bot.banner
? {
background: `linear-gradient(to right, rgba(34, 36, 38, 0.68), rgba(34, 36, 38, 0.68)), url("${bot.banner}") center top / cover no-repeat`,
color: 'white',
}
: {}
}
>
<Link href={makeBotURL(bot)}>
<div>
<div className='flex h-44'>
<div className='w-3/5'>
<div className='flex justify-start'>
<DiscordAvatar
size={128}
userID={bot.id}
alt='Avatar'
className='absolute -left-2 -top-8 mx-auto w-32 h-32 bg-white rounded-full'
/>
</div>
<div className='mt-28 px-4'>
<h2 className='px-1 text-sm'>
<i className={`fas fa-circle text-${Status[bot.status]?.color}`} />
{Status[bot.status]?.text}
</h2>
<h1 className='mb-3 text-left text-2xl font-bold truncate'>{bot.name}</h1>
</div>
const BotCard: React.FC<BotCardProps> = ({ manage = false, bot }) => {
return <div className='container mb-16 transform hover:-translate-y-1 transition duration-100 ease-in cursor-pointer'>
<div className='relative'>
<div className='container mx-auto'>
<div className='h-full'>
<div
className='relative mx-auto h-full text-black dark:text-white dark:bg-discord-black bg-little-white rounded-2xl shadow-xl'
style={
checkBotFlag(bot.flags, 'trusted') && bot.banner
? {
background: `linear-gradient(to right, rgba(34, 36, 38, 0.68), rgba(34, 36, 38, 0.68)), url("${bot.banner}") center top / cover no-repeat`,
color: 'white',
}
: {}
}
>
<Link href={makeBotURL(bot)}>
<div>
<div className='flex h-44'>
<div className='w-3/5'>
<div className='flex justify-start'>
<DiscordAvatar
size={128}
userID={bot.id}
alt='Avatar'
className='absolute -left-2 -top-8 mx-auto w-32 h-32 bg-white rounded-full'
/>
</div>
<div className='grid grid-cols-1 pr-5 py-5 w-2/5 h-0'>
<Tag
text={
<>
<i className='fas fa-heart text-red-600' /> {formatNumber(bot.votes)}
</>
}
dark
/>
<Tag
blurple
text={bot.servers ? <>{formatNumber(bot.servers)} </> : 'N/A'}
dark
/>
<div className='mt-28 px-4'>
<h2 className='px-1 text-sm'>
<i className={`fas fa-circle text-${Status[bot.status]?.color}`} />
{Status[bot.status]?.text}
</h2>
<h1 className='mb-3 text-left text-2xl font-bold truncate'>{bot.name}</h1>
</div>
</div>
<p className='mb-10 px-4 h-6 text-left text-gray-400 text-sm font-medium'>
{bot.intro}
</p>
<div>
<div className='category flex flex-wrap px-2'>
{bot.category.slice(0, 3).map(el => (
<Tag key={el} text={el} href={`/categories/${el}`} dark />
))}{' '}
{bot.category.length > 3 && <Tag text={`+${bot.category.length - 3}`} dark />}
</div>
<div className='grid grid-cols-1 pr-5 py-5 w-2/5 h-0'>
<Tag
text={
<>
<i className='fas fa-heart text-red-600' /> {formatNumber(bot.votes)}
</>
}
dark
/>
<Tag
blurple
text={bot.servers ? <>{formatNumber(bot.servers)} </> : 'N/A'}
dark
/>
</div>
</div>
</Link>
<Divider />
<div className='w-full'>
<div className='flex justify-evenly'>
<Link href={makeBotURL(bot)}>
<a className='py-3 w-full text-center text-koreanbots-blue hover:text-white text-sm font-bold hover:bg-koreanbots-blue rounded-bl-2xl hover:shadow-lg transition duration-100 ease-in'>
<p className='mb-10 px-4 h-6 text-left text-gray-400 text-sm font-medium'>
{bot.intro}
</p>
<div>
<div className='category flex flex-wrap px-2'>
{bot.category.slice(0, 3).map(el => (
<Tag key={el} text={el} href={`/categories/${el}`} dark />
))}{' '}
{bot.category.length > 3 && <Tag text={`+${bot.category.length - 3}`} dark />}
</div>
</div>
</div>
</Link>
<Divider />
<div className='w-full'>
<div className='flex justify-evenly'>
<Link href={makeBotURL(bot)}>
<a className='py-3 w-full text-center text-koreanbots-blue hover:text-white text-sm font-bold hover:bg-koreanbots-blue rounded-bl-2xl hover:shadow-lg transition duration-100 ease-in'>
</a>
</Link>
{manage ? (
<Link href={`/manage/${bot.id}`}>
<a className='py-3 w-full text-center text-green-500 hover:text-white text-sm font-bold hover:bg-green-500 rounded-br-2xl hover:shadow-lg transition duration-100 ease-in'>
</a>
</Link>
{manage ? (
<Link href={`/manage/${bot.id}`}>
<a className='py-3 w-full text-center text-green-500 hover:text-white text-sm font-bold hover:bg-green-500 rounded-br-2xl hover:shadow-lg transition duration-100 ease-in'>
</a>
</Link>
) : bot.state !== 'ok' ? <a
className='py-3 w-full text-center text-discord-blurple text-sm font-bold rounded-br-2xl hover:shadow-lg transition duration-100 ease-in opacity-50 cursor-default select-none'
>
) : bot.state !== 'ok' ? <a
className='py-3 w-full text-center text-discord-blurple text-sm font-bold rounded-br-2xl hover:shadow-lg transition duration-100 ease-in opacity-50 cursor-default select-none'
>
</a> :
<a
href={
bot.url ||
</a> :
<a
href={
bot.url ||
`https://discordapp.com/oauth2/authorize?client_id=${bot.id}&scope=bot&permissions=0`
}
rel='noopener noreferrer'
target='_blank'
className='py-3 w-full text-center text-discord-blurple hover:text-white text-sm font-bold hover:bg-discord-blurple rounded-br-2xl hover:shadow-lg transition duration-100 ease-in'
>
}
rel='noopener noreferrer'
target='_blank'
className='py-3 w-full text-center text-discord-blurple hover:text-white text-sm font-bold hover:bg-discord-blurple rounded-br-2xl hover:shadow-lg transition duration-100 ease-in'
>
</a>
}
</div>
</a>
}
</div>
</div>
</div>
</div>
</div>
</div>
)
</div>
}
interface BotProps {
interface BotCardProps {
manage?: boolean
bot: Bot
}

View File

@ -1,25 +1,23 @@
import Link from 'next/link'
import { ReactNode } from 'react'
const Button = ({
const Button: React.FC<ButtonProps> = ({
type = 'button',
className,
children,
href,
disabled=false,
onClick,
}: ButtonProps): JSX.Element => {
return href ? (
<Link href={!disabled && href}>
<a
className={`cursor-pointer rounded-md px-4 py-2 transition duration-300 ease select-none outline-none foucs:outline-none mr-1.5 ${className ??
}) => {
return href ? <Link href={!disabled && href}>
<a
className={`cursor-pointer rounded-md px-4 py-2 transition duration-300 ease select-none outline-none foucs:outline-none mr-1.5 ${className ??
'bg-discord-blurple hover:opacity-80 dark:bg-very-black dark:hover:bg-discord-dark-hover text-white'}`}
>
{children}
</a>
</Link>
) : onClick ? (
<button
>
{children}
</a>
</Link>
: onClick ? <button
type={disabled ? 'button' : type}
onClick={disabled ? null : onClick}
className={`cursor-pointer rounded-md px-4 py-2 transition duration-300 ease select-none outline-none foucs:outline-none mr-1.5 ${className ??
@ -27,15 +25,14 @@ const Button = ({
>
{children}
</button>
) : (
<button
type={disabled ? 'button' : type}
className={`cursor-pointer rounded-md px-4 py-2 transition duration-300 ease select-none outline-none foucs:outline-none mr-1.5 ${className ??
:
<button
type={disabled ? 'button' : type}
className={`cursor-pointer rounded-md px-4 py-2 transition duration-300 ease select-none outline-none foucs:outline-none mr-1.5 ${className ??
'bg-discord-blurple hover:opacity-80 dark:bg-very-black dark:hover:bg-discord-dark-hover text-white'}`}
>
{children}
</button>
)
>
{children}
</button>
}
interface ButtonProps {

View File

@ -2,7 +2,7 @@ import { Ref } from 'react'
import HCaptcha from '@hcaptcha/react-hcaptcha'
const Captcha = ({ dark, onVerify }:CaptchaProps):JSX.Element => {
const Captcha: React.FC<CaptchaProps> = ({ dark, onVerify }) => {
return <HCaptcha sitekey='43e556b4-cc90-494f-b100-378b906bb736' theme={dark ? 'dark' : 'light'} onVerify={onVerify}/>
}

View File

@ -1,4 +1,4 @@
const ColorCard = ({ header, first, second, className }: ColorCardProps): JSX.Element => {
const ColorCard: React.FC<ColorCardProps> = ({ header, first, second, className }) => {
return (
<div className={`rounded-lg p-10 ${className} shadow-lg`}>
<h2 className='text-2xl font-bold'>{header}</h2>

View File

@ -1,11 +1,11 @@
import { ReactNode } from 'react'
const Container = ({
const Container: React.FC<ContainerProps> = ({
ignoreColor,
className,
paddingTop = false,
children,
}: ContainerProps): JSX.Element => {
}) => {
return (
<div
className={`${ignoreColor ? '' : 'text-black dark:text-gray-100'} ${

View File

@ -9,7 +9,7 @@ const Container = dynamic(() => import('@components/Container'))
const Divider = dynamic(() => import('@components/Divider'))
const SEO = dynamic(() => import('@components/SEO'))
const DeveloperLayout = ({ children, enabled, docs, currentDoc }:DeveloperLayout):JSX.Element => {
const DeveloperLayout: React.FC<DeveloperLayout> = ({ children, enabled, docs, currentDoc }:DeveloperLayout) => {
const [ navbarEnabled, setNavbarOpen ] = useState(false)
return <div className='flex min-h-screen'>

View File

@ -3,12 +3,7 @@ import { KoreanbotsEndPoints } from '@utils/Constants'
import { supportsWebP } from '@utils/Tools'
import Logger from '@utils/Logger'
const DiscordAvatar = (props: {
alt?: string
userID: string
className?: string
size? : 128 | 256 | 512
}) => {
const DiscordAvatar: React.FC<DiscordAvatarProps> = props => {
const fallback = '/img/default.png'
const [ webpUnavailable, setWebpUnavailable ] = useState<boolean>()
@ -46,7 +41,12 @@ const DiscordAvatar = (props: {
/>
}
export default DiscordAvatar
interface DiscordAvatarProps {
alt?: string
userID: string
className?: string
size? : 128 | 256 | 512
}
interface ImageEvent extends Event {
target: ImageTarget
@ -55,4 +55,6 @@ interface ImageEvent extends Event {
interface ImageTarget extends EventTarget {
src: string
onerror: (event: SyntheticEvent<HTMLImageElement, ImageEvent>) => void
}
}
export default DiscordAvatar

View File

@ -1,4 +1,4 @@
const Divider = ({ className }: { className?: string }) => {
const Divider: React.FC<DividerProps> = ({ className }) => {
return (
<div
className={`my-2 px-5 ${className || ''}`}
@ -10,4 +10,8 @@ const Divider = ({ className }: { className?: string }) => {
)
}
interface DividerProps {
className?: string
}
export default Divider

View File

@ -2,7 +2,8 @@ import dynamic from 'next/dynamic'
const Container = dynamic(() => import('@components/Container'))
const SEO = dynamic(() => import('@components/SEO'))
const Docs = ({ title, header, description, subheader, children }: DocsProps): JSX.Element => {
const Docs: React.FC<DocsProps> = ({ title, header, description, subheader, children }) => {
return (
<>
<SEO
@ -32,9 +33,9 @@ const Docs = ({ title, header, description, subheader, children }: DocsProps): J
export default Docs
interface DocsProps {
header: string | JSX.Element
header: string | React.ReactNode
title?: string
description?: string
subheader?: string
children: JSX.Element | JSX.Element[]
children: React.ReactNode
}

View File

@ -6,7 +6,7 @@ import { Theme } from '@types'
const Container = dynamic(() => import('@components/Container'))
const Toggle = dynamic(() => import('@components/Toggle'))
const Footer = ({ theme, setTheme }: FooterProps): JSX.Element => {
const Footer: React.FC<FooterProps> = ({ theme, setTheme }) => {
return (
<div className='releative z-30'>
<div className='bottom-0 text-white bg-discord-black py-24'>

View File

@ -6,7 +6,7 @@ import { ErrorText } from '@utils/Constants'
const SEO = dynamic(() => import('@components/SEO'))
const Button = dynamic(() => import('@components/Button'))
const Forbidden = ():JSX.Element => {
const Forbidden:React.FC = () => {
const router = useRouter()
return <>
<SEO title='권한이 없습니다' />

View File

@ -1,6 +1,6 @@
import { Field } from 'formik'
const CheckBox = ({ name, ...props }: CheckBoxProps): JSX.Element => {
const CheckBox: React.FC<CheckBoxProps> = ({ name, ...props }) => {
return <Field type='checkbox' name={name} className='form-checkbox text-koreanbots-blue bg-gray-300 h-4 w-4 rounded' {...props} />
}

View File

@ -1,6 +1,6 @@
import { Field } from 'formik'
const CsrfToken = ({ token }: CsrfTokenProps): JSX.Element => {
const CsrfToken: React.FC<CsrfTokenProps> = ({ token }) => {
return <Field name='_csrf' hidden value={token} readOnly />
}

View File

@ -1,18 +1,18 @@
import { Field } from 'formik'
const Input = ({ name, placeholder }: InputProps): JSX.Element => {
return (
<Field
name={name}
className='border-grey-light relative px-3 w-full h-10 text-black dark:text-white dark:bg-very-black border dark:border-transparent rounded outline-none'
placeholder={placeholder}
/>
)
const Input: React.FC<InputProps> = ({ name, placeholder, ...props }) => {
return <Field
{...props}
name={name}
className='border-grey-light relative px-3 w-full h-10 text-black dark:text-white dark:bg-very-black border dark:border-transparent rounded outline-none'
placeholder={placeholder}
/>
}
interface InputProps {
name: string
placeholder?: string
[key: string]: unknown
}
export default Input

View File

@ -1,4 +1,4 @@
const Label = ({
const Label: React.FC<LabelProps> = ({
For,
children,
label,
@ -7,31 +7,27 @@ const Label = ({
grid = true,
short = false,
required = false,
}: LabelProps): JSX.Element => {
return (
<>
<label
className={grid ? 'grid grid-cols-1 xl:grid-cols-4 gap-2 my-4' : 'inline-flex items-center'}
htmlFor={For}
>
{label && (
<div className='col-span-1 text-sm'>
<h3 className='text-koreanbots-blue text-lg font-bold'>
{label}
{required && (
<span className='align-text-top text-red-500 text-base font-semibold'> *</span>
)}
</h3>
{labelDesc}
</div>
)}
<div className={short ? 'col-span-1' : 'col-span-3'}>
{children}
<div className='mt-1 text-red-500 text-xs font-light'>{error}</div>
</div>
</label>
</>
)
}) => {
return <label
className={grid ? 'grid grid-cols-1 xl:grid-cols-4 gap-2 my-4' : 'inline-flex items-center'}
htmlFor={For}
>
{label && (
<div className='col-span-1 text-sm'>
<h3 className='text-koreanbots-blue text-lg font-bold'>
{label}
{required && (
<span className='align-text-top text-red-500 text-base font-semibold'> *</span>
)}
</h3>
{labelDesc}
</div>
)}
<div className={short ? 'col-span-1' : 'col-span-3'}>
{children}
<div className='mt-1 text-red-500 text-xs font-light'>{error}</div>
</div>
</label>
}
interface LabelProps {

View File

@ -1,32 +1,30 @@
import ReactSelect from 'react-select'
const Select = ({ placeholder, options, handleChange, handleTouch, value }: SelectProps): JSX.Element => {
return (
<ReactSelect
styles={{
control: provided => {
return { ...provided, border: 'none' }
},
option: provided => {
return {
...provided,
cursor: 'pointer',
':hover': {
opacity: '0.7',
},
}
},
}}
className='border-grey-light border dark:border-transparent rounded'
classNamePrefix='outline-none text-black dark:bg-very-black dark:text-white '
placeholder={placeholder || '선택해주세요.'}
options={options}
onChange={handleChange}
onBlur={handleTouch}
noOptionsMessage={() => '검색 결과가 없습니다.'}
defaultValue={value}
/>
)
const Select: React.FC<SelectProps> = ({ placeholder, options, handleChange, handleTouch, value }) => {
return <ReactSelect
styles={{
control: provided => {
return { ...provided, border: 'none' }
},
option: provided => {
return {
...provided,
cursor: 'pointer',
':hover': {
opacity: '0.7',
},
}
},
}}
className='border-grey-light border dark:border-transparent rounded'
classNamePrefix='outline-none text-black dark:bg-very-black dark:text-white '
placeholder={placeholder || '선택해주세요.'}
options={options}
onChange={handleChange}
onBlur={handleTouch}
noOptionsMessage={() => '검색 결과가 없습니다.'}
defaultValue={value}
/>
}
interface SelectProps {

View File

@ -31,7 +31,7 @@ const SortableMultiValueLabel = SortableHandle(props => (
const SortableSelect = SortableContainer(ReactSelect)
const Select = ({ placeholder, options, values, setValues, handleChange, handleTouch }:SelectProps):JSX.Element => {
const Select: React.FC<SelectProps> = ({ placeholder, options, values, setValues, handleChange, handleTouch }) => {
const onSortEnd = ({ oldIndex, newIndex }) => {
const newValue = arrayMove(values, oldIndex, newIndex)
setValues(newValue)

View File

@ -10,7 +10,7 @@ import 'emoji-mart/css/emoji-mart.css'
const TextArea = ({ name, placeholder, theme='auto', setValue, value }:TextAreaProps):JSX.Element => {
const TextArea: React.FC<TextAreaProps> = ({ name, placeholder, theme='auto', setValue, value }) => {
const ref = useRef()
const [ emojiPickerHidden, setEmojiPickerHidden ] = useState(true)
useOutsideClick(ref, () => {

View File

@ -6,7 +6,7 @@ const Container = dynamic(()=> import('@components/Container'))
const Tag = dynamic(()=> import('@components/Tag'))
const Search = dynamic(()=> import('@components/Search'))
const Hero = ({ header, description }:HeroProps):JSX.Element => {
const Hero:React.FC<HeroProps> = ({ header, description }) => {
return <>
<div className='dark:bg-discord-black bg-discord-blurple text-gray-100 md:p-0 mb-8'>
<Container className='pt-24 pb-16 md:pb-20' ignoreColor>

View File

@ -1,4 +1,4 @@
const Loader = ({ text, visible = true }: LoaderProps): JSX.Element => {
const Loader: React.FC<LoaderProps> = ({ text, visible = true }) => {
return (
<div
className={`${
@ -13,7 +13,7 @@ const Loader = ({ text, visible = true }: LoaderProps): JSX.Element => {
}
interface LoaderProps {
text: string | JSX.Element
text: string | React.ReactNode
visible?: boolean
}

View File

@ -1,6 +1,7 @@
import { redirectTo } from '@utils/Tools'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import { redirectTo } from '@utils/Tools'
const Login: React.FC = ({ children }) => {
const router = useRouter()

View File

@ -1,7 +1,7 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import Link from 'next/link'
const LongButton = ({ children, newTab=false, href, onClick, center=false }:LongButtonProps):JSX.Element => {
const LongButton: React.FC<LongButtonProps> = ({ children, newTab=false, href, onClick, center=false }) => {
if(href) {
if(newTab) return <a href={href} rel='noopener noreferrer'
target='_blank'>

View File

@ -5,7 +5,7 @@ import { FunctionComponent } from 'react'
import { anchorHeader, customEmoji, twemoji } from '@utils/Tools'
const Markdown = ({ text, options={}, allowedTag=[], components={} }: MarkdownProps): JSX.Element => {
const Markdown: React.FC<MarkdownProps> = ({ text, options={}, allowedTag=[], components={} }) => {
return (
<div className='markdown-body w-full'>
<MarkdownView

View File

@ -1,7 +1,7 @@
import { MessageColor } from '@utils/Constants'
import Markdown from './Markdown'
const Message = ({ type, children }: MessageProps): JSX.Element => {
const Message: React.FC<MessageProps> = ({ type, children }) => {
return (
<div
className={`${MessageColor[type]} px-6 py-4 rounded-md text-base mx-auto w-full text-left`}

View File

@ -2,7 +2,7 @@ import { ReactNode } from 'react'
import { Modal as ReactModal } from 'react-responsive-modal'
import 'react-responsive-modal/styles.css'
const Modal = ({ children, isOpen, onClose, closeIcon=false, dark, header, full=false }: ModalProps): JSX.Element => {
const Modal: React.FC<ModalProps> = ({ children, isOpen, onClose, closeIcon=false, dark, header, full=false }) => {
return (
<ReactModal
open={isOpen}

View File

@ -3,7 +3,7 @@ import dynamic from 'next/dynamic'
const Button = dynamic(() => import('@components/Button'))
const Container = dynamic(() => import('@components/Container'))
const NSFW = ({ onClick, onDisableClick }:NSFWProps): JSX.Element => {
const NSFW: React.FC<NSFWProps> = ({ onClick, onDisableClick }) => {
return <Container>
<div className='flex items-center h-screen select-none'>
<div className='px-10'>

View File

@ -3,15 +3,16 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import { useEffect, useState } from 'react'
import Link from 'next/link'
import dynamic from 'next/dynamic'
import { useRouter } from 'next/router'
import { redirectTo } from '@utils/Tools'
import Fetch from '@utils/Fetch'
import { User, UserCache } from '@types'
import DiscordAvatar from '@components/DiscordAvatar'
import Fetch from '@utils/Fetch'
const DiscordAvatar = dynamic(() => import('@components/DiscordAvatar'))
const Navbar = ({ token, pwa }:{ token: string, pwa: boolean }): JSX.Element => {
const Navbar: React.FC<NavbarProps> = ({ token, pwa }) => {
const [userCache, setUserCache] = useState<UserCache>()
const [navbarOpen, setNavbarOpen] = useState<boolean>(false)
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false)
@ -213,4 +214,9 @@ const Navbar = ({ token, pwa }:{ token: string, pwa: boolean }): JSX.Element =>
)
}
interface NavbarProps {
token: string
pwa: boolean
}
export default Navbar

View File

@ -1,4 +1,4 @@
const Notice = ({ header, desc }: NoticeProps) => {
const Notice: React.FC<NoticeProps> = ({ header, desc }) => {
return (
<div className='mx-auto my-auto px-10 py-48 h-screen text-center'>
<h1 className='text-4xl font-bold'>KOREANBOTS</h1>

View File

@ -1,7 +1,7 @@
import Link from 'next/link'
import DiscordAvatar from '@components/DiscordAvatar'
const Owner = ({ id, username, tag }: OwnerProps): JSX.Element => {
const Owner: React.FC<OwnerProps> = ({ id, username, tag }) => {
return (
<Link href={`/users/${id}`}>
<a className='dark:hover:bg-discord-dark-hover flex mb-1 px-4 py-4 text-black dark:text-gray-400 text-base dark:bg-discord-black bg-little-white hover:bg-little-white-hover rounded cursor-pointer'>

View File

@ -1,5 +1,5 @@
import Link from 'next/link'
const Paginator = ({ currentPage, totalPage, pathname, searchParams }: PaginatorProps): JSX.Element => {
const Paginator: React.FC<PaginatorProps> = ({ currentPage, totalPage, pathname, searchParams }) => {
let pages = []
if (currentPage < 4)
pages = [

View File

@ -1,6 +1,6 @@
import { ReactNode } from 'react'
const PlatformDisplay = ({ osx, children }:PlatformDisplayProps): JSX.Element => {
const PlatformDisplay: React.FC<PlatformDisplayProps> = ({ osx, children }:PlatformDisplayProps) => {
const isOSX = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)
return <>{isOSX ? osx ?? children : children}</>
}

View File

@ -6,7 +6,7 @@ import { redirectTo } from '@utils/Tools'
const Container = dynamic(() => import('@components/Container'))
const Redirect = ({ to, text=true, children }:RedirectProps):JSX.Element => {
const Redirect: React.FC<RedirectProps> = ({ to, text=true, children }) => {
const router = useRouter()
if(!to) throw new Error('No Link')
useEffect(() => {

View File

@ -1,6 +1,4 @@
import { ReactNode } from 'react'
const ResponsiveGrid = ({ children }:{ children: ReactNode }):JSX.Element => {
const ResponsiveGrid: React.FC = ({ children }) => {
return <div className='grid gap-x-4 grid-rows-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 mt-10 -mb-10'>
{children}
</div>

View File

@ -1,6 +1,6 @@
import Head from 'next/head'
const SEO = ({ title, description, image }: SEOProps): JSX.Element => {
const SEO: React.FC<SEOProps> = ({ title, description, image }: SEOProps) => {
return (
<Head>
<title>{title} - </title>

View File

@ -11,7 +11,7 @@ import DiscordAvatar from '@components/DiscordAvatar'
import Day from '@utils/Day'
import useOutsideClick from '@utils/useOutsideClick'
const Search = (): JSX.Element => {
const Search: React.FC = () => {
const router = useRouter()
const ref = useRef()
const [query, setQuery] = useState('')

View File

@ -1,6 +1,6 @@
import { ReactNode } from 'react'
const Segment = ({ children, className = '' }: SegmentProps): JSX.Element => {
const Segment: React.FC<SegmentProps> = ({ children, className = '' }) => {
return (
<div
className={`py-3 px-7 text-black dark:text-white dark:bg-discord-black bg-little-white rounded ${className}`}

View File

@ -5,7 +5,7 @@ import Tag from '@components/Tag'
import { SubmittedBot } from '@types'
import Link from 'next/link'
const SubmittedBotCard = ({ href, submit }: SubmittedBotProps): JSX.Element => {
const SubmittedBotCard: React.FC<SubmittedBotProps> = ({ href, submit }) => {
return (
<Link href={href}>
<a className='relative mx-auto px-4 py-5 w-full h-full text-black dark:text-white dark:bg-discord-black bg-little-white rounded-2xl shadow-xl transform hover:-translate-y-1 transition duration-100 ease-in'>

View File

@ -1,7 +1,7 @@
import Link from 'next/link'
import { ReactNode } from 'react'
const Tag = ({
const Tag: React.FC<LabelProps> = ({
blurple = false,
github = false,
href,
@ -13,7 +13,7 @@ const Tag = ({
newTab = false,
bigger = false,
...props
}: LabelProps): JSX.Element => {
}) => {
return href ? (
newTab ? (
<a

View File

@ -1,4 +1,4 @@
const Toggle = ({ checked, onChange }: ToggleProps): JSX.Element => {
const Toggle: React.FC<ToggleProps> = ({ checked, onChange }: ToggleProps) => {
return (
<button
className='relative inline-block align-middle mr-2 w-10 outline-none select-none'

View File

@ -1,12 +1,12 @@
import Link from 'next/link'
const Tooltip = ({
const Tooltip: React.FC<TooltipProps> = ({
href,
size = 'small',
children,
direction = 'center',
text,
}: TooltipProps): JSX.Element => {
}) => {
return href ? (
<Link href={href}>
<a className='inline'>

View File

@ -1,4 +1,4 @@
const Wave = ({ color, className }: WaveProps): JSX.Element => {
const Wave: React.FC<WaveProps> = ({ color, className }) => {
return (
<svg viewBox='0 0 1440 320' className={className}>
<path