feat: shortcut delete and clean thread (#3423)
This commit is contained in:
parent
9aa3a61347
commit
dc8acc0d49
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Fragment, ReactNode, useEffect } from 'react'
|
import { Fragment, ReactNode, useEffect } from 'react'
|
||||||
|
|
||||||
import { useAtomValue, useSetAtom } from 'jotai'
|
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
||||||
|
|
||||||
import { MainViewState } from '@/constants/screens'
|
import { MainViewState } from '@/constants/screens'
|
||||||
|
|
||||||
@ -14,6 +14,11 @@ import {
|
|||||||
showRightPanelAtom,
|
showRightPanelAtom,
|
||||||
} from '@/helpers/atoms/App.atom'
|
} from '@/helpers/atoms/App.atom'
|
||||||
import { assistantsAtom } from '@/helpers/atoms/Assistant.atom'
|
import { assistantsAtom } from '@/helpers/atoms/Assistant.atom'
|
||||||
|
import {
|
||||||
|
activeThreadAtom,
|
||||||
|
modalActionThreadAtom,
|
||||||
|
ThreadModalAction,
|
||||||
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
@ -22,9 +27,11 @@ type Props = {
|
|||||||
export default function KeyListener({ children }: Props) {
|
export default function KeyListener({ children }: Props) {
|
||||||
const setShowLeftPanel = useSetAtom(showLeftPanelAtom)
|
const setShowLeftPanel = useSetAtom(showLeftPanelAtom)
|
||||||
const setShowRightPanel = useSetAtom(showRightPanelAtom)
|
const setShowRightPanel = useSetAtom(showRightPanelAtom)
|
||||||
const setMainViewState = useSetAtom(mainViewStateAtom)
|
const [mainViewState, setMainViewState] = useAtom(mainViewStateAtom)
|
||||||
const { requestCreateNewThread } = useCreateNewThread()
|
const { requestCreateNewThread } = useCreateNewThread()
|
||||||
const assistants = useAtomValue(assistantsAtom)
|
const assistants = useAtomValue(assistantsAtom)
|
||||||
|
const activeThread = useAtomValue(activeThreadAtom)
|
||||||
|
const setModalActionThread = useSetAtom(modalActionThreadAtom)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
@ -35,7 +42,26 @@ export default function KeyListener({ children }: Props) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Backspace' && prefixKey && e.shiftKey) {
|
||||||
|
if (!activeThread || mainViewState !== MainViewState.Thread) return
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: ThreadModalAction.Delete,
|
||||||
|
thread: activeThread,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'c' && prefixKey && e.shiftKey) {
|
||||||
|
if (!activeThread || mainViewState !== MainViewState.Thread) return
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: ThreadModalAction.Clean,
|
||||||
|
thread: activeThread,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (e.key === 'n' && prefixKey) {
|
if (e.key === 'n' && prefixKey) {
|
||||||
|
if (mainViewState !== MainViewState.Thread) return
|
||||||
requestCreateNewThread(assistants[0])
|
requestCreateNewThread(assistants[0])
|
||||||
setMainViewState(MainViewState.Thread)
|
setMainViewState(MainViewState.Thread)
|
||||||
return
|
return
|
||||||
@ -54,9 +80,12 @@ export default function KeyListener({ children }: Props) {
|
|||||||
document.addEventListener('keydown', onKeyDown)
|
document.addEventListener('keydown', onKeyDown)
|
||||||
return () => document.removeEventListener('keydown', onKeyDown)
|
return () => document.removeEventListener('keydown', onKeyDown)
|
||||||
}, [
|
}, [
|
||||||
|
activeThread,
|
||||||
assistants,
|
assistants,
|
||||||
|
mainViewState,
|
||||||
requestCreateNewThread,
|
requestCreateNewThread,
|
||||||
setMainViewState,
|
setMainViewState,
|
||||||
|
setModalActionThread,
|
||||||
setShowLeftPanel,
|
setShowLeftPanel,
|
||||||
setShowRightPanel,
|
setShowRightPanel,
|
||||||
])
|
])
|
||||||
|
|||||||
@ -9,6 +9,12 @@ import {
|
|||||||
import { atom } from 'jotai'
|
import { atom } from 'jotai'
|
||||||
import { atomWithStorage } from 'jotai/utils'
|
import { atomWithStorage } from 'jotai/utils'
|
||||||
|
|
||||||
|
export enum ThreadModalAction {
|
||||||
|
Clean = 'clean',
|
||||||
|
Delete = 'delete',
|
||||||
|
EditTitle = 'edit-title',
|
||||||
|
}
|
||||||
|
|
||||||
export const engineParamsUpdateAtom = atom<boolean>(false)
|
export const engineParamsUpdateAtom = atom<boolean>(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,3 +144,11 @@ export const activeSettingInputBoxAtom = atomWithStorage<boolean>(
|
|||||||
ACTIVE_SETTING_INPUT_BOX,
|
ACTIVE_SETTING_INPUT_BOX,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const modalActionThreadAtom = atom<{
|
||||||
|
showModal: ThreadModalAction | undefined
|
||||||
|
thread: Thread | undefined
|
||||||
|
}>({
|
||||||
|
showModal: undefined,
|
||||||
|
thread: undefined,
|
||||||
|
})
|
||||||
|
|||||||
@ -16,6 +16,16 @@ const availableHotkeys = [
|
|||||||
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
||||||
description: 'Toggle right panel',
|
description: 'Toggle right panel',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
combination: 'Shift Backspace',
|
||||||
|
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
||||||
|
description: 'Delete current active thread',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
combination: 'Shift C',
|
||||||
|
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
||||||
|
description: 'Clean current active thread',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
combination: ',',
|
combination: ',',
|
||||||
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
modifierKeys: [isMac ? '⌘' : 'Ctrl'],
|
||||||
|
|||||||
@ -1,54 +1,54 @@
|
|||||||
import { useCallback, memo } from 'react'
|
import { useCallback, memo } from 'react'
|
||||||
|
|
||||||
import { Button, Modal, ModalClose } from '@janhq/joi'
|
import { Button, Modal, ModalClose } from '@janhq/joi'
|
||||||
import { Paintbrush } from 'lucide-react'
|
import { useAtom } from 'jotai'
|
||||||
|
|
||||||
import useDeleteThread from '@/hooks/useDeleteThread'
|
import useDeleteThread from '@/hooks/useDeleteThread'
|
||||||
|
|
||||||
type Props = {
|
import {
|
||||||
threadId: string
|
modalActionThreadAtom,
|
||||||
closeContextMenu?: () => void
|
ThreadModalAction,
|
||||||
}
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
const ModalCleanThread = ({ threadId, closeContextMenu }: Props) => {
|
const ModalCleanThread = () => {
|
||||||
const { cleanThread } = useDeleteThread()
|
const { cleanThread } = useDeleteThread()
|
||||||
|
const [modalActionThread, setModalActionThread] = useAtom(
|
||||||
|
modalActionThreadAtom
|
||||||
|
)
|
||||||
|
|
||||||
const onCleanThreadClick = useCallback(
|
const onCleanThreadClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
cleanThread(threadId)
|
cleanThread(modalActionThread.thread?.id as string)
|
||||||
},
|
},
|
||||||
[cleanThread, threadId]
|
[cleanThread, modalActionThread.thread?.id]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onCloseModal = useCallback(() => {
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: undefined,
|
||||||
|
thread: undefined,
|
||||||
|
})
|
||||||
|
}, [setModalActionThread])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Clean Thread"
|
title="Clean Thread"
|
||||||
onOpenChange={(open) => {
|
open={modalActionThread.showModal === ThreadModalAction.Clean}
|
||||||
if (open && closeContextMenu) {
|
onOpenChange={onCloseModal}
|
||||||
closeContextMenu()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
trigger={
|
|
||||||
<div
|
|
||||||
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<Paintbrush
|
|
||||||
size={16}
|
|
||||||
className="text-[hsla(var(--text-secondary))]"
|
|
||||||
/>
|
|
||||||
<span className="text-bold text-[hsla(var(--app-text-primary))]">
|
|
||||||
Clean thread
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
content={
|
content={
|
||||||
<div>
|
<div>
|
||||||
<p className="text-[hsla(var(--text-secondary))]">
|
<p className="text-[hsla(var(--text-secondary))]">
|
||||||
Are you sure you want to clean this thread?
|
Are you sure you want to clean this thread?
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-4 flex justify-end gap-x-2">
|
<div className="mt-4 flex justify-end gap-x-2">
|
||||||
<ModalClose asChild onClick={(e) => e.stopPropagation()}>
|
<ModalClose
|
||||||
|
asChild
|
||||||
|
onClick={(e) => {
|
||||||
|
onCloseModal()
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Button theme="ghost">No</Button>
|
<Button theme="ghost">No</Button>
|
||||||
</ModalClose>
|
</ModalClose>
|
||||||
<ModalClose asChild>
|
<ModalClose asChild>
|
||||||
|
|||||||
@ -1,48 +1,41 @@
|
|||||||
import { useCallback, memo } from 'react'
|
import { useCallback, memo } from 'react'
|
||||||
|
|
||||||
import { Modal, ModalClose, Button } from '@janhq/joi'
|
import { Modal, ModalClose, Button } from '@janhq/joi'
|
||||||
import { Trash2Icon } from 'lucide-react'
|
import { useAtom } from 'jotai'
|
||||||
|
|
||||||
import useDeleteThread from '@/hooks/useDeleteThread'
|
import useDeleteThread from '@/hooks/useDeleteThread'
|
||||||
|
|
||||||
type Props = {
|
import {
|
||||||
threadId: string
|
modalActionThreadAtom,
|
||||||
closeContextMenu?: () => void
|
ThreadModalAction,
|
||||||
}
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
const ModalDeleteThread = ({ threadId, closeContextMenu }: Props) => {
|
const ModalDeleteThread = () => {
|
||||||
const { deleteThread } = useDeleteThread()
|
const { deleteThread } = useDeleteThread()
|
||||||
|
const [modalActionThread, setModalActionThread] = useAtom(
|
||||||
|
modalActionThreadAtom
|
||||||
|
)
|
||||||
|
|
||||||
const onDeleteThreadClick = useCallback(
|
const onDeleteThreadClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
deleteThread(threadId)
|
deleteThread(modalActionThread.thread?.id as string)
|
||||||
},
|
},
|
||||||
[deleteThread, threadId]
|
[deleteThread, modalActionThread.thread?.id]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onCloseModal = useCallback(() => {
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: undefined,
|
||||||
|
thread: undefined,
|
||||||
|
})
|
||||||
|
}, [setModalActionThread])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Delete Thread"
|
title="Delete Thread"
|
||||||
onOpenChange={(open) => {
|
onOpenChange={onCloseModal}
|
||||||
if (open && closeContextMenu) {
|
open={modalActionThread.showModal === ThreadModalAction.Delete}
|
||||||
closeContextMenu()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
trigger={
|
|
||||||
<div
|
|
||||||
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<Trash2Icon
|
|
||||||
size={16}
|
|
||||||
className="text-[hsla(var(--destructive-bg))]"
|
|
||||||
/>
|
|
||||||
<span className="text-bold text-[hsla(var(--destructive-bg))]">
|
|
||||||
Delete thread
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
content={
|
content={
|
||||||
<div>
|
<div>
|
||||||
<p className="text-[hsla(var(--text-secondary))]">
|
<p className="text-[hsla(var(--text-secondary))]">
|
||||||
|
|||||||
@ -1,57 +1,52 @@
|
|||||||
import { useCallback, useLayoutEffect, memo, useState } from 'react'
|
import { useCallback, useLayoutEffect, memo, useState } from 'react'
|
||||||
|
|
||||||
import { Thread } from '@janhq/core'
|
|
||||||
import { Modal, ModalClose, Button, Input } from '@janhq/joi'
|
import { Modal, ModalClose, Button, Input } from '@janhq/joi'
|
||||||
import { PencilIcon } from 'lucide-react'
|
import { useAtom } from 'jotai'
|
||||||
|
|
||||||
import { useCreateNewThread } from '@/hooks/useCreateNewThread'
|
import { useCreateNewThread } from '@/hooks/useCreateNewThread'
|
||||||
|
|
||||||
type Props = {
|
import {
|
||||||
thread: Thread
|
modalActionThreadAtom,
|
||||||
closeContextMenu?: () => void
|
ThreadModalAction,
|
||||||
}
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
const ModalEditTitleThread = ({ thread, closeContextMenu }: Props) => {
|
const ModalEditTitleThread = () => {
|
||||||
const [title, setTitle] = useState(thread.title)
|
|
||||||
const { updateThreadMetadata } = useCreateNewThread()
|
const { updateThreadMetadata } = useCreateNewThread()
|
||||||
|
const [modalActionThread, setModalActionThread] = useAtom(
|
||||||
|
modalActionThreadAtom
|
||||||
|
)
|
||||||
|
const [title, setTitle] = useState(modalActionThread.thread?.title as string)
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (thread.title) {
|
if (modalActionThread.thread?.title) {
|
||||||
setTitle(thread.title)
|
setTitle(modalActionThread.thread?.title)
|
||||||
}
|
}
|
||||||
}, [thread.title])
|
}, [modalActionThread.thread?.title])
|
||||||
|
|
||||||
const onUpdateTitle = useCallback(
|
const onUpdateTitle = useCallback(
|
||||||
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
if (!modalActionThread.thread) return null
|
||||||
updateThreadMetadata({
|
updateThreadMetadata({
|
||||||
...thread,
|
...modalActionThread?.thread,
|
||||||
title: title || 'New Thread',
|
title: title || 'New Thread',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[thread, title, updateThreadMetadata]
|
[modalActionThread?.thread, title, updateThreadMetadata]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onCloseModal = useCallback(() => {
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: undefined,
|
||||||
|
thread: undefined,
|
||||||
|
})
|
||||||
|
}, [setModalActionThread])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Edit title thread"
|
title="Edit title thread"
|
||||||
onOpenChange={(open) => {
|
onOpenChange={onCloseModal}
|
||||||
if (open && closeContextMenu) {
|
open={modalActionThread.showModal === ThreadModalAction.EditTitle}
|
||||||
closeContextMenu()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
trigger={
|
|
||||||
<div
|
|
||||||
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<PencilIcon size={16} className="text-[hsla(var(--secondary))]" />
|
|
||||||
<span className="text-bold text-[hsla(var(--secondary))]">
|
|
||||||
Edit title
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
content={
|
content={
|
||||||
<form className="mt-4">
|
<form className="mt-4">
|
||||||
<Input
|
<Input
|
||||||
@ -64,11 +59,7 @@ const ModalEditTitleThread = ({ thread, closeContextMenu }: Props) => {
|
|||||||
<Button theme="ghost">Cancel</Button>
|
<Button theme="ghost">Cancel</Button>
|
||||||
</ModalClose>
|
</ModalClose>
|
||||||
<ModalClose asChild>
|
<ModalClose asChild>
|
||||||
<Button
|
<Button type="submit" onClick={onUpdateTitle} disabled={!title}>
|
||||||
type="submit"
|
|
||||||
onClick={onUpdateTitle}
|
|
||||||
disabled={title.length === 0}
|
|
||||||
>
|
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</ModalClose>
|
</ModalClose>
|
||||||
|
|||||||
@ -5,7 +5,13 @@ import { Thread } from '@janhq/core'
|
|||||||
import { Button } from '@janhq/joi'
|
import { Button } from '@janhq/joi'
|
||||||
import { motion as m } from 'framer-motion'
|
import { motion as m } from 'framer-motion'
|
||||||
import { useAtomValue, useSetAtom } from 'jotai'
|
import { useAtomValue, useSetAtom } from 'jotai'
|
||||||
import { GalleryHorizontalEndIcon, MoreHorizontalIcon } from 'lucide-react'
|
import {
|
||||||
|
GalleryHorizontalEndIcon,
|
||||||
|
MoreHorizontalIcon,
|
||||||
|
Paintbrush,
|
||||||
|
PencilIcon,
|
||||||
|
Trash2Icon,
|
||||||
|
} from 'lucide-react'
|
||||||
|
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
@ -15,16 +21,14 @@ import { useCreateNewThread } from '@/hooks/useCreateNewThread'
|
|||||||
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
||||||
import useSetActiveThread from '@/hooks/useSetActiveThread'
|
import useSetActiveThread from '@/hooks/useSetActiveThread'
|
||||||
|
|
||||||
import ModalCleanThread from './ModalCleanThread'
|
|
||||||
import ModalDeleteThread from './ModalDeleteThread'
|
|
||||||
import ModalEditTitleThread from './ModalEditTitleThread'
|
|
||||||
|
|
||||||
import { assistantsAtom } from '@/helpers/atoms/Assistant.atom'
|
import { assistantsAtom } from '@/helpers/atoms/Assistant.atom'
|
||||||
import { editMessageAtom } from '@/helpers/atoms/ChatMessage.atom'
|
import { editMessageAtom } from '@/helpers/atoms/ChatMessage.atom'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getActiveThreadIdAtom,
|
getActiveThreadIdAtom,
|
||||||
|
modalActionThreadAtom,
|
||||||
threadDataReadyAtom,
|
threadDataReadyAtom,
|
||||||
|
ThreadModalAction,
|
||||||
threadsAtom,
|
threadsAtom,
|
||||||
} from '@/helpers/atoms/Thread.atom'
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
@ -37,6 +41,7 @@ const ThreadLeftPanel = () => {
|
|||||||
const { requestCreateNewThread } = useCreateNewThread()
|
const { requestCreateNewThread } = useCreateNewThread()
|
||||||
const setEditMessage = useSetAtom(editMessageAtom)
|
const setEditMessage = useSetAtom(editMessageAtom)
|
||||||
const { recommendedModel, downloadedModels } = useRecommendedModel()
|
const { recommendedModel, downloadedModels } = useRecommendedModel()
|
||||||
|
const setModalActionThread = useSetAtom(modalActionThreadAtom)
|
||||||
|
|
||||||
const [contextMenu, setContextMenu] = useState<{
|
const [contextMenu, setContextMenu] = useState<{
|
||||||
visible: boolean
|
visible: boolean
|
||||||
@ -147,18 +152,60 @@ const ThreadLeftPanel = () => {
|
|||||||
'visible'
|
'visible'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ModalEditTitleThread
|
<div
|
||||||
thread={thread}
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
||||||
closeContextMenu={closeContextMenu}
|
onClick={(e) => {
|
||||||
/>
|
setModalActionThread({
|
||||||
<ModalCleanThread
|
showModal: ThreadModalAction.EditTitle,
|
||||||
threadId={thread.id}
|
thread,
|
||||||
closeContextMenu={closeContextMenu}
|
})
|
||||||
/>
|
e.stopPropagation()
|
||||||
<ModalDeleteThread
|
}}
|
||||||
threadId={thread.id}
|
>
|
||||||
closeContextMenu={closeContextMenu}
|
<PencilIcon
|
||||||
/>
|
size={16}
|
||||||
|
className="text-[hsla(var(--secondary))]"
|
||||||
|
/>
|
||||||
|
<span className="text-bold text-[hsla(var(--secondary))]">
|
||||||
|
Edit title
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
||||||
|
onClick={(e) => {
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: ThreadModalAction.Clean,
|
||||||
|
thread,
|
||||||
|
})
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paintbrush
|
||||||
|
size={16}
|
||||||
|
className="text-[hsla(var(--text-secondary))]"
|
||||||
|
/>
|
||||||
|
<span className="text-bold text-[hsla(var(--app-text-primary))]">
|
||||||
|
Clean thread
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="flex cursor-pointer items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]"
|
||||||
|
onClick={(e) => {
|
||||||
|
setModalActionThread({
|
||||||
|
showModal: ThreadModalAction.Delete,
|
||||||
|
thread,
|
||||||
|
})
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2Icon
|
||||||
|
size={16}
|
||||||
|
className="text-[hsla(var(--destructive-bg))]"
|
||||||
|
/>
|
||||||
|
<span className="text-bold text-[hsla(var(--destructive-bg))]">
|
||||||
|
Delete thread
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{activeThreadId === thread.id && (
|
{activeThreadId === thread.id && (
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import ThreadLeftPanel from '@/screens/Thread/ThreadLeftPanel'
|
import ThreadLeftPanel from '@/screens/Thread/ThreadLeftPanel'
|
||||||
|
|
||||||
import ThreadCenterPanel from './ThreadCenterPanel'
|
import ThreadCenterPanel from './ThreadCenterPanel'
|
||||||
|
import ModalCleanThread from './ThreadLeftPanel/ModalCleanThread'
|
||||||
|
import ModalDeleteThread from './ThreadLeftPanel/ModalDeleteThread'
|
||||||
|
import ModalEditTitleThread from './ThreadLeftPanel/ModalEditTitleThread'
|
||||||
import ThreadRightPanel from './ThreadRightPanel'
|
import ThreadRightPanel from './ThreadRightPanel'
|
||||||
|
|
||||||
const ThreadScreen = () => {
|
const ThreadScreen = () => {
|
||||||
@ -9,6 +12,11 @@ const ThreadScreen = () => {
|
|||||||
<ThreadLeftPanel />
|
<ThreadLeftPanel />
|
||||||
<ThreadCenterPanel />
|
<ThreadCenterPanel />
|
||||||
<ThreadRightPanel />
|
<ThreadRightPanel />
|
||||||
|
|
||||||
|
{/* Showing variant modal action for thread screen */}
|
||||||
|
<ModalEditTitleThread />
|
||||||
|
<ModalCleanThread />
|
||||||
|
<ModalDeleteThread />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user