FloatingButton.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. "use client";
  2. import { useState } from "react";
  3. import { Button } from "@/components/ui/button";
  4. interface FloatingButtonProps {
  5. onClick: () => void;
  6. isOpen?: boolean;
  7. unreadCount?: number;
  8. }
  9. /**
  10. * 浮动按钮组件
  11. * 显示在页面右下角,用于打开聊天小窗
  12. */
  13. export function FloatingButton({
  14. onClick,
  15. isOpen = false,
  16. unreadCount = 0,
  17. }: FloatingButtonProps) {
  18. return (
  19. <Button
  20. onClick={onClick}
  21. className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 w-12 h-12 sm:w-14 sm:h-14 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 z-50 bg-primary text-primary-foreground hover:bg-primary/90 flex items-center justify-center p-0"
  22. aria-label={isOpen ? "关闭聊天" : "打开聊天"}
  23. >
  24. {isOpen ? (
  25. // 关闭图标(X)
  26. <svg
  27. className="w-6 h-6"
  28. fill="none"
  29. stroke="currentColor"
  30. viewBox="0 0 24 24"
  31. >
  32. <path
  33. strokeLinecap="round"
  34. strokeLinejoin="round"
  35. strokeWidth={2}
  36. d="M6 18L18 6M6 6l12 12"
  37. />
  38. </svg>
  39. ) : (
  40. // 聊天图标
  41. <svg
  42. className="w-6 h-6"
  43. fill="none"
  44. stroke="currentColor"
  45. viewBox="0 0 24 24"
  46. >
  47. <path
  48. strokeLinecap="round"
  49. strokeLinejoin="round"
  50. strokeWidth={2}
  51. d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
  52. />
  53. </svg>
  54. )}
  55. {/* 未读消息数量徽章 */}
  56. {!isOpen && unreadCount > 0 && (
  57. <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs font-bold rounded-full w-5 h-5 flex items-center justify-center">
  58. {unreadCount > 99 ? "99+" : unreadCount}
  59. </span>
  60. )}
  61. </Button>
  62. );
  63. }