mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 04:26:30 +08:00
feat: emoji-picker
This commit is contained in:
parent
01384e634c
commit
db1e311519
@ -4,7 +4,7 @@ import { useEffect } from 'react'
|
|||||||
import AppCard from './AppCard'
|
import AppCard from './AppCard'
|
||||||
import NewAppCard from './NewAppCard'
|
import NewAppCard from './NewAppCard'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import EmojiPicker from '@/app/components/base/emoji-picker'
|
|
||||||
const Apps = () => {
|
const Apps = () => {
|
||||||
const { apps, mutateApps } = useAppContext()
|
const { apps, mutateApps } = useAppContext()
|
||||||
|
|
||||||
@ -13,12 +13,11 @@ const Apps = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
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'>
|
<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} />))}
|
{apps.map(app => (<AppCard key={app.id} app={app} />))}
|
||||||
<NewAppCard />
|
<NewAppCard />
|
||||||
</nav>
|
</nav>
|
||||||
<EmojiPicker /></>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import NewAppDialog from './NewAppDialog'
|
|||||||
const CreateAppCard = () => {
|
const CreateAppCard = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a className={classNames(style.listItem, style.newItemCard)} onClick={() => setShowNewAppDialog(true)}>
|
<a className={classNames(style.listItem, style.newItemCard)} onClick={() => setShowNewAppDialog(true)}>
|
||||||
<div className={style.listItemTitle}>
|
<div className={style.listItemTitle}>
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import { createApp, fetchAppTemplates } from '@/service/apps'
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import AppsContext from '@/context/app-context'
|
import AppsContext from '@/context/app-context'
|
||||||
|
|
||||||
|
import EmojiPicker from '@/app/components/base/emoji-picker'
|
||||||
|
|
||||||
type NewAppDialogProps = {
|
type NewAppDialogProps = {
|
||||||
show: boolean
|
show: boolean
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
@ -31,6 +33,7 @@ const NewAppDialog = ({ show, onClose }: NewAppDialogProps) => {
|
|||||||
const [newAppMode, setNewAppMode] = useState<AppMode>()
|
const [newAppMode, setNewAppMode] = useState<AppMode>()
|
||||||
const [isWithTemplate, setIsWithTemplate] = useState(false)
|
const [isWithTemplate, setIsWithTemplate] = useState(false)
|
||||||
const [selectedTemplateIndex, setSelectedTemplateIndex] = useState<number>(-1)
|
const [selectedTemplateIndex, setSelectedTemplateIndex] = useState<number>(-1)
|
||||||
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false)
|
||||||
const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
|
const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
|
||||||
|
|
||||||
const { data: templates, mutate } = useSWR({ url: '/app-templates' }, fetchAppTemplates)
|
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>
|
<h3 className={style.newItemCaption}>{t('app.newApp.captionName')}</h3>
|
||||||
|
|
||||||
<div className='flex items-center justify-between gap-3 mb-8'>
|
<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' />
|
<input ref={nameInputRef} className='h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg grow' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export type AppIconProps = {
|
|||||||
background?: string
|
background?: string
|
||||||
className?: string
|
className?: string
|
||||||
innerIcon?: React.ReactNode
|
innerIcon?: React.ReactNode
|
||||||
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppIcon: FC<AppIconProps> = ({
|
const AppIcon: FC<AppIconProps> = ({
|
||||||
@ -17,6 +18,7 @@ const AppIcon: FC<AppIconProps> = ({
|
|||||||
background,
|
background,
|
||||||
className,
|
className,
|
||||||
innerIcon,
|
innerIcon,
|
||||||
|
onClick,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
@ -29,6 +31,7 @@ const AppIcon: FC<AppIconProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
background,
|
background,
|
||||||
}}
|
}}
|
||||||
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{innerIcon ? innerIcon : <>🤖</>}
|
{innerIcon ? innerIcon : <>🤖</>}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import {
|
|||||||
MagnifyingGlassIcon
|
MagnifyingGlassIcon
|
||||||
} from '@heroicons/react/24/outline'
|
} from '@heroicons/react/24/outline'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import Modal from '@/app/components/base/modal'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
@ -95,7 +96,6 @@ const EmojiSelect: FC<IEmojiSelectProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const { categories, emojis } = data as any
|
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">
|
return <div className="w-full max-h-[200px] overflow-x-hidden overflow-y-auto px-3">
|
||||||
{categories.map((category: any) => {
|
{categories.map((category: any) => {
|
||||||
return <div key={category.id} className='flex flex-col'>
|
return <div key={category.id} className='flex flex-col'>
|
||||||
@ -122,16 +122,21 @@ const EmojiSelect: FC<IEmojiSelectProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IEmojiPickerProps {
|
interface IEmojiPickerProps {
|
||||||
|
isModal?: boolean
|
||||||
onSelect?: (emoji: string, background: string) => void
|
onSelect?: (emoji: string, background: string) => void
|
||||||
}
|
}
|
||||||
const EmojiPicker: FC<IEmojiPickerProps> = ({
|
const EmojiPicker: FC<IEmojiPickerProps> = ({
|
||||||
|
isModal = true,
|
||||||
onSelect
|
onSelect
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedEmoji, setSelectedEmoji] = useState('')
|
const [selectedEmoji, setSelectedEmoji] = useState('')
|
||||||
const [selectBackground, setSelectBackground] = useState('')
|
|
||||||
|
|
||||||
const Elem = () => {
|
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='flex flex-col items-center w-full p-3'>
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
|
<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)
|
setSelectedEmoji(itm)
|
||||||
}} />
|
}} />
|
||||||
<ColorSelect selectedEmoji={selectedEmoji} onSelect={color => {
|
<ColorSelect selectedEmoji={selectedEmoji} onSelect={color => {
|
||||||
setSelectBackground(color)
|
|
||||||
onSelect && onSelect(selectedEmoji, color)
|
onSelect && onSelect(selectedEmoji, color)
|
||||||
}} />
|
}} />
|
||||||
<Divider className='m-0' />
|
<Divider className='m-0' />
|
||||||
@ -154,11 +158,10 @@ const EmojiPicker: FC<IEmojiPickerProps> = ({
|
|||||||
OK
|
OK
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Modal> : <>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <Elem />
|
||||||
<Elem />
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
export default EmojiPicker
|
export default EmojiPicker
|
||||||
|
|||||||
@ -23,51 +23,51 @@ export default function Modal({
|
|||||||
closable = false,
|
closable = false,
|
||||||
}: IModal) {
|
}: IModal) {
|
||||||
return (
|
return (
|
||||||
<Transition appear show={isShow} as={Fragment}>
|
<Transition appear show={isShow} as={Fragment}>
|
||||||
<Dialog as="div" className="relative z-10" onClose={onClose}>
|
<Dialog as="div" className="relative z-10" onClose={onClose}>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-in duration-200"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 overflow-y-auto">
|
<div className="fixed inset-0 overflow-y-auto">
|
||||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-in duration-200"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
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}`}>
|
<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
|
{title && <Dialog.Title
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-medium leading-6 text-gray-900"
|
className="text-lg font-medium leading-6 text-gray-900"
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</Dialog.Title>}
|
</Dialog.Title>}
|
||||||
{description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
|
{description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
|
||||||
{description}
|
{description}
|
||||||
</Dialog.Description>}
|
</Dialog.Description>}
|
||||||
{closable
|
{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'>
|
&& <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} />
|
<XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
|
||||||
</div>}
|
</div>}
|
||||||
{children}
|
{children}
|
||||||
</Dialog.Panel>
|
</Dialog.Panel>
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition>
|
</Transition>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user