more refactoring, add folder open indicators

This commit is contained in:
Quinten Kock 2025-08-22 07:25:35 +02:00
parent b9c499a87e
commit 920cc53ce3
4 changed files with 67 additions and 73 deletions

31
src/app/editor.ts Normal file
View File

@ -0,0 +1,31 @@
import { basicSetup } from "codemirror";
import { EditorView } from "@codemirror/view";
import { oneDark } from "@codemirror/theme-one-dark";
const fixedHeightEditor = EditorView.theme({
"&": {
height: "100%",
minHeight: "0px",
resize: "horizontal",
overflow: "auto",
width: "600px",
minWidth: "8em",
flex: "none",
},
".cm-scroller": { overflow: "auto" },
});
export class Editor {
view: EditorView;
constructor() {
this.view = new EditorView({
doc: "Start document",
extensions: [basicSetup, oneDark, fixedHeightEditor],
});
}
get dom() {
return this.view.dom;
}
}

View File

@ -12,7 +12,7 @@ async function openFolder() {
folderTreeState.val = folderTree; folderTreeState.val = folderTree;
} }
const FolderTreeView = () => { export const FolderTreeView = () => {
if (!folderTreeState.val) { if (!folderTreeState.val) {
return v.div( return v.div(
{ class: "text-center m-4" }, { class: "text-center m-4" },
@ -21,10 +21,11 @@ const FolderTreeView = () => {
); );
} }
return v.div( return v.div(
{ class: "mx-1" },
v.div( v.div(
{ class: "flex w-full" }, { class: "flex w-full" },
v.span( v.span(
{ class: "font-bold mx-1 flex-1" }, { class: "font-bold flex-1" },
folderTreeState.val?.name ?? "No folder", folderTreeState.val?.name ?? "No folder",
), ),
u.InlineButton(openFolder, "Refresh current folder", "⟳"), u.InlineButton(openFolder, "Refresh current folder", "⟳"),
@ -37,20 +38,21 @@ const FolderTreeView = () => {
// TODO: determine if lazy DOM creation is better or not. // TODO: determine if lazy DOM creation is better or not.
// Alternatively, investigate lazy FS traversal in main. // Alternatively, investigate lazy FS traversal in main.
const FsItemView = (tree: FolderTree): HTMLElement => { const FsItemView = (tree: FolderTree): HTMLElement => {
if (tree.type === "file") return v.p(tree.name); if (tree.type === "file") return v.p(v.span("📄"), tree.name);
const isOpen = van.state(false); const isOpen = van.state(false);
const children = () => const children = () =>
isOpen.val isOpen.val
? v.div({ class: "ml-4" }, tree.children?.map(FsItemView)) ? v.ul({}, tree.children?.map(FsItemView))
: v.div({ ariaBusy: true }); : v.div({ ariaBusy: true });
const folder = v.details( const folder = v.details(
{ ontoggle: () => (isOpen.val = folder.open) }, { class: "inline", ontoggle: () => (isOpen.val = folder.open) },
v.summary(tree.name), v.summary(tree.name),
children, children,
); );
return folder; return v.div(
{ class: "flex" },
v.span(() => (isOpen.val ? "📂" : "📁")),
folder,
);
}; };
// Mount the folder tree view to the nav
van.add(document.querySelector("aside nav"), FolderTreeView);

View File

@ -1 +1,8 @@
@import "tailwindcss"; @import "tailwindcss";
details > summary {
list-style: none;
}
details > summary::-webkit-details-marker {
display: none;
}

View File

@ -1,31 +1,3 @@
/**
* This file will automatically be loaded by vite and run in the "renderer" context.
* To learn more about the differences between the "main" and the "renderer" context in
* Electron, visit:
*
* https://electronjs.org/docs/tutorial/process-model
*
* By default, Node.js integration in this file is disabled. When enabling Node.js integration
* in a renderer process, please be aware of potential security implications. You can read
* more about security risks here:
*
* https://electronjs.org/docs/tutorial/security
*
* To enable Node.js integration in this file, open up `main.ts` and enable the `nodeIntegration`
* flag:
*
* ```
* // Create the browser window.
* mainWindow = new BrowserWindow({
* width: 800,
* height: 600,
* webPreferences: {
* nodeIntegration: true
* }
* });
* ```
*/
// import "./pico.jade.css"; // import "./pico.jade.css";
import "./index.css"; import "./index.css";
@ -33,50 +5,32 @@ import van from "vanjs-core";
import * as vanX from "vanjs-ext"; import * as vanX from "vanjs-ext";
const v = van.tags; const v = van.tags;
import { basicSetup } from "codemirror"; import { Editor } from "./editor";
import { EditorView } from "@codemirror/view"; import { FolderTreeView } from "./foldernav";
import { oneDark } from "@codemirror/theme-one-dark"; import * as u from "./utils";
import "./foldernav.ts"; const EditorWrapper = (editor: any, del: any, k: any) =>
v.div(
const fixedHeightEditor = EditorView.theme({ { class: "flex flex-col" },
"&": { v.div(
height: "100%", { class: "flex" },
minHeight: "0px", v.span({ class: "mx-1 flex-1" }, "Editor " + k),
resize: "horizontal", u.InlineButton(del, "Close", "❌"),
overflow: "auto", ),
width: "600px", v.div({ class: "h-full" }, editor.val.dom),
minWidth: "8em", );
flex: "none",
},
".cm-scroller": { overflow: "auto" },
});
class EditorColumn {
view: EditorView;
wrapper: HTMLElement;
constructor() {
this.view = new EditorView({
doc: "Start document",
extensions: [basicSetup, oneDark, fixedHeightEditor],
});
console.log("Character width: ", this.view.defaultCharacterWidth);
this.wrapper = v.div({ class: "editorWrapper min-h-0" }, this.view.dom);
}
get dom() {
return this.wrapper;
}
}
// Create and mount editor list // Create and mount editor list
const editors = vanX.reactive([]); const editors = vanX.reactive([]);
vanX.list(document.getElementById("editorGrid"), editors, (v) => v.val.dom); vanX.list(document.getElementById("editorGrid"), editors, EditorWrapper);
function addView() { function addView() {
editors.push(vanX.noreactive(new EditorColumn())); editors.push(vanX.noreactive(new Editor()));
} }
document.getElementById("addEditor")?.addEventListener("click", addView); document.getElementById("addEditor")?.addEventListener("click", addView);
addView(); addView();
// Mount the folder tree view to the nav
van.add(document.querySelector("aside nav"), FolderTreeView);