diff --git a/front_end/messages/cs.json b/front_end/messages/cs.json index 44e855d0f1..d1888d7f12 100644 --- a/front_end/messages/cs.json +++ b/front_end/messages/cs.json @@ -1761,5 +1761,6 @@ "noPrivateNotes": "Žádné soukromé poznámky", "privateNotes": "Soukromé poznámky", "justNow": "právě teď", + "cmmButtonShort": "Mysl", "othersCount": "Ostatní ({count})" } diff --git a/front_end/messages/en.json b/front_end/messages/en.json index 1141da9ea6..adf8909139 100644 --- a/front_end/messages/en.json +++ b/front_end/messages/en.json @@ -1755,5 +1755,6 @@ "noPrivateNotes": "No private notes yet", "privateNotes": "Private Notes", "justNow": "just now", + "cmmButtonShort": "Mind", "none": "none" } diff --git a/front_end/messages/es.json b/front_end/messages/es.json index 3f00323289..ad0ee7040c 100644 --- a/front_end/messages/es.json +++ b/front_end/messages/es.json @@ -1761,5 +1761,6 @@ "noPrivateNotes": "Aún no hay notas privadas", "privateNotes": "Notas privadas", "justNow": "justo ahora", + "cmmButtonShort": "Mente", "othersCount": "Otros ({count})" } diff --git a/front_end/messages/pt.json b/front_end/messages/pt.json index a6032727f1..59c65a41d2 100644 --- a/front_end/messages/pt.json +++ b/front_end/messages/pt.json @@ -1759,5 +1759,6 @@ "noPrivateNotes": "Ainda não há notas privadas", "privateNotes": "Notas Privadas", "justNow": "agora mesmo", + "cmmButtonShort": "Mente", "othersCount": "Outros ({count})" } diff --git a/front_end/messages/zh-TW.json b/front_end/messages/zh-TW.json index 567200ea88..8066f45bcf 100644 --- a/front_end/messages/zh-TW.json +++ b/front_end/messages/zh-TW.json @@ -1758,5 +1758,6 @@ "noPrivateNotes": "尚無私人筆記", "privateNotes": "私人筆記", "justNow": "剛剛", + "cmmButtonShort": "心智", "withdrawAfterPercentSetting2": "問題總生命周期後撤回" } diff --git a/front_end/messages/zh.json b/front_end/messages/zh.json index 06a4366fdb..afced1e250 100644 --- a/front_end/messages/zh.json +++ b/front_end/messages/zh.json @@ -1763,5 +1763,6 @@ "noPrivateNotes": "尚無私人筆記", "privateNotes": "私人筆記", "justNow": "刚刚", + "cmmButtonShort": "心情", "othersCount": "其他({count})" } diff --git a/front_end/src/components/comment_feed/comment.tsx b/front_end/src/components/comment_feed/comment.tsx index 100b4822fc..d04aa86104 100644 --- a/front_end/src/components/comment_feed/comment.tsx +++ b/front_end/src/components/comment_feed/comment.tsx @@ -241,15 +241,12 @@ const Comment: FC = ({ const userCanPredict = postData && canPredictQuestion(postData); const userForecast = postData?.question?.my_forecasts?.latest?.forecast_values[1] ?? 0.5; + const isCommentAuthor = comment.author.id === user?.id; const isCmmButtonVisible = - user?.id !== comment.author.id && - (!!postData?.question || - !!postData?.group_of_questions || - !!postData?.conditional); - const isCmmButtonDisabled = !user || !userCanPredict; - // TODO: find a better way to dedect whether on mobile or not. For now we need to know in JS - // too and can't use tw classes - const isMobileScreen = window.innerWidth < 640; + !!postData?.question || + !!postData?.group_of_questions || + !!postData?.conditional; + const isCmmButtonDisabled = !user || !userCanPredict || isCommentAuthor; const { draftReady: editDraftReady, @@ -372,8 +369,6 @@ const Comment: FC = ({ ].includes(postData?.status ?? PostStatus.CLOSED); const limitNotReached = factorsLimit > 0; - const isCommentAuthor = comment.author.id === user?.id; - const canShowAddKeyFactorsButton = isCommentAuthor && questionNotClosed && canListKeyFactors; @@ -497,22 +492,6 @@ const Comment: FC = ({ }, [comment.id]); const menuItems: MenuItemProps[] = [ - { - hidden: !isMobileScreen || !isCmmButtonVisible, - id: "cmm", - element: ( -
- -
- ), - onClick: () => { - return null; // handled by the button element - }, - }, { hidden: !(user?.id === comment.author.id), id: "edit", @@ -839,7 +818,7 @@ const Comment: FC = ({
-
+
= ({ icon={isKeyfactorsFormOpen ? faXmark : faPlus} className="size-4 p-1" /> - {t("addKeyFactor")} + + {t("addKeyFactor")} + + {t("add")}
)} - {isCmmButtonVisible && !isMobileScreen && ( - - )} - {!onProfile && (isReplying ? ( ))} + + {isCmmButtonVisible && ( + + )}
-
0 && "pr-1.5 md:pr-2")} - > +
0 && "pr-1.5 md:pr-2")}>
diff --git a/front_end/src/components/comment_feed/comment_cmm.tsx b/front_end/src/components/comment_feed/comment_cmm.tsx index b6cfee82ce..af46ba8662 100644 --- a/front_end/src/components/comment_feed/comment_cmm.tsx +++ b/front_end/src/components/comment_feed/comment_cmm.tsx @@ -13,12 +13,17 @@ import { import { faChevronLeft, faChevronRight, - faCaretUp, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { isNil } from "lodash"; import { useTranslations } from "next-intl"; -import React, { useState, forwardRef, FC } from "react"; +import React, { + useState, + forwardRef, + FC, + useLayoutEffect, + useCallback, +} from "react"; import { toggleCMMComment } from "@/app/(main)/questions/actions"; import ForecastTextInput from "@/components/forecast_maker/forecast_text_input"; @@ -292,6 +297,48 @@ const CmmOverlay = ({ ); }; +type LabelVariant = "full" | "mid" | "tiny"; + +function useFittingLabel< + TContainer extends HTMLElement, + TFull extends HTMLElement, + TMid extends HTMLElement, + TTiny extends HTMLElement, +>(params: { + containerRef: React.RefObject; + fullRef: React.RefObject; + midRef: React.RefObject; + tinyRef: React.RefObject; +}) { + const [variant, setVariant] = useState("full"); + + const recompute = useCallback(() => { + const container = params.containerRef.current; + if (!container) return; + + const available = container.clientWidth; + const wFull = params.fullRef.current?.offsetWidth ?? 0; + const wMid = params.midRef.current?.offsetWidth ?? 0; + + const next = + wFull <= available ? "full" : wMid <= available ? "mid" : "tiny"; + + setVariant((prev) => (prev === next ? prev : next)); + }, [params.containerRef, params.fullRef, params.midRef]); + + useLayoutEffect(() => { + recompute(); + const el = params.containerRef.current; + if (!el) return; + + const ro = new ResizeObserver(recompute); + ro.observe(el); + return () => ro.disconnect(); + }, [recompute, params.containerRef]); + + return variant; +} + interface CmmToggleButtonProps { comment_id: number; disabled?: boolean; @@ -320,34 +367,72 @@ const CmmToggleButton = forwardRef( } }; + const isDisabled = isLoading || !!disabled; + + const count = cmmContext.count; + + const fullLabel = `${t("cmmButton")} (${count})`; + const midLabel = `${t("cmmButtonShort")} (${count})`; + const tinyLabel = `(${count})`; + + const labelBoxRef = React.useRef(null); + const fullMeasureRef = React.useRef(null); + const midMeasureRef = React.useRef(null); + const tinyMeasureRef = React.useRef(null); + + const variant = useFittingLabel({ + containerRef: labelBoxRef, + fullRef: fullMeasureRef, + midRef: midMeasureRef, + tinyRef: tinyMeasureRef, + }); + return ( //