diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2a3ab3d5f..6e54d9dc5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -37,6 +37,7 @@ "d3-selection": "^3.0.0", "d3-shape": "^3.0.0", "d3-time-format": "^4.0.0", + "path-browserify": "^1.0.1", "svelte": "^3.38.3" }, "devDependencies": { @@ -5710,6 +5711,11 @@ "node": ">=6" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -12300,6 +12306,11 @@ "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", "dev": true }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 738b197c3..4c22d54f7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -81,6 +81,7 @@ "d3-selection": "^3.0.0", "d3-shape": "^3.0.0", "d3-time-format": "^4.0.0", + "path-browserify": "^1.0.1", "svelte": "^3.38.3" } } diff --git a/frontend/src/editor/EditorMenu.svelte b/frontend/src/editor/EditorMenu.svelte index d24b9a722..a2b4caa90 100644 --- a/frontend/src/editor/EditorMenu.svelte +++ b/frontend/src/editor/EditorMenu.svelte @@ -2,6 +2,7 @@ import { toggleComment } from "@codemirror/comment"; import { foldAll, unfoldAll } from "@codemirror/fold"; import type { EditorView } from "@codemirror/view"; + import path from "path-browserify"; import { beancountFormat } from "../codemirror/beancount-format"; import { scrollToLine } from "../codemirror/scroll-to-line"; @@ -11,6 +12,7 @@ import router from "../router"; import { favaOptions, options } from "../stores"; + import Folder from "./Folder.svelte"; import Key from "./Key.svelte"; export let file_path: string; @@ -31,6 +33,79 @@ editor.focus(); } } + + function _dummy_folder(name: string, sub_node) { + if ("subfolders" in sub_node) { + return { name, subfolders: [sub_node], subfiles: [] }; + } + return { name, subfolders: [], subfiles: [sub_node] }; + } + function dummy_folder(path_str: string) { + let p = path.parse(path_str); + let folder_path = p.dir; + const { root } = p; + + const file_node = { name: p.base, path: path_str }; + let last_node = file_node; + while (folder_path !== root) { + p = path.parse(folder_path); + last_node = _dummy_folder(p.base, last_node); + folder_path = p.dir; + } + return _dummy_folder(root, last_node); + } + function shorten_folder(folder) { + // Flatten the nested folder when possible. + if (folder.subfiles.length === 0 && folder.subfolders.length === 1) { + const subfolder = folder.subfolders[0]; + const new_name = path.join(folder.name, subfolder.name); + return shorten_folder({ + name: new_name, + subfolders: subfolder.subfolders, + subfiles: subfolder.subfiles, + }); + } + return { + name: folder.name, + subfolders: folder.subfolders.map(shorten_folder), + subfiles: folder.subfiles, + }; + } + let merge_folder; + function merge_same_name_folder(name: string, i_folders: []) { + if (i_folders.length === 1) { + return i_folders[0]; + } + return { + name, + subfolders: merge_folder(i_folders.map((o) => o.subfolders).flat()), + subfiles: i_folders.map((o) => o.subfiles).flat(), + }; + } + function groupBy(xs: [], key: string) { + return xs.reduce((rv, x) => { + (rv[x[key]] = rv[x[key]] || []).push(x); + return rv; + }, {}); + } + merge_folder = (i_folders: []): [] => { + const dict = groupBy( + i_folders.sort((a, b) => { + if (a.name === b.name) { + return 0; + } + return a.name > b.name ? 1 : -1; + }), + "name" + ); + return Object.entries(dict).map(([name, group]) => + merge_same_name_folder(name, group) + ); + }; + function source_tree(files: string[]): [] { + return merge_folder(files.map(dummy_folder)).map(shorten_folder); + } + $: folders = source_tree(sources);
@@ -38,13 +113,8 @@ {_("File")} @@ -104,10 +174,6 @@ margin-right: 0.5rem; } - .selected::before { - content: "›"; - } - li { padding: 2px 10px; cursor: pointer; diff --git a/frontend/src/editor/File.svelte b/frontend/src/editor/File.svelte new file mode 100644 index 000000000..3284ca19b --- /dev/null +++ b/frontend/src/editor/File.svelte @@ -0,0 +1,22 @@ + + + + {file.name} + + + diff --git a/frontend/src/editor/Folder.svelte b/frontend/src/editor/Folder.svelte new file mode 100644 index 000000000..f12fb10fc --- /dev/null +++ b/frontend/src/editor/Folder.svelte @@ -0,0 +1,52 @@ + + +{folder.name} + +{#if expanded} + +{/if} + +