From 73fb4a4de8e101a6a7992dce96ff8609939d9864 Mon Sep 17 00:00:00 2001 From: Joel Keyser Date: Wed, 4 Dec 2024 22:11:22 -0600 Subject: [PATCH] feat: add zen mode --- .../components/Edge/ScoreEdge.styles.tsx | 11 -------- src/web/topic/components/Edge/ScoreEdge.tsx | 9 +++++++ .../components/Indicator/CommonIndicators.tsx | 25 ++++++++++++----- .../Indicator/ContentIndicators.tsx | 4 +++ .../components/Indicator/StatusIndicators.tsx | 5 +++- src/web/topic/components/Node/NodeHandle.tsx | 4 ++- .../TopicWorkspace/TopicWorkspace.tsx | 2 ++ .../TopicWorkspace/WorkspaceToolbar.tsx | 27 +++++++++++++++---- src/web/topic/utils/hotkeys.ts | 1 + src/web/view/userConfigStore.ts | 10 +++++++ 10 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/web/topic/components/Edge/ScoreEdge.styles.tsx b/src/web/topic/components/Edge/ScoreEdge.styles.tsx index 03bb7f02..f9e130f6 100644 --- a/src/web/topic/components/Edge/ScoreEdge.styles.tsx +++ b/src/web/topic/components/Edge/ScoreEdge.styles.tsx @@ -47,18 +47,7 @@ const divOptions = { }; export const StyledDiv = styled("div", divOptions)` - pointer-events: all; - cursor: default; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - background-color: white; border: 1px solid ${edgeColor}; - border-radius: 15%; - padding: 4px; ${({ labelX, labelY }) => css` position: absolute; diff --git a/src/web/topic/components/Edge/ScoreEdge.tsx b/src/web/topic/components/Edge/ScoreEdge.tsx index 7d3cdda3..8a1bd202 100644 --- a/src/web/topic/components/Edge/ScoreEdge.tsx +++ b/src/web/topic/components/Edge/ScoreEdge.tsx @@ -27,6 +27,7 @@ import { useUserCanEditTopicData } from "@/web/topic/store/userHooks"; import { Edge } from "@/web/topic/utils/graph"; import { useUnrestrictedEditing } from "@/web/view/actionConfigStore"; import { setSelected, useDrawSimpleEdgePaths } from "@/web/view/currentViewStore/store"; +import { useZenMode } from "@/web/view/userConfigStore"; const flowMarkerId = "flowMarker"; const nonFlowMarkerId = "nonFlowMarker"; @@ -95,7 +96,9 @@ interface Props { export const ScoreEdge = ({ inReactFlow, ...flowEdge }: EdgeProps & Props) => { const { sessionUser } = useSessionUser(); const userCanEditTopicData = useUserCanEditTopicData(sessionUser?.username); + const unrestrictedEditing = useUnrestrictedEditing(); + const zenMode = useZenMode(); const drawSimpleEdgePaths = useDrawSimpleEdgePaths(); const edge = convertToEdge(flowEdge); @@ -149,6 +152,12 @@ export const ScoreEdge = ({ inReactFlow, ...flowEdge }: EdgeProps & Props) => { onClick={() => setSelected(edge.id)} onContextMenu={(event) => openContextMenu(event, { edge })} spotlight={spotlight} + className={ + // pointer-events and cursor are set because this div is within an SVG and doesn't handle pointer-events properly by default + "[pointer-events:all] cursor-default flex flex-col items-center justify-center bg-white p-1 rounded-xl" + + // during zenMode, div only contains the label text (no indicators), so border doesn't seem necessary (if this looks awkward, we can always show border instead) + (zenMode && spotlight === "normal" ? " border-none" : "") + } > { + const zenMode = useZenMode(); + const workspaceContext = useContext(WorkspaceContext); + return ( - {/* TODO: should this be moved because it's not used for all graph parts? */} - - {/* TODO: should this be moved because it's only used for problem? */} - - - + {!zenMode && ( + <> + {/* TODO: should this be moved because it's not used for all graph parts? */} + + {/* TODO: should this be moved because it's only used for problem? */} + + + + )} + + {/* table's purpose is mainly for scores, so show scores there even if in zen mode */} + {(!zenMode || workspaceContext === "table") && } ); }; diff --git a/src/web/topic/components/Indicator/ContentIndicators.tsx b/src/web/topic/components/Indicator/ContentIndicators.tsx index ecdbfaf2..c9d37401 100644 --- a/src/web/topic/components/Indicator/ContentIndicators.tsx +++ b/src/web/topic/components/Indicator/ContentIndicators.tsx @@ -6,6 +6,7 @@ import { FoundResearchIndicator } from "@/web/topic/components/Indicator/FoundRe import { JustificationIndicator } from "@/web/topic/components/Indicator/JustificationIndicator"; import { QuestionIndicator } from "@/web/topic/components/Indicator/QuestionIndicator"; import { GraphPartType } from "@/web/topic/utils/graph"; +import { useZenMode } from "@/web/view/userConfigStore"; interface Props { graphPartId: string; @@ -15,6 +16,9 @@ interface Props { } const ContentIndicatorsBase = ({ graphPartId, graphPartType, color, className }: Props) => { + const zenMode = useZenMode(); + if (zenMode) return <>; + return ( diff --git a/src/web/topic/components/Indicator/StatusIndicators.tsx b/src/web/topic/components/Indicator/StatusIndicators.tsx index d75dcfbe..db5abad0 100644 --- a/src/web/topic/components/Indicator/StatusIndicators.tsx +++ b/src/web/topic/components/Indicator/StatusIndicators.tsx @@ -2,7 +2,7 @@ import { type ButtonProps, Stack } from "@mui/material"; import { memo } from "react"; import { ForceShownIndicator } from "@/web/topic/components/Indicator/ForceShownIndicator"; -import { useIndicateWhenNodeForcedToShow } from "@/web/view/userConfigStore"; +import { useIndicateWhenNodeForcedToShow, useZenMode } from "@/web/view/userConfigStore"; interface Props { graphPartId: string; @@ -15,6 +15,9 @@ interface Props { */ const StatusIndicatorsBase = ({ graphPartId, color, className }: Props) => { const indicateWhenNodeForcedToShow = useIndicateWhenNodeForcedToShow(); + const zenMode = useZenMode(); + + if (zenMode) return <>; return ( diff --git a/src/web/topic/components/Node/NodeHandle.tsx b/src/web/topic/components/Node/NodeHandle.tsx index c03e7e05..1f09d2d5 100644 --- a/src/web/topic/components/Node/NodeHandle.tsx +++ b/src/web/topic/components/Node/NodeHandle.tsx @@ -12,6 +12,7 @@ import { Node, RelationDirection } from "@/web/topic/utils/graph"; import { Orientation } from "@/web/topic/utils/layout"; import { nodeDecorations } from "@/web/topic/utils/node"; import { showNode } from "@/web/view/currentViewStore/filter"; +import { useZenMode } from "@/web/view/userConfigStore"; const NodeSummary = ({ node, beforeSlot }: { node: Node; beforeSlot?: ReactNode }) => { const { NodeIcon, title } = nodeDecorations[node.type]; @@ -37,6 +38,7 @@ const NodeHandleBase = ({ node, direction, orientation }: Props) => { const { sessionUser } = useSessionUser(); const userCanEditTopicData = useUserCanEditTopicData(sessionUser?.username); + const zenMode = useZenMode(); const neighborsInDirection = useNeighborsInDirection(node.id, direction); const hiddenNeighbors = useHiddenNodes(neighborsInDirection); @@ -47,7 +49,7 @@ const NodeHandleBase = ({ node, direction, orientation }: Props) => { }); const hasHiddenNeighbors = sortedHiddenNeighbors.length > 0; - const showHandle = userCanEditTopicData || hasHiddenNeighbors; + const showHandle = !zenMode && (userCanEditTopicData || hasHiddenNeighbors); const type = direction === "parent" ? "target" : "source"; diff --git a/src/web/topic/components/TopicWorkspace/TopicWorkspace.tsx b/src/web/topic/components/TopicWorkspace/TopicWorkspace.tsx index 92976a9d..7a8b8531 100644 --- a/src/web/topic/components/TopicWorkspace/TopicWorkspace.tsx +++ b/src/web/topic/components/TopicWorkspace/TopicWorkspace.tsx @@ -21,9 +21,11 @@ import { userCanEditScores } from "@/web/topic/utils/score"; import { getReadonlyMode, toggleReadonlyMode } from "@/web/view/actionConfigStore"; import { getSelectedGraphPart, setSelected, useFormat } from "@/web/view/currentViewStore/store"; import { getPerspectives } from "@/web/view/perspectiveStore"; +import { toggleZenMode } from "@/web/view/userConfigStore"; const useWorkspaceHotkeys = (user: { username: string } | null | undefined) => { useHotkeys([hotkeys.deselectPart], () => setSelected(null)); + useHotkeys([hotkeys.zenMode], () => toggleZenMode()); useHotkeys([hotkeys.readonlyMode], () => toggleReadonlyMode()); useHotkeys([hotkeys.score], (_, hotkeysEvent) => { diff --git a/src/web/topic/components/TopicWorkspace/WorkspaceToolbar.tsx b/src/web/topic/components/TopicWorkspace/WorkspaceToolbar.tsx index 766f929b..c00848f5 100644 --- a/src/web/topic/components/TopicWorkspace/WorkspaceToolbar.tsx +++ b/src/web/topic/components/TopicWorkspace/WorkspaceToolbar.tsx @@ -9,6 +9,7 @@ import { Highlight, QuestionMark, Redo, + SelfImprovement, Undo, } from "@mui/icons-material"; import { AppBar, Divider, IconButton, ToggleButton, Toolbar, Tooltip } from "@mui/material"; @@ -24,6 +25,7 @@ import { useOnPlayground } from "@/web/topic/store/topicHooks"; import { useUserCanEditTopicData } from "@/web/topic/store/userHooks"; import { redo, undo } from "@/web/topic/store/utilActions"; import { useTemporalHooks } from "@/web/topic/store/utilHooks"; +import { hotkeys } from "@/web/topic/utils/hotkeys"; import { toggleFlashlightMode, toggleReadonlyMode, @@ -41,6 +43,7 @@ import { resetPerspectives, useIsComparingPerspectives, } from "@/web/view/perspectiveStore"; +import { toggleZenMode, useZenMode } from "@/web/view/userConfigStore"; export const WorkspaceToolbar = () => { const { sessionUser } = useSessionUser(); @@ -50,6 +53,7 @@ export const WorkspaceToolbar = () => { const [canUndo, canRedo] = useTemporalHooks(); const [canGoBack, canGoForward] = useCanGoBackForward(); + const zenMode = useZenMode(); const isComparingPerspectives = useIsComparingPerspectives(); const flashlightMode = useFlashlightMode(); const readonlyMode = useReadonlyMode(); @@ -137,10 +141,23 @@ export const WorkspaceToolbar = () => { )} + + + toggleZenMode()} + className="rounded-full border-none" + > + + + {!onPlayground && ( <> - - { size="small" selected={flashlightMode} onClick={() => toggleFlashlightMode(!flashlightMode)} - className="rounded-full border-none" + className="hidden rounded-full border-none sm:flex" // hide on mobile because there's not enough space > @@ -180,8 +197,8 @@ export const WorkspaceToolbar = () => { {readonlyMode && ( ()( ); // hooks +export const useZenMode = () => { + return useUserConfigStore((state) => state.zenMode); +}; + export const useFillNodesWithColor = () => { return useUserConfigStore((state) => state.fillNodesWithColor); }; @@ -27,6 +33,10 @@ export const useIndicateWhenNodeForcedToShow = () => { }; // actions +export const toggleZenMode = () => { + useUserConfigStore.setState((state) => ({ zenMode: !state.zenMode })); +}; + export const toggleFillNodesWithColor = (fill: boolean) => { useUserConfigStore.setState({ fillNodesWithColor: fill }); };