playground: Persist source and panel (#6071)

This commit is contained in:
Micha Reiser 2023-07-26 07:55:59 +02:00 committed by GitHub
parent c8ee357613
commit 1fdadee59c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 32 deletions

View File

@ -10,7 +10,7 @@ import init, { Diagnostic, Workspace } from "../pkg";
import { ErrorMessage } from "./ErrorMessage"; import { ErrorMessage } from "./ErrorMessage";
import Header from "./Header"; import Header from "./Header";
import { useTheme } from "./theme"; import { useTheme } from "./theme";
import { persist, restore, stringify } from "./settings"; import { persist, persistLocal, restore, stringify } from "./settings";
import SettingsEditor from "./SettingsEditor"; import SettingsEditor from "./SettingsEditor";
import SourceEditor from "./SourceEditor"; import SourceEditor from "./SourceEditor";
import { Panel, PanelGroup } from "react-resizable-panels"; import { Panel, PanelGroup } from "react-resizable-panels";
@ -50,17 +50,45 @@ export default function Editor() {
}); });
const [tab, setTab] = useState<Tab>("Source"); const [tab, setTab] = useState<Tab>("Source");
const [theme, setTheme] = useTheme();
const [secondaryTool, setSecondaryTool] = useState<SecondaryTool | null>( const [secondaryTool, setSecondaryTool] = useState<SecondaryTool | null>(
null, () => {
const secondaryValue = new URLSearchParams(location.search).get(
"secondary",
);
if (secondaryValue == null) {
return null;
} else {
return parseSecondaryTool(secondaryValue);
}
},
); );
const [theme, setTheme] = useTheme();
const initialized = ruffVersion != null; const initialized = ruffVersion != null;
// Ideally this would be retrieved right from the URl... but routing without a proper
// router is hard (there's no location changed event) and pulling in a router
// feels overkill.
const handleSecondaryToolSelected = (tool: SecondaryTool | null) => {
if (tool === secondaryTool) {
tool = null;
}
const url = new URL(location.href);
if (tool == null) {
url.searchParams.delete("secondary");
} else {
url.searchParams.set("secondary", tool);
}
history.replaceState(null, "", url);
setSecondaryTool(tool);
};
useEffect(() => { useEffect(() => {
init().then(() => { init().then(() => {
setRuffVersion(Workspace.version());
const [settingsSource, pythonSource] = restore() ?? [ const [settingsSource, pythonSource] = restore() ?? [
stringify(Workspace.defaultSettings()), stringify(Workspace.defaultSettings()),
DEFAULT_PYTHON_SOURCE, DEFAULT_PYTHON_SOURCE,
@ -71,6 +99,7 @@ export default function Editor() {
revision: 0, revision: 0,
settingsSource, settingsSource,
}); });
setRuffVersion(Workspace.version());
}); });
}, []); }, []);
@ -141,6 +170,12 @@ export default function Editor() {
} }
}, [initialized, deferredSource, secondaryTool]); }, [initialized, deferredSource, secondaryTool]);
useEffect(() => {
if (initialized) {
persistLocal(source);
}
}, [initialized, source]);
const handleShare = useMemo(() => { const handleShare = useMemo(() => {
if (!initialized) { if (!initialized) {
return undefined; return undefined;
@ -215,13 +250,7 @@ export default function Editor() {
)} )}
<SecondarySideBar <SecondarySideBar
selected={secondaryTool} selected={secondaryTool}
onSelected={(tool) => { onSelected={handleSecondaryToolSelected}
if (secondaryTool === tool) {
setSecondaryTool(null);
} else {
setSecondaryTool(tool);
}
}}
/> />
</PanelGroup> </PanelGroup>
) : null} ) : null}
@ -241,3 +270,11 @@ export default function Editor() {
</main> </main>
); );
} }
function parseSecondaryTool(tool: string): SecondaryTool | null {
if (Object.hasOwn(SecondaryTool, tool)) {
return tool as any;
}
return null;
}

View File

@ -1,7 +1,12 @@
import Editor from "@monaco-editor/react"; import Editor from "@monaco-editor/react";
import { Theme } from "./theme"; import { Theme } from "./theme";
export type SecondaryTool = "Format" | "AST" | "Tokens" | "FIR"; export enum SecondaryTool {
"Format" = "Format",
"AST" = "AST",
"Tokens" = "Tokens",
"FIR" = "FIR",
}
export type SecondaryPanelResult = export type SecondaryPanelResult =
| null | null

View File

@ -15,32 +15,32 @@ export default function SecondarySideBar({
<SideBar position="right"> <SideBar position="right">
<SideBarEntry <SideBarEntry
title="Format (alpha)" title="Format (alpha)"
selected={selected === "Format"} selected={selected === SecondaryTool.Format}
onClick={() => onSelected("Format")} onClick={() => onSelected(SecondaryTool.Format)}
> >
<FormatIcon /> <FormatIcon />
</SideBarEntry> </SideBarEntry>
<SideBarEntry <SideBarEntry
title="AST" title="AST"
selected={selected === "AST"} selected={selected === SecondaryTool.AST}
onClick={() => onSelected("AST")} onClick={() => onSelected(SecondaryTool.AST)}
> >
<StructureIcon /> <StructureIcon />
</SideBarEntry> </SideBarEntry>
<SideBarEntry <SideBarEntry
title="Tokens" title="Tokens"
selected={selected === "Tokens"} selected={selected === SecondaryTool.Tokens}
onClick={() => onSelected("Tokens")} onClick={() => onSelected(SecondaryTool.Tokens)}
> >
<TokensIcon /> <TokensIcon />
</SideBarEntry> </SideBarEntry>
<SideBarEntry <SideBarEntry
title="Formatter IR" title="Formatter IR"
selected={selected === "FIR"} selected={selected === SecondaryTool.FIR}
onClick={() => onSelected("FIR")} onClick={() => onSelected(SecondaryTool.FIR)}
> >
FIR FIR
</SideBarEntry> </SideBarEntry>

View File

@ -39,10 +39,33 @@ export function restore(): [string, string] | null {
window.location.hash.slice(1), window.location.hash.slice(1),
); );
if (value != null) { if (value == null) {
return restoreLocal();
} else {
const [settingsSource, pythonSource] = value.split("$$$"); const [settingsSource, pythonSource] = value.split("$$$");
return [settingsSource.replaceAll("$$$$$$", "$$$"), pythonSource]; return [settingsSource.replaceAll("$$$$$$", "$$$"), pythonSource];
} else {
return null;
} }
} }
function restoreLocal(): [string, string] | null {
const source = localStorage.getItem("source");
if (source == null) {
return null;
} else {
return JSON.parse(source);
}
}
export function persistLocal({
settingsSource,
pythonSource,
}: {
settingsSource: string;
pythonSource: string;
}) {
localStorage.setItem(
"source",
JSON.stringify([settingsSource, pythonSource]),
);
}

View File

@ -29,8 +29,8 @@ html,
@font-face { @font-face {
font-family: "Alliance Text"; font-family: "Alliance Text";
src: src:
url("../public/fonts/Alliance-TextRegular.woff2") format("woff2"), url("../fonts/Alliance-TextRegular.woff2") format("woff2"),
url("../public/fonts/Alliance-TextRegular.woff") format("woff"); url("../fonts/Alliance-TextRegular.woff") format("woff");
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
font-display: block; font-display: block;
@ -39,8 +39,8 @@ html,
@font-face { @font-face {
font-family: "Alliance Text"; font-family: "Alliance Text";
src: src:
url("../public/fonts/Alliance-TextMedium.woff2") format("woff2"), url("../fonts/Alliance-TextMedium.woff2") format("woff2"),
url("../public/fonts/Alliance-TextMedium.woff") format("woff"); url("../fonts/Alliance-TextMedium.woff") format("woff");
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
font-display: block; font-display: block;
@ -49,8 +49,8 @@ html,
@font-face { @font-face {
font-family: "Alliance Platt"; font-family: "Alliance Platt";
src: src:
url("../public/fonts/Alliance-PlattMedium.woff2") format("woff2"), url("../fonts/Alliance-PlattMedium.woff2") format("woff2"),
url("../public/fonts/Alliance-PlattMedium.woff") format("woff"); url("../fonts/Alliance-PlattMedium.woff") format("woff");
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
font-display: block; font-display: block;
@ -59,8 +59,8 @@ html,
@font-face { @font-face {
font-family: "Alliance Platt"; font-family: "Alliance Platt";
src: src:
url("../public/fonts/Alliance-PlattRegular.woff2") format("woff2"), url("../fonts/Alliance-PlattRegular.woff2") format("woff2"),
url("../public/fonts/Alliance-PlattRegular.woff") format("woff"); url("../fonts/Alliance-PlattRegular.woff") format("woff");
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
font-display: block; font-display: block;