Skip to content

Commit

Permalink
feat: Add optional "inline" mode for displaying nodes
Browse files Browse the repository at this point in the history
This uses up less space, and reads nicely (more text-like) for `λ`/`∀`/`Λ` nodes.

We can trigger this mode through the tree/text toggle. This is a slight abuse of this element, and we'll likely revisit this if/when we have more optional display behaviour. On the other hand, this display option is fairly experimental for now, and it may well be that we don't keep both tree styles around in the long run.

Signed-off-by: George Thomas <georgefsthomas@gmail.com>
  • Loading branch information
georgefst committed Aug 2, 2023
1 parent 67f5cfd commit 0cd5979
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 53 deletions.
24 changes: 19 additions & 5 deletions src/components/Edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ import {
} from "@/primer-api";
import {
defaultTreeReactFlowProps,
inlineTreeReactFlowProps,
ScrollToDef,
} from "@/components/TreeReactFlow";
import { Mode } from "../Toolbar";

// hardcoded values (for now)
const initialLevel: Level = "Expert";
Expand Down Expand Up @@ -198,6 +200,8 @@ const AppNoError = ({
undoAvailable: boolean;
redoAvailable: boolean;
}): JSX.Element => {
const initialMode = "tree 1";
const [mode, setMode] = useState<Mode>(initialMode);
const [level, setLevel] = useState<Level>(initialLevel);
const toggleLevel = (): void => {
switch (level) {
Expand Down Expand Up @@ -265,14 +269,25 @@ const AppNoError = ({
.sort((a, b) => cmpName(a.name, b.name))
.map((d) => d.name.baseName);

const treeProps = (() => {
switch (mode) {
case "text":
return defaultTreeReactFlowProps;
case "tree 1":
return defaultTreeReactFlowProps;
case "tree 2":
return inlineTreeReactFlowProps;
}
})();

return (
<div className="grid h-[100dvh] grid-cols-[auto_20rem]">
<div className="relative h-full">
<ReactFlowProvider>
<TreeReactFlow
scrollToDefRef={scrollToDefRef}
scrollToTypeDefRef={scrollToTypeDefRef}
{...defaultTreeReactFlowProps}
{...treeProps}
{...(selection && { selection })}
onNodeClick={(_e, sel) => sel && setSelection(sel)}
defs={p.module.defs}
Expand All @@ -286,9 +301,7 @@ const AppNoError = ({

<div className="absolute bottom-4 right-4 z-30">
<Toolbar
onModeChange={() => {
console.log("Toggle mode");
}}
onModeChange={setMode}
level={level}
onLevelChange={toggleLevel}
undoAvailable={p.undoAvailable}
Expand All @@ -307,7 +320,7 @@ const AppNoError = ({
})
.then(p.setProg);
}}
initialMode="tree"
initialMode={mode}
/>
</div>

Expand All @@ -324,6 +337,7 @@ const AppNoError = ({
defs={defs}
initialEvalDef={evalTarget}
typeOrKind={p.selectionTypeOrKind}
extraTreeProps={treeProps}
/>
</TreeReactFlow>
</ReactFlowProvider>
Expand Down
10 changes: 9 additions & 1 deletion src/components/EvalFull/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { useState } from "react";
import { NodeChange, ReactFlowProvider, useReactFlow } from "reactflow";
import { EvalFullResp, GlobalName, Level } from "@/primer-api";
import { SelectMenu, TreeReactFlowOne } from "@/components";
import { defaultTreeReactFlowProps } from "../TreeReactFlow";
import {
TreeReactFlowOneProps,
defaultTreeReactFlowProps,
} from "../TreeReactFlow";

export type EvalFullProps = {
moduleName: string[];
Expand All @@ -13,12 +16,14 @@ export type EvalFullProps = {
level: Level;
defs: string[];
initialEvalDef: string | undefined;
extraTreeProps: Partial<TreeReactFlowOneProps>;
};

const Evaluated = (p: {
defName: GlobalName;
evaluated?: EvalFullResp;
level: Level;
extraTreeProps: Partial<TreeReactFlowOneProps>;
}) => {
const padding = 1.0;
const { fitView } = useReactFlow();
Expand All @@ -34,6 +39,7 @@ const Evaluated = (p: {
zoomBarProps={{ padding }}
onNodesChange={onNodesChange}
fitViewOptions={{ padding }}
{...p.extraTreeProps}
/>
);
};
Expand All @@ -47,6 +53,7 @@ export const EvalFull = ({
moduleName,
level,
initialEvalDef,
extraTreeProps,
}: EvalFullProps): JSX.Element => {
const [evalDef, setEvalDef0] = useState(initialEvalDef ?? disableEval);
const setEvalDef = (e: string) => {
Expand All @@ -73,6 +80,7 @@ export const EvalFull = ({
defName={{ qualifiedModule: moduleName, baseName: evalDef }}
{...(evalFull.result ? { evaluated: evalFull.result } : {})}
level={level}
extraTreeProps={extraTreeProps}
/>
</ReactFlowProvider>
</div>
Expand Down
20 changes: 17 additions & 3 deletions src/components/SelectionInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { NodeChange, ReactFlowProvider, useReactFlow } from "reactflow";
import { Level, TypeOrKind } from "@/primer-api";
import { TreeReactFlowOne } from "@/components";
import { defaultTreeReactFlowProps } from "../TreeReactFlow";
import {
TreeReactFlowOneProps,
defaultTreeReactFlowProps,
} from "../TreeReactFlow";

export type SelectionInfoProps = {
typeOrKind: TypeOrKind | undefined;
level: Level;
extraTreeProps: Partial<TreeReactFlowOneProps>;
};

const TypeOrKindTree = (p: { typeOrKind: TypeOrKind; level: Level }) => {
const TypeOrKindTree = (p: {
typeOrKind: TypeOrKind;
level: Level;
extraTreeProps: Partial<TreeReactFlowOneProps>;
}) => {
const padding = 1.0;
const { fitView } = useReactFlow();
const onNodesChange = (_: NodeChange[]) => {
Expand All @@ -23,13 +31,15 @@ const TypeOrKindTree = (p: { typeOrKind: TypeOrKind; level: Level }) => {
zoomBarProps={{ padding }}
onNodesChange={onNodesChange}
fitViewOptions={{ padding }}
{...p.extraTreeProps}
/>
);
};

export const SelectionInfo = ({
typeOrKind,
level,
extraTreeProps,
}: SelectionInfoProps): JSX.Element => {
return (
<div className="flex h-full flex-col overflow-auto">
Expand All @@ -40,7 +50,11 @@ export const SelectionInfo = ({
</div>
<div className="grow">
<ReactFlowProvider>
<TypeOrKindTree typeOrKind={typeOrKind} level={level} />
<TypeOrKindTree
typeOrKind={typeOrKind}
level={level}
extraTreeProps={extraTreeProps}
/>
</ReactFlowProvider>
</div>
</>
Expand Down
13 changes: 8 additions & 5 deletions src/components/Toolbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export type ToolbarProps = {
undoAvailable: boolean;
onClickUndo: MouseEventHandler<HTMLButtonElement>;
};
export type Mode = "text" | "tree";
export type Mode = "text" | "tree 1" | "tree 2";

const iconClasses = "stroke-[2] p-1";
const heavyIconClasses = "w-7 stroke-[3] p-1";
Expand All @@ -32,17 +32,20 @@ const modeSvg = (m: Mode) => {
switch (m) {
case "text":
return <CodeBracketIcon className={iconClasses} />;
case "tree":
case "tree 1":
case "tree 2":
return <ShareIcon className={classNames(iconClasses, "rotate-90")} />;
}
};

const nextMode = (m: Mode): Mode => {
switch (m) {
case "text":
return "tree";
case "tree":
return "text";
return "tree 1";
case "tree 1":
return "tree 2";
case "tree 2":
return "tree 1";
}
};

Expand Down
18 changes: 18 additions & 0 deletions src/components/TreeReactFlow/TreeReactFlow.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ComponentStory, ComponentMeta } from "@storybook/react";
import {
defaultTreeReactFlowProps,
inlineTreeReactFlowProps,
TreeReactFlow,
TreeReactFlowProps,
} from "./";
Expand Down Expand Up @@ -294,3 +295,20 @@ export const OddAndEvenMiscStyles: ComponentStory<typeof TreeReactFlow> = (
contents: { def: def5.name, node: { nodeType: "BodyNode", meta: 5 } },
},
});
export const OddAndEvenInline: ComponentStory<typeof TreeReactFlow> = (
args: TreeReactFlowProps
) =>
treeSized({
...inlineTreeReactFlowProps,
...args,
defs: oddEvenTrees.map(([baseName, term]) => ({
name: { qualifiedModule: [], baseName },
term,
type_: emptyTypeTree(baseName),
})),
typeDefs: [],
selection: {
tag: "SelectionDef",
contents: { def: def5.name, node: { nodeType: "BodyNode", meta: 5 } },
},
});
1 change: 1 addition & 0 deletions src/components/TreeReactFlow/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ export type PrimerCommonNodeProps = {
width: number;
height: number;
selected: boolean;
style: "inline" | "corner";
};

/** Our edge type. Much like `PrimerNode`, `PrimerEdge` extends ReactFlow's `Edge`.
Expand Down
Loading

0 comments on commit 0cd5979

Please sign in to comment.