From d2fe0cc8ead793f97edf8470c8a90aa9d59aa86e Mon Sep 17 00:00:00 2001 From: Jessica McInchak Date: Wed, 16 Oct 2024 13:39:17 +0200 Subject: [PATCH] feat: toggle node images and data fields on editor graph (#3789) --- .../components/Flow/components/Checklist.tsx | 11 +++++ .../components/Flow/components/DataField.tsx | 33 ++++++++++++++ .../components/Flow/components/Option.tsx | 10 +++++ .../components/Flow/components/Question.tsx | 11 +++++ .../components/Flow/components/Thumbnail.tsx | 24 ++++++++++ .../FlowEditor/ToggleDataFieldsButton.tsx | 44 +++++++++++++++++++ .../FlowEditor/ToggleImagesButton.tsx | 44 +++++++++++++++++++ .../src/pages/FlowEditor/floweditor.scss | 2 +- .../src/pages/FlowEditor/index.tsx | 12 ++++- .../src/pages/FlowEditor/lib/store/editor.ts | 15 ++++++- 10 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/Flow/components/DataField.tsx create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Thumbnail.tsx create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleDataFieldsButton.tsx create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleImagesButton.tsx diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Checklist.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Checklist.tsx index 3c2214f2be..e31eab25b6 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Checklist.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Checklist.tsx @@ -12,9 +12,11 @@ import { Link } from "react-navi"; import { useStore } from "../../../lib/store"; import { getParentId } from "../lib/utils"; +import { DataField } from "./DataField"; import Hanger from "./Hanger"; import Node from "./Node"; import { Tag } from "./Tag"; +import { Thumbnail } from "./Thumbnail"; type Props = { type: TYPES; @@ -92,9 +94,18 @@ const Checklist: React.FC = React.memo((props) => { onContextMenu={handleContext} ref={drag} > + {props.data?.img && ( + + )} {Icon && } {props.text} + {props.data?.fn && ( + + )} {props.tags?.map((tag) => )} {groupedOptions ? ( diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/DataField.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/DataField.tsx new file mode 100644 index 0000000000..86686beb4f --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/DataField.tsx @@ -0,0 +1,33 @@ +import Box from "@mui/material/Box"; +import { useStore } from "pages/FlowEditor/lib/store"; +import React from "react"; + +export const DataField: React.FC<{ + value: string; + variant: "parent" | "child"; +}> = ({ value, variant }) => { + const showDataFields = useStore((state) => state.showDataFields); + if (!showDataFields) return null; + + return ( + ({ + fontFamily: theme.typography.data.fontFamily, + fontSize: theme.typography.data, + backgroundColor: "#f0f0f0", + borderColor: + variant === "parent" + ? theme.palette.common.black + : theme.palette.grey[400], + borderWidth: + variant === "parent" ? "0 1px 1px 1px" : "1px 0 0 0", + borderStyle: "solid", + width: "100%", + p: 0.5, + textAlign: "center", + })} + > + {value} + + ); +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Option.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Option.tsx index 8a48609f6e..8f1802dd70 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Option.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Option.tsx @@ -4,8 +4,10 @@ import React from "react"; import { Link } from "react-navi"; import { useStore } from "../../../lib/store"; +import { DataField } from "./DataField"; import Hanger from "./Hanger"; import Node from "./Node"; +import { Thumbnail } from "./Thumbnail"; const Option: React.FC = (props) => { const childNodes = useStore((state) => state.childNodesOf(props.id)); @@ -14,6 +16,7 @@ const Option: React.FC = (props) => { let background = "#666"; // no flag color let color = "#000"; + try { const flag = flatFlags.find(({ value }) => [props.data?.flag, props.data?.val].filter(Boolean).includes(value), @@ -27,8 +30,15 @@ const Option: React.FC = (props) => { className={classNames("card", "option", { wasVisited: props.wasVisited })} > e.preventDefault()}> + {props.data?.img && ( + + )}
{props.data.text}
+ {props.data?.val && }
    {childNodes.map((child: any) => ( diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Question.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Question.tsx index a63d20827c..b2b1a20069 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Question.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Question.tsx @@ -11,9 +11,11 @@ import { Link } from "react-navi"; import { useStore } from "../../../lib/store"; import { getParentId } from "../lib/utils"; +import { DataField } from "./DataField"; import Hanger from "./Hanger"; import Node from "./Node"; import { Tag } from "./Tag"; +import { Thumbnail } from "./Thumbnail"; type Props = { type: TYPES | "Error"; @@ -80,9 +82,18 @@ const Question: React.FC = React.memo((props) => { onContextMenu={handleContext} ref={drag} > + {props.data?.img && ( + + )} {Icon && } {props.text} + {props.type !== TYPES.SetValue && props.data?.fn && ( + + )} {props.tags?.map((tag) => )}
      {childNodes.map((child: any) => ( diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Thumbnail.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Thumbnail.tsx new file mode 100644 index 0000000000..7250a30c65 --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/Flow/components/Thumbnail.tsx @@ -0,0 +1,24 @@ +import Box from "@mui/material/Box"; +import { useStore } from "pages/FlowEditor/lib/store"; +import React from "react"; + +export const Thumbnail: React.FC<{ + imageSource: string; + imageAltText?: string; +}> = ({ imageSource, imageAltText }) => { + const showImages = useStore((state) => state.showImages); + if (!showImages) return null; + + return ( + + ); +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleDataFieldsButton.tsx b/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleDataFieldsButton.tsx new file mode 100644 index 0000000000..8c2ae3eb28 --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleDataFieldsButton.tsx @@ -0,0 +1,44 @@ +import DataFieldIcon from "@mui/icons-material/Code"; +import DataFieldOffIcon from "@mui/icons-material/CodeOff"; +import Box from "@mui/material/Box"; +import IconButton from "@mui/material/IconButton"; +import Tooltip from "@mui/material/Tooltip"; +import { useStore } from "pages/FlowEditor/lib/store"; +import React from "react"; + +export const ToggleDataFieldsButton: React.FC = () => { + const [showDataFields, toggleShowDataFields] = useStore((state) => [ + state.showDataFields, + state.toggleShowDataFields, + ]); + + return ( + ({ + position: "fixed", + bottom: theme.spacing(6), + left: theme.spacing(7), + zIndex: theme.zIndex.appBar, + border: `1px solid ${theme.palette.border.main}`, + borderRadius: "3px", + background: theme.palette.background.paper, + })} + > + + ({ + padding: theme.spacing(1), + color: showDataFields + ? theme.palette.text.primary + : theme.palette.text.disabled, + })} + > + {showDataFields ? : } + + + + ); +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleImagesButton.tsx b/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleImagesButton.tsx new file mode 100644 index 0000000000..5e27b46a0a --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/FlowEditor/ToggleImagesButton.tsx @@ -0,0 +1,44 @@ +import ImageOffIcon from "@mui/icons-material/HideImage"; +import ImageIcon from "@mui/icons-material/Image"; +import Box from "@mui/material/Box"; +import IconButton from "@mui/material/IconButton"; +import Tooltip from "@mui/material/Tooltip"; +import { useStore } from "pages/FlowEditor/lib/store"; +import React from "react"; + +export const ToggleImagesButton: React.FC = () => { + const [showImages, toggleShowImages] = useStore((state) => [ + state.showImages, + state.toggleShowImages, + ]); + + return ( + ({ + position: "fixed", + bottom: theme.spacing(10), + left: theme.spacing(7), + zIndex: theme.zIndex.appBar, + border: `1px solid ${theme.palette.border.main}`, + borderRadius: "3px", + background: theme.palette.background.paper, + })} + > + + ({ + padding: theme.spacing(1), + color: showImages + ? theme.palette.text.primary + : theme.palette.text.disabled, + })} + > + {showImages ? : } + + + + ); +}; diff --git a/editor.planx.uk/src/pages/FlowEditor/floweditor.scss b/editor.planx.uk/src/pages/FlowEditor/floweditor.scss index 5998350e7b..561d37248a 100644 --- a/editor.planx.uk/src/pages/FlowEditor/floweditor.scss +++ b/editor.planx.uk/src/pages/FlowEditor/floweditor.scss @@ -251,7 +251,7 @@ $fontMonospace: "Source Code Pro", monospace; flex-direction: column; padding: 0; min-width: 60px; - max-width: 200px; + max-width: fit-content; } .band { width: 100%; diff --git a/editor.planx.uk/src/pages/FlowEditor/index.tsx b/editor.planx.uk/src/pages/FlowEditor/index.tsx index 167b517006..50f0c96b7f 100644 --- a/editor.planx.uk/src/pages/FlowEditor/index.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/index.tsx @@ -1,12 +1,15 @@ import "./floweditor.scss"; import Box from "@mui/material/Box"; +import ButtonGroup from "@mui/material/ButtonGroup"; import { styled } from "@mui/material/styles"; import { HEADER_HEIGHT_EDITOR } from "components/Header"; import React, { useRef } from "react"; import { useCurrentRoute } from "react-navi"; import Flow from "./components/Flow"; +import { ToggleDataFieldsButton } from "./components/FlowEditor/ToggleDataFieldsButton"; +import { ToggleImagesButton } from "./components/FlowEditor/ToggleImagesButton"; import { ToggleTagsButton } from "./components/FlowEditor/ToggleTagsButton"; import Sidebar from "./components/Sidebar"; import { useStore } from "./lib/store"; @@ -50,7 +53,14 @@ const FlowEditor = () => { > - + + + + + diff --git a/editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts b/editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts index 02db9a6b77..b12d7f920e 100644 --- a/editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts +++ b/editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts @@ -3,7 +3,6 @@ import { getPathForNode, sortFlow } from "@opensystemslab/planx-core"; import { ComponentType, FlowGraph, - IndexedNode, NodeId, OrderedFlow, } from "@opensystemslab/planx-core/types"; @@ -52,6 +51,10 @@ export interface EditorUIStore { hideTestEnvBanner: () => void; showTags: boolean; toggleShowTags: () => void; + showImages: boolean; + toggleShowImages: () => void; + showDataFields: boolean; + toggleShowDataFields: () => void; } export const editorUIStore: StateCreator< @@ -76,12 +79,22 @@ export const editorUIStore: StateCreator< showTags: false, toggleShowTags: () => set({ showTags: !get().showTags }), + + showImages: false, + + toggleShowImages: () => set({ showImages: !get().showImages }), + + showDataFields: false, + + toggleShowDataFields: () => set({ showDataFields: !get().showDataFields }), }), { name: "editorUIStore", partialize: (state) => ({ showSidebar: state.showSidebar, showTags: state.showTags, + showImages: state.showImages, + showDataFields: state.showDataFields, }), }, );