header.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { LogoBar } from "@/components/header/logo";
  2. import { Items } from "../items";
  3. import { Switch, addToast, Tooltip } from "@heroui/react";
  4. import { UserMinusIcon, UserPlusIcon, SpeakerWaveIcon, SpeakerXMarkIcon } from "@heroicons/react/24/solid";
  5. import { useSentioChatModeStore, useChatRecordStore, useSentioAsrStore } from "@/lib/store/sentio";
  6. import { CHAT_MODE } from "@/lib/protocol";
  7. import { useTranslations } from 'next-intl';
  8. import clsx from 'clsx';
  9. function ChatModeSwitch() {
  10. const t = useTranslations('Products.sentio');
  11. const { chatMode, setChatMode } = useSentioChatModeStore();
  12. const { enable } = useSentioAsrStore();
  13. const { clearChatRecord } = useChatRecordStore();
  14. const isImmersive = chatMode === CHAT_MODE.IMMSERSIVE;
  15. const onSelect = (isSelected: boolean) => {
  16. if (enable) {
  17. setChatMode(isSelected ? CHAT_MODE.IMMSERSIVE : CHAT_MODE.DIALOGUE)
  18. clearChatRecord();
  19. } else {
  20. addToast({
  21. title: t('asrEnableTip'),
  22. color: "warning"
  23. })
  24. }
  25. }
  26. return (
  27. <Tooltip
  28. content={isImmersive ? "沉浸模式:可打断" : "噪音模式:不可打断"}
  29. placement="bottom"
  30. className="opacity-90"
  31. >
  32. <div className="relative inline-flex items-center">
  33. <button
  34. onClick={() => onSelect(!isImmersive)}
  35. disabled={!enable}
  36. className={clsx(
  37. "relative inline-flex h-10 w-20 items-center rounded-full transition-all duration-300 ease-in-out",
  38. "focus:outline-none focus:ring-2 focus:ring-offset-2",
  39. isImmersive
  40. ? "bg-gradient-to-r from-blue-500 to-cyan-500 focus:ring-blue-500"
  41. : "bg-gradient-to-r from-gray-400 to-gray-500 focus:ring-gray-500",
  42. !enable && "opacity-50 cursor-not-allowed"
  43. )}
  44. style={{
  45. boxShadow: isImmersive
  46. ? "0 4px 12px rgba(59, 130, 246, 0.4), 0 0 8px rgba(59, 130, 246, 0.3)"
  47. : "0 2px 8px rgba(0, 0, 0, 0.2)"
  48. }}
  49. aria-label={isImmersive ? "切换到噪音模式" : "切换到沉浸模式"}
  50. >
  51. {/* 滑动指示器 */}
  52. <span
  53. className={clsx(
  54. "absolute left-1 top-1 h-8 w-8 transform rounded-full bg-white shadow-lg transition-all duration-300 ease-in-out",
  55. "flex items-center justify-center",
  56. isImmersive ? "translate-x-10" : "translate-x-0"
  57. )}
  58. style={{
  59. boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)"
  60. }}
  61. >
  62. {isImmersive ? (
  63. <SpeakerWaveIcon className="h-4 w-4 text-blue-500" />
  64. ) : (
  65. <SpeakerXMarkIcon className="h-4 w-4 text-gray-500" />
  66. )}
  67. </span>
  68. {/* 模式标签 */}
  69. <div className="flex w-full items-center justify-between px-3 text-xs font-semibold">
  70. <span className={clsx(
  71. "transition-opacity duration-300",
  72. isImmersive ? "opacity-0" : "opacity-100 text-white"
  73. )}>
  74. 噪音
  75. </span>
  76. <span className={clsx(
  77. "transition-opacity duration-300",
  78. isImmersive ? "opacity-100 text-white" : "opacity-0"
  79. )}>
  80. 沉浸
  81. </span>
  82. </div>
  83. </button>
  84. </div>
  85. </Tooltip>
  86. )
  87. }
  88. export function Header() {
  89. return (
  90. <div className="flex w-full h-[64px] p-6 justify-between z-10">
  91. <LogoBar isExternal={true}/>
  92. <div className="flex flex-row gap-4 items-center">
  93. <ChatModeSwitch />
  94. {/* <Items /> */}
  95. </div>
  96. </div>
  97. )
  98. }