Skip to content

Commit

Permalink
Double-Clicking Node Jumps Cursor to Relevant Text (#634)
Browse files Browse the repository at this point in the history
* Basic jump to line in editor

* Move mobile tab state into zustand

* Toggle tab if necessary before focusing
  • Loading branch information
rob-gordon authored Jan 2, 2024
1 parent 8d823f6 commit af6b2f9
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 25 deletions.
15 changes: 0 additions & 15 deletions app/src/components/AppContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,12 @@ const defaultLanguage = Object.keys(languages).includes(browserLanguage)
? browserLanguage
: "en";

type mobileEditorTab = "text" | "graph";

type TAppContext = {
updateUserSettings: (newSettings: Partial<UserSettings>) => void;
theme: Theme;
language: string;
shareModal: boolean;
setShareModal: Dispatch<SetStateAction<boolean>>;
mobileEditorTab: mobileEditorTab;
toggleMobileEditorTab: () => void;
session: Session | null;
customer?: CustomerInfo;
customerIsLoading: boolean;
Expand All @@ -64,15 +60,6 @@ const Provider = ({ children }: { children?: ReactNode }) => {
LOCAL_STORAGE_SETTINGS_KEY,
"{}"
);
const [mobileEditorTab, setMobileEditorTab] =
useState<mobileEditorTab>("text");
const toggleMobileEditorTab = useCallback(
() =>
setMobileEditorTab((currentTab) =>
currentTab === "text" ? "graph" : "text"
),
[]
);

const { settings, theme } = useMemo<{
settings: UserSettings;
Expand Down Expand Up @@ -157,8 +144,6 @@ const Provider = ({ children }: { children?: ReactNode }) => {
updateUserSettings,
setShareModal,
shareModal,
mobileEditorTab,
toggleMobileEditorTab,
session,
customer,
customerIsLoading,
Expand Down
8 changes: 4 additions & 4 deletions app/src/components/EditWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { ReactNode, useContext } from "react";
import { ReactNode } from "react";

import { useFullscreen } from "../lib/hooks";
import { Box } from "../slang";
import { AppContext } from "./AppContextProvider";
import styles from "./EditWrapper.module.css";
import MobileTabToggle from "./MobileTabToggle";
import { useMobileStore } from "../lib/useMobileStore";
/**
* Adds the wrapper for the toggle between the editor and the graph
* on mobile.
*/
export function EditWrapper({ children }: { children: ReactNode }) {
const { mobileEditorTab } = useContext(AppContext);
const tab = useMobileStore((state) => state.tab);
const isFullscreen = useFullscreen();
return (
<Box
as="main"
className={styles.EditWrapper}
data-mobile-tab={mobileEditorTab}
data-mobile-tab={tab}
template="[main] minmax(0, 1fr) auto / [main] minmax(0, 1fr)"
>
{children}
Expand Down
16 changes: 15 additions & 1 deletion app/src/components/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import {
} from "../lib/preprocessStyle";
import { useContextMenuState } from "../lib/useContextMenuState";
import { Doc, useDoc, useParseErrorStore } from "../lib/useDoc";
import { updateModelMarkers, useEditorStore } from "../lib/useEditorStore";
import {
moveCursorToLine,
updateModelMarkers,
useEditorStore,
} from "../lib/useEditorStore";
import { useGraphStore } from "../lib/useGraphStore";
import { Box } from "../slang";
import { getNodePositionsFromCy } from "./getNodePositionsFromCy";
Expand Down Expand Up @@ -222,6 +226,16 @@ function initializeGraph({
}
});

// on double click, focus the line number in the editor
cyCurrent.on(
"dblclick",
"node, edge",
function handleDblClick(this: NodeSingular | EdgeSingular) {
const { lineNumber } = this.data();
moveCursorToLine(lineNumber);
}
);

cyCurrent.on("dragfree", handleDragFree);

// on zoom
Expand Down
10 changes: 5 additions & 5 deletions app/src/components/MobileTabToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { t } from "@lingui/macro";
import { useContext } from "react";

import { Box } from "../slang";
import { AppContext } from "./AppContextProvider";
import { useMobileStore } from "../lib/useMobileStore";

export default function MobileTabToggle() {
const { toggleMobileEditorTab, mobileEditorTab } = useContext(AppContext);
const tab = useMobileStore((state) => state.tab);
const toggleTab = useMobileStore((state) => state.toggleTab);
return (
<Box p={1} at={{ tablet: { display: "none" } }}>
<Box
Expand All @@ -14,10 +14,10 @@ export default function MobileTabToggle() {
color="palette-white-0"
rad={1}
p={3}
onClick={toggleMobileEditorTab}
onClick={toggleTab}
>
<span className="text-xs">
{mobileEditorTab === "graph" ? t`Editor` : t`Graph`}
{tab === "graph" ? t`Editor` : t`Graph`}
</span>
</Box>
</Box>
Expand Down
22 changes: 22 additions & 0 deletions app/src/lib/useEditorStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { editor } from "monaco-editor";
import { create } from "zustand";
import { useMobileStore } from "./useMobileStore";

/**
* Stores client-side state related to the editor.
Expand Down Expand Up @@ -29,3 +30,24 @@ export function updateModelMarkers() {
if (!model) return;
monaco.editor.setModelMarkers(model, "editor", markers);
}

/**
* Focuses the editor. Then moves the cursor to the given line.
*/
export function moveCursorToLine(line: number) {
// We toggle the tab just in case we're in mobile view
const { tab, toggleTab } = useMobileStore.getState();
if (tab === "graph") {
toggleTab();
requestAnimationFrame(focus);
} else {
focus();
}

function focus() {
const { editor } = useEditorStore.getState();
if (!editor) return;
editor.focus();
editor.setPosition({ lineNumber: line, column: Infinity });
}
}
27 changes: 27 additions & 0 deletions app/src/lib/useMobileStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";

export type MobileEditorTab = "text" | "graph";

export type MobileStore = {
tab: MobileEditorTab;
toggleTab: () => void;
};

/**
* Stores client-side state related to the editor.
*/
export const useMobileStore = create<MobileStore>()(
persist(
(set) => ({
tab: "text",
toggleTab: () =>
set((state) => ({
tab: state.tab === "text" ? "graph" : "text",
})),
}),
{
name: "ff-mobile-store",
}
)
);

0 comments on commit af6b2f9

Please sign in to comment.