diff --git a/app/src/components/Actions.tsx b/app/src/components/Actions.tsx new file mode 100644 index 000000000..9ec5cde06 --- /dev/null +++ b/app/src/components/Actions.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from "react"; + +import { useIsProUser } from "../lib/hooks"; +import { ImportDataDialog } from "./ImportDataDialog"; +import { ImportDataUnauthenticatedDialog } from "./ImportDataUnauthenticatedDialog"; +import { LearnSyntaxDialog } from "./LearnSyntaxDialog"; +import { LoadTemplateDialog } from "./LoadTemplateDialog"; +import { LoadFileButton } from "./LoadFileButton"; +import { useLocation } from "react-router-dom"; +import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; +import { Sliders } from "phosphor-react"; + +export function Actions() { + const isProUser = useIsProUser(); + const isSandbox = useLocation().pathname === "/"; + const [open, setOpen] = useState(false); + useEffect(() => { + // when open, bind a listener to the window that catches clicks which bubble up from the editor-options dropdown + if (!open) return; + const listener = (e: MouseEvent) => { + const target = e.target as HTMLElement; + if (target.closest("#editor-options")) { + // debugger; + // setOpen(false); + } + }; + + window.addEventListener("click", listener); + + return () => { + window.removeEventListener("click", listener); + }; + }, [setOpen, open]); + return ( + <> +
+ + + {isSandbox ? : null} + {isProUser ? : } +
+ + + + + + + + {isSandbox ? : null} + {isProUser ? ( + + ) : ( + + )} + + + + ); +} diff --git a/app/src/components/CloneButton.tsx b/app/src/components/CloneButton.tsx index a508a5323..7b4444df7 100644 --- a/app/src/components/CloneButton.tsx +++ b/app/src/components/CloneButton.tsx @@ -6,11 +6,12 @@ import { useContext } from "react"; import { AppContext } from "./AppContextProvider"; import { getFunFlowchartName } from "../lib/getFunFlowchartName"; import { languages } from "../locales/i18n"; -import { useUserId } from "../lib/hooks"; +import { useIsProUser, useUserId } from "../lib/hooks"; import { makeChart, queryClient } from "../lib/queries"; import { useMutation } from "react-query"; export function CloneButton() { + const isProUser = useIsProUser(); const language = useContext(AppContext).language; const userId = useUserId(); const makeChartMutation = useMutation( @@ -34,6 +35,7 @@ export function CloneButton() { }, } ); + if (!isProUser) return null; return ( -
-
- - - {isSandbox ? : null} - {isProUser ? ( - - ) : ( - - )} -
-
- {children} - - ); -} diff --git a/app/src/components/EditorWrapper.module.css b/app/src/components/EditorWrapper.module.css deleted file mode 100644 index 6364ca838..000000000 --- a/app/src/components/EditorWrapper.module.css +++ /dev/null @@ -1,58 +0,0 @@ -.EditorWrapper { - display: grid; - width: 100%; - max-width: 100%; - grid-template-columns: minmax(0, 1fr); - grid-template-rows: auto minmax(0, 1fr); - overflow: hidden; -} - -.HeaderTitle button:first-child h1 { - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; - overflow: hidden; -} - -.ShareButton { - padding: 10px 16px 10px 17px; - display: grid; - grid-auto-flow: column; - align-items: center; - justify-content: start; - gap: 9px; - color: var(--palette-white-0); - background-color: var(--palette-purple-0); - line-height: 1 !important; -} - -.ShareButton:focus { - box-shadow: none; -} - -.ShareButton:hover, -.ShareButton:focus-visible { - box-shadow: 0px 0px 0px 4px hsla(var(--color-brandHsl), 0.33); -} - -.ShareButton:active { - background-color: var(--palette-purple-4); - outline-color: var(--palette-purple-2); -} - -.EditorWrapper [data-rename-button] { - padding: calc(var(--spacer-px) * 0.5); - margin-left: calc(var(--spacer-px) * -0.5); -} - -.EditorWrapper [data-rename-button]:hover, -.EditorWrapper [data-rename-button]:focus-visible { - text-decoration: underline; - text-decoration-thickness: 1px; - text-underline-offset: 5px; - text-decoration-color: #bbb; -} - -.EditorWrapper [data-rename-button]:focus { - box-shadow: none; -} diff --git a/app/src/components/FlowchartHeader.module.css b/app/src/components/FlowchartHeader.module.css new file mode 100644 index 000000000..b9d1fa5a8 --- /dev/null +++ b/app/src/components/FlowchartHeader.module.css @@ -0,0 +1,6 @@ +.HeaderTitle button:first-child h1 { + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + overflow: hidden; +} diff --git a/app/src/components/EditorWrapper.tsx b/app/src/components/FlowchartHeader.tsx similarity index 78% rename from app/src/components/EditorWrapper.tsx rename to app/src/components/FlowchartHeader.tsx index d2e0e86a1..6af5ac449 100644 --- a/app/src/components/EditorWrapper.tsx +++ b/app/src/components/FlowchartHeader.tsx @@ -1,12 +1,11 @@ import { Trans } from "@lingui/macro"; -import { Suspense, useContext, useEffect, useRef, useState } from "react"; +import { useContext, useEffect, useRef, useState } from "react"; import { useIsLoggedIn, useIsProUser, useIsReadOnly } from "../lib/hooks"; import { docToString, useDoc, useDocDetails } from "../lib/useDoc"; import { Button2, Input } from "../ui/Shared"; import { AppContext } from "./AppContextProvider"; import { CloneButton } from "./CloneButton"; -import styles from "./EditorWrapper.module.css"; -import Loading from "./Loading"; +import styles from "./FlowchartHeader.module.css"; import { RenameButton } from "./RenameButton"; import ShareDialog from "./ShareDialog"; import { Cloud, DownloadSimple, Export, File } from "phosphor-react"; @@ -23,60 +22,51 @@ import { useMutation } from "react-query"; import { makeChart } from "../lib/queries"; import { saveAs } from "file-saver"; -/** - * Adds title and export button to the editor - */ -export function EditorWrapper({ children }: { children: React.ReactNode }) { +export function FlowchartHeader() { const title = useDocDetails("title", "flowchart.fun"); const { setShareModal } = useContext(AppContext); const isReadOnly = useIsReadOnly(); const isPro = useIsProUser(); const pageTitle = title || "flowchart.fun"; const isSandbox = useLocation().pathname === "/"; - return ( -
-
- {isSandbox ? ( +
+ {isSandbox ? ( + {pageTitle} + ) : ( + {pageTitle} - ) : ( - - {pageTitle} - + + )} +
+ {isReadOnly && ( + + Read-only + )} -
- {isReadOnly && ( - - Read-only - - )} - {isReadOnly && isPro ? : null} - {!isReadOnly ? ( - <> - {isSandbox ? : null} - - setShareModal(true)} - leftIcon={} - aria-label="Export" - > - Share - - - - ) : null} -
-
- }> -
{children}
-
-
+ {isReadOnly && isPro ? : null} + {!isReadOnly ? ( + <> + {isSandbox ? : null} + + setShareModal(true)} + leftIcon={} + aria-label="Export" + > + Share + + + + ) : null} + + ); } @@ -98,6 +88,8 @@ function LogInToSaveButton() { const navigate = useNavigate(); return ( } + color="zinc" onClick={() => { navigate("/l"); }} @@ -137,6 +129,7 @@ function CanSaveButton() { } + color="zinc" onClick={() => { setOpen(true); }} @@ -252,7 +245,7 @@ function FlowchartTitle({ return (

+ {children} + + ); +} diff --git a/app/src/components/Graph.tsx b/app/src/components/Graph.tsx index 4b140eb2e..7acea22d0 100644 --- a/app/src/components/Graph.tsx +++ b/app/src/components/Graph.tsx @@ -91,9 +91,13 @@ const Graph = memo(function Graph({ shouldResize }: { shouldResize: number }) { // then we set autoungrabify to true const canEdit = useCanEdit(); useEffect(() => { - if (cy.current && !canEdit) { + if (!cy.current) return; + if (!canEdit) { cy.current.autoungrabify(true); cy.current.autounselectify(true); + } else { + cy.current.autoungrabify(false); + cy.current.autounselectify(false); } }, [canEdit]); diff --git a/app/src/components/GraphWrapper.module.css b/app/src/components/GraphWrapper.module.css index 31acf2e80..e6fc0a366 100644 --- a/app/src/components/GraphWrapper.module.css +++ b/app/src/components/GraphWrapper.module.css @@ -15,7 +15,7 @@ z-index: -1; } - [data-mobile-tab="graph"] .GraphWrapper { + [data-selected-tab="Graph"] .GraphWrapper { z-index: 1; } } diff --git a/app/src/components/Header.tsx b/app/src/components/Header.tsx index 0f83384c0..dccc514bd 100644 --- a/app/src/components/Header.tsx +++ b/app/src/components/Header.tsx @@ -70,16 +70,16 @@ export const Header = memo(function SharedHeader() { return ( <> -
+