mirror of
https://github.com/koreanbots/core.git
synced 2025-12-15 14:10:22 +00:00
feat: added emoji picker
This commit is contained in:
parent
cc0485e8a9
commit
6d80be3296
22
app.css
22
app.css
@ -88,4 +88,26 @@ html .dark * ::-webkit-scrollbar-track {
|
||||
|
||||
button {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.emoji-selector-button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: inline-block;
|
||||
background-image: url("https://unpkg.com/emoji-datasource-twitter@5.0.1/img/twitter/sheets-256/64.png");
|
||||
background-size: 5700% 5700%;
|
||||
background-position: 53.5714% 62.5%;
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.emoji-selector-button:hover {
|
||||
filter: grayscale(0%);
|
||||
transform: scale(1.1, 1.1);
|
||||
opacity: 90%;
|
||||
transition: ease-in 100ms;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.emoji-mart-category-list > *, .emoji-mart-emoji > span {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -1,12 +1,67 @@
|
||||
/* eslint-disable jsx-a11y/no-autofocus */
|
||||
import { useRef, useState } from 'react'
|
||||
import { Field } from 'formik'
|
||||
import { Picker } from 'emoji-mart'
|
||||
|
||||
const TextArea = ({ name, placeholder }:TextAreaProps):JSX.Element => {
|
||||
return <Field as='textarea' name={name} className='border border-grey-light dark:border-transparent text-black dark:bg-very-black dark:text-white w-full rounded px-4 py-3 relative min-h-3 resize-none outline-none' placeholder={placeholder} />
|
||||
import useOutsideClick from '@utils/useOutsideClick'
|
||||
|
||||
import 'emoji-mart/css/emoji-mart.css'
|
||||
|
||||
|
||||
|
||||
const TextArea = ({ name, placeholder, theme='auto', setValue, value }:TextAreaProps):JSX.Element => {
|
||||
const ref = useRef()
|
||||
const [ emojiPickerHidden, setEmojiPickerHidden ] = useState(true)
|
||||
useOutsideClick(ref, () => {
|
||||
setEmojiPickerHidden(true)
|
||||
})
|
||||
|
||||
return <div className='border-none h-96 text-black dark:bg-very-black dark:text-white rounded px-4 py-3 inline-block relative w-full'>
|
||||
<Field as='textarea' name={name} className='dark:border-transparent text-black dark:bg-very-black dark:text-white w-full relative h-full resize-none outline-none' placeholder={placeholder} />
|
||||
<div ref={ref}>
|
||||
<div className='absolute bottom-12 right-10 z-30'>
|
||||
{
|
||||
!emojiPickerHidden && <Picker set='twitter' autoFocus enableFrequentEmojiSort theme={theme} showSkinTones={false} onSelect={(e) => {
|
||||
setEmojiPickerHidden(true)
|
||||
setValue(value + ((e as { native: string }).native || e.colons))
|
||||
}} i18n={{
|
||||
search: '검색',
|
||||
notfound: '검색 결과가 없습니다.',
|
||||
categories: {
|
||||
search: '검색 결과',
|
||||
recent: '최근 사용',
|
||||
people: '사람',
|
||||
nature: '자연',
|
||||
foods: '음식',
|
||||
activity: '활동',
|
||||
places: '장소',
|
||||
objects: '사물',
|
||||
symbols: '기호',
|
||||
flags: '국기',
|
||||
custom: '커스텀'
|
||||
}
|
||||
}} custom={[{
|
||||
name: '한국 디스코드봇 리스트',
|
||||
short_names: ['koreanbots', 'kbots', 'dbkr'],
|
||||
emoticons: [],
|
||||
keywords: ['koreanbots', '한국 디스코드봇 리스트', '한디리', 'kbots'],
|
||||
imageUrl: '/logo.png'
|
||||
}]}/>
|
||||
}
|
||||
</div>
|
||||
<div className='absolute bottom-3 right-8'>
|
||||
<button className='emoji-selector-button' onClick={() => setEmojiPickerHidden(false)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
interface TextAreaProps {
|
||||
name: string
|
||||
placeholder?: string
|
||||
theme?: 'auto' | 'dark' | 'light'
|
||||
value: string
|
||||
setValue(value: string): void
|
||||
}
|
||||
|
||||
export default TextArea
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { NextPage, NextPageContext } from 'next'
|
||||
import { useState } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Link from 'next/link'
|
||||
@ -9,9 +9,10 @@ import { get } from '@utils/Query'
|
||||
import { cleanObject, parseCookie, redirectTo } from '@utils/Tools'
|
||||
import { AddBotSubmit, AddBotSubmitSchema } from '@utils/Yup'
|
||||
import { categories, library } from '@utils/Constants'
|
||||
import { ResponseProps, SubmittedBot, User } from '@types'
|
||||
import { ResponseProps, SubmittedBot, Theme, User } from '@types'
|
||||
import { getToken } from '@utils/Csrf'
|
||||
import Fetch from '@utils/Fetch'
|
||||
import useOutsideClick from '@utils/useOutsideClick'
|
||||
|
||||
const CheckBox = dynamic(() => import('@components/Form/CheckBox'))
|
||||
const Label = dynamic(() => import('@components/Form/Label'))
|
||||
@ -27,7 +28,7 @@ const Container = dynamic(() => import('@components/Container'))
|
||||
const Message = dynamic(() => import('@components/Message'))
|
||||
const SEO = dynamic(() => import('@components/SEO'))
|
||||
|
||||
const AddBot:NextPage<AddBotProps> = ({ logged, user, csrfToken }) => {
|
||||
const AddBot:NextPage<AddBotProps> = ({ logged, user, csrfToken, theme }) => {
|
||||
const [ data, setData ] = useState<ResponseProps<SubmittedBot>>(null)
|
||||
const router = useRouter()
|
||||
function toLogin() {
|
||||
@ -149,7 +150,7 @@ const AddBot:NextPage<AddBotProps> = ({ logged, user, csrfToken }) => {
|
||||
<Input name='intro' placeholder='국내 봇을 한 곳에서.' />
|
||||
</Label>
|
||||
<Label For='intro' label='봇 설명' labelDesc={<>봇을 자세하게 설명해주세요! (최대 1500자)<br/>마크다운을 지원합니다!</>} error={errors.desc && touched.desc ? errors.desc : null} required>
|
||||
<TextArea name='desc' placeholder='봇에 대해 최대한 자세히 설명해주세요!' />
|
||||
<TextArea name='desc' placeholder='봇에 대해 최대한 자세히 설명해주세요!' theme={theme === 'dark' ? 'dark' : 'light'} value={values.desc} setValue={(value) => setFieldValue('desc', value)} />
|
||||
</Label>
|
||||
<Label For='preview' label='설명 미리보기' labelDesc='다음 결과는 실제와 다를 수 있습니다'>
|
||||
<Segment>
|
||||
@ -178,6 +179,7 @@ interface AddBotProps {
|
||||
logged: boolean
|
||||
user: User
|
||||
csrfToken: string
|
||||
theme: Theme
|
||||
}
|
||||
|
||||
export default AddBot
|
||||
19
utils/useOutsideClick.ts
Normal file
19
utils/useOutsideClick.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { RefObject, useEffect } from 'react'
|
||||
|
||||
const useOutsideClick = (ref: RefObject<HTMLElement>, callback: () => void) => {
|
||||
const handleClick = (e) => {
|
||||
if (ref.current && !ref.current.contains(e.target)) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleClick)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleClick)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default useOutsideClick
|
||||
Loading…
x
Reference in New Issue
Block a user