new-chat.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { useEffect, useRef } from "react";
  2. import { SlotID } from "../constant";
  3. import { IconButton } from "./button";
  4. import { EmojiAvatar } from "./emoji";
  5. import styles from "./new-chat.module.scss";
  6. import LeftIcon from "../icons/left.svg";
  7. import { useNavigate } from "react-router-dom";
  8. function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
  9. const xmin = Math.max(aRect.x, bRect.x);
  10. const xmax = Math.min(aRect.x + aRect.width, bRect.x + bRect.width);
  11. const ymin = Math.max(aRect.y, bRect.y);
  12. const ymax = Math.min(aRect.y + aRect.height, bRect.y + bRect.height);
  13. const width = xmax - xmin;
  14. const height = ymax - ymin;
  15. const intersectionArea = width < 0 || height < 0 ? 0 : width * height;
  16. return intersectionArea;
  17. }
  18. function Mask(props: { avatar: string; name: string }) {
  19. const domRef = useRef<HTMLDivElement>(null);
  20. useEffect(() => {
  21. const changeOpacity = () => {
  22. const dom = domRef.current;
  23. const parent = document.getElementById(SlotID.AppBody);
  24. if (!parent || !dom) return;
  25. const domRect = dom.getBoundingClientRect();
  26. const parentRect = parent.getBoundingClientRect();
  27. const intersectionArea = getIntersectionArea(domRect, parentRect);
  28. const domArea = domRect.width * domRect.height;
  29. const ratio = intersectionArea / domArea;
  30. const opacity = ratio > 0.9 ? 1 : 0.4;
  31. dom.style.opacity = opacity.toString();
  32. };
  33. setTimeout(changeOpacity, 30);
  34. window.addEventListener("resize", changeOpacity);
  35. return () => window.removeEventListener("resize", changeOpacity);
  36. }, [domRef]);
  37. return (
  38. <div className={styles["mask"]} ref={domRef}>
  39. <div className={styles["mask-avatar"]}>
  40. <EmojiAvatar avatar={props.avatar} />
  41. </div>
  42. <div className={styles["mask-name"] + " one-line"}>{props.name}</div>
  43. </div>
  44. );
  45. }
  46. export function NewChat() {
  47. const masks = new Array(20).fill(0).map(() =>
  48. new Array(10).fill(0).map((_, i) => ({
  49. avatar: "1f" + (Math.round(Math.random() * 50) + 600).toString(),
  50. name: ["撩妹达人", "编程高手", "情感大师", "健康医生", "数码通"][
  51. Math.floor(Math.random() * 4)
  52. ],
  53. })),
  54. );
  55. const navigate = useNavigate();
  56. return (
  57. <div className={styles["new-chat"]}>
  58. <div className={styles["mask-header"]}>
  59. <IconButton
  60. icon={<LeftIcon />}
  61. text="返回"
  62. onClick={() => navigate(-1)}
  63. ></IconButton>
  64. <IconButton text="跳过"></IconButton>
  65. </div>
  66. <div className={styles["mask-cards"]}>
  67. <div className={styles["mask-card"]}>
  68. <EmojiAvatar avatar="1f606" size={24} />
  69. </div>
  70. <div className={styles["mask-card"]}>
  71. <EmojiAvatar avatar="1f916" size={24} />
  72. </div>
  73. <div className={styles["mask-card"]}>
  74. <EmojiAvatar avatar="1f479" size={24} />
  75. </div>
  76. </div>
  77. <div className={styles["title"]}>挑选一个面具</div>
  78. <div className={styles["sub-title"]}>
  79. 现在开始,与面具背后的灵魂思维碰撞
  80. </div>
  81. <input className={styles["search-bar"]} placeholder="搜索" type="text" />
  82. <div className={styles["masks"]}>
  83. {masks.map((masks, i) => (
  84. <div key={i} className={styles["mask-row"]}>
  85. {masks.map((mask, index) => (
  86. <Mask key={index} {...mask} />
  87. ))}
  88. </div>
  89. ))}
  90. </div>
  91. </div>
  92. );
  93. }