diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0607ac4..670c451 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.231.3/containers/javascript-node { - "name": "Node.js", + "name": "Schmackhaft", "build": { "dockerfile": "Dockerfile", // Update 'VARIANT' to pick a Node version: 16, 14, 12. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1645c0c..10cd1db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.2.0 + +- Auto-Focus the "quicksearch" field +- Provide keyboard shortcuts to navigate links when using the quicksearch. + # 1.1.0 - Fix scrolling issue in the settings & help page diff --git a/Makefile b/Makefile index 4c8667b..85abbf6 100644 --- a/Makefile +++ b/Makefile @@ -13,17 +13,17 @@ mozilla: pages bundled_docs chrome: pages bundled_docs mkdir -p unpackaged/chrome/src/core cp -r build/pages/* unpackaged/chrome/ - inkscape -w 48 -h 48 public/assets/icon.svg \ + inkscape -w 48 -h 48 assets/icon.svg \ -o unpackaged/chrome/assets/icon48.png || \ - inkscape -w 48 -h 48 public/assets/icon.svg \ + inkscape -w 48 -h 48 assets/icon.svg \ -e unpackaged/chrome/assets/icon48.png - inkscape -w 96 -h 96 public/assets/icon.svg \ + inkscape -w 96 -h 96 assets/icon.svg \ -o unpackaged/chrome/assets/icon96.png || \ - inkscape -w 96 -h 96 public/assets/icon.svg \ + inkscape -w 96 -h 96 assets/icon.svg \ -e unpackaged/chrome/assets/icon96.png - inkscape -w 128 -h 128 public/assets/icon.svg \ + inkscape -w 128 -h 128 assets/icon.svg \ -o unpackaged/chrome/assets/icon128.png || \ - inkscape -w 128 -h 128 public/assets/icon.svg \ + inkscape -w 128 -h 128 assets/icon.svg \ -e unpackaged/chrome/assets/icon128.png sed -e 's/__version__/$(CURRENT_VERSION)/' \ manifest-chrome.json > unpackaged/chrome/manifest.json diff --git a/TODO b/TODO index ff8d1d7..60e0b9f 100644 --- a/TODO +++ b/TODO @@ -3,5 +3,5 @@ - Add default tags per source - Replace arrays with sets where possible - Add a name to each source -- Add default tags to each source - Deduplicate bookmarks (if more than one source has the same bookmark, it is added with duplicates) +- Is "postcss" still needed? diff --git a/public/assets/icon.png b/assets/icon.png similarity index 100% rename from public/assets/icon.png rename to assets/icon.png diff --git a/public/assets/icon.svg b/assets/icon.svg similarity index 100% rename from public/assets/icon.svg rename to assets/icon.svg diff --git a/demo/demo.ts b/demo/demo.ts index ff4c7fb..3a0a4a4 100644 --- a/demo/demo.ts +++ b/demo/demo.ts @@ -1,113 +1,164 @@ -import "../src/components/views/sh-settings"; -import "../src/components/components/layout-vsplit"; +import "../src/views/sh-settings"; +import "../src/components/layout-vsplit"; import { BookmarkSource } from "../src/types"; import { FakeBrowser } from "./fake-browser"; +import { Schmackhaft } from "../src/app-schmackhaft"; import { Settings } from "../src/model/settings"; -import { SettingsBridge } from "../src/core/settings"; +import { Settings as SettingsElement } from "../src/views/sh-settings"; -let settingsElementV1 = document.getElementById("SettingsV1") as SettingsBridge; -let settingsElementV2 = document.getElementById("SettingsV2") as SettingsBridge; -settingsElementV2.settings = JSON.stringify({ - remoteUrls: [ - "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", - "https://demo-2.json", - ], - enableBrowserBookmarks: true, - version: 2, -}); -settingsElementV2.addEventListener("change", (event) => { - console.log(JSON.parse(event.detail["settings"])); -}); +/** + * Initialise the HTML elements which are used to play with the component + * settings + */ +function initSettingsUI() { + let settingsElementV1 = document.getElementById( + "SettingsV1" + ) as SettingsElement; + let settingsElementV2 = document.getElementById( + "SettingsV2" + ) as SettingsElement; + settingsElementV2.settings = JSON.stringify({ + remoteUrls: [ + "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", + "https://demo-2.json", + ], + enableBrowserBookmarks: true, + version: 2, + }); + settingsElementV2.addEventListener("change", (event) => { + let evt = event as CustomEvent; + console.log(JSON.parse(evt.detail["settings"])); + }); -settingsElementV1.settings = JSON.stringify({ - remoteUrl: - "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", - version: 1, -}); + settingsElementV1.settings = JSON.stringify({ + remoteUrl: + "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", + version: 1, + }); +} -let bookmarksElement = document.getElementById("schmackhaft"); +/** + * Initialise a core "schmackhaft custom-element" + */ +function initSchmackhaftUI() { + let bookmarksElement = document.getElementById("schmackhaft") as Schmackhaft; -// We can't use the default settings bridge here, because this only works in a -// browser-extension execution context. -let settings = new Settings( - [ - { - type: BookmarkSource.HTTP, - settings: { - url: "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", + // We can't use the default settings bridge here, because this only works in a + // browser-extension execution context. + let settings = new Settings( + [ + { + type: BookmarkSource.HTTP, + settings: { + url: "https://raw.githubusercontent.com/exhuma/dotfiles/master/bookmarks.json", + }, }, - }, - { - type: BookmarkSource.HTTP, - settings: { - url: "https://raw.githubusercontent.com/exhuma/schmackhaft/e6439061eedd24c50e00e8b2374ec50d376bc6e5/docs/examples/external-file.json", + { + type: BookmarkSource.HTTP, + settings: { + url: "https://raw.githubusercontent.com/exhuma/schmackhaft/e6439061eedd24c50e00e8b2374ec50d376bc6e5/docs/examples/external-file.json", + }, }, - }, - { - type: BookmarkSource.BROWSER, - settings: {}, - }, - { - type: BookmarkSource.EXTENSION_STORAGE, - settings: {}, - }, - ], - 3 -); -bookmarksElement.settings = settings.toJson(); -bookmarksElement?.addEventListener("settingsChanged", (event) => { - console.log("Settings Changed to:"); - console.log(JSON.parse(event.detail["settings"])); -}); -bookmarksElement.injections = { getBrowser: async () => new FakeBrowser() }; + { + type: BookmarkSource.BROWSER, + settings: {}, + }, + { + type: BookmarkSource.EXTENSION_STORAGE, + settings: {}, + }, + ], + 3 + ); + bookmarksElement.settings = settings.toJson(); + bookmarksElement?.addEventListener("settingsChanged", (event) => { + let evt = event as CustomEvent; + console.log("Settings Changed to:"); + console.log(JSON.parse(evt.detail["settings"])); + }); + bookmarksElement.injections = { getBrowser: async () => new FakeBrowser() }; +} /** - * Ensure only the div related to the clicked link is visible + * Toggle the visibility of a single element with the "togglable" class. * - * @param evt A click-event from the browser + * All "togglable" elements will be hidden *except* the one with the given + * SGML-ID + * + * @param id The ID of the element which should become/remain visible. */ -function toggleDiv(evt) { - let enabledName = evt.target.dataset["div"]; +function toggleDiv(id: string): void { document.querySelectorAll(".toggleable").forEach((element) => { - let currentName = element.id; - let displayValue = enabledName === currentName ? "block" : "none"; - element.style.display = displayValue; + let elmt = element as HTMLElement; + let currentName = elmt.id; + let displayValue = id === currentName ? "block" : "none"; + elmt.style.display = displayValue; }); } -document.querySelectorAll(".clickable").forEach((element) => { - element.addEventListener("click", toggleDiv); -}); +/** + * Delegate click events to the visibility "toggler". The clicked element *must* + * have the attribute "data-div" with the SGML-ID as value of the element that + * should be displayed. + * + * @param evt A click-event from the browser + */ +function onTabClicked(evt: Event) { + let enabledName = evt.target.dataset["div"]; + toggleDiv(enabledName); +} /** * Update bookmarks from an external JSON file * * @param url The URL from which to fetch the JSON */ -async function reloadJson(url) { +async function reloadJson(url: string) { if (url === undefined || url.trim() === "") { return; } - let response = await fetch(url); - if (!response.ok) { - console.error(`Unable to fetch ${url} (${response.statusText})`); - return; - } - let text = await response.text(); - let bookmarksElement = document.getElementById("schmackhaft"); - bookmarksElement.links = text; + let bookmarksElement = document.getElementById("schmackhaft") as Schmackhaft; + let settings = new Settings([ + { + type: BookmarkSource.HTTP, + settings: { + url: url, + }, + }, + ]); + bookmarksElement.settings = settings.toJson(); } -document.getElementById("ReloadJsonButton").addEventListener("click", () => { +/** + * Initialise the elements in the demo-page toolbar + */ +function initToolbar() { + document.getElementById("ReloadJsonButton").addEventListener("click", () => { + let txtJsonFile = document.getElementById( + "ExternalJsonFile" + ) as HTMLInputElement; + let url = txtJsonFile.value; + reloadJson(url); + }); + let txtJsonFile = document.getElementById("ExternalJsonFile"); - let url = txtJsonFile.value; - reloadJson(url); -}); + txtJsonFile.addEventListener("change", async (evt) => { + let target = evt.target as HTMLInputElement; + let url = target.value; + reloadJson(url); + }); -let txtJsonFile = document.getElementById("ExternalJsonFile"); -txtJsonFile.addEventListener("change", async (evt) => { - let url = evt.target.value; - reloadJson(url); -}); + document.querySelectorAll(".clickable").forEach((element) => { + element.addEventListener("click", onTabClicked); + }); +} -document.querySelector(".toggleable").style.display = "block"; +/** + * Initialise all UI elements for the demo page + */ +export function initUI() { + initSettingsUI(); + initSchmackhaftUI(); + initToolbar(); + toggleDiv("Bookmarks"); +} diff --git a/demo/fake-browser.ts b/demo/fake-browser.ts index b09bba3..c3c5406 100644 --- a/demo/fake-browser.ts +++ b/demo/fake-browser.ts @@ -30,7 +30,16 @@ class FakeStorage { } } +class FakeTabs { + create(createProperties: { url: string }) { + console.info(`Would open a new tab to the URL ${createProperties.url}`); + } +} + export class FakeBrowser { + tabs: FakeTabs = new FakeTabs(); + runtime: any; + get bookmarks() { return new BookmarkTree(); } diff --git a/demo/index.html b/demo/index.html index 8aff1ee..498fc56 100644 --- a/demo/index.html +++ b/demo/index.html @@ -5,8 +5,7 @@