Migrate text size menu to embedded tooltip (#4147)

* migrate font size menu to embedded tooltip modal

* lint

* fix text size menu ui

---------

Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
Sean Hatfield 2025-07-15 15:29:30 -07:00 committed by GitHub
parent fe1dfb1fde
commit b0407a6bf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,140 +1,119 @@
import { useState, useRef, useEffect } from "react";
import { useState, useRef } from "react";
import { TextT } from "@phosphor-icons/react";
import { Tooltip } from "react-tooltip";
import { useTranslation } from "react-i18next";
import { useTheme } from "@/hooks/useTheme";
export default function TextSizeButton() {
const [showTextSizeMenu, setShowTextSizeMenu] = useState(false);
const buttonRef = useRef(null);
const tooltipRef = useRef(null);
const { t } = useTranslation();
const { theme } = useTheme();
const toggleTooltip = () => {
if (!tooltipRef.current) return;
tooltipRef.current.isOpen
? tooltipRef.current.close()
: tooltipRef.current.open();
};
return (
<>
<div
ref={buttonRef}
id="text-size-btn"
data-tooltip-id="tooltip-text-size-btn"
data-tooltip-content={t("chat_window.text_size")}
aria-label={t("chat_window.text_size")}
onClick={() => setShowTextSizeMenu(!showTextSizeMenu)}
className={`border-none relative flex justify-center items-center opacity-60 hover:opacity-100 light:opacity-100 light:hover:opacity-60 cursor-pointer ${
showTextSizeMenu ? "!opacity-100" : ""
}`}
onClick={toggleTooltip}
className="border-none flex justify-center items-center opacity-60 hover:opacity-100 light:opacity-100 light:hover:opacity-60 cursor-pointer"
>
<TextT
color="var(--theme-sidebar-footer-icon-fill)"
weight="fill"
className="w-[22px] h-[22px] pointer-events-none text-white"
/>
<Tooltip
id="tooltip-text-size-btn"
place="top"
delayShow={300}
className="tooltip !text-xs z-99"
/>
</div>
<TextSizeMenu
showing={showTextSizeMenu}
setShowing={setShowTextSizeMenu}
buttonRef={buttonRef}
/>
<Tooltip
ref={tooltipRef}
id="tooltip-text-size-btn"
place="top"
opacity={1}
clickable={true}
delayShow={300}
delayHide={800}
arrowColor={
theme === "light"
? "var(--theme-modal-border)"
: "var(--theme-bg-primary)"
}
className="z-99 !w-[140px] !bg-theme-bg-primary !px-[5px] !rounded-lg !pointer-events-auto light:border-2 light:border-theme-modal-border"
>
<TextSizeMenu tooltipRef={tooltipRef} />
</Tooltip>
</>
);
}
function TextSizeMenu({ showing, setShowing, buttonRef }) {
function TextSizeMenu({ tooltipRef }) {
const { t } = useTranslation();
const formRef = useRef(null);
const [selectedSize, setSelectedSize] = useState(
window.localStorage.getItem("anythingllm_text_size") || "normal"
);
useEffect(() => {
function listenForOutsideClick() {
if (!showing || !formRef.current) return false;
document.addEventListener("click", closeIfOutside);
}
listenForOutsideClick();
}, [showing, formRef.current]);
const closeIfOutside = ({ target }) => {
if (target.id === "text-size-btn") return;
const isOutside = !formRef?.current?.contains(target);
if (!isOutside) return;
setShowing(false);
};
const handleTextSizeChange = (size) => {
setSelectedSize(size);
window.localStorage.setItem("anythingllm_text_size", size);
window.dispatchEvent(new CustomEvent("textSizeChange", { detail: size }));
tooltipRef.current?.close();
};
if (!buttonRef.current) return null;
return (
<div hidden={!showing}>
<div
ref={formRef}
className="absolute bottom-16 -ml-8 w-[140px] p-2 bg-theme-action-menu-bg rounded-lg shadow-md flex flex-col justify-center items-start gap-2 z-50"
<div className="flex flex-col justify-start items-stretch gap-1 p-2">
<button
onClick={(e) => {
e.preventDefault();
handleTextSizeChange("small");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-2 rounded-md flex items-center group ${
selectedSize === "small"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<button
onClick={(e) => {
e.preventDefault();
setShowing(false);
handleTextSizeChange("small");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-1 rounded-md flex flex-col justify-start group ${
selectedSize === "small"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<div className="w-full flex-col text-left flex pointer-events-none">
<div className="text-theme-text-primary text-xs">
{t("chat_window.small")}
</div>
</div>
</button>
<div className="text-theme-text-primary text-xs">
{t("chat_window.small")}
</div>
</button>
<button
onClick={(e) => {
e.preventDefault();
setShowing(false);
handleTextSizeChange("normal");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-1 rounded-md flex flex-col justify-start group ${
selectedSize === "normal"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<div className="w-full flex-col text-left flex pointer-events-none">
<div className="text-theme-text-primary text-sm">
{t("chat_window.normal")}
</div>
</div>
</button>
<button
onClick={(e) => {
e.preventDefault();
handleTextSizeChange("normal");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-2 rounded-md flex items-center group ${
selectedSize === "normal"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<div className="text-theme-text-primary text-sm">
{t("chat_window.normal")}
</div>
</button>
<button
onClick={(e) => {
e.preventDefault();
setShowing(false);
handleTextSizeChange("large");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-1 rounded-md flex flex-col justify-start group ${
selectedSize === "large"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<div className="w-full flex-col text-left flex pointer-events-none">
<div className="text-theme-text-primary text-[16px]">
{t("chat_window.large")}
</div>
</div>
</button>
</div>
<button
onClick={(e) => {
e.preventDefault();
handleTextSizeChange("large");
}}
className={`border-none w-full hover:cursor-pointer px-2 py-2 rounded-md flex items-center group ${
selectedSize === "large"
? "bg-theme-action-menu-item-hover"
: "hover:bg-theme-action-menu-item-hover"
}`}
>
<div className="text-theme-text-primary text-[16px]">
{t("chat_window.large")}
</div>
</button>
</div>
);
}