menu-dropdown.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback, useRef, useState } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import type { Placement } from '@floating-ui/react'
  6. import {
  7. RiEqualizer2Line,
  8. } from '@remixicon/react'
  9. import ActionButton from '@/app/components/base/action-button'
  10. import {
  11. PortalToFollowElem,
  12. PortalToFollowElemContent,
  13. PortalToFollowElemTrigger,
  14. } from '@/app/components/base/portal-to-follow-elem'
  15. import InfoModal from './info-modal'
  16. import type { SiteInfo } from '@/models/share'
  17. import cn from '@/utils/classnames'
  18. type Props = {
  19. data?: SiteInfo
  20. placement?: Placement
  21. }
  22. const MenuDropdown: FC<Props> = ({
  23. data,
  24. placement,
  25. }) => {
  26. const { t } = useTranslation()
  27. const [open, doSetOpen] = useState(false)
  28. const openRef = useRef(open)
  29. const setOpen = useCallback((v: boolean) => {
  30. doSetOpen(v)
  31. openRef.current = v
  32. }, [doSetOpen])
  33. const handleTrigger = useCallback(() => {
  34. setOpen(!openRef.current)
  35. }, [setOpen])
  36. const [show, setShow] = useState(false)
  37. return (
  38. <>
  39. <PortalToFollowElem
  40. open={open}
  41. onOpenChange={setOpen}
  42. placement={placement || 'bottom-end'}
  43. offset={{
  44. mainAxis: 4,
  45. crossAxis: -4,
  46. }}
  47. >
  48. <PortalToFollowElemTrigger onClick={handleTrigger}>
  49. <div>
  50. <ActionButton size='l' className={cn(open && 'bg-state-base-hover')}>
  51. <RiEqualizer2Line className='h-[18px] w-[18px]' />
  52. </ActionButton>
  53. </div>
  54. </PortalToFollowElemTrigger>
  55. <PortalToFollowElemContent className='z-50'>
  56. <div className='w-[224px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm'>
  57. <div className='p-1'>
  58. {data?.privacy_policy && (
  59. <a href={data.privacy_policy} target='_blank' className='system-md-regular flex cursor-pointer items-center rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'>
  60. <span className='grow'>{t('share.chat.privacyPolicyMiddle')}</span>
  61. </a>
  62. )}
  63. <div
  64. onClick={() => {
  65. handleTrigger()
  66. setShow(true)
  67. }}
  68. className='system-md-regular cursor-pointer rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'
  69. >{t('common.userProfile.about')}</div>
  70. </div>
  71. </div>
  72. </PortalToFollowElemContent>
  73. </PortalToFollowElem>
  74. {show && (
  75. <InfoModal
  76. isShow={show}
  77. onClose={() => {
  78. setShow(false)
  79. }}
  80. data={data}
  81. />
  82. )}
  83. </>
  84. )
  85. }
  86. export default React.memo(MenuDropdown)