diff --git a/ui/src/components/Canvas.tsx b/ui/src/components/Canvas.tsx index 3674b8dd..aaaf2ac7 100644 --- a/ui/src/components/Canvas.tsx +++ b/ui/src/components/Canvas.tsx @@ -38,6 +38,7 @@ import { RepoContext } from "../lib/store"; import { MyMonaco } from "./MyMonaco"; import { useApolloClient } from "@apollo/client"; +import { CanvasContextMenu } from "./CanvasContextMenu"; const nanoid = customAlphabet(nolookalikes, 10); @@ -727,36 +728,12 @@ export function Canvas() { {showContextMenu && ( - - - - - - + addNode(client.x, client.y, "code")} + addScope={() => addNode(client.x, client.y, "scope")} + /> )} diff --git a/ui/src/components/CanvasContextMenu.tsx b/ui/src/components/CanvasContextMenu.tsx new file mode 100644 index 00000000..ac89c65c --- /dev/null +++ b/ui/src/components/CanvasContextMenu.tsx @@ -0,0 +1,68 @@ +import { useStore } from "zustand"; +import { RepoContext } from "../lib/store"; +import Box from "@mui/material/Box"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import MenuList from "@mui/material/MenuList"; +import MenuItem from "@mui/material/MenuItem"; +import React, { useContext } from "react"; +import CodeIcon from "@mui/icons-material/Code"; +import PostAddIcon from "@mui/icons-material/PostAdd"; +import FormatListNumberedIcon from "@mui/icons-material/FormatListNumbered"; + +const paneMenuStyle = (left, top) => { + return { + left: `${left}px`, + top: `${top}px`, + zIndex: 100, + position: "absolute", + boxShadow: "0px 1px 8px 0px rgba(0, 0, 0, 0.1)", + // width: '200px', + backgroundColor: "#fff", + borderRadius: "5px", + boxSizing: "border-box", + } as React.CSSProperties; +}; + +const ItemStyle = { + "&:hover": { + background: "#f1f3f7", + color: "#4b00ff", + }, +}; + +export function CanvasContextMenu(props) { + const store = useContext(RepoContext); + if (!store) throw new Error("Missing BearContext.Provider in the tree"); + const showLineNumbers = useStore(store, (state) => state.showLineNumbers); + const flipShowLineNumbers = useStore( + store, + (state) => state.flipShowLineNumbers + ); + return ( + + + + + + + New Code + + + + + + New Scope + + + + + + + {showLineNumbers ? "Hide " : "Show "} Line Numbers + + + + + ); +} diff --git a/ui/src/components/MyMonaco.tsx b/ui/src/components/MyMonaco.tsx index 0ec54f1d..efd36ab7 100644 --- a/ui/src/components/MyMonaco.tsx +++ b/ui/src/components/MyMonaco.tsx @@ -1,7 +1,9 @@ import { Position } from "monaco-editor"; -import { useState } from "react"; +import { useState, useContext } from "react"; import MonacoEditor, { MonacoDiffEditor } from "react-monaco-editor"; import { monaco } from "react-monaco-editor"; +import { useStore } from "zustand"; +import { RepoContext } from "../lib/store"; monaco.languages.setLanguageConfiguration("julia", { indentationRules: { @@ -304,6 +306,10 @@ export function MyMonaco({ }) { // console.log("rendering monaco .."); // there's no racket language support + const store = useContext(RepoContext); + if (!store) throw new Error("Missing BearContext.Provider in the tree"); + const showLineNumbers = useStore(store, (state) => state.showLineNumbers); + if (lang === "racket") { lang = "scheme"; } @@ -334,6 +340,7 @@ export function MyMonaco({ // autoIndent: true, overviewRulerLanes: 0, automaticLayout: true, + lineNumbers: showLineNumbers ? "on" : "off", scrollbar: { alwaysConsumeMouseWheel: false, vertical: "hidden", diff --git a/ui/src/index.css b/ui/src/index.css index ec2585e8..3e3b6a19 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -10,4 +10,4 @@ body { code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; -} +} \ No newline at end of file diff --git a/ui/src/lib/store.tsx b/ui/src/lib/store.tsx index 01c0cc4c..4a014e34 100644 --- a/ui/src/lib/store.tsx +++ b/ui/src/lib/store.tsx @@ -15,8 +15,9 @@ import { import { createRuntimeSlice, RuntimeSlice } from "./runtime"; import { ApolloClient } from "@apollo/client"; -export const RepoContext = - createContext | null>(null); +export const RepoContext = createContext | null>(null); // TODO use a selector to compute and retrieve the status // TODO this need to cooperate with syncing indicator @@ -67,6 +68,7 @@ const initialState = { queueProcessing: false, socket: null, socketIntervalId: null, + showLineNumbers: true, }; export type Pod = { @@ -125,6 +127,7 @@ export interface RepoSlice { kernels: Record; // queueProcessing: boolean; socket: WebSocket | null; + showLineNumbers: boolean; error: { type: string; msg: string } | null; updatePod: ({ id, data }: { id: string; data: Partial }) => void; remoteUpdateAllPods: (client) => void; @@ -151,6 +154,7 @@ export interface RepoSlice { }) => void; setPodPosition: ({ id, x, y }: any) => void; setPodParent: ({ id, parent }: any) => void; + flipShowLineNumbers: () => void; } type BearState = RepoSlice & RuntimeSlice; @@ -622,6 +626,8 @@ const createRepoSlice: StateCreator< // state.pods[action.meta.arg.id].isSyncing = false; // state.pods[action.meta.arg.id].dirty = false; }, + flipShowLineNumbers: () => + set((state) => ({ showLineNumbers: !state.showLineNumbers })), }); export const createRepoStore = () =>