From 2a92e42952858ccd4b33419293cb235bd4039c7c Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 17:37:37 +0200 Subject: [PATCH 1/6] html file refactor --- html/e.html | 14 -------------- html/edit.html | 10 ++++++++++ html/v.html | 14 -------------- html/view.html | 10 ++++++++++ js/html/edit.js | 2 +- js/html/index.js | 2 +- js/html/view.js | 2 +- 7 files changed, 23 insertions(+), 31 deletions(-) delete mode 100644 html/e.html create mode 100644 html/edit.html delete mode 100644 html/v.html create mode 100644 html/view.html diff --git a/html/e.html b/html/e.html deleted file mode 100644 index 4478452..0000000 --- a/html/e.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - StartTreeV2 - Edit - - - - - - \ No newline at end of file diff --git a/html/edit.html b/html/edit.html new file mode 100644 index 0000000..0338610 --- /dev/null +++ b/html/edit.html @@ -0,0 +1,10 @@ + + + + + + + StartTreeV2 - Edit + + + diff --git a/html/v.html b/html/v.html deleted file mode 100644 index dc78b2b..0000000 --- a/html/v.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - StartTreeV2 - - - - - - diff --git a/html/view.html b/html/view.html new file mode 100644 index 0000000..fa1cbe5 --- /dev/null +++ b/html/view.html @@ -0,0 +1,10 @@ + + + + + + + + StartTreeV2 + + diff --git a/js/html/edit.js b/js/html/edit.js index c9b3eec..71868ef 100644 --- a/js/html/edit.js +++ b/js/html/edit.js @@ -15,7 +15,7 @@ const getExportUrl = () => { path = location.pathname, affix = "?t=", data = stringify(t.export()); - return host + path.replace("e.html", "v.html") + affix + data; + return host + path.replace("edit.html", "view.html") + affix + data; }; const cancelButtonHtml = () => { diff --git a/js/html/index.js b/js/html/index.js index 5fc1007..531f3ac 100644 --- a/js/html/index.js +++ b/js/html/index.js @@ -6,4 +6,4 @@ const exampleData = await fetch("./js/views/tree/exampleConfig.json").then( const jsonStringified = stringify(exampleData); -document.location.replace(`./html/e.html?t=${jsonStringified}`); +document.location.replace(`./html/edit.html?t=${jsonStringified}`); diff --git a/js/html/view.js b/js/html/view.js index 30f39da..467286c 100644 --- a/js/html/view.js +++ b/js/html/view.js @@ -5,7 +5,7 @@ import Button from "../views/other/button.js"; const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const treeConfig = parse(urlParams.get("t")) || {}; -const editModeHref = "./e.html"; +const editModeHref = "./edit.html"; const t = new Tree(treeConfig, false); document.body.appendChild(t.html()); From 11019fcbc1ea44c49e32030e59b683c3afb3ecb0 Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 18:14:32 +0200 Subject: [PATCH 2/6] update start link in readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5696e91..b142437 100644 --- a/readme.md +++ b/readme.md @@ -10,7 +10,7 @@ StartTreeV2 is a custom start page for your browser, also it's: - 🔒 **Private**: no database, saved via url - ⚡ **Lightweight**: zero dependencies -→ Start [HERE](https://alexw00.github.io/StartTreeV2/) +→ Start [HERE](https://macarthur955.github.io/StartTreeV3/) ## Guides From 5f8c8b46b13476650566304a1b451067e6575956 Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 18:36:46 +0200 Subject: [PATCH 3/6] support ts --- .github/workflows/pages.yml | 42 +++++++++++++++++++ .gitignore | 11 ++++- js/helper/{dragOptions.js => dragOptions.ts} | 3 ++ js/helper/{jsurl.js => jsurl.ts} | 0 .../{makeDraggable.js => makeDraggable.ts} | 0 js/helper/{utils.js => utils.ts} | 0 js/html/{edit.js => edit.ts} | 2 +- js/html/{index.js => index.ts} | 0 js/html/{view.js => view.ts} | 2 +- js/views/other/{button.js => button.ts} | 5 ++- .../components/{searchBar.js => searchBar.ts} | 8 ++++ js/views/tree/components/{tree.js => tree.ts} | 8 ++++ .../{treeColumn.js => treeColumn.ts} | 7 ++++ ...olumnCategory.js => treeColumnCategory.ts} | 7 ++++ .../components/{treeItem.js => treeItem.ts} | 6 +++ .../{editSearchBar.js => editSearchBar.ts} | 1 + .../components/{editTree.js => editTree.ts} | 1 + .../{editTreeColumn.js => editTreeColumn.ts} | 10 +++-- ...nCategory.js => editTreeColumnCategory.ts} | 5 ++- .../{editTreeItem.js => editTreeItem.ts} | 6 ++- .../components/{editor.js => editor.ts} | 19 ++++++++- .../components/{toolbar.js => toolbar.ts} | 6 +++ ...torFinishEvent.js => editorFinishEvent.ts} | 4 ++ .../{editorOptions.js => editorOptions.ts} | 12 +++++- .../{editorTarget.js => editorTarget.ts} | 4 ++ ...{treeUpdateEvent.js => treeUpdateEvent.ts} | 10 ++++- .../{theme-changer.js => theme-changer.ts} | 21 ++++++---- .../{themeItem.js => themeItem.ts} | 2 + justfile | 22 ++++++++++ package-lock.json | 27 ++++++++++++ package.json | 7 ++++ readme.md | 12 +++++- tsconfig.json | 14 +++++++ 33 files changed, 257 insertions(+), 27 deletions(-) create mode 100644 .github/workflows/pages.yml rename js/helper/{dragOptions.js => dragOptions.ts} (84%) rename js/helper/{jsurl.js => jsurl.ts} (100%) rename js/helper/{makeDraggable.js => makeDraggable.ts} (100%) rename js/helper/{utils.js => utils.ts} (100%) rename js/html/{edit.js => edit.ts} (98%) rename js/html/{index.js => index.ts} (100%) rename js/html/{view.js => view.ts} (94%) rename js/views/other/{button.js => button.ts} (99%) rename js/views/tree/components/{searchBar.js => searchBar.ts} (94%) rename js/views/tree/components/{tree.js => tree.ts} (94%) rename js/views/tree/components/{treeColumn.js => treeColumn.ts} (95%) rename js/views/tree/components/{treeColumnCategory.js => treeColumnCategory.ts} (94%) rename js/views/tree/components/{treeItem.js => treeItem.ts} (95%) rename js/views/tree/editTree/components/{editSearchBar.js => editSearchBar.ts} (99%) rename js/views/tree/editTree/components/{editTree.js => editTree.ts} (99%) rename js/views/tree/editTree/components/{editTreeColumn.js => editTreeColumn.ts} (95%) rename js/views/tree/editTree/components/{editTreeColumnCategory.js => editTreeColumnCategory.ts} (98%) rename js/views/tree/editTree/components/{editTreeItem.js => editTreeItem.ts} (97%) rename js/views/tree/editTree/editor/components/{editor.js => editor.ts} (94%) rename js/views/tree/editTree/editor/components/{toolbar.js => toolbar.ts} (93%) rename js/views/tree/editTree/editor/events/{editorFinishEvent.js => editorFinishEvent.ts} (90%) rename js/views/tree/editTree/editor/helperObjects/{editorOptions.js => editorOptions.ts} (76%) rename js/views/tree/editTree/editor/helperObjects/{editorTarget.js => editorTarget.ts} (91%) rename js/views/tree/editTree/events/{treeUpdateEvent.js => treeUpdateEvent.ts} (79%) rename js/views/tree/themechanger/{theme-changer.js => theme-changer.ts} (81%) rename js/views/tree/themechanger/{themeItem.js => themeItem.ts} (98%) create mode 100644 justfile create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..d7ffab6 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,42 @@ +name: Build and deploy Pages + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-slim + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - uses: taiki-e/install-action@just + - run: npm ci + - run: just style + - run: just build + - uses: actions/upload-pages-artifact@v3 + if: github.event_name != 'pull_request' + with: + path: dist + + deploy: + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-slim + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 3d72576..f62cc61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ +# System files .DS_Store -.idea \ No newline at end of file + +# Editor settings +.idea/ + +# Installed dependencies +node_modules/ + +# Generated site +dist/ diff --git a/js/helper/dragOptions.js b/js/helper/dragOptions.ts similarity index 84% rename from js/helper/dragOptions.js rename to js/helper/dragOptions.ts index ec912ee..796baea 100644 --- a/js/helper/dragOptions.js +++ b/js/helper/dragOptions.ts @@ -1,4 +1,7 @@ export default class DragOptions { + data: any; + validDropzones: any; + constructor({ data, validDropzones }) { this.data = data ?? ""; this.validDropzones = validDropzones ?? []; // classes that this draggable can be dropped on diff --git a/js/helper/jsurl.js b/js/helper/jsurl.ts similarity index 100% rename from js/helper/jsurl.js rename to js/helper/jsurl.ts diff --git a/js/helper/makeDraggable.js b/js/helper/makeDraggable.ts similarity index 100% rename from js/helper/makeDraggable.js rename to js/helper/makeDraggable.ts diff --git a/js/helper/utils.js b/js/helper/utils.ts similarity index 100% rename from js/helper/utils.js rename to js/helper/utils.ts diff --git a/js/html/edit.js b/js/html/edit.ts similarity index 98% rename from js/html/edit.js rename to js/html/edit.ts index 71868ef..ca18481 100644 --- a/js/html/edit.js +++ b/js/html/edit.ts @@ -7,7 +7,7 @@ const urlParams = new URLSearchParams(queryString); const treeConfig = parse(urlParams.get("t")) || {}; const REPO_URL = "https://github.com/AlexW00/StartTreeV2"; -const t = new EditTree(treeConfig, true); +const t = new EditTree(treeConfig); document.body.appendChild(t.html()); const getExportUrl = () => { diff --git a/js/html/index.js b/js/html/index.ts similarity index 100% rename from js/html/index.js rename to js/html/index.ts diff --git a/js/html/view.js b/js/html/view.ts similarity index 94% rename from js/html/view.js rename to js/html/view.ts index 467286c..b46df07 100644 --- a/js/html/view.js +++ b/js/html/view.ts @@ -7,7 +7,7 @@ const urlParams = new URLSearchParams(queryString); const treeConfig = parse(urlParams.get("t")) || {}; const editModeHref = "./edit.html"; -const t = new Tree(treeConfig, false); +const t = new Tree(treeConfig); document.body.appendChild(t.html()); const editModeButtonHtml = () => { diff --git a/js/views/other/button.js b/js/views/other/button.ts similarity index 99% rename from js/views/other/button.js rename to js/views/other/button.ts index 7bb3b2e..eeeee5c 100644 --- a/js/views/other/button.js +++ b/js/views/other/button.ts @@ -3,8 +3,11 @@ // ====================================================== // export default class Button { + svg: any; + type: any; + // possible values for type: "save", "cancel", "add" or "delete" - constructor(type, width, height) { + constructor(type, width?: number, height?: number) { this.type = type; if (type === "add") { this.svg = ` diff --git a/js/views/tree/components/searchBar.js b/js/views/tree/components/searchBar.ts similarity index 94% rename from js/views/tree/components/searchBar.js rename to js/views/tree/components/searchBar.ts index 774d967..774ee77 100644 --- a/js/views/tree/components/searchBar.js +++ b/js/views/tree/components/searchBar.ts @@ -3,6 +3,14 @@ // ====================================================== //; export default class SearchBar { + form: any; + formInput: any; + h1: any; + root: any; + searchEngineNameShort: any; + searchEngineUrl: any; + sectionName: any; + constructor(config) { this.searchEngineUrl = config.u ?? "https://duckduckgo.com/?q="; this.searchEngineNameShort = config.n ?? "ddg"; diff --git a/js/views/tree/components/tree.js b/js/views/tree/components/tree.ts similarity index 94% rename from js/views/tree/components/tree.js rename to js/views/tree/components/tree.ts index 781bb3f..30c3658 100644 --- a/js/views/tree/components/tree.js +++ b/js/views/tree/components/tree.ts @@ -7,6 +7,14 @@ import TreeColumn from "./treeColumn.js"; // ====================================================== // export default class Tree { + bookmarkColumns: any; + bookmarkRow: any; + root: any; + searchBar: any; + themeChanger: any; + titlePrompt: any; + version: any; + constructor(config) { this.version = config.v || "0.0"; diff --git a/js/views/tree/components/treeColumn.js b/js/views/tree/components/treeColumn.ts similarity index 95% rename from js/views/tree/components/treeColumn.js rename to js/views/tree/components/treeColumn.ts index a41d6ba..8240732 100644 --- a/js/views/tree/components/treeColumn.js +++ b/js/views/tree/components/treeColumn.ts @@ -5,6 +5,13 @@ import TreeColumnCategory from "./treeColumnCategory.js"; // ====================================================== // export default class TreeColumn { + bookmarkCategories: any; + categoryList: any; + columnTitle: any; + id: any; + root: any; + tree: any; + static count = 0; constructor(bookmarkColumn) { TreeColumn.count++; diff --git a/js/views/tree/components/treeColumnCategory.js b/js/views/tree/components/treeColumnCategory.ts similarity index 94% rename from js/views/tree/components/treeColumnCategory.js rename to js/views/tree/components/treeColumnCategory.ts index eb9305a..dd38132 100644 --- a/js/views/tree/components/treeColumnCategory.js +++ b/js/views/tree/components/treeColumnCategory.ts @@ -5,6 +5,13 @@ import TreeItem from "./treeItem.js"; export default class TreeColumnCategory { + bookmarkList: any; + categoryTitle: any; + id: any; + name: any; + root: any; + treeItems: any; + static count = 0; constructor(bookmarkCategory) { TreeColumnCategory.count++; diff --git a/js/views/tree/components/treeItem.js b/js/views/tree/components/treeItem.ts similarity index 95% rename from js/views/tree/components/treeItem.js rename to js/views/tree/components/treeItem.ts index 03b4b79..bb7c5de 100644 --- a/js/views/tree/components/treeItem.js +++ b/js/views/tree/components/treeItem.ts @@ -4,6 +4,12 @@ // export default class TreeItem { + a: any; + id: any; + name: any; + root: any; + url: any; + static count = 0; constructor(bookmark) { TreeItem.count++; diff --git a/js/views/tree/editTree/components/editSearchBar.js b/js/views/tree/editTree/components/editSearchBar.ts similarity index 99% rename from js/views/tree/editTree/components/editSearchBar.js rename to js/views/tree/editTree/components/editSearchBar.ts index 4a7e8bd..2d85215 100644 --- a/js/views/tree/editTree/components/editSearchBar.js +++ b/js/views/tree/editTree/components/editSearchBar.ts @@ -9,6 +9,7 @@ import editorTarget from "../editor/helperObjects/editorTarget.js"; import Button from "../../../other/button.js"; export default class EditSearchBar extends SearchBar { + constructor(config) { super(config); } diff --git a/js/views/tree/editTree/components/editTree.js b/js/views/tree/editTree/components/editTree.ts similarity index 99% rename from js/views/tree/editTree/components/editTree.js rename to js/views/tree/editTree/components/editTree.ts index d42ea35..77c83d7 100644 --- a/js/views/tree/editTree/components/editTree.js +++ b/js/views/tree/editTree/components/editTree.ts @@ -9,6 +9,7 @@ import Tree from "../../components/tree.js"; // ====================================================== // export default class EditTree extends Tree { + constructor(config) { super(config); } diff --git a/js/views/tree/editTree/components/editTreeColumn.js b/js/views/tree/editTree/components/editTreeColumn.ts similarity index 95% rename from js/views/tree/editTree/components/editTreeColumn.js rename to js/views/tree/editTree/components/editTreeColumn.ts index ca14029..84b3a79 100644 --- a/js/views/tree/editTree/components/editTreeColumn.js +++ b/js/views/tree/editTree/components/editTreeColumn.ts @@ -11,6 +11,8 @@ import TreeColumn from "../../components/treeColumn.js"; // ====================================================== // export default class EditTreeColumn extends TreeColumn { + onUpdate: any; + constructor(bookmarkColumn, onUpdate) { super(bookmarkColumn); this.onUpdate = onUpdate; @@ -37,7 +39,7 @@ export default class EditTreeColumn extends TreeColumn { columnTitleHtml() { const h1 = super.columnTitleHtml(); - h1.addEventListener("click", () => this.#categoryTitleListener); + h1.addEventListener("click", this.#categoryTitleListener); return h1; } @@ -46,7 +48,7 @@ export default class EditTreeColumn extends TreeColumn { #categoryTitleListener = () => { new Editor( this.tree, - new editorTarget(".", null, this.h1.id), + new editorTarget(".", null, this.columnTitle.id), new EditorOptions({ allowTextEdit: false, buttons: ["cancel", "delete"], @@ -60,7 +62,7 @@ export default class EditTreeColumn extends TreeColumn { this.root.remove(); } else { this.tree.insertBefore( - this.h1, + this.columnTitle, this.tree.querySelectorAll("ul")[editorFinishEvent.index] ); } @@ -137,7 +139,7 @@ export default class EditTreeColumn extends TreeColumn { // else if this was the last category in the list, append the add button to the new last category else if (categoryIndex === this.bookmarkCategories.length) { const lastCategory = this.root.querySelector("ul").lastChild; - lastCategory.appendChild(this.#newAddCategoryButton(this.root)); + lastCategory.appendChild(this.#newAddCategoryButton()); } } if (treeUpdateEvent.type === "add") { diff --git a/js/views/tree/editTree/components/editTreeColumnCategory.js b/js/views/tree/editTree/components/editTreeColumnCategory.ts similarity index 98% rename from js/views/tree/editTree/components/editTreeColumnCategory.js rename to js/views/tree/editTree/components/editTreeColumnCategory.ts index e2ea67d..88cca5c 100644 --- a/js/views/tree/editTree/components/editTreeColumnCategory.js +++ b/js/views/tree/editTree/components/editTreeColumnCategory.ts @@ -13,6 +13,8 @@ import TreeColumnCategory from "../../components/treeColumnCategory.js"; // ====================================================== // export default class EditTreeColumnCategory extends TreeColumnCategory { + onUpdate: any; + static count = 0; constructor(bookmarkCategory, onUpdate) { super(bookmarkCategory); @@ -53,8 +55,7 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { } #makeDraggable = () => { - const dragOptionsData = this.export(); - dragOptionsData.classList = ["category"]; + const dragOptionsData = { ...this.export(), classList: ["category"] }; const dragOptions = new DragOptions({ data: JSON.stringify(dragOptionsData), validDropzones: ["category", "bookmark"], diff --git a/js/views/tree/editTree/components/editTreeItem.js b/js/views/tree/editTree/components/editTreeItem.ts similarity index 97% rename from js/views/tree/editTree/components/editTreeItem.js rename to js/views/tree/editTree/components/editTreeItem.ts index ed19f2c..581a086 100644 --- a/js/views/tree/editTree/components/editTreeItem.js +++ b/js/views/tree/editTree/components/editTreeItem.ts @@ -13,6 +13,9 @@ import editorTarget from "../editor/helperObjects/editorTarget.js"; import TreeUpdateEvent from "../events/treeUpdateEvent.js"; export default class EditTreeItem extends TreeItem { + editButton: any; + onUpdate: any; + constructor(bookmark, onUpdate) { super(bookmark); this.onUpdate = onUpdate; @@ -51,8 +54,7 @@ export default class EditTreeItem extends TreeItem { } #makeDraggable = () => { - const dragOptionsData = this.export(); - dragOptionsData.classList = ["bookmark"]; + const dragOptionsData = { ...this.export(), classList: ["bookmark"] }; const dragOptions = new DragOptions({ data: JSON.stringify(dragOptionsData), validDropzones: ["bookmark"], diff --git a/js/views/tree/editTree/editor/components/editor.js b/js/views/tree/editTree/editor/components/editor.ts similarity index 94% rename from js/views/tree/editTree/editor/components/editor.js rename to js/views/tree/editTree/editor/components/editor.ts index 084a877..61124ad 100644 --- a/js/views/tree/editTree/editor/components/editor.js +++ b/js/views/tree/editTree/editor/components/editor.ts @@ -5,6 +5,21 @@ import EditorFinishEvent from "../events/editorFinishEvent.js"; import Toolbar from "./toolbar.js"; export default class Editor { + allowTextEdit: any; + buttons: any; + cb: any; + editorTarget: any; + index: any; + isClosed: any; + link: any; + linkEditorIsOpen: any; + nodeType: any; + parentNode: any; + root: any; + secondRow: any; + text: any; + toolbar: any; + static openInstance = null; // ~~~~~~~~~ Initialization functions ~~~~~~~~~ // @@ -149,7 +164,7 @@ export default class Editor { // ~~~~~~~ Toolbar event callbacks ~~~~~~ // - save() { + save(_parentNode?: Node) { if (this.isClosed) return; this.#remove(); this.cb( @@ -182,7 +197,7 @@ export default class Editor { }); } - #closeLinkInput() { + #closeLinkInput(_li?: Node): Promise { if (!this.linkEditorIsOpen) return Promise.resolve(); return new Promise((resolve) => { const linkInput = this.root.querySelector(".secondRow"); diff --git a/js/views/tree/editTree/editor/components/toolbar.js b/js/views/tree/editTree/editor/components/toolbar.ts similarity index 93% rename from js/views/tree/editTree/editor/components/toolbar.js rename to js/views/tree/editTree/editor/components/toolbar.ts index 2243a5b..1dcf1aa 100644 --- a/js/views/tree/editTree/editor/components/toolbar.js +++ b/js/views/tree/editTree/editor/components/toolbar.ts @@ -4,6 +4,12 @@ import Button from "../../../../other/button.js"; export default class Toolbar { + buttons: any; + cancelButton: any; + cb: any; + deleteButton: any; + linkButton: any; + constructor(buttons, cb) { this.cb = cb; // callback function this.buttons = buttons; // ["link", "delete", "cancel"]; diff --git a/js/views/tree/editTree/editor/events/editorFinishEvent.js b/js/views/tree/editTree/editor/events/editorFinishEvent.ts similarity index 90% rename from js/views/tree/editTree/editor/events/editorFinishEvent.js rename to js/views/tree/editTree/editor/events/editorFinishEvent.ts index 751ac84..468dc62 100644 --- a/js/views/tree/editTree/editor/events/editorFinishEvent.js +++ b/js/views/tree/editTree/editor/events/editorFinishEvent.ts @@ -3,6 +3,10 @@ // ====================================================== // export default class EditorFinishEvent { + editResult: any; + index: any; + type: any; + constructor(type, editResult, index) { this.type = type; // either "save", "cancel" or "delete" this.editResult = editResult; // { text, link } diff --git a/js/views/tree/editTree/editor/helperObjects/editorOptions.js b/js/views/tree/editTree/editor/helperObjects/editorOptions.ts similarity index 76% rename from js/views/tree/editTree/editor/helperObjects/editorOptions.js rename to js/views/tree/editTree/editor/helperObjects/editorOptions.ts index 867f598..eae2771 100644 --- a/js/views/tree/editTree/editor/helperObjects/editorOptions.js +++ b/js/views/tree/editTree/editor/helperObjects/editorOptions.ts @@ -3,7 +3,17 @@ // ====================================================== // export default class EditorOptions { - constructor({ allowTextEdit, openWithLinkInput, buttons, nodeType }) { + allowTextEdit: any; + buttons: any; + nodeType: any; + openWithLinkInput: any; + + constructor({ allowTextEdit, openWithLinkInput, buttons, nodeType }: { + allowTextEdit?: boolean; + openWithLinkInput?: boolean; + buttons?: string[]; + nodeType?: string; + } = {}) { this.allowTextEdit = allowTextEdit ?? true; // whether or not to allow the user to edit the text of the editor this.openWithLinkInput = openWithLinkInput ?? false; // whether or not to open the link input when the editor is opened this.buttons = buttons ?? ["cancel", "delete"]; // the buttons to show in the editor diff --git a/js/views/tree/editTree/editor/helperObjects/editorTarget.js b/js/views/tree/editTree/editor/helperObjects/editorTarget.ts similarity index 91% rename from js/views/tree/editTree/editor/helperObjects/editorTarget.js rename to js/views/tree/editTree/editor/helperObjects/editorTarget.ts index dfdf9d0..a972f1d 100644 --- a/js/views/tree/editTree/editor/helperObjects/editorTarget.js +++ b/js/views/tree/editTree/editor/helperObjects/editorTarget.ts @@ -3,6 +3,10 @@ // ====================================================== // export default class editorTarget { + id: any; + text: any; + url: any; + constructor(text, url, id) { this.text = text ?? ""; // text to be edited this.url = url ?? "#"; // url to be edited diff --git a/js/views/tree/editTree/events/treeUpdateEvent.js b/js/views/tree/editTree/events/treeUpdateEvent.ts similarity index 79% rename from js/views/tree/editTree/events/treeUpdateEvent.js rename to js/views/tree/editTree/events/treeUpdateEvent.ts index 4676a5f..2e3b972 100644 --- a/js/views/tree/editTree/events/treeUpdateEvent.js +++ b/js/views/tree/editTree/events/treeUpdateEvent.ts @@ -3,9 +3,17 @@ // ====================================================== // export default class TreeUpdateEvent { + newObject: any; + type: any; + updatedObject: any; + static legalTypes = ["save", "delete", "add"]; - constructor({ type, updatedObject, newObject }) { + constructor({ type, updatedObject, newObject }: { + type: string; + updatedObject: unknown; + newObject?: unknown; + }) { this.type = this.checkType(type); // event type, must be one of legalTypes this.updatedObject = updatedObject; // the updated object this.newObject = newObject; // the new object (if available) diff --git a/js/views/tree/themechanger/theme-changer.js b/js/views/tree/themechanger/theme-changer.ts similarity index 81% rename from js/views/tree/themechanger/theme-changer.js rename to js/views/tree/themechanger/theme-changer.ts index a6f35f8..f62d148 100644 --- a/js/views/tree/themechanger/theme-changer.js +++ b/js/views/tree/themechanger/theme-changer.ts @@ -4,6 +4,8 @@ import ThemeItem from "./themeItem.js"; export default class ThemeChanger { + themeNr: any; + themeChanger = document.createElement("div"); selectedThemeId = 2; @@ -39,7 +41,7 @@ export default class ThemeChanger { "catppuccin" ]; - themeCssLink = document.querySelector("link[href='../styles/colors.css']"); + themeCssLink = document.querySelector("link[href='../styles/colors.css']"); constructor(config) { this.themeNr = config.nr ?? 0; @@ -70,7 +72,7 @@ export default class ThemeChanger { themeChangerContainer.appendChild(h1); themeChangerContainer.appendChild(this.themeChanger); // Change id for selected theme div - this.themeChanger.childNodes[this.selectedThemeId].id = "selected"; + (this.themeChanger.childNodes[this.selectedThemeId] as HTMLElement).id = "selected"; // Insert selected theme on the top this.themeChanger.insertBefore( this.themeChanger.childNodes[this.selectedThemeId], @@ -83,14 +85,15 @@ export default class ThemeChanger { addListener = () => { document.addEventListener("click", (e) => { - if (e.target.name === "theme-radio") { + const target = e.target as HTMLInputElement; + if (target.name === "theme-radio") { // print index of clicked element - this.themeNr = this.THEMES.indexOf(e.target.id); - this.changeTheme(e.target.id); + this.themeNr = this.THEMES.indexOf(target.id); + this.changeTheme(target.id); const selectedTheme = document.querySelector("#selected"); selectedTheme.removeAttribute("id"); - e.target.parentElement.id = "selected"; + target.parentElement.id = "selected"; } }); }; @@ -98,9 +101,9 @@ export default class ThemeChanger { addListenerMouseLeave = () => { this.themeChanger.addEventListener("mouseleave", function (event) { const selectedTheme = document.querySelector("#selected"); - const path = event.path || (event.composedPath && event.composedPath()); - path[0].insertBefore(selectedTheme, path[0].firstChild); - event.target.scrollTop = 0; + const target = event.currentTarget as HTMLElement; + target.insertBefore(selectedTheme, target.firstChild); + target.scrollTop = 0; }); }; diff --git a/js/views/tree/themechanger/themeItem.js b/js/views/tree/themechanger/themeItem.ts similarity index 98% rename from js/views/tree/themechanger/themeItem.js rename to js/views/tree/themechanger/themeItem.ts index 56216c8..cadc983 100644 --- a/js/views/tree/themechanger/themeItem.js +++ b/js/views/tree/themechanger/themeItem.ts @@ -3,6 +3,8 @@ // ====================================================== // export default class ThemeItem { + name: any; + static themeCssLink = document.querySelector( "link[href='./styles/colors.css']" ); diff --git a/justfile b/justfile new file mode 100644 index 0000000..7242c89 --- /dev/null +++ b/justfile @@ -0,0 +1,22 @@ +# Show available commands. +default: + @just --list + +# Check TypeScript types without writing files. +style: + ./node_modules/.bin/tsc --noEmit + +# Check types and build the static site in dist/. +build: style + rm -rf dist + mkdir -p dist + cp index.html dist/index.html + cp -R html styles themes dist/ + ./node_modules/.bin/tsc + mkdir -p dist/js/views/tree + cp js/views/tree/exampleConfig.json dist/js/views/tree/exampleConfig.json + touch dist/.nojekyll + +# Build and serve the site at http://localhost:8000/. +run: build + python3 -m http.server 8000 --bind 127.0.0.1 --directory dist diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..88ae0a8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "starttree-v3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "starttree-v3", + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5718e64 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "starttree-v3", + "private": true, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/readme.md b/readme.md index b142437..7a2e6fd 100644 --- a/readme.md +++ b/readme.md @@ -91,8 +91,16 @@ Click on the top right check button to **copy** and **go** to your new URL. ## Development -The current version is stable and tested in Firefox, Chrome and Safari. -If you want to contribute, feel free to make a pull request. Please keep it simple and lightweight. +Install Node.js and [just](https://just.systems/), then run `npm ci`. + +| Command | Purpose | +| --- | --- | +| `just style` | Check TypeScript types | +| `just build` | Build the site in `dist/` | +| `just run` | Build and serve at `http://localhost:8000/` | + +Run `just` to see the command list. For GitHub Pages, select **GitHub Actions** +as the publishing source in the repository's Pages settings.
Adding themes diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4f52866 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "rootDir": "js", + "outDir": "dist/js", + "skipLibCheck": true, + "noImplicitAny": false, + "noEmitOnError": true + }, + "include": ["js/**/*.ts"] +} From 2e576541972e31416dd39373a334d219cc9f9f08 Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 18:54:46 +0200 Subject: [PATCH 4/6] use node instead of python --- justfile | 20 ++++++++++---------- readme.md | 19 ++++++++++--------- scripts/serve.mjs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 scripts/serve.mjs diff --git a/justfile b/justfile index 7242c89..0ce9fc7 100644 --- a/justfile +++ b/justfile @@ -4,19 +4,19 @@ default: # Check TypeScript types without writing files. style: - ./node_modules/.bin/tsc --noEmit + @./node_modules/.bin/tsc --noEmit # Check types and build the static site in dist/. build: style - rm -rf dist - mkdir -p dist - cp index.html dist/index.html - cp -R html styles themes dist/ - ./node_modules/.bin/tsc - mkdir -p dist/js/views/tree - cp js/views/tree/exampleConfig.json dist/js/views/tree/exampleConfig.json - touch dist/.nojekyll + @rm -rf dist + @mkdir -p dist + @cp index.html dist/index.html + @cp -R html styles themes dist/ + @./node_modules/.bin/tsc + @mkdir -p dist/js/views/tree + @cp js/views/tree/exampleConfig.json dist/js/views/tree/exampleConfig.json + @touch dist/.nojekyll # Build and serve the site at http://localhost:8000/. run: build - python3 -m http.server 8000 --bind 127.0.0.1 --directory dist + @node scripts/serve.mjs diff --git a/readme.md b/readme.md index 7a2e6fd..9b875ff 100644 --- a/readme.md +++ b/readme.md @@ -84,20 +84,21 @@ Click on the top right check button to **copy** and **go** to your new URL.
-## Featured - -StartTreeV2 - A $tree styled start page generator. | Product Hunt - - ## Development -Install Node.js and [just](https://just.systems/), then run `npm ci`. +Install [Node.js 22](https://nodejs.org/en/download) (which includes +[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)) and +[just](https://just.systems/man/en/packages.html). These are the only tools +needed for local development; `npm ci` installs the project's TypeScript +dependency from `package-lock.json`. + +Run `npm ci` in the project directory before using the commands below. | Command | Purpose | | --- | --- | | `just style` | Check TypeScript types | | `just build` | Build the site in `dist/` | -| `just run` | Build and serve at `http://localhost:8000/` | +| `just run` | Build and serve locally at `http://localhost:8000/` using Node.js | Run `just` to see the command list. For GitHub Pages, select **GitHub Actions** as the publishing source in the repository's Pages settings. @@ -105,9 +106,9 @@ as the publishing source in the repository's Pages settings.
Adding themes - 1. Create a new .css file in [/themes](https://github.com/AlexW00/StartTreeV2/tree/master/themes), which follows the same structure as the existing ones (most of them were generated using [Pywal](https://github.com/dylanaraps/pywal)). + 1. Create a new .css file in [/themes](https://github.com/MacArthur955/StartTreeV3/tree/main/themes), which follows the same structure as the existing ones (most of them were generated using [Pywal](https://github.com/dylanaraps/pywal)). - 2. Add a new entry **at the end** of the `THEMES` array in [theme-changer.js](https://github.com/AlexW00/StartTreeV2/blob/master/js/views/tree/themechanger/theme-changer.js) + 2. Add a new entry **at the end** of the `THEMES` array in [theme-changer.ts](https://github.com/MacArthur955/StartTreeV3/blob/main/js/views/tree/themechanger/theme-changer.ts) 3. (make a pull request)
diff --git a/scripts/serve.mjs b/scripts/serve.mjs new file mode 100644 index 0000000..7f64d76 --- /dev/null +++ b/scripts/serve.mjs @@ -0,0 +1,38 @@ +import { createServer } from "node:http"; +import { readFile } from "node:fs/promises"; +import { extname, resolve, sep } from "node:path"; + +const root = resolve("dist"); +const types = { + ".css": "text/css", + ".html": "text/html", + ".js": "text/javascript", + ".json": "application/json", + ".ttf": "font/ttf", +}; + +createServer(async (request, response) => { + if (request.method !== "GET" && request.method !== "HEAD") { + response.writeHead(405, { Allow: "GET, HEAD" }).end(); + return; + } + + let file; + try { + const pathname = decodeURIComponent(new URL(request.url, "http://localhost").pathname); + file = resolve(root, `.${pathname === "/" ? "/index.html" : pathname}`); + if (!file.startsWith(root + sep)) { + response.writeHead(403).end(); + return; + } + const body = await readFile(file); + response.writeHead(200, { + "Content-Type": `${types[extname(file)] ?? "application/octet-stream"}; charset=utf-8`, + }); + response.end(request.method === "HEAD" ? undefined : body); + } catch (error) { + response.writeHead(error.code === "ENOENT" || error.code === "EISDIR" ? 404 : 400).end(); + } +}).listen(8000, "127.0.0.1", () => { + console.log("Serving http://localhost:8000/"); +}); From db4586cf26e0923c64fb3671c02741c3dac5b3dc Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 21:11:09 +0200 Subject: [PATCH 5/6] refactor project structure --- app/index.html | 10 ++++++++++ {html => app/pages}/edit.html | 2 +- {html => app/pages}/view.html | 2 +- {js => app/src}/helper/dragOptions.ts | 0 {js => app/src}/helper/jsurl.ts | 0 {js => app/src}/helper/makeDraggable.ts | 0 {js => app/src}/helper/utils.ts | 0 {js/html => app/src/pages}/edit.ts | 0 app/src/pages/index.ts | 9 +++++++++ {js/html => app/src/pages}/view.ts | 0 {js => app/src}/views/other/button.ts | 0 .../src}/views/tree/components/searchBar.ts | 0 {js => app/src}/views/tree/components/tree.ts | 0 .../src}/views/tree/components/treeColumn.ts | 0 .../views/tree/components/treeColumnCategory.ts | 0 .../src}/views/tree/components/treeItem.ts | 0 .../tree/editTree/components/editSearchBar.ts | 0 .../views/tree/editTree/components/editTree.ts | 0 .../tree/editTree/components/editTreeColumn.ts | 0 .../components/editTreeColumnCategory.ts | 0 .../tree/editTree/components/editTreeItem.ts | 0 .../tree/editTree/editor/components/editor.ts | 0 .../tree/editTree/editor/components/toolbar.ts | 0 .../editTree/editor/events/editorFinishEvent.ts | 0 .../editor/helperObjects/editorOptions.ts | 0 .../editor/helperObjects/editorTarget.ts | 0 .../tree/editTree/events/treeUpdateEvent.ts | 0 {js => app/src}/views/tree/exampleConfig.json | 0 .../views/tree/themechanger/theme-changer.ts | 0 .../src}/views/tree/themechanger/themeItem.ts | 0 {styles => app/styles}/Hack.ttf | Bin {styles => app/styles}/colors.css | 0 {styles => app/styles}/style.css | 0 {themes => app/themes}/MonokaiPro.css | 0 {themes => app/themes}/Programiz.css | 0 {themes => app/themes}/autumn-mech.css | 0 {themes => app/themes}/bigsur.css | 0 {themes => app/themes}/black-ice.css | 0 {themes => app/themes}/capitane.css | 0 {themes => app/themes}/carnival.css | 0 {themes => app/themes}/catppuccin.css | 0 {themes => app/themes}/cotton-candy.css | 0 {themes => app/themes}/desert-sky.css | 0 {themes => app/themes}/ferns.css | 0 {themes => app/themes}/forest.css | 0 {themes => app/themes}/gold-hunter.css | 0 {themes => app/themes}/gruvbox.css | 0 {themes => app/themes}/intrigue.css | 0 {themes => app/themes}/just-red.css | 0 {themes => app/themes}/monterey.css | 0 {themes => app/themes}/neon-pink-dark.css | 0 {themes => app/themes}/neon.css | 0 {themes => app/themes}/nord.css | 0 {themes => app/themes}/orange-dark.css | 0 {themes => app/themes}/sierra.css | 0 {themes => app/themes}/slick-red.css | 0 {themes => app/themes}/storm.css | 0 {themes => app/themes}/this-ones-good.css | 0 .../themes}/tomorrow-night-eighties.css | 0 {themes => app/themes}/void.css | 0 {themes => app/themes}/water-fire.css | 0 index.html | 15 --------------- js/html/index.ts | 9 --------- justfile | 8 ++++---- readme.md | 9 +++++++-- tsconfig.json | 6 +++--- 66 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 app/index.html rename {html => app/pages}/edit.html (79%) rename {html => app/pages}/view.html (79%) rename {js => app/src}/helper/dragOptions.ts (100%) rename {js => app/src}/helper/jsurl.ts (100%) rename {js => app/src}/helper/makeDraggable.ts (100%) rename {js => app/src}/helper/utils.ts (100%) rename {js/html => app/src/pages}/edit.ts (100%) create mode 100644 app/src/pages/index.ts rename {js/html => app/src/pages}/view.ts (100%) rename {js => app/src}/views/other/button.ts (100%) rename {js => app/src}/views/tree/components/searchBar.ts (100%) rename {js => app/src}/views/tree/components/tree.ts (100%) rename {js => app/src}/views/tree/components/treeColumn.ts (100%) rename {js => app/src}/views/tree/components/treeColumnCategory.ts (100%) rename {js => app/src}/views/tree/components/treeItem.ts (100%) rename {js => app/src}/views/tree/editTree/components/editSearchBar.ts (100%) rename {js => app/src}/views/tree/editTree/components/editTree.ts (100%) rename {js => app/src}/views/tree/editTree/components/editTreeColumn.ts (100%) rename {js => app/src}/views/tree/editTree/components/editTreeColumnCategory.ts (100%) rename {js => app/src}/views/tree/editTree/components/editTreeItem.ts (100%) rename {js => app/src}/views/tree/editTree/editor/components/editor.ts (100%) rename {js => app/src}/views/tree/editTree/editor/components/toolbar.ts (100%) rename {js => app/src}/views/tree/editTree/editor/events/editorFinishEvent.ts (100%) rename {js => app/src}/views/tree/editTree/editor/helperObjects/editorOptions.ts (100%) rename {js => app/src}/views/tree/editTree/editor/helperObjects/editorTarget.ts (100%) rename {js => app/src}/views/tree/editTree/events/treeUpdateEvent.ts (100%) rename {js => app/src}/views/tree/exampleConfig.json (100%) rename {js => app/src}/views/tree/themechanger/theme-changer.ts (100%) rename {js => app/src}/views/tree/themechanger/themeItem.ts (100%) rename {styles => app/styles}/Hack.ttf (100%) rename {styles => app/styles}/colors.css (100%) rename {styles => app/styles}/style.css (100%) rename {themes => app/themes}/MonokaiPro.css (100%) rename {themes => app/themes}/Programiz.css (100%) rename {themes => app/themes}/autumn-mech.css (100%) rename {themes => app/themes}/bigsur.css (100%) rename {themes => app/themes}/black-ice.css (100%) rename {themes => app/themes}/capitane.css (100%) rename {themes => app/themes}/carnival.css (100%) rename {themes => app/themes}/catppuccin.css (100%) rename {themes => app/themes}/cotton-candy.css (100%) rename {themes => app/themes}/desert-sky.css (100%) rename {themes => app/themes}/ferns.css (100%) rename {themes => app/themes}/forest.css (100%) rename {themes => app/themes}/gold-hunter.css (100%) rename {themes => app/themes}/gruvbox.css (100%) rename {themes => app/themes}/intrigue.css (100%) rename {themes => app/themes}/just-red.css (100%) rename {themes => app/themes}/monterey.css (100%) rename {themes => app/themes}/neon-pink-dark.css (100%) rename {themes => app/themes}/neon.css (100%) rename {themes => app/themes}/nord.css (100%) rename {themes => app/themes}/orange-dark.css (100%) rename {themes => app/themes}/sierra.css (100%) rename {themes => app/themes}/slick-red.css (100%) rename {themes => app/themes}/storm.css (100%) rename {themes => app/themes}/this-ones-good.css (100%) rename {themes => app/themes}/tomorrow-night-eighties.css (100%) rename {themes => app/themes}/void.css (100%) rename {themes => app/themes}/water-fire.css (100%) delete mode 100644 index.html delete mode 100644 js/html/index.ts diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..742ed87 --- /dev/null +++ b/app/index.html @@ -0,0 +1,10 @@ + + + + + + + + StartTreeV2 - Home + + diff --git a/html/edit.html b/app/pages/edit.html similarity index 79% rename from html/edit.html rename to app/pages/edit.html index 0338610..054ce37 100644 --- a/html/edit.html +++ b/app/pages/edit.html @@ -5,6 +5,6 @@ StartTreeV2 - Edit - + diff --git a/html/view.html b/app/pages/view.html similarity index 79% rename from html/view.html rename to app/pages/view.html index fa1cbe5..b9e4b8b 100644 --- a/html/view.html +++ b/app/pages/view.html @@ -4,7 +4,7 @@ - + StartTreeV2 diff --git a/js/helper/dragOptions.ts b/app/src/helper/dragOptions.ts similarity index 100% rename from js/helper/dragOptions.ts rename to app/src/helper/dragOptions.ts diff --git a/js/helper/jsurl.ts b/app/src/helper/jsurl.ts similarity index 100% rename from js/helper/jsurl.ts rename to app/src/helper/jsurl.ts diff --git a/js/helper/makeDraggable.ts b/app/src/helper/makeDraggable.ts similarity index 100% rename from js/helper/makeDraggable.ts rename to app/src/helper/makeDraggable.ts diff --git a/js/helper/utils.ts b/app/src/helper/utils.ts similarity index 100% rename from js/helper/utils.ts rename to app/src/helper/utils.ts diff --git a/js/html/edit.ts b/app/src/pages/edit.ts similarity index 100% rename from js/html/edit.ts rename to app/src/pages/edit.ts diff --git a/app/src/pages/index.ts b/app/src/pages/index.ts new file mode 100644 index 0000000..8dd1f2e --- /dev/null +++ b/app/src/pages/index.ts @@ -0,0 +1,9 @@ +import { stringify } from "../helper/jsurl.js"; + +const exampleData = await fetch("./src/views/tree/exampleConfig.json").then( + (response) => response.json() +); + +const jsonStringified = stringify(exampleData); + +document.location.replace(`./pages/edit.html?t=${jsonStringified}`); diff --git a/js/html/view.ts b/app/src/pages/view.ts similarity index 100% rename from js/html/view.ts rename to app/src/pages/view.ts diff --git a/js/views/other/button.ts b/app/src/views/other/button.ts similarity index 100% rename from js/views/other/button.ts rename to app/src/views/other/button.ts diff --git a/js/views/tree/components/searchBar.ts b/app/src/views/tree/components/searchBar.ts similarity index 100% rename from js/views/tree/components/searchBar.ts rename to app/src/views/tree/components/searchBar.ts diff --git a/js/views/tree/components/tree.ts b/app/src/views/tree/components/tree.ts similarity index 100% rename from js/views/tree/components/tree.ts rename to app/src/views/tree/components/tree.ts diff --git a/js/views/tree/components/treeColumn.ts b/app/src/views/tree/components/treeColumn.ts similarity index 100% rename from js/views/tree/components/treeColumn.ts rename to app/src/views/tree/components/treeColumn.ts diff --git a/js/views/tree/components/treeColumnCategory.ts b/app/src/views/tree/components/treeColumnCategory.ts similarity index 100% rename from js/views/tree/components/treeColumnCategory.ts rename to app/src/views/tree/components/treeColumnCategory.ts diff --git a/js/views/tree/components/treeItem.ts b/app/src/views/tree/components/treeItem.ts similarity index 100% rename from js/views/tree/components/treeItem.ts rename to app/src/views/tree/components/treeItem.ts diff --git a/js/views/tree/editTree/components/editSearchBar.ts b/app/src/views/tree/editTree/components/editSearchBar.ts similarity index 100% rename from js/views/tree/editTree/components/editSearchBar.ts rename to app/src/views/tree/editTree/components/editSearchBar.ts diff --git a/js/views/tree/editTree/components/editTree.ts b/app/src/views/tree/editTree/components/editTree.ts similarity index 100% rename from js/views/tree/editTree/components/editTree.ts rename to app/src/views/tree/editTree/components/editTree.ts diff --git a/js/views/tree/editTree/components/editTreeColumn.ts b/app/src/views/tree/editTree/components/editTreeColumn.ts similarity index 100% rename from js/views/tree/editTree/components/editTreeColumn.ts rename to app/src/views/tree/editTree/components/editTreeColumn.ts diff --git a/js/views/tree/editTree/components/editTreeColumnCategory.ts b/app/src/views/tree/editTree/components/editTreeColumnCategory.ts similarity index 100% rename from js/views/tree/editTree/components/editTreeColumnCategory.ts rename to app/src/views/tree/editTree/components/editTreeColumnCategory.ts diff --git a/js/views/tree/editTree/components/editTreeItem.ts b/app/src/views/tree/editTree/components/editTreeItem.ts similarity index 100% rename from js/views/tree/editTree/components/editTreeItem.ts rename to app/src/views/tree/editTree/components/editTreeItem.ts diff --git a/js/views/tree/editTree/editor/components/editor.ts b/app/src/views/tree/editTree/editor/components/editor.ts similarity index 100% rename from js/views/tree/editTree/editor/components/editor.ts rename to app/src/views/tree/editTree/editor/components/editor.ts diff --git a/js/views/tree/editTree/editor/components/toolbar.ts b/app/src/views/tree/editTree/editor/components/toolbar.ts similarity index 100% rename from js/views/tree/editTree/editor/components/toolbar.ts rename to app/src/views/tree/editTree/editor/components/toolbar.ts diff --git a/js/views/tree/editTree/editor/events/editorFinishEvent.ts b/app/src/views/tree/editTree/editor/events/editorFinishEvent.ts similarity index 100% rename from js/views/tree/editTree/editor/events/editorFinishEvent.ts rename to app/src/views/tree/editTree/editor/events/editorFinishEvent.ts diff --git a/js/views/tree/editTree/editor/helperObjects/editorOptions.ts b/app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts similarity index 100% rename from js/views/tree/editTree/editor/helperObjects/editorOptions.ts rename to app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts diff --git a/js/views/tree/editTree/editor/helperObjects/editorTarget.ts b/app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts similarity index 100% rename from js/views/tree/editTree/editor/helperObjects/editorTarget.ts rename to app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts diff --git a/js/views/tree/editTree/events/treeUpdateEvent.ts b/app/src/views/tree/editTree/events/treeUpdateEvent.ts similarity index 100% rename from js/views/tree/editTree/events/treeUpdateEvent.ts rename to app/src/views/tree/editTree/events/treeUpdateEvent.ts diff --git a/js/views/tree/exampleConfig.json b/app/src/views/tree/exampleConfig.json similarity index 100% rename from js/views/tree/exampleConfig.json rename to app/src/views/tree/exampleConfig.json diff --git a/js/views/tree/themechanger/theme-changer.ts b/app/src/views/tree/themechanger/theme-changer.ts similarity index 100% rename from js/views/tree/themechanger/theme-changer.ts rename to app/src/views/tree/themechanger/theme-changer.ts diff --git a/js/views/tree/themechanger/themeItem.ts b/app/src/views/tree/themechanger/themeItem.ts similarity index 100% rename from js/views/tree/themechanger/themeItem.ts rename to app/src/views/tree/themechanger/themeItem.ts diff --git a/styles/Hack.ttf b/app/styles/Hack.ttf similarity index 100% rename from styles/Hack.ttf rename to app/styles/Hack.ttf diff --git a/styles/colors.css b/app/styles/colors.css similarity index 100% rename from styles/colors.css rename to app/styles/colors.css diff --git a/styles/style.css b/app/styles/style.css similarity index 100% rename from styles/style.css rename to app/styles/style.css diff --git a/themes/MonokaiPro.css b/app/themes/MonokaiPro.css similarity index 100% rename from themes/MonokaiPro.css rename to app/themes/MonokaiPro.css diff --git a/themes/Programiz.css b/app/themes/Programiz.css similarity index 100% rename from themes/Programiz.css rename to app/themes/Programiz.css diff --git a/themes/autumn-mech.css b/app/themes/autumn-mech.css similarity index 100% rename from themes/autumn-mech.css rename to app/themes/autumn-mech.css diff --git a/themes/bigsur.css b/app/themes/bigsur.css similarity index 100% rename from themes/bigsur.css rename to app/themes/bigsur.css diff --git a/themes/black-ice.css b/app/themes/black-ice.css similarity index 100% rename from themes/black-ice.css rename to app/themes/black-ice.css diff --git a/themes/capitane.css b/app/themes/capitane.css similarity index 100% rename from themes/capitane.css rename to app/themes/capitane.css diff --git a/themes/carnival.css b/app/themes/carnival.css similarity index 100% rename from themes/carnival.css rename to app/themes/carnival.css diff --git a/themes/catppuccin.css b/app/themes/catppuccin.css similarity index 100% rename from themes/catppuccin.css rename to app/themes/catppuccin.css diff --git a/themes/cotton-candy.css b/app/themes/cotton-candy.css similarity index 100% rename from themes/cotton-candy.css rename to app/themes/cotton-candy.css diff --git a/themes/desert-sky.css b/app/themes/desert-sky.css similarity index 100% rename from themes/desert-sky.css rename to app/themes/desert-sky.css diff --git a/themes/ferns.css b/app/themes/ferns.css similarity index 100% rename from themes/ferns.css rename to app/themes/ferns.css diff --git a/themes/forest.css b/app/themes/forest.css similarity index 100% rename from themes/forest.css rename to app/themes/forest.css diff --git a/themes/gold-hunter.css b/app/themes/gold-hunter.css similarity index 100% rename from themes/gold-hunter.css rename to app/themes/gold-hunter.css diff --git a/themes/gruvbox.css b/app/themes/gruvbox.css similarity index 100% rename from themes/gruvbox.css rename to app/themes/gruvbox.css diff --git a/themes/intrigue.css b/app/themes/intrigue.css similarity index 100% rename from themes/intrigue.css rename to app/themes/intrigue.css diff --git a/themes/just-red.css b/app/themes/just-red.css similarity index 100% rename from themes/just-red.css rename to app/themes/just-red.css diff --git a/themes/monterey.css b/app/themes/monterey.css similarity index 100% rename from themes/monterey.css rename to app/themes/monterey.css diff --git a/themes/neon-pink-dark.css b/app/themes/neon-pink-dark.css similarity index 100% rename from themes/neon-pink-dark.css rename to app/themes/neon-pink-dark.css diff --git a/themes/neon.css b/app/themes/neon.css similarity index 100% rename from themes/neon.css rename to app/themes/neon.css diff --git a/themes/nord.css b/app/themes/nord.css similarity index 100% rename from themes/nord.css rename to app/themes/nord.css diff --git a/themes/orange-dark.css b/app/themes/orange-dark.css similarity index 100% rename from themes/orange-dark.css rename to app/themes/orange-dark.css diff --git a/themes/sierra.css b/app/themes/sierra.css similarity index 100% rename from themes/sierra.css rename to app/themes/sierra.css diff --git a/themes/slick-red.css b/app/themes/slick-red.css similarity index 100% rename from themes/slick-red.css rename to app/themes/slick-red.css diff --git a/themes/storm.css b/app/themes/storm.css similarity index 100% rename from themes/storm.css rename to app/themes/storm.css diff --git a/themes/this-ones-good.css b/app/themes/this-ones-good.css similarity index 100% rename from themes/this-ones-good.css rename to app/themes/this-ones-good.css diff --git a/themes/tomorrow-night-eighties.css b/app/themes/tomorrow-night-eighties.css similarity index 100% rename from themes/tomorrow-night-eighties.css rename to app/themes/tomorrow-night-eighties.css diff --git a/themes/void.css b/app/themes/void.css similarity index 100% rename from themes/void.css rename to app/themes/void.css diff --git a/themes/water-fire.css b/app/themes/water-fire.css similarity index 100% rename from themes/water-fire.css rename to app/themes/water-fire.css diff --git a/index.html b/index.html deleted file mode 100644 index e342ee0..0000000 --- a/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - StartTreeV2 - Home - - - - - - - diff --git a/js/html/index.ts b/js/html/index.ts deleted file mode 100644 index 531f3ac..0000000 --- a/js/html/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { stringify } from "../helper/jsurl.js"; - -const exampleData = await fetch("./js/views/tree/exampleConfig.json").then( - (response) => response.json() -); - -const jsonStringified = stringify(exampleData); - -document.location.replace(`./html/edit.html?t=${jsonStringified}`); diff --git a/justfile b/justfile index 0ce9fc7..0ec5191 100644 --- a/justfile +++ b/justfile @@ -10,11 +10,11 @@ style: build: style @rm -rf dist @mkdir -p dist - @cp index.html dist/index.html - @cp -R html styles themes dist/ + @cp app/index.html dist/index.html + @cp -R app/pages app/styles app/themes dist/ @./node_modules/.bin/tsc - @mkdir -p dist/js/views/tree - @cp js/views/tree/exampleConfig.json dist/js/views/tree/exampleConfig.json + @mkdir -p dist/src/views/tree + @cp app/src/views/tree/exampleConfig.json dist/src/views/tree/exampleConfig.json @touch dist/.nojekyll # Build and serve the site at http://localhost:8000/. diff --git a/readme.md b/readme.md index 9b875ff..f664cbb 100644 --- a/readme.md +++ b/readme.md @@ -94,6 +94,11 @@ dependency from `package-lock.json`. Run `npm ci` in the project directory before using the commands below. +The site source lives in `app/`: TypeScript in `app/src/`, pages in +`app/pages/`, and CSS and fonts in `app/styles/` and `app/themes/`. +The build writes browser-ready files to `dist/`, including compiled JavaScript +in `dist/src/` and pages in `dist/pages/`. + | Command | Purpose | | --- | --- | | `just style` | Check TypeScript types | @@ -106,9 +111,9 @@ as the publishing source in the repository's Pages settings.
Adding themes - 1. Create a new .css file in [/themes](https://github.com/MacArthur955/StartTreeV3/tree/main/themes), which follows the same structure as the existing ones (most of them were generated using [Pywal](https://github.com/dylanaraps/pywal)). + 1. Create a new .css file in [app/themes](https://github.com/MacArthur955/StartTreeV3/tree/main/app/themes), which follows the same structure as the existing ones (most of them were generated using [Pywal](https://github.com/dylanaraps/pywal)). - 2. Add a new entry **at the end** of the `THEMES` array in [theme-changer.ts](https://github.com/MacArthur955/StartTreeV3/blob/main/js/views/tree/themechanger/theme-changer.ts) + 2. Add a new entry **at the end** of the `THEMES` array in [theme-changer.ts](https://github.com/MacArthur955/StartTreeV3/blob/main/app/src/views/tree/themechanger/theme-changer.ts) 3. (make a pull request)
diff --git a/tsconfig.json b/tsconfig.json index 4f52866..6494dd0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,11 +4,11 @@ "module": "ES2022", "moduleResolution": "Bundler", "lib": ["ES2022", "DOM", "DOM.Iterable"], - "rootDir": "js", - "outDir": "dist/js", + "rootDir": "app/src", + "outDir": "dist/src", "skipLibCheck": true, "noImplicitAny": false, "noEmitOnError": true }, - "include": ["js/**/*.ts"] + "include": ["app/src/**/*.ts"] } From 1137a3451f61dd95fedafec57b7122ab1069e666 Mon Sep 17 00:00:00 2001 From: Artur Lepioszka Date: Sat, 19 Sep 2026 21:19:44 +0200 Subject: [PATCH 6/6] add types into ts files --- app/pages/edit.html | 2 +- app/pages/view.html | 2 +- app/src/helper/dragOptions.ts | 6 +- app/src/helper/jsurl.ts | 34 +++++------ app/src/helper/makeDraggable.ts | 16 +++--- app/src/helper/utils.ts | 4 +- app/src/pages/edit.ts | 3 +- app/src/pages/view.ts | 3 +- app/src/views/other/button.ts | 6 +- app/src/views/tree/components/searchBar.ts | 18 +++--- app/src/views/tree/components/tree.ts | 25 +++++---- app/src/views/tree/components/treeColumn.ts | 16 +++--- .../tree/components/treeColumnCategory.ts | 16 +++--- app/src/views/tree/components/treeItem.ts | 14 ++--- app/src/views/tree/components/treeTypes.ts | 3 + .../tree/editTree/components/editSearchBar.ts | 8 +-- .../tree/editTree/components/editTree.ts | 14 +++-- .../editTree/components/editTreeColumn.ts | 31 +++++----- .../components/editTreeColumnCategory.ts | 41 +++++++------- .../tree/editTree/components/editTreeItem.ts | 27 ++++----- .../tree/editTree/editor/components/editor.ts | 56 ++++++++++--------- .../editTree/editor/components/toolbar.ts | 12 ++-- .../editor/events/editorFinishEvent.ts | 8 +-- .../editor/helperObjects/editorOptions.ts | 8 +-- .../editor/helperObjects/editorTarget.ts | 8 +-- .../tree/editTree/events/treeUpdateEvent.ts | 14 ++--- .../views/tree/themechanger/theme-changer.ts | 18 +++--- app/src/views/tree/themechanger/themeItem.ts | 4 +- package.json | 3 + tsconfig.json | 10 +++- 30 files changed, 228 insertions(+), 202 deletions(-) create mode 100644 app/src/views/tree/components/treeTypes.ts diff --git a/app/pages/edit.html b/app/pages/edit.html index 054ce37..d26f951 100644 --- a/app/pages/edit.html +++ b/app/pages/edit.html @@ -4,7 +4,7 @@ - StartTreeV2 - Edit + StartTreeV3 - Edit diff --git a/app/pages/view.html b/app/pages/view.html index b9e4b8b..c578345 100644 --- a/app/pages/view.html +++ b/app/pages/view.html @@ -5,6 +5,6 @@ - StartTreeV2 + StartTreeV3 diff --git a/app/src/helper/dragOptions.ts b/app/src/helper/dragOptions.ts index 796baea..677372d 100644 --- a/app/src/helper/dragOptions.ts +++ b/app/src/helper/dragOptions.ts @@ -1,8 +1,8 @@ export default class DragOptions { - data: any; - validDropzones: any; + data: string; + validDropzones: string[]; - constructor({ data, validDropzones }) { + constructor({ data, validDropzones }: { data?: string; validDropzones?: string[] }) { this.data = data ?? ""; this.validDropzones = validDropzones ?? []; // classes that this draggable can be dropped on } diff --git a/app/src/helper/jsurl.ts b/app/src/helper/jsurl.ts index 37145ed..46957eb 100644 --- a/app/src/helper/jsurl.ts +++ b/app/src/helper/jsurl.ts @@ -23,17 +23,17 @@ * OTHER DEALINGS IN THE SOFTWARE. */ // -let stringify = function stringify(v) { - function encode(s) { +let stringify = function stringify(v: unknown): string | undefined { + function encode(s: string): string { return !/[^\w-.]/.test(s) ? s - : s.replace(/[^\w-.]/g, function (ch) { + : s.replace(/[^\w-.]/g, function (ch: string) { if (ch === "$") return "!"; - ch = ch.charCodeAt(0); + const code = ch.charCodeAt(0); // thanks to Douglas Crockford for the negative slice trick - return ch < 0x100 - ? "*" + ("00" + ch.toString(16)).slice(-2) - : "**" + ("0000" + ch.toString(16)).slice(-4); + return code < 0x100 + ? "*" + ("00" + code.toString(16)).slice(-2) + : "**" + ("0000" + code.toString(16)).slice(-4); }); } @@ -59,8 +59,8 @@ let stringify = function stringify(v) { return "~(" + (tmpAry.join("") || "~") + ")"; } else { for (var key in v) { - if (v.hasOwnProperty(key)) { - var val = stringify(v[key]); + if (Object.prototype.hasOwnProperty.call(v, key)) { + var val = stringify((v as Record)[key]); // skip undefined and functions if (val) { @@ -83,13 +83,13 @@ var reserved = { null: null, }; -let parse = function (s) { - if (!s) return s; - s = s.replace(/%(25)*27/g, "'"); +let parse = function (input: string | null): unknown { + if (!input) return input; + let s = input.replace(/%(25)*27/g, "'"); var i = 0, len = s.length; - function eat(expected) { + function eat(expected: string) { if (s.charAt(i) !== expected) throw new Error( "bad JSURL syntax: expected " + expected + ", got " + (s && s.charAt(i)) @@ -123,7 +123,7 @@ let parse = function (s) { return r + s.substring(beg, i); } - return (function parseOne() { + return (function parseOne(): unknown { var result, ch, beg; eat("~"); switch ((ch = s.charAt(i))) { @@ -138,11 +138,11 @@ let parse = function (s) { } while (s.charAt(i) === "~"); } } else { - result = {}; + result = {} as Record; if (s.charAt(i) !== ")") { do { var key = decode(); - result[key] = parseOne(); + (result as Record)[key] = parseOne(); } while (s.charAt(i) === "~" && ++i); } } @@ -159,7 +159,7 @@ let parse = function (s) { if (/[\d\-]/.test(ch)) { result = parseFloat(sub); } else { - result = reserved[sub]; + result = reserved[sub as keyof typeof reserved]; if (typeof result === "undefined") throw new Error("bad value keyword: " + sub); } diff --git a/app/src/helper/makeDraggable.ts b/app/src/helper/makeDraggable.ts index 1bc5d2e..e3c774a 100644 --- a/app/src/helper/makeDraggable.ts +++ b/app/src/helper/makeDraggable.ts @@ -1,3 +1,5 @@ +import DragOptions from "./dragOptions.js"; +export type DragAction = "dragstart" | "dragend" | "dragover" | "dragenter" | "dragleave" | "drop"; // ====================================================== // // ==================== makeDraggable =================== // // ====================================================== // @@ -5,19 +7,19 @@ // helper method to make an element draggable, configured with DragOptions let lastDropWasValid = false; -export default (element, dragOptions, callback) => { +export default (element: HTMLElement, dragOptions: DragOptions, callback: (type: DragAction, event: DragEvent) => void) => { element.draggable = true; element.classList.add("dropzone"); element.addEventListener("dragstart", (event) => { event.stopPropagation(); - event.dataTransfer.setData("text", dragOptions.data); + event.dataTransfer?.setData("text", dragOptions.data); callback("dragstart", event); }); element.addEventListener("dragend", (event) => { event.preventDefault(); - if (event.dataTransfer.dropEffect != "none" && lastDropWasValid) { + if (event.dataTransfer?.dropEffect != "none" && lastDropWasValid) { callback("dragend", event); event.stopPropagation(); } @@ -45,7 +47,7 @@ export default (element, dragOptions, callback) => { element.addEventListener("drop", (event) => { event.preventDefault(); lastDropWasValid = _isValidDropzone( - JSON.parse(event.dataTransfer.getData("text")) + JSON.parse(event.dataTransfer?.getData("text") ?? "{}") ); if (lastDropWasValid) { event.stopPropagation(); @@ -53,14 +55,14 @@ export default (element, dragOptions, callback) => { } }); - const _isValidDropzone = (dropZone) => { + const _isValidDropzone = (dropZone: { classList: string[] }) => { // check if an element of dropzone.classlist is in the array dragOptions.classList return _isValid(dropZone, dragOptions.validDropzones); }; - const _isValid = (element, classes) => { + const _isValid = (element: { classList: string[] }, classes: string[]) => { for (let i = 0; i < classes.length; i++) { - if ([...element.classList].indexOf(classes[i]) > -1) { + if ([...element.classList].indexOf(classes[i]!) > -1) { return true; } } diff --git a/app/src/helper/utils.ts b/app/src/helper/utils.ts index b3bc283..a7daa8a 100644 --- a/app/src/helper/utils.ts +++ b/app/src/helper/utils.ts @@ -1,3 +1,3 @@ -export function insertAfter(newNode, existingNode) { - existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); +export function insertAfter(newNode: Node, existingNode: Node) { + existingNode.parentNode?.insertBefore(newNode, existingNode.nextSibling); } diff --git a/app/src/pages/edit.ts b/app/src/pages/edit.ts index ca18481..c593778 100644 --- a/app/src/pages/edit.ts +++ b/app/src/pages/edit.ts @@ -1,10 +1,11 @@ +import type { TreeConfig } from "../views/tree/components/treeTypes.js"; import EditTree from "../views/tree/editTree/components/editTree.js"; import { parse, stringify } from "../helper/jsurl.js"; import Button from "../views/other/button.js"; const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); -const treeConfig = parse(urlParams.get("t")) || {}; +const treeConfig = (parse(urlParams.get("t")) as TreeConfig | null) ?? { bmc: [], s: {}, t: {} }; const REPO_URL = "https://github.com/AlexW00/StartTreeV2"; const t = new EditTree(treeConfig); diff --git a/app/src/pages/view.ts b/app/src/pages/view.ts index b46df07..393b94b 100644 --- a/app/src/pages/view.ts +++ b/app/src/pages/view.ts @@ -1,10 +1,11 @@ +import type { TreeConfig } from "../views/tree/components/treeTypes.js"; import Tree from "../views/tree/components/tree.js"; import { parse } from "../helper/jsurl.js"; import Button from "../views/other/button.js"; const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); -const treeConfig = parse(urlParams.get("t")) || {}; +const treeConfig = (parse(urlParams.get("t")) as TreeConfig | null) ?? { bmc: [], s: {}, t: {} }; const editModeHref = "./edit.html"; const t = new Tree(treeConfig); diff --git a/app/src/views/other/button.ts b/app/src/views/other/button.ts index eeeee5c..23a88ce 100644 --- a/app/src/views/other/button.ts +++ b/app/src/views/other/button.ts @@ -3,11 +3,11 @@ // ====================================================== // export default class Button { - svg: any; - type: any; + svg: string; + type: string; // possible values for type: "save", "cancel", "add" or "delete" - constructor(type, width?: number, height?: number) { + constructor(type: string, width?: number, height?: number) { this.type = type; if (type === "add") { this.svg = ` diff --git a/app/src/views/tree/components/searchBar.ts b/app/src/views/tree/components/searchBar.ts index 774ee77..071976b 100644 --- a/app/src/views/tree/components/searchBar.ts +++ b/app/src/views/tree/components/searchBar.ts @@ -3,15 +3,15 @@ // ====================================================== //; export default class SearchBar { - form: any; - formInput: any; - h1: any; - root: any; - searchEngineNameShort: any; - searchEngineUrl: any; - sectionName: any; - - constructor(config) { + form!: HTMLFormElement; + formInput!: HTMLInputElement; + h1!: HTMLHeadingElement; + root!: HTMLDivElement; + searchEngineNameShort: string; + searchEngineUrl: string; + sectionName!: HTMLDivElement; + + constructor(config: { n?: string; u?: string }) { this.searchEngineUrl = config.u ?? "https://duckduckgo.com/?q="; this.searchEngineNameShort = config.n ?? "ddg"; } diff --git a/app/src/views/tree/components/tree.ts b/app/src/views/tree/components/tree.ts index 30c3658..9fa6b87 100644 --- a/app/src/views/tree/components/tree.ts +++ b/app/src/views/tree/components/tree.ts @@ -1,3 +1,4 @@ +import type { TreeConfig, CategoryConfig } from "./treeTypes.js"; import ThemeChanger from "../themechanger/theme-changer.js"; import SearchBar from "./searchBar.js"; import TreeColumn from "./treeColumn.js"; @@ -7,15 +8,15 @@ import TreeColumn from "./treeColumn.js"; // ====================================================== // export default class Tree { - bookmarkColumns: any; - bookmarkRow: any; - root: any; - searchBar: any; - themeChanger: any; - titlePrompt: any; - version: any; - - constructor(config) { + bookmarkColumns: TreeColumn[]; + bookmarkRow!: HTMLDivElement; + root!: HTMLDivElement; + searchBar: SearchBar; + themeChanger: ThemeChanger; + titlePrompt!: HTMLDivElement; + version: string; + + constructor(config: TreeConfig) { this.version = config.v || "0.0"; this.bookmarkColumns = this.initBookmarkColumns(config.bmc); @@ -25,15 +26,15 @@ export default class Tree { // ~~~~~~~~ initialization methods ~~~~~~~ // - initBookmarkColumns(config) { + initBookmarkColumns(config: CategoryConfig[][]) { return config.map((column) => new TreeColumn(column)); } - initSearchBar(config) { + initSearchBar(config: TreeConfig["s"]) { return new SearchBar(config); } - initThemeChanger(config) { + initThemeChanger(config: TreeConfig["t"]) { return new ThemeChanger(config); } diff --git a/app/src/views/tree/components/treeColumn.ts b/app/src/views/tree/components/treeColumn.ts index 8240732..fae0501 100644 --- a/app/src/views/tree/components/treeColumn.ts +++ b/app/src/views/tree/components/treeColumn.ts @@ -5,15 +5,15 @@ import TreeColumnCategory from "./treeColumnCategory.js"; // ====================================================== // export default class TreeColumn { - bookmarkCategories: any; - categoryList: any; - columnTitle: any; - id: any; - root: any; - tree: any; + bookmarkCategories: TreeColumnCategory[]; + categoryList!: HTMLUListElement; + columnTitle!: HTMLHeadingElement; + id: string; + root!: HTMLDivElement; + tree!: HTMLDivElement; static count = 0; - constructor(bookmarkColumn) { + constructor(bookmarkColumn: { cn: string; b: { n: string; u: string }[] }[]) { TreeColumn.count++; this.id = `column-${TreeColumn.count}`; this.bookmarkCategories = this.initBookmarkCategories(bookmarkColumn); @@ -74,7 +74,7 @@ export default class TreeColumn { // ~~~~~~~~~~~~ class functionality ~~~~~~~~~~~~ // - initBookmarkCategories(categoryConfig) { + initBookmarkCategories(categoryConfig: { cn: string; b: { n: string; u: string }[] }[]) { return categoryConfig.map((bookmarkCategory) => { return new TreeColumnCategory(bookmarkCategory); }); diff --git a/app/src/views/tree/components/treeColumnCategory.ts b/app/src/views/tree/components/treeColumnCategory.ts index dd38132..1dbc230 100644 --- a/app/src/views/tree/components/treeColumnCategory.ts +++ b/app/src/views/tree/components/treeColumnCategory.ts @@ -5,15 +5,15 @@ import TreeItem from "./treeItem.js"; export default class TreeColumnCategory { - bookmarkList: any; - categoryTitle: any; - id: any; - name: any; - root: any; - treeItems: any; + bookmarkList!: HTMLUListElement; + categoryTitle!: HTMLHeadingElement; + id: string; + name: string; + root!: HTMLLIElement; + treeItems: TreeItem[]; static count = 0; - constructor(bookmarkCategory) { + constructor(bookmarkCategory: { cn: string; b: { n: string; u: string }[] }) { TreeColumnCategory.count++; this.id = `category-${TreeColumnCategory.count}`; this.name = bookmarkCategory.cn; @@ -65,7 +65,7 @@ export default class TreeColumnCategory { // ~~~~~~~~~~~~ class functionality ~~~~~~~~~~~~ // - initTreeItems(bookmarkConfig) { + initTreeItems(bookmarkConfig: { n: string; u: string }[]) { return bookmarkConfig.map((bookmark) => { return new TreeItem(bookmark); }); diff --git a/app/src/views/tree/components/treeItem.ts b/app/src/views/tree/components/treeItem.ts index bb7c5de..d318e96 100644 --- a/app/src/views/tree/components/treeItem.ts +++ b/app/src/views/tree/components/treeItem.ts @@ -4,14 +4,14 @@ // export default class TreeItem { - a: any; - id: any; - name: any; - root: any; - url: any; + a!: HTMLAnchorElement; + id: string; + name: string; + root!: HTMLLIElement; + url: string; static count = 0; - constructor(bookmark) { + constructor(bookmark: { n: string; u: string }) { TreeItem.count++; this.id = `bookmark-${TreeItem.count}`; this.name = bookmark.n; @@ -45,7 +45,7 @@ export default class TreeItem { return root; } - generateLinkText(url) { + generateLinkText(url: string) { // if the url has a protocol, return the url, else append a protocol if (url.includes("//")) { return url; diff --git a/app/src/views/tree/components/treeTypes.ts b/app/src/views/tree/components/treeTypes.ts new file mode 100644 index 0000000..449e843 --- /dev/null +++ b/app/src/views/tree/components/treeTypes.ts @@ -0,0 +1,3 @@ +export type BookmarkConfig = { n: string; u: string }; +export type CategoryConfig = { cn: string; b: BookmarkConfig[] }; +export type TreeConfig = { v?: string; bmc: CategoryConfig[][]; s: { n?: string; u?: string }; t: { nr?: number } }; diff --git a/app/src/views/tree/editTree/components/editSearchBar.ts b/app/src/views/tree/editTree/components/editSearchBar.ts index 2d85215..a51706a 100644 --- a/app/src/views/tree/editTree/components/editSearchBar.ts +++ b/app/src/views/tree/editTree/components/editSearchBar.ts @@ -10,13 +10,13 @@ import Button from "../../../other/button.js"; export default class EditSearchBar extends SearchBar { - constructor(config) { + constructor(config: { n?: string; u?: string }) { super(config); } // ~~~~~~~ override parent methods ~~~~~~~ // - renderHtml() { + override renderHtml() { this.root = this.rootHtml(); this.sectionName = this.#sectionNameHtml(); @@ -57,8 +57,8 @@ export default class EditSearchBar extends SearchBar { }), (editorFinishEvent) => { if (editorFinishEvent.type === "save") { - this.searchEngineUrl = editorFinishEvent.editResult.link; - this.searchEngineNameShort = editorFinishEvent.editResult.text; + this.searchEngineUrl = editorFinishEvent.editResult!.link; + this.searchEngineNameShort = editorFinishEvent.editResult!.text; this.root.prepend(this.#sectionNameHtml()); } else { this.root.prepend(this.#sectionNameHtml()); diff --git a/app/src/views/tree/editTree/components/editTree.ts b/app/src/views/tree/editTree/components/editTree.ts index 77c83d7..c83929d 100644 --- a/app/src/views/tree/editTree/components/editTree.ts +++ b/app/src/views/tree/editTree/components/editTree.ts @@ -2,6 +2,8 @@ import ThemeChanger from "../../themechanger/theme-changer.js"; import EditSearchBar from "./editSearchBar.js"; import EditTreeColumn from "./editTreeColumn.js"; import Button from "../../../other/button.js"; +import type { TreeConfig, CategoryConfig } from "../../components/treeTypes.js"; +import TreeUpdateEvent from "../events/treeUpdateEvent.js"; import Tree from "../../components/tree.js"; // ====================================================== // @@ -10,27 +12,27 @@ import Tree from "../../components/tree.js"; export default class EditTree extends Tree { - constructor(config) { + constructor(config: TreeConfig) { super(config); } // ~~~~~~~~ override parent methods ~~~~~~~ // - initBookmarkColumns(config) { + override initBookmarkColumns(config: CategoryConfig[][]) { return config.map( (column) => new EditTreeColumn(column, this.onColumnUpdate.bind(this)) ); } - initSearchBar(config) { + override initSearchBar(config: TreeConfig["s"]) { return new EditSearchBar(config); } - initThemeChanger(config) { + override initThemeChanger(config: TreeConfig["t"]) { return new ThemeChanger(config); } - renderHtml() { + override renderHtml() { this.root = super.renderHtml(); this.root.append(this.themeChanger.html()); this.titlePrompt.appendChild(this.#addColumnButtonHtml()); @@ -55,7 +57,7 @@ export default class EditTree extends Tree { // ~~~~~~~~~~~ callback methods ~~~~~~~~~~ // - onColumnUpdate(treeUpdateEvent) { + onColumnUpdate(treeUpdateEvent: TreeUpdateEvent) { if (treeUpdateEvent.type === "delete") { const index = this.bookmarkColumns.indexOf(treeUpdateEvent.updatedObject); this.bookmarkColumns.splice(index, 1); diff --git a/app/src/views/tree/editTree/components/editTreeColumn.ts b/app/src/views/tree/editTree/components/editTreeColumn.ts index 84b3a79..e3b4906 100644 --- a/app/src/views/tree/editTree/components/editTreeColumn.ts +++ b/app/src/views/tree/editTree/components/editTreeColumn.ts @@ -4,6 +4,7 @@ import Editor from "../editor/components/editor.js"; import editorTarget from "../editor/helperObjects/editorTarget.js"; import EditorOptions from "../editor/helperObjects/editorOptions.js"; import TreeUpdateEvent from "../events/treeUpdateEvent.js"; +import type { CategoryConfig } from "../../components/treeTypes.js"; import TreeColumn from "../../components/treeColumn.js"; // ====================================================== // @@ -11,16 +12,16 @@ import TreeColumn from "../../components/treeColumn.js"; // ====================================================== // export default class EditTreeColumn extends TreeColumn { - onUpdate: any; + onUpdate: (event: TreeUpdateEvent) => void; - constructor(bookmarkColumn, onUpdate) { + constructor(bookmarkColumn: CategoryConfig[], onUpdate: (event: TreeUpdateEvent) => void) { super(bookmarkColumn); this.onUpdate = onUpdate; } // ~~~~~~~~~~~~ override parent methods ~~~~~~~~~~~~ // - initBookmarkCategories(categoryConfig) { + override initBookmarkCategories(categoryConfig: CategoryConfig[]) { return categoryConfig.map((bookmarkCategory) => { return new EditTreeColumnCategory( bookmarkCategory, @@ -29,15 +30,15 @@ export default class EditTreeColumn extends TreeColumn { }); } - renderHtml() { + override renderHtml() { this.root = super.renderHtml(); - this.categoryList.lastElementChild.appendChild( + this.categoryList.lastElementChild?.appendChild( this.#newAddCategoryButton() ); return this.root; } - columnTitleHtml() { + override columnTitleHtml() { const h1 = super.columnTitleHtml(); h1.addEventListener("click", this.#categoryTitleListener); return h1; @@ -63,7 +64,7 @@ export default class EditTreeColumn extends TreeColumn { } else { this.tree.insertBefore( this.columnTitle, - this.tree.querySelectorAll("ul")[editorFinishEvent.index] + this.tree.querySelectorAll("ul")[editorFinishEvent.index] ?? null ); } } @@ -84,10 +85,10 @@ export default class EditTreeColumn extends TreeColumn { } // listener for when the add button is clicked - #onAddCategoryButtonClick = (addCategoryButton) => { + #onAddCategoryButtonClick = (addCategoryButton: HTMLDivElement) => { // removes add button from last category const elements = this.categoryList.querySelectorAll("li.category"); - elements[elements.length - 1].removeChild(addCategoryButton); + elements[elements.length - 1]?.removeChild(addCategoryButton); // creates new category and appends it to the end of the node const newBookmarkCategory = new EditTreeColumnCategory( @@ -106,7 +107,7 @@ export default class EditTreeColumn extends TreeColumn { (editorFinishEvent) => { if (editorFinishEvent.type === "save") { // append new bookmark category to end of list and push to array - newBookmarkCategory.name = editorFinishEvent.editResult.text; + newBookmarkCategory.name = editorFinishEvent.editResult!.text; const newBookmarkCategoryHtml = newBookmarkCategory.renderHtml(); this.categoryList.appendChild(newBookmarkCategoryHtml); newBookmarkCategoryHtml.appendChild(addCategoryButton); @@ -114,7 +115,7 @@ export default class EditTreeColumn extends TreeColumn { this.bookmarkCategories.push(newBookmarkCategory); } else { // re append the button - this.categoryList.lastElementChild.appendChild(addCategoryButton); + this.categoryList.lastElementChild?.appendChild(addCategoryButton); } } ); @@ -122,7 +123,7 @@ export default class EditTreeColumn extends TreeColumn { // ~~~~~~~~~~~~ callbacks ~~~~~~~~~~~~ // - onCategoryUpdate(treeUpdateEvent) { + onCategoryUpdate(treeUpdateEvent: TreeUpdateEvent) { if (treeUpdateEvent.type === "delete") { const categoryIndex = this.bookmarkCategories.indexOf( treeUpdateEvent.updatedObject @@ -138,11 +139,11 @@ export default class EditTreeColumn extends TreeColumn { } // else if this was the last category in the list, append the add button to the new last category else if (categoryIndex === this.bookmarkCategories.length) { - const lastCategory = this.root.querySelector("ul").lastChild; - lastCategory.appendChild(this.#newAddCategoryButton()); + const lastCategory = this.root.querySelector("ul")?.lastChild; + lastCategory?.appendChild(this.#newAddCategoryButton()); } } - if (treeUpdateEvent.type === "add") { + if (treeUpdateEvent.type === "add" && treeUpdateEvent.newObject) { // get the index of the category to add const categoryIndex = this.bookmarkCategories.indexOf( treeUpdateEvent.updatedObject diff --git a/app/src/views/tree/editTree/components/editTreeColumnCategory.ts b/app/src/views/tree/editTree/components/editTreeColumnCategory.ts index 88cca5c..090ae1d 100644 --- a/app/src/views/tree/editTree/components/editTreeColumnCategory.ts +++ b/app/src/views/tree/editTree/components/editTreeColumnCategory.ts @@ -6,6 +6,7 @@ import EditorOptions from "../editor/helperObjects/editorOptions.js"; import TreeUpdateEvent from "../events/treeUpdateEvent.js"; import DragOptions from "../../../../helper/dragOptions.js"; import makeDraggable from "../../../../helper/makeDraggable.js"; +import type { CategoryConfig, BookmarkConfig } from "../../components/treeTypes.js"; import TreeColumnCategory from "../../components/treeColumnCategory.js"; // ====================================================== // @@ -13,30 +14,30 @@ import TreeColumnCategory from "../../components/treeColumnCategory.js"; // ====================================================== // export default class EditTreeColumnCategory extends TreeColumnCategory { - onUpdate: any; + onUpdate: (event: TreeUpdateEvent) => void; - static count = 0; - constructor(bookmarkCategory, onUpdate) { + static override count = 0; + constructor(bookmarkCategory: CategoryConfig, onUpdate: (event: TreeUpdateEvent) => void) { super(bookmarkCategory); this.onUpdate = onUpdate; } // ~~~~~~~ override parent methods ~~~~~~~ // - initTreeItems(bookmarkConfig) { + override initTreeItems(bookmarkConfig: BookmarkConfig[]) { return bookmarkConfig.map((bookmark) => { return new EditTreeItem(bookmark, this.onBookmarkUpdate.bind(this)); }); } - renderHtml() { + override renderHtml() { super.renderHtml(); this.root.appendChild(this.#newAddCategoryButton(this.bookmarkList)); this.#makeDraggable(); return this.root; } - categoryTitleHtml() { + override categoryTitleHtml() { const h1 = super.categoryTitleHtml(); h1.addEventListener("click", () => { this.#categoryTitleClickListener(h1); @@ -78,8 +79,8 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { this.onUpdate(new TreeUpdateEvent({ type: "delete", updatedObject: this })); } - #onDrop = (event) => { - const dragItemData = JSON.parse(event.dataTransfer.getData("text")); + #onDrop = (event: DragEvent) => { + const dragItemData = JSON.parse(event.dataTransfer?.getData("text") ?? "{}"); const dragItemClass = dragItemData.classList[0]; @@ -87,13 +88,13 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { else if (dragItemClass === "category") this.#onDropCategory(dragItemData); }; - #onDropCategory(dragItemData) { + #onDropCategory(dragItemData: CategoryConfig) { const draggedItem = new EditTreeColumnCategory( { cn: dragItemData.cn, b: dragItemData.b }, this.onUpdate ); const draggedItemHtml = draggedItem.html(); - this.root.parentNode.insertBefore(draggedItemHtml, this.root); + this.root.parentNode?.insertBefore(draggedItemHtml, this.root); this.onUpdate( new TreeUpdateEvent({ type: "add", @@ -103,7 +104,7 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { ); } - #onDropBookmark(dragItemData) { + #onDropBookmark(dragItemData: BookmarkConfig) { const draggedItem = new EditTreeItem( { n: dragItemData.n, u: dragItemData.u }, this.onBookmarkUpdate.bind(this) @@ -113,14 +114,14 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { // prepend this item to the list const categoryList = this.root.querySelector("ul"); this.treeItems.unshift(draggedItem); - categoryList.insertBefore( + categoryList?.insertBefore( draggedItemHtml, - categoryList.querySelector(".bookmark") + categoryList?.querySelector(".bookmark") ); } // TODO: create extra class for this?? - #newAddCategoryButton = (ul) => { + #newAddCategoryButton = (ul: HTMLUListElement) => { const addBookmarkButton = new Button("add").html(); addBookmarkButton.classList.add("add-bookmark-button"); addBookmarkButton.style.paddingLeft = "1.5rem"; @@ -143,8 +144,8 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { (editorFinishEvent) => { if (editorFinishEvent.type === "save") { // append new bookmark to end of list and push to array - newBookmark.name = editorFinishEvent.editResult.text; - newBookmark.url = editorFinishEvent.editResult.link ?? "#"; + newBookmark.name = editorFinishEvent.editResult!.text; + newBookmark.url = editorFinishEvent.editResult!.link ?? "#"; this.treeItems.push(newBookmark); ul.appendChild(newBookmark.renderHtml()); } @@ -154,7 +155,7 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { return addBookmarkButton; }; - #categoryTitleClickListener = (h1) => { + #categoryTitleClickListener = (h1: HTMLHeadingElement) => { new Editor( this.root, new editorTarget(this.name, null, h1.id), @@ -162,7 +163,7 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { (editorFinishEvent) => { if (editorFinishEvent.type === "save") { // if the editor exits with "save", update the category name - this.name = editorFinishEvent.editResult.text; + this.name = editorFinishEvent.editResult!.text; h1 = this.categoryTitleHtml(); this.root.insertBefore(h1, this.bookmarkList); this.onUpdate( @@ -184,13 +185,13 @@ export default class EditTreeColumnCategory extends TreeColumnCategory { // ~~~~~~~~~~~~~~ callbacks ~~~~~~~~~~~~~~ // - onBookmarkUpdate(treeUpdateEvent) { + onBookmarkUpdate(treeUpdateEvent: TreeUpdateEvent) { if (treeUpdateEvent.type === "delete") { this.treeItems.splice( this.treeItems.indexOf(treeUpdateEvent.updatedObject), 1 ); - } else if (treeUpdateEvent.type === "add") { + } else if (treeUpdateEvent.type === "add" && treeUpdateEvent.newObject) { // add the bookmark to bookmarks after the updated object, if updated object isn't in listit will be added to the end const dragTargetIndex = this.treeItems.indexOf(treeUpdateEvent.updatedObject) ?? diff --git a/app/src/views/tree/editTree/components/editTreeItem.ts b/app/src/views/tree/editTree/components/editTreeItem.ts index 581a086..4b54910 100644 --- a/app/src/views/tree/editTree/components/editTreeItem.ts +++ b/app/src/views/tree/editTree/components/editTreeItem.ts @@ -6,6 +6,7 @@ import DragOptions from "../../../../helper/dragOptions.js"; import makeDraggable from "../../../../helper/makeDraggable.js"; import { insertAfter } from "../../../../helper/utils.js"; import Button from "../../../other/button.js"; +import type { BookmarkConfig } from "../../components/treeTypes.js"; import TreeItem from "../../components/treeItem.js"; import Editor from "../editor/components/editor.js"; import EditorOptions from "../editor/helperObjects/editorOptions.js"; @@ -13,21 +14,21 @@ import editorTarget from "../editor/helperObjects/editorTarget.js"; import TreeUpdateEvent from "../events/treeUpdateEvent.js"; export default class EditTreeItem extends TreeItem { - editButton: any; - onUpdate: any; + editButton!: HTMLDivElement; + onUpdate: (event: TreeUpdateEvent) => void; - constructor(bookmark, onUpdate) { + constructor(bookmark: BookmarkConfig, onUpdate: (event: TreeUpdateEvent) => void) { super(bookmark); this.onUpdate = onUpdate; } // ~~~~~~~ override parent methods ~~~~~~ // - html() { + override html() { return this.root ?? this.renderHtml(); } - renderHtml() { + override renderHtml() { this.root = super.renderHtml(); this.editButton = this.editButtonHtml(); this.root.appendChild(this.editButton); @@ -35,7 +36,7 @@ export default class EditTreeItem extends TreeItem { return this.root; } - linkHtml() { + override linkHtml() { const a = super.linkHtml(); a.addEventListener("click", (event) => { event.preventDefault(); @@ -70,8 +71,8 @@ export default class EditTreeItem extends TreeItem { }; // valid element is dropped on this element - #onDrop(event) { - const dragItemData = JSON.parse(event.dataTransfer.getData("text")), + #onDrop(event: DragEvent) { + const dragItemData = JSON.parse(event.dataTransfer?.getData("text") ?? "{}"), newEditTreeItem = new EditTreeItem( { n: dragItemData.n, u: dragItemData.u }, this.onUpdate @@ -95,7 +96,7 @@ export default class EditTreeItem extends TreeItem { // creates a new editor and adds it to the DOM #onBookmarkClick = () => { - const parentNode = this.root.parentNode; + const parentNode = this.root.parentNode as HTMLElement; new Editor( parentNode, new editorTarget(this.name, this.url, this.id), @@ -105,16 +106,16 @@ export default class EditTreeItem extends TreeItem { }), (editorFinishEvent) => { if (editorFinishEvent.type === "save") { - this.name = editorFinishEvent.editResult.text; - this.url = editorFinishEvent.editResult.link ?? "#"; + this.name = editorFinishEvent.editResult!.text; + this.url = editorFinishEvent.editResult!.link ?? "#"; parentNode.insertBefore( this.renderHtml(), - parentNode.querySelectorAll("li")[editorFinishEvent.index] + parentNode.querySelectorAll("li")[editorFinishEvent.index] ?? null ); } else if (editorFinishEvent.type === "cancel") { parentNode.insertBefore( this.html(), - parentNode.querySelectorAll("li")[editorFinishEvent.index] + parentNode.querySelectorAll("li")[editorFinishEvent.index] ?? null ); } else if (editorFinishEvent.type === "delete") { this.onUpdate( diff --git a/app/src/views/tree/editTree/editor/components/editor.ts b/app/src/views/tree/editTree/editor/components/editor.ts index 61124ad..975bcc3 100644 --- a/app/src/views/tree/editTree/editor/components/editor.ts +++ b/app/src/views/tree/editTree/editor/components/editor.ts @@ -3,28 +3,30 @@ // ====================================================== // import EditorFinishEvent from "../events/editorFinishEvent.js"; +import EditorOptions from "../helperObjects/editorOptions.js"; +import EditorTarget from "../helperObjects/editorTarget.js"; import Toolbar from "./toolbar.js"; export default class Editor { - allowTextEdit: any; - buttons: any; - cb: any; - editorTarget: any; - index: any; - isClosed: any; - link: any; - linkEditorIsOpen: any; - nodeType: any; - parentNode: any; - root: any; - secondRow: any; - text: any; - toolbar: any; - - static openInstance = null; + allowTextEdit: boolean; + buttons: string[]; + cb: (event: EditorFinishEvent) => void; + editorTarget: EditorTarget; + index = 0; + isClosed = false; + link: string; + linkEditorIsOpen: boolean; + nodeType: string; + parentNode: HTMLElement; + root!: HTMLElement; + secondRow?: HTMLDivElement; + text: string; + toolbar!: Toolbar; + + static openInstance: Editor | null = null; // ~~~~~~~~~ Initialization functions ~~~~~~~~~ // - constructor(parentNode, editorTarget, editorOptions, cb) { + constructor(parentNode: HTMLElement, editorTarget: EditorTarget, editorOptions: EditorOptions, cb: (event: EditorFinishEvent) => void) { this.cb = cb; // callback function this.buttons = editorOptions.buttons; // ["link", "delete", "cancel"]; this.parentNode = parentNode; // the parent node of the edit target @@ -49,13 +51,13 @@ export default class Editor { this.root = this.html(); this.parentNode.replaceChild( this.root, - this.parentNode.querySelector("#" + this.editorTarget.id) + this.parentNode.querySelector("#" + this.editorTarget.id)! ); const children = this.parentNode.children; // loop over all for (let i = 0; i < children.length; i++) { - if (children[i].classList.contains("editor")) { + if (children[i]!.classList.contains("editor")) { this.index = i; break; } @@ -87,7 +89,7 @@ export default class Editor { #setMouseDownListener = () => { document.addEventListener("mousedown", (e) => { - if (this.root.contains(e.target)) return; + if (e.target instanceof Node && this.root.contains(e.target)) return; this.save(); }); }; @@ -108,7 +110,7 @@ export default class Editor { this.link = input.value; if (e.keyCode === 13 && input === document.activeElement) { e.preventDefault(); - this.save(this.root.parentNode); + this.save(this.root.parentNode ?? undefined); } }); @@ -117,7 +119,7 @@ export default class Editor { }; // creates an input field - #createInputField(li) { + #createInputField(li: HTMLElement) { // create input field const input = document.createElement("input"); @@ -126,7 +128,7 @@ export default class Editor { input.addEventListener("keyup", (e) => { this.text = input.value; if (e.keyCode === 13 && input === document.activeElement) { - this.save(li.parentNode); + this.save(li.parentNode ?? undefined); } }); if (!this.allowTextEdit) input.disabled = true; @@ -134,7 +136,7 @@ export default class Editor { } // creates the toolbar html - #createToolbar(li) { + #createToolbar(li: HTMLElement) { this.toolbar = new Toolbar(this.buttons, (buttonName) => { console.log(buttonName); if (buttonName === "cancel") { @@ -148,7 +150,7 @@ export default class Editor { return this.toolbar.html(); } - #toggleLinkInput(li) { + #toggleLinkInput(li: HTMLElement) { if (this.linkEditorIsOpen) { this.#closeLinkInput(li); this.toolbar.linkButton.classList.remove("active"); @@ -158,7 +160,7 @@ export default class Editor { } } - #openLinkInput(li) { + #openLinkInput(li: HTMLElement) { li.appendChild(this.#secondRowHtml()); } @@ -200,7 +202,7 @@ export default class Editor { #closeLinkInput(_li?: Node): Promise { if (!this.linkEditorIsOpen) return Promise.resolve(); return new Promise((resolve) => { - const linkInput = this.root.querySelector(".secondRow"); + const linkInput = this.root.querySelector(".secondRow")!; linkInput.classList.add("slide-down-animate-out"); linkInput.onanimationend = () => { this.linkEditorIsOpen = false; diff --git a/app/src/views/tree/editTree/editor/components/toolbar.ts b/app/src/views/tree/editTree/editor/components/toolbar.ts index 1dcf1aa..26709d4 100644 --- a/app/src/views/tree/editTree/editor/components/toolbar.ts +++ b/app/src/views/tree/editTree/editor/components/toolbar.ts @@ -4,13 +4,13 @@ import Button from "../../../../other/button.js"; export default class Toolbar { - buttons: any; - cancelButton: any; - cb: any; - deleteButton: any; - linkButton: any; + buttons: string[]; + cancelButton?: HTMLDivElement; + cb: (button: string) => void; + deleteButton?: HTMLDivElement; + linkButton!: HTMLDivElement; - constructor(buttons, cb) { + constructor(buttons: string[], cb: (button: string) => void) { this.cb = cb; // callback function this.buttons = buttons; // ["link", "delete", "cancel"]; } diff --git a/app/src/views/tree/editTree/editor/events/editorFinishEvent.ts b/app/src/views/tree/editTree/editor/events/editorFinishEvent.ts index 468dc62..acb63db 100644 --- a/app/src/views/tree/editTree/editor/events/editorFinishEvent.ts +++ b/app/src/views/tree/editTree/editor/events/editorFinishEvent.ts @@ -3,11 +3,11 @@ // ====================================================== // export default class EditorFinishEvent { - editResult: any; - index: any; - type: any; + editResult: { text: string; link: string } | null; + index: number; + type: string; - constructor(type, editResult, index) { + constructor(type: string, editResult: { text: string; link: string } | null, index: number) { this.type = type; // either "save", "cancel" or "delete" this.editResult = editResult; // { text, link } this.index = index; // index of the edited item in the parent node diff --git a/app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts b/app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts index eae2771..3332a18 100644 --- a/app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts +++ b/app/src/views/tree/editTree/editor/helperObjects/editorOptions.ts @@ -3,10 +3,10 @@ // ====================================================== // export default class EditorOptions { - allowTextEdit: any; - buttons: any; - nodeType: any; - openWithLinkInput: any; + allowTextEdit: boolean; + buttons: string[]; + nodeType: string; + openWithLinkInput: boolean; constructor({ allowTextEdit, openWithLinkInput, buttons, nodeType }: { allowTextEdit?: boolean; diff --git a/app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts b/app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts index a972f1d..9d867b4 100644 --- a/app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts +++ b/app/src/views/tree/editTree/editor/helperObjects/editorTarget.ts @@ -3,11 +3,11 @@ // ====================================================== // export default class editorTarget { - id: any; - text: any; - url: any; + id: string; + text: string; + url: string; - constructor(text, url, id) { + constructor(text: string, url: string | null, id: string) { this.text = text ?? ""; // text to be edited this.url = url ?? "#"; // url to be edited this.id = id; // id of the edited item diff --git a/app/src/views/tree/editTree/events/treeUpdateEvent.ts b/app/src/views/tree/editTree/events/treeUpdateEvent.ts index 2e3b972..6adc878 100644 --- a/app/src/views/tree/editTree/events/treeUpdateEvent.ts +++ b/app/src/views/tree/editTree/events/treeUpdateEvent.ts @@ -2,24 +2,24 @@ // =================== TreeUpdateEvent ================== // // ====================================================== // -export default class TreeUpdateEvent { - newObject: any; - type: any; - updatedObject: any; +export default class TreeUpdateEvent { + newObject: T | undefined; + type: string; + updatedObject: T; static legalTypes = ["save", "delete", "add"]; constructor({ type, updatedObject, newObject }: { type: string; - updatedObject: unknown; - newObject?: unknown; + updatedObject: T; + newObject?: T; }) { this.type = this.checkType(type); // event type, must be one of legalTypes this.updatedObject = updatedObject; // the updated object this.newObject = newObject; // the new object (if available) } - checkType(type) { + checkType(type: string) { if (!TreeUpdateEvent.legalTypes.includes(type)) { throw new Error( "TreeUpdateEvent: type must be 'save', 'cancel', or 'delete'. Found: " + diff --git a/app/src/views/tree/themechanger/theme-changer.ts b/app/src/views/tree/themechanger/theme-changer.ts index f62d148..1ebef7f 100644 --- a/app/src/views/tree/themechanger/theme-changer.ts +++ b/app/src/views/tree/themechanger/theme-changer.ts @@ -4,7 +4,7 @@ import ThemeItem from "./themeItem.js"; export default class ThemeChanger { - themeNr: any; + themeNr: number; themeChanger = document.createElement("div"); selectedThemeId = 2; @@ -43,15 +43,15 @@ export default class ThemeChanger { themeCssLink = document.querySelector("link[href='../styles/colors.css']"); - constructor(config) { + constructor(config: { nr?: number }) { this.themeNr = config.nr ?? 0; this.addListener(); this.addListenerMouseLeave(); - this.changeTheme(this.THEMES[this.themeNr]); + this.changeTheme(this.THEMES[this.themeNr] ?? this.THEMES[0]!); } - changeTheme(nameTheme) { - this.themeCssLink.href = `../themes/${nameTheme}.css`; + changeTheme(nameTheme: string) { + this.themeCssLink!.href = `../themes/${nameTheme}.css`; } html() { @@ -75,7 +75,7 @@ export default class ThemeChanger { (this.themeChanger.childNodes[this.selectedThemeId] as HTMLElement).id = "selected"; // Insert selected theme on the top this.themeChanger.insertBefore( - this.themeChanger.childNodes[this.selectedThemeId], + this.themeChanger.childNodes[this.selectedThemeId]!, this.themeChanger.firstChild ); @@ -92,8 +92,8 @@ export default class ThemeChanger { this.changeTheme(target.id); const selectedTheme = document.querySelector("#selected"); - selectedTheme.removeAttribute("id"); - target.parentElement.id = "selected"; + selectedTheme?.removeAttribute("id"); + target.parentElement!.id = "selected"; } }); }; @@ -102,7 +102,7 @@ export default class ThemeChanger { this.themeChanger.addEventListener("mouseleave", function (event) { const selectedTheme = document.querySelector("#selected"); const target = event.currentTarget as HTMLElement; - target.insertBefore(selectedTheme, target.firstChild); + if (selectedTheme) target.insertBefore(selectedTheme, target.firstChild); target.scrollTop = 0; }); }; diff --git a/app/src/views/tree/themechanger/themeItem.ts b/app/src/views/tree/themechanger/themeItem.ts index cadc983..47b817d 100644 --- a/app/src/views/tree/themechanger/themeItem.ts +++ b/app/src/views/tree/themechanger/themeItem.ts @@ -3,13 +3,13 @@ // ====================================================== // export default class ThemeItem { - name: any; + name: string; static themeCssLink = document.querySelector( "link[href='./styles/colors.css']" ); - constructor(themeName) { + constructor(themeName: string) { this.name = themeName; } diff --git a/package.json b/package.json index 5718e64..f4087a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { "name": "starttree-v3", "private": true, + "scripts": { + "typecheck": "tsc --noEmit" + }, "devDependencies": { "typescript": "^5.9.3" } diff --git a/tsconfig.json b/tsconfig.json index 6494dd0..5449079 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,15 @@ "rootDir": "app/src", "outDir": "dist/src", "skipLibCheck": true, - "noImplicitAny": false, + "strict": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noPropertyAccessFromIndexSignature": true, "noEmitOnError": true }, "include": ["app/src/**/*.ts"]