import { useEffect, useRef, useState } from "react"; import { Path, SlotID } from "../constant"; import { IconButton } from "./button"; import { EmojiAvatar } from "./emoji"; import styles from "./new-chat.module.scss"; import LeftIcon from "../icons/left.svg"; import LightningIcon from "../icons/lightning.svg"; import EyeIcon from "../icons/eye.svg"; import { useLocation, useNavigate } from "react-router-dom"; import { Mask, useMaskStore } from "../store/mask"; import Locale from "../locales"; import { useAppConfig, useChatStore } from "../store"; import { MaskAvatar } from "./mask"; import { useCommand } from "../command"; import { showConfirm } from "./ui-lib"; import { BUILTIN_MASK_STORE } from "../masks"; function MaskItem(props: { mask: Mask; onClick?: () => void }) { return (
{props.mask.name}
); } function useMaskGroup(masks: Mask[]) { const [groups, setGroups] = useState([]); useEffect(() => { const computeGroup = () => { const appBody = document.getElementById(SlotID.AppBody); if (!appBody || masks.length === 0) return; const rect = appBody.getBoundingClientRect(); const maxWidth = rect.width; const maxHeight = rect.height * 0.6; const maskItemWidth = 120; const maskItemHeight = 50; const randomMask = () => masks[Math.floor(Math.random() * masks.length)]; let maskIndex = 0; const nextMask = () => masks[maskIndex++ % masks.length]; const rows = Math.ceil(maxHeight / maskItemHeight); const cols = Math.ceil(maxWidth / maskItemWidth); const newGroups = new Array(rows) .fill(0) .map((_, _i) => new Array(cols) .fill(0) .map((_, j) => (j < 1 || j > cols - 2 ? randomMask() : nextMask())), ); setGroups(newGroups); }; computeGroup(); window.addEventListener("resize", computeGroup); return () => window.removeEventListener("resize", computeGroup); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return groups; } export function NewChat() { const chatStore = useChatStore(); const maskStore = useMaskStore(); const masks = maskStore.getAll(); const groups = useMaskGroup(masks); const navigate = useNavigate(); const config = useAppConfig(); const maskRef = useRef(null); const { state } = useLocation(); const startChat = (mask?: Mask) => { setTimeout(() => { chatStore.newSession(mask); navigate(Path.Chat); }, 10); }; useCommand({ mask: (id) => { try { const mask = maskStore.get(id) ?? BUILTIN_MASK_STORE.get(id); startChat(mask ?? undefined); } catch { console.error("[New Chat] failed to create chat from mask id=", id); } }, }); useEffect(() => { if (maskRef.current) { maskRef.current.scrollLeft = (maskRef.current.scrollWidth - maskRef.current.clientWidth) / 2; } }, [groups]); return (
} text={Locale.NewChat.Return} onClick={() => navigate(Path.Home)} > {!state?.fromHome && ( { if (await showConfirm(Locale.NewChat.ConfirmNoShow)) { startChat(); config.update( (config) => (config.dontShowMaskSplashScreen = true), ); } }} > )}
{Locale.NewChat.Title}
{Locale.NewChat.SubTitle}
navigate(Path.Masks)} icon={} bordered shadow /> startChat()} icon={} type="primary" shadow className={styles["skip"]} />
{groups.map((masks, i) => (
{masks.map((mask, index) => ( startChat(mask)} /> ))}
))}
); }