feat: emoji-picker

This commit is contained in:
crazywoola 2023-05-18 09:10:36 +08:00
parent 01384e634c
commit db1e311519
6 changed files with 70 additions and 58 deletions

View File

@ -4,7 +4,7 @@ import { useEffect } from 'react'
import AppCard from './AppCard'
import NewAppCard from './NewAppCard'
import { useAppContext } from '@/context/app-context'
import EmojiPicker from '@/app/components/base/emoji-picker'
const Apps = () => {
const { apps, mutateApps } = useAppContext()
@ -13,12 +13,11 @@ const Apps = () => {
}, [])
return (
<>
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-8 sm:grid-cols-2 lg:grid-cols-4 grow shrink-0'>
{apps.map(app => (<AppCard key={app.id} app={app} />))}
<NewAppCard />
</nav>
<EmojiPicker /></>
)
}

View File

@ -9,7 +9,6 @@ import NewAppDialog from './NewAppDialog'
const CreateAppCard = () => {
const { t } = useTranslation()
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
return (
<a className={classNames(style.listItem, style.newItemCard)} onClick={() => setShowNewAppDialog(true)}>
<div className={style.listItemTitle}>

View File

@ -17,6 +17,8 @@ import { createApp, fetchAppTemplates } from '@/service/apps'
import AppIcon from '@/app/components/base/app-icon'
import AppsContext from '@/context/app-context'
import EmojiPicker from '@/app/components/base/emoji-picker'
type NewAppDialogProps = {
show: boolean
onClose?: () => void
@ -31,6 +33,7 @@ const NewAppDialog = ({ show, onClose }: NewAppDialogProps) => {
const [newAppMode, setNewAppMode] = useState<AppMode>()
const [isWithTemplate, setIsWithTemplate] = useState(false)
const [selectedTemplateIndex, setSelectedTemplateIndex] = useState<number>(-1)
const [showEmojiPicker, setShowEmojiPicker] = useState(false)
const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
const { data: templates, mutate } = useSWR({ url: '/app-templates' }, fetchAppTemplates)
@ -93,10 +96,15 @@ const NewAppDialog = ({ show, onClose }: NewAppDialogProps) => {
</>
}
>
{showEmojiPicker && <EmojiPicker onSelect={(emoji, background) => {
console.log(emoji, background)
setShowEmojiPicker(false)
}} />}
<h3 className={style.newItemCaption}>{t('app.newApp.captionName')}</h3>
<div className='flex items-center justify-between gap-3 mb-8'>
<AppIcon size='large' />
<AppIcon size='large' onClick={() => { setShowEmojiPicker(true) }} />
<input ref={nameInputRef} className='h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg grow' />
</div>

View File

@ -9,6 +9,7 @@ export type AppIconProps = {
background?: string
className?: string
innerIcon?: React.ReactNode
onClick?: () => void
}
const AppIcon: FC<AppIconProps> = ({
@ -17,6 +18,7 @@ const AppIcon: FC<AppIconProps> = ({
background,
className,
innerIcon,
onClick,
}) => {
return (
<span
@ -29,6 +31,7 @@ const AppIcon: FC<AppIconProps> = ({
style={{
background,
}}
onClick={onClick}
>
{innerIcon ? innerIcon : <>🤖</>}
</span>

View File

@ -12,6 +12,7 @@ import {
MagnifyingGlassIcon
} from '@heroicons/react/24/outline'
import React from 'react'
import Modal from '@/app/components/base/modal'
declare global {
namespace JSX {
@ -95,7 +96,6 @@ const EmojiSelect: FC<IEmojiSelectProps> = ({
}) => {
const { categories, emojis } = data as any
console.log(categories, emojis);
return <div className="w-full max-h-[200px] overflow-x-hidden overflow-y-auto px-3">
{categories.map((category: any) => {
return <div key={category.id} className='flex flex-col'>
@ -122,16 +122,21 @@ const EmojiSelect: FC<IEmojiSelectProps> = ({
}
interface IEmojiPickerProps {
isModal?: boolean
onSelect?: (emoji: string, background: string) => void
}
const EmojiPicker: FC<IEmojiPickerProps> = ({
isModal = true,
onSelect
}) => {
const [selectedEmoji, setSelectedEmoji] = useState('')
const [selectBackground, setSelectBackground] = useState('')
const Elem = () => {
return <div className={cn(s.container, 'bg-white')} >
return isModal ? <Modal
onClose={() => { }}
isShow
className={cn(s.container, '!w-[362px] !p-0')}
>
<div className='flex flex-col items-center w-full p-3'>
<div className="relative w-full">
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@ -145,7 +150,6 @@ const EmojiPicker: FC<IEmojiPickerProps> = ({
setSelectedEmoji(itm)
}} />
<ColorSelect selectedEmoji={selectedEmoji} onSelect={color => {
setSelectBackground(color)
onSelect && onSelect(selectedEmoji, color)
}} />
<Divider className='m-0' />
@ -154,11 +158,10 @@ const EmojiPicker: FC<IEmojiPickerProps> = ({
OK
</Button>
</div>
</div>
</Modal> : <>
</>
}
return <>
<Elem />
</>
return <Elem />
}
export default EmojiPicker

View File

@ -23,51 +23,51 @@ export default function Modal({
closable = false,
}: IModal) {
return (
<Transition appear show={isShow} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>
<Transition appear show={isShow} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all ${className}`}>
{title && <Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
>
{title}
</Dialog.Title>}
{description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
{description}
</Dialog.Description>}
{closable
&& <div className='absolute top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
<XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
</div>}
{children}
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all ${className}`}>
{title && <Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
>
{title}
</Dialog.Title>}
{description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
{description}
</Dialog.Description>}
{closable
&& <div className='absolute top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
<XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
</div>}
{children}
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
)
}