operator.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import {
  2. memo,
  3. useState,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { RiMoreFill } from '@remixicon/react'
  7. import cn from '@/utils/classnames'
  8. import ShortcutsName from '@/app/components/workflow/shortcuts-name'
  9. import {
  10. PortalToFollowElem,
  11. PortalToFollowElemContent,
  12. PortalToFollowElemTrigger,
  13. } from '@/app/components/base/portal-to-follow-elem'
  14. import Switch from '@/app/components/base/switch'
  15. export type OperatorProps = {
  16. onCopy: () => void
  17. onDuplicate: () => void
  18. onDelete: () => void
  19. showAuthor: boolean
  20. onShowAuthorChange: (showAuthor: boolean) => void
  21. }
  22. const Operator = ({
  23. onCopy,
  24. onDelete,
  25. onDuplicate,
  26. showAuthor,
  27. onShowAuthorChange,
  28. }: OperatorProps) => {
  29. const { t } = useTranslation()
  30. const [open, setOpen] = useState(false)
  31. return (
  32. <PortalToFollowElem
  33. open={open}
  34. onOpenChange={setOpen}
  35. placement='bottom-end'
  36. offset={4}
  37. >
  38. <PortalToFollowElemTrigger onClick={() => setOpen(!open)}>
  39. <div
  40. className={cn(
  41. 'flex items-center justify-center w-8 h-8 cursor-pointer rounded-lg hover:bg-black/5',
  42. open && 'bg-black/5',
  43. )}
  44. >
  45. <RiMoreFill className='w-4 h-4 text-gray-500' />
  46. </div>
  47. </PortalToFollowElemTrigger>
  48. <PortalToFollowElemContent>
  49. <div className='min-w-[192px] bg-white rounded-md border-[0.5px] border-gray-200 shadow-xl'>
  50. <div className='p-1'>
  51. <div
  52. className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
  53. onClick={() => {
  54. onCopy()
  55. setOpen(false)
  56. }}
  57. >
  58. {t('workflow.common.copy')}
  59. <ShortcutsName keys={['ctrl', 'c']} />
  60. </div>
  61. <div
  62. className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
  63. onClick={() => {
  64. onDuplicate()
  65. setOpen(false)
  66. }}
  67. >
  68. {t('workflow.common.duplicate')}
  69. <ShortcutsName keys={['ctrl', 'd']} />
  70. </div>
  71. </div>
  72. <div className='h-[1px] bg-gray-100'></div>
  73. <div className='p-1'>
  74. <div
  75. className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:bg-black/5'
  76. onClick={e => e.stopPropagation()}
  77. >
  78. <div>{t('workflow.nodes.note.editor.showAuthor')}</div>
  79. <Switch
  80. size='l'
  81. defaultValue={showAuthor}
  82. onChange={onShowAuthorChange}
  83. />
  84. </div>
  85. </div>
  86. <div className='h-[1px] bg-gray-100'></div>
  87. <div className='p-1'>
  88. <div
  89. className='flex items-center justify-between px-3 h-8 cursor-pointer rounded-md text-sm text-gray-700 hover:text-[#D92D20] hover:bg-[#FEF3F2]'
  90. onClick={() => {
  91. onDelete()
  92. setOpen(false)
  93. }}
  94. >
  95. {t('common.operation.delete')}
  96. <ShortcutsName keys={['del']} />
  97. </div>
  98. </div>
  99. </div>
  100. </PortalToFollowElemContent>
  101. </PortalToFollowElem>
  102. )
  103. }
  104. export default memo(Operator)