support dark mode
This commit is contained in:
@@ -9,7 +9,7 @@ monaco.languages.register({ id: "newt" });
|
|||||||
monaco.languages.setMonarchTokensProvider("newt", newtTokens);
|
monaco.languages.setMonarchTokensProvider("newt", newtTokens);
|
||||||
monaco.languages.setLanguageConfiguration("newt", newtConfig);
|
monaco.languages.setLanguageConfiguration("newt", newtConfig);
|
||||||
|
|
||||||
const newtWorker = new Worker("worker.js"); //new URL("worker.js", import.meta.url))
|
const newtWorker = new Worker("worker.js");
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.src = "frame.html";
|
iframe.src = "frame.html";
|
||||||
iframe.style.display = "none";
|
iframe.style.display = "none";
|
||||||
@@ -20,7 +20,7 @@ function run(src: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function runOutput() {
|
function runOutput() {
|
||||||
const src = state.javascript.value
|
const src = state.javascript.value;
|
||||||
console.log("RUN", iframe.contentWindow);
|
console.log("RUN", iframe.contentWindow);
|
||||||
try {
|
try {
|
||||||
iframe.contentWindow?.postMessage({ cmd: "exec", src }, "*");
|
iframe.contentWindow?.postMessage({ cmd: "exec", src }, "*");
|
||||||
@@ -31,8 +31,7 @@ function runOutput() {
|
|||||||
|
|
||||||
window.onmessage = (ev) => {
|
window.onmessage = (ev) => {
|
||||||
console.log("window got", ev.data);
|
console.log("window got", ev.data);
|
||||||
if (ev.data.messages)
|
if (ev.data.messages) state.messages.value = ev.data.messages;
|
||||||
state.messages.value = ev.data.messages;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
newtWorker.onmessage = (ev) => {
|
newtWorker.onmessage = (ev) => {
|
||||||
@@ -52,8 +51,27 @@ const state = {
|
|||||||
javascript: signal(""),
|
javascript: signal(""),
|
||||||
messages: signal<string[]>([]),
|
messages: signal<string[]>([]),
|
||||||
editor: signal<monaco.editor.IStandaloneCodeEditor | null>(null),
|
editor: signal<monaco.editor.IStandaloneCodeEditor | null>(null),
|
||||||
|
dark: signal(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (window.matchMedia) {
|
||||||
|
function checkDark(ev: { matches: boolean }) {
|
||||||
|
console.log("CHANGE", ev);
|
||||||
|
if (ev.matches) {
|
||||||
|
monaco.editor.setTheme("vs-dark");
|
||||||
|
document.body.className = "dark";
|
||||||
|
state.dark.value = true;
|
||||||
|
} else {
|
||||||
|
monaco.editor.setTheme("vs");
|
||||||
|
document.body.className = "light";
|
||||||
|
state.dark.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let query = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
query.addEventListener("change", checkDark);
|
||||||
|
checkDark(query);
|
||||||
|
}
|
||||||
|
|
||||||
async function loadFile(fn: string) {
|
async function loadFile(fn: string) {
|
||||||
if (fn) {
|
if (fn) {
|
||||||
const res = await fetch(fn);
|
const res = await fetch(fn);
|
||||||
@@ -69,10 +87,10 @@ document.addEventListener("keydown", (ev) => {
|
|||||||
if (ev.metaKey && ev.code == "KeyS") ev.preventDefault();
|
if (ev.metaKey && ev.code == "KeyS") ev.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
const LOADING = "module Loading\n"
|
const LOADING = "module Loading\n";
|
||||||
|
|
||||||
let value = localStorage.code || LOADING;
|
let value = localStorage.code || LOADING;
|
||||||
let initialVertical = localStorage.vertical == 'true'
|
let initialVertical = localStorage.vertical == "true";
|
||||||
|
|
||||||
// let result = document.getElementById("result")!;
|
// let result = document.getElementById("result")!;
|
||||||
|
|
||||||
@@ -94,7 +112,6 @@ function Editor({ initialValue }: EditorProps) {
|
|||||||
const editor = monaco.editor.create(container, {
|
const editor = monaco.editor.create(container, {
|
||||||
value,
|
value,
|
||||||
language: "newt",
|
language: "newt",
|
||||||
theme: "vs",
|
|
||||||
fontFamily: "Comic Code, Menlo, Monaco, Courier New, sans",
|
fontFamily: "Comic Code, Menlo, Monaco, Courier New, sans",
|
||||||
automaticLayout: true,
|
automaticLayout: true,
|
||||||
acceptSuggestionOnEnter: "off",
|
acceptSuggestionOnEnter: "off",
|
||||||
@@ -111,10 +128,8 @@ function Editor({ initialValue }: EditorProps) {
|
|||||||
localStorage.code = value;
|
localStorage.code = value;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
if (initialValue === LOADING)
|
if (initialValue === LOADING) loadFile("Tour.newt");
|
||||||
loadFile("Tour.newt")
|
else run(initialValue);
|
||||||
else
|
|
||||||
run(initialValue);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return h("div", { id: "editor", ref });
|
return h("div", { id: "editor", ref });
|
||||||
@@ -132,7 +147,7 @@ function Result() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Console() {
|
function Console() {
|
||||||
const messages = state.messages.value ?? []
|
const messages = state.messages.value ?? [];
|
||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{ id: "console" },
|
{ id: "console" },
|
||||||
@@ -149,16 +164,16 @@ function Tabs() {
|
|||||||
const Tab = (label: string) => {
|
const Tab = (label: string) => {
|
||||||
let onClick = () => {
|
let onClick = () => {
|
||||||
setSelected(label);
|
setSelected(label);
|
||||||
localStorage.tab = label
|
localStorage.tab = label;
|
||||||
}
|
};
|
||||||
let className = "tab";
|
let className = "tab";
|
||||||
if (label == selected) className += " selected";
|
if (label == selected) className += " selected";
|
||||||
return h("div", { className, onClick }, label);
|
return h("div", { className, onClick }, label);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.messages.value) setSelected(CONSOLE)
|
if (state.messages.value) setSelected(CONSOLE);
|
||||||
}, [state.messages.value])
|
}, [state.messages.value]);
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
switch (selected) {
|
switch (selected) {
|
||||||
@@ -178,7 +193,13 @@ function Tabs() {
|
|||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{ className: "tabPanel right" },
|
{ className: "tabPanel right" },
|
||||||
h("div", { className: "tabBar" }, Tab(RESULTS), Tab(JAVASCRIPT), Tab(CONSOLE)),
|
h(
|
||||||
|
"div",
|
||||||
|
{ className: "tabBar" },
|
||||||
|
Tab(RESULTS),
|
||||||
|
Tab(JAVASCRIPT),
|
||||||
|
Tab(CONSOLE)
|
||||||
|
),
|
||||||
h("div", { className: "tabBody" }, body)
|
h("div", { className: "tabBody" }, body)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -197,18 +218,28 @@ const SAMPLES = [
|
|||||||
"Combinatory.newt",
|
"Combinatory.newt",
|
||||||
];
|
];
|
||||||
|
|
||||||
function EditWrap({vertical, toggle}: {vertical: boolean, toggle: () => void}) {
|
function EditWrap({
|
||||||
|
vertical,
|
||||||
|
toggle,
|
||||||
|
}: {
|
||||||
|
vertical: boolean;
|
||||||
|
toggle: () => void;
|
||||||
|
}) {
|
||||||
const options = SAMPLES.map((value) => h("option", { value }, value));
|
const options = SAMPLES.map((value) => h("option", { value }, value));
|
||||||
|
|
||||||
const onChange = async (ev: ChangeEvent) => {
|
const onChange = async (ev: ChangeEvent) => {
|
||||||
if (ev.target instanceof HTMLSelectElement) {
|
if (ev.target instanceof HTMLSelectElement) {
|
||||||
let fn = ev.target.value;
|
let fn = ev.target.value;
|
||||||
ev.target.value = "";
|
ev.target.value = "";
|
||||||
loadFile(fn)
|
loadFile(fn);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let d = vertical ? "M0 0 h20 v20 h-20 z M0 10 h20" : "M0 0 h20 v20 h-20 z M10 0 v20"
|
let d = vertical
|
||||||
|
? "M0 0 h20 v20 h-20 z M0 10 h20"
|
||||||
|
: "M0 0 h20 v20 h-20 z M10 0 v20";
|
||||||
|
let play = "M0 0 L20 10 L0 20 z";
|
||||||
|
let svg = (d: string) =>
|
||||||
|
h("svg", { width: 20, height: 20, className: "icon" }, h("path", { d }));
|
||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{ className: "tabPanel left" },
|
{ className: "tabPanel left" },
|
||||||
@@ -222,29 +253,20 @@ function EditWrap({vertical, toggle}: {vertical: boolean, toggle: () => void}) {
|
|||||||
options
|
options
|
||||||
),
|
),
|
||||||
h("div", { style: { flex: "1 1" } }),
|
h("div", { style: { flex: "1 1" } }),
|
||||||
h("button", { onClick: runOutput
|
h("button", { onClick: runOutput }, svg(play)),
|
||||||
}, "⏵"),
|
h("button", { onClick: toggle }, svg(d))
|
||||||
h(
|
|
||||||
"button",
|
|
||||||
{ onClick: toggle },
|
|
||||||
h(
|
|
||||||
"svg",
|
|
||||||
{ width: 20, height: 20 },
|
|
||||||
h("path", { d, fill: "none", stroke: "black" })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
h("div", { className: "tabBody" }, h(Editor, { initialValue: value }))
|
h("div", { className: "tabBody" }, h(Editor, { initialValue: value }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
let [vertical,setVertical] = useState(initialVertical)
|
let [vertical, setVertical] = useState(initialVertical);
|
||||||
let toggle = () => {
|
let toggle = () => {
|
||||||
setVertical(!vertical)
|
setVertical(!vertical);
|
||||||
localStorage.vertical = !vertical
|
localStorage.vertical = !vertical;
|
||||||
}
|
};
|
||||||
let className = `wrapper ${vertical?"vertical":"horizontal"}`
|
let className = `wrapper ${vertical ? "vertical" : "horizontal"}`;
|
||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{ className },
|
{ className },
|
||||||
|
|||||||
@@ -1,3 +1,20 @@
|
|||||||
|
|
||||||
|
svg.icon path {
|
||||||
|
stroke: black;
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
color: white;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
svg.icon path {
|
||||||
|
stroke: white;
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user