ChatSettingsMenu.tsx 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. 'use client';
  2. import { useState, useRef, useEffect } from 'react';
  3. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  4. import { faGear, faRotate, faUpRightFromSquare, faEraser, faMagnifyingGlassPlus, faMagnifyingGlassMinus } from '@fortawesome/free-solid-svg-icons';
  5. type Props = {
  6. onRefresh: () => void;
  7. onOpenPopup: () => void;
  8. onClear: () => void;
  9. onFontLarger: () => void;
  10. onFontSmaller: () => void;
  11. // 팝업 창 내부에서는 "새창으로 보기" 숨김
  12. showPopup?: boolean;
  13. };
  14. // 채팅 설정 dropdown (톱니바퀴) — 새로고침 / 새창으로 보기 / 지우개(로컬) / 글씨 크게·작게
  15. export default function ChatSettingsMenu({ onRefresh, onOpenPopup, onClear, onFontLarger, onFontSmaller, showPopup = true }: Props)
  16. {
  17. const [open, setOpen] = useState(false);
  18. const ref = useRef<HTMLDivElement>(null);
  19. useEffect(() => {
  20. const handleClickOutside = (e: MouseEvent) => {
  21. if (ref.current && !ref.current.contains(e.target as Node)) {
  22. setOpen(false);
  23. }
  24. };
  25. if (open) {
  26. document.addEventListener('mousedown', handleClickOutside);
  27. }
  28. return () => {
  29. document.removeEventListener('mousedown', handleClickOutside);
  30. };
  31. }, [open]);
  32. // 실행 후 dropdown 닫기 (글씨 크게/작게는 연속 조작을 위해 열어둠)
  33. const run = (fn: () => void, keepOpen = false) => () => {
  34. fn();
  35. if (!keepOpen) {
  36. setOpen(false);
  37. }
  38. };
  39. return (
  40. <div className='chat-menu' ref={ref}>
  41. <button
  42. type='button'
  43. className='chat-menu__trigger'
  44. onClick={() => setOpen((v) => !v)}
  45. aria-haspopup='menu'
  46. aria-expanded={open}
  47. title='채팅 설정'
  48. >
  49. <FontAwesomeIcon icon={faGear} />
  50. </button>
  51. {open && (
  52. <div className='chat-menu__dropdown' role='menu'>
  53. <button type='button' role='menuitem' className='chat-menu__item' onClick={run(onRefresh)}>
  54. <FontAwesomeIcon icon={faRotate} />
  55. <span>새로고침</span>
  56. </button>
  57. {showPopup && (
  58. <button type='button' role='menuitem' className='chat-menu__item' onClick={run(onOpenPopup)}>
  59. <FontAwesomeIcon icon={faUpRightFromSquare} />
  60. <span>새창으로 보기</span>
  61. </button>
  62. )}
  63. <button type='button' role='menuitem' className='chat-menu__item' onClick={run(onClear)}>
  64. <FontAwesomeIcon icon={faEraser} />
  65. <span>지우개</span>
  66. </button>
  67. <div className='chat-menu__divider' role='separator' />
  68. <button type='button' role='menuitem' className='chat-menu__item' onClick={run(onFontLarger, true)}>
  69. <FontAwesomeIcon icon={faMagnifyingGlassPlus} />
  70. <span>글씨 크게</span>
  71. </button>
  72. <button type='button' role='menuitem' className='chat-menu__item' onClick={run(onFontSmaller, true)}>
  73. <FontAwesomeIcon icon={faMagnifyingGlassMinus} />
  74. <span>글씨 작게</span>
  75. </button>
  76. </div>
  77. )}
  78. </div>
  79. );
  80. }