diff --git a/atcoder-problems-frontend/src/components/ProblemLink.tsx b/atcoder-problems-frontend/src/components/ProblemLink.tsx index d18c4b5a1..50b8b3d7e 100644 --- a/atcoder-problems-frontend/src/components/ProblemLink.tsx +++ b/atcoder-problems-frontend/src/components/ProblemLink.tsx @@ -4,6 +4,7 @@ import * as Url from "../utils/Url"; import { getRatingColorClass } from "../utils"; import ProblemModel from "../interfaces/ProblemModel"; import { RatingInfo } from "../utils/RatingInfo"; +import { ShowDifficultyMode } from "../utils/ShowDifficultyMode"; import { DifficultyCircle } from "./DifficultyCircle"; import { NewTabLink } from "./NewTabLink"; @@ -13,7 +14,7 @@ interface Props { contestId: string; problemIndex?: string; problemName: string; - showDifficulty?: boolean; + showDifficultyMode: ShowDifficultyMode; isExperimentalDifficulty?: boolean; showDifficultyUnavailable?: boolean; problemModel?: ProblemModel | null; @@ -22,13 +23,16 @@ interface Props { export const ProblemLink: React.FC = (props) => { const [tooltipOpen, setTooltipOpen] = useState(false); + const [showDifficultySubClicked, setshowDifficultySubClicked] = useState( + false + ); const { contestId, problemId, problemIndex, problemName, - showDifficulty, + showDifficultyMode, isExperimentalDifficulty, showDifficultyUnavailable, problemModel, @@ -38,7 +42,7 @@ export const ProblemLink: React.FC = (props) => { ? `${problemIndex}. ${problemName}` : problemName; - const link = ( + const simpleLink = ( = (props) => { const difficulty = problemModel?.difficulty; if ( - !showDifficulty || problemModel === undefined || (difficulty === undefined && !showDifficultyUnavailable) ) { - return link; + return simpleLink; } const uniqueId = problemId + "-" + contestId; const experimentalIconId = "experimental-" + uniqueId; + const showDifficultySubIconId = "show-difficulty-sub-" + uniqueId; const ratingColorClass = difficulty === undefined ? undefined : getRatingColorClass(difficulty); - return ( + const experimentalDifficultySymbol = ( + <> + + ๐Ÿงช + + setTooltipOpen(!tooltipOpen)} + > + This estimate is experimental. + + + ); + const showDifficultySubSymbol = ( + <> + + + ); + + const difficultyColoredLink = ( + // Don't add rel="noreferrer" to AtCoder links + // to allow AtCoder get the referral information. + // eslint-disable-next-line react/jsx-no-target-blank + + {problemTitle} + + ); + const difficultySymbol = ( <> - {isExperimentalDifficulty ? ( - <> - - ๐Ÿงช - - setTooltipOpen(!tooltipOpen)} - > - This estimate is experimental. - - - ) : null} - { - // Don't add rel="noreferrer" to AtCoder links - // to allow AtCoder get the referral information. - // eslint-disable-next-line react/jsx-no-target-blank - - {problemTitle} - - } + {isExperimentalDifficulty ? experimentalDifficultySymbol : null} ); + + switch (showDifficultyMode) { + case ShowDifficultyMode.None: + return <>{simpleLink}; + case ShowDifficultyMode.Full: + return ( + <> + {difficultySymbol} + {difficultyColoredLink} + + ); + case ShowDifficultyMode.Sub: + return ( + <> + {showDifficultySubSymbol} + {showDifficultySubClicked ? difficultySymbol : null} + {showDifficultySubClicked ? difficultyColoredLink : simpleLink} + + ); + } }; diff --git a/atcoder-problems-frontend/src/components/SubmissionListTable.tsx b/atcoder-problems-frontend/src/components/SubmissionListTable.tsx index 4187227ef..9076294ef 100644 --- a/atcoder-problems-frontend/src/components/SubmissionListTable.tsx +++ b/atcoder-problems-frontend/src/components/SubmissionListTable.tsx @@ -7,6 +7,7 @@ import { formatMomentDateTime, parseSecond } from "../utils/DateUtil"; import { isAccepted } from "../utils"; import * as Url from "../utils/Url"; import { RatingInfo } from "../utils/RatingInfo"; +import { ShowDifficultyMode } from "../utils/ShowDifficultyMode"; import { ProblemLink } from "./ProblemLink"; import { ListPaginationPanel, @@ -130,7 +131,7 @@ export const SubmissionListTable: React.FC = (props) => { isExperimentalDifficulty={ problemModels?.get(problem_id)?.is_experimental } - showDifficulty={true} + showDifficultyMode={ShowDifficultyMode.Full} problemId={problem_id} problemIndex={problemIndexMap.get(problem_id) || ""} problemName={name || ""} diff --git a/atcoder-problems-frontend/src/pages/Internal/MyAccountPage/ResetProgress.tsx b/atcoder-problems-frontend/src/pages/Internal/MyAccountPage/ResetProgress.tsx index 4cf20a117..73bba2aa8 100644 --- a/atcoder-problems-frontend/src/pages/Internal/MyAccountPage/ResetProgress.tsx +++ b/atcoder-problems-frontend/src/pages/Internal/MyAccountPage/ResetProgress.tsx @@ -6,6 +6,7 @@ import { ProblemSearchBox } from "../../../components/ProblemSearchBox"; import { ProblemLink } from "../../../components/ProblemLink"; import { formatMomentDateTime, parseSecond } from "../../../utils/DateUtil"; import { useProgressResetList } from "../../../api/InternalAPIClient"; +import { ShowDifficultyMode } from "../../../utils/ShowDifficultyMode"; import { addResetProgress, deleteResetProgress } from "./ApiClient"; export const ResetProgress: React.FC = () => { @@ -50,6 +51,7 @@ export const ResetProgress: React.FC = () => { {problem ? ( = ({ contestId={problem.contest_id} problemIndex={problem.problem_index} problemName={problem.name} - showDifficulty={true} + showDifficultyMode={ShowDifficultyMode.Full} problemModel={problemModel} isExperimentalDifficulty={problemModel?.is_experimental} /> diff --git a/atcoder-problems-frontend/src/pages/Internal/VirtualContest/ShowContest/ContestTable.tsx b/atcoder-problems-frontend/src/pages/Internal/VirtualContest/ShowContest/ContestTable.tsx index 59d8f8f0d..0112befeb 100644 --- a/atcoder-problems-frontend/src/pages/Internal/VirtualContest/ShowContest/ContestTable.tsx +++ b/atcoder-problems-frontend/src/pages/Internal/VirtualContest/ShowContest/ContestTable.tsx @@ -23,6 +23,7 @@ import { makeBotRunners, } from "../../../../utils/RatingSystem"; import { VirtualContestItem, VirtualContestProblem } from "../../types"; +import { ShowDifficultyMode } from "../../../../utils/ShowDifficultyMode"; import { ContestTableRow } from "./ContestTableRow"; import { FirstAcceptanceRow } from "./FirstAcceptanceRow"; import { @@ -260,6 +261,7 @@ export const ContestTable = (props: Props) => { {p.contestId && p.title ? ( = (props) => { {problem.title && problem.contestId ? ( = (props) => {
{problem.contestId && problem.title ? ( {p.contestId && p.title ? ( {p.contestId && p.title ? ( = (props) => { dataFormat: function DataFormat(_, row): React.ReactElement { return ( ; hideCompletedContest: boolean; - showDifficulty: boolean; + showDifficultyMode: ShowDifficultyMode; colorMode: ColorMode; title: string; statusLabelMap: Map; @@ -181,7 +182,7 @@ const AtCoderRegularTableSFC: React.FC = (props) => { !!model && model.is_experimental } showDifficultyUnavailable - showDifficulty={props.showDifficulty} + showDifficultyMode={props.showDifficultyMode} contestId={contest.id} problemId={problem.problem.id} problemIndex={problem.problem.problem_index} diff --git a/atcoder-problems-frontend/src/pages/TablePage/ContestTable.tsx b/atcoder-problems-frontend/src/pages/TablePage/ContestTable.tsx index 1144a4219..92268a0c5 100644 --- a/atcoder-problems-frontend/src/pages/TablePage/ContestTable.tsx +++ b/atcoder-problems-frontend/src/pages/TablePage/ContestTable.tsx @@ -11,12 +11,13 @@ import { SubmitTimespan } from "../../components/SubmitTimespan"; import { RatingInfo } from "../../utils/RatingInfo"; import { isRatedContest } from "../../utils/ContestClassifier"; import { ProblemPoint } from "../../components/Problempoint"; +import { ShowDifficultyMode } from "../../utils/ShowDifficultyMode"; interface Props { contests: Contest[]; contestToProblems: Map; hideCompletedContest: boolean; - showDifficulty: boolean; + showDifficultyMode: ShowDifficultyMode; colorMode: ColorMode; statusLabelMap: Map; showPenalties: boolean; @@ -118,7 +119,7 @@ export const ContestTable: React.FC = (props) => { contest, problemInfo.length )} - showDifficulty={props.showDifficulty} + showDifficultyMode={props.showDifficultyMode} problemId={problem.id} contestId={contest.id} problemIndex={problem.problem_index} diff --git a/atcoder-problems-frontend/src/pages/TablePage/Options.tsx b/atcoder-problems-frontend/src/pages/TablePage/Options.tsx index 7106b11e6..132c6edc4 100644 --- a/atcoder-problems-frontend/src/pages/TablePage/Options.tsx +++ b/atcoder-problems-frontend/src/pages/TablePage/Options.tsx @@ -14,12 +14,13 @@ import { } from "reactstrap"; import { HelpBadgeTooltip } from "../../components/HelpBadgeTooltip"; import { ColorMode } from "../../utils/TableColor"; +import { ShowDifficultyMode } from "../../utils/ShowDifficultyMode"; interface Props { hideCompletedContest: boolean; toggleHideCompletedContest: () => void; - showDifficulties: boolean; - toggleShowDifficulties: () => void; + showDifficultyMode: ShowDifficultyMode; + setShowDifficultyMode: (showDifficultyMode: ShowDifficultyMode) => void; colorMode: ColorMode; setColorMode: (colorMode: ColorMode) => void; showPenalties: boolean; @@ -46,17 +47,43 @@ export const Options: React.FC = (props) => { /> + + + { + { + [ShowDifficultyMode.None]: "None", + [ShowDifficultyMode.Full]: "Full", + [ShowDifficultyMode.Sub]: "Sub", + }[props.showDifficultyMode] + } + + + Show Difficulty Mode + + props.setShowDifficultyMode(ShowDifficultyMode.None) + } + > + None + + + props.setShowDifficultyMode(ShowDifficultyMode.Full) + } + > + Full + + + props.setShowDifficultyMode(ShowDifficultyMode.Sub) + } + > + Sub + + + - -   +   Show Difficulty   Internal rating to have 50% Solve Probability diff --git a/atcoder-problems-frontend/src/pages/TablePage/index.tsx b/atcoder-problems-frontend/src/pages/TablePage/index.tsx index e1c899941..dfa1655ca 100644 --- a/atcoder-problems-frontend/src/pages/TablePage/index.tsx +++ b/atcoder-problems-frontend/src/pages/TablePage/index.tsx @@ -22,6 +22,7 @@ import { ContestCategory, } from "../../utils/ContestClassifier"; import { getLikeContestCategory } from "../../utils/LikeContestUtils"; +import { ShowDifficultyMode } from "../../utils/ShowDifficultyMode"; import { TableTabButtons } from "./TableTab"; import { Options } from "./Options"; import { ContestTable } from "./ContestTable"; @@ -41,9 +42,9 @@ export const TablePage: React.FC = (props) => { "hideCompletedContest", false ); - const [showDifficulty, setShowDifficulty] = useLocalStorage( - "showDifficulty", - true + const [showDifficultyMode, setShowDifficultyMode] = useLocalStorage( + "showDifficultyMode", + ShowDifficultyMode.None ); const [colorMode, setColorMode] = useLocalStorage( "colorMode", @@ -104,8 +105,8 @@ export const TablePage: React.FC = (props) => { toggleHideCompletedContest={(): void => setHideCompletedContest(!hideCompletedContest) } - showDifficulties={showDifficulty} - toggleShowDifficulties={(): void => setShowDifficulty(!showDifficulty)} + showDifficultyMode={showDifficultyMode} + setShowDifficultyMode={setShowDifficultyMode} colorMode={colorMode} setColorMode={setColorMode} showPenalties={showPenalties} @@ -135,7 +136,7 @@ export const TablePage: React.FC = (props) => { "PAST", ].includes(activeTab) ? ( = (props) => { /> ) : ( = (props) => { contestId={problem.contest_id} problemModel={model} isExperimentalDifficulty={!!model && model.is_experimental} - showDifficulty={submission !== undefined} + showDifficultyMode={ + submission !== undefined + ? ShowDifficultyMode.Full + : ShowDifficultyMode.None + } showDifficultyUnavailable /> diff --git a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx index 9c556870e..9fe27a6ea 100644 --- a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx +++ b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx @@ -34,6 +34,7 @@ import { getLastSolvedTimeMap, getMaximumExcludeElapsedSecond, } from "../../../utils/LastSolvedTime"; +import { ShowDifficultyMode } from "../../../utils/ShowDifficultyMode"; import { recommendProblems } from "./RecommendProblems"; import { RecommendController, RecommendOption } from "./RecommendController"; @@ -162,7 +163,7 @@ export const Recommendations = (props: Props) => { ): React.ReactElement => (