From acb7ddf189c6520ea071fb78de937aa103cfb7c6 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Thu, 4 Jan 2024 14:27:04 +0100 Subject: [PATCH] Add Settings to web app (#125) * Add support for opening settings dialog in the webapp * Add tests for settings dialog * Hide stand-alone app specific settings in web app * Remove debug log --- assets/icons/settings.svg | 1 + electron/preload/index.ts | 1 + src/components/App.vue | 1 + src/components/StatusBar.vue | 41 +++++++++++++----- src/components/settings/Settings.vue | 8 ++-- src/components/settings/TabContent.vue | 2 +- src/components/settings/TabListItem.vue | 2 +- tests/basic-editing.spec.js | 1 - tests/formatting.spec.js | 1 - tests/language-detection.spec.js | 1 - tests/markdown.spec.js | 1 - tests/math.spec.js | 1 - tests/settings.spec.js | 40 +++++++++++++++++ tests/test-utils.js | 4 ++ webapp/bridge.js | 57 ++++++++++++++++++++++--- webapp/index.html | 5 ++- 16 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 assets/icons/settings.svg create mode 100644 tests/settings.spec.js diff --git a/assets/icons/settings.svg b/assets/icons/settings.svg new file mode 100644 index 0000000..77ae879 --- /dev/null +++ b/assets/icons/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 71267ef..bf0f7f0 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -25,6 +25,7 @@ contextBridge.exposeInMainWorld("heynote", { isWindows, isLinux, }, + isWebApp: false, themeMode: themeMode, diff --git a/src/components/App.vue b/src/components/App.vue index d689648..0588ada 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -135,6 +135,7 @@ @toggleTheme="toggleTheme" @openLanguageSelector="openLanguageSelector" @formatCurrentBlock="formatCurrentBlock" + @openSettings="showSettings = true" class="status" />
diff --git a/src/components/StatusBar.vue b/src/components/StatusBar.vue index b671a78..d2622fd 100644 --- a/src/components/StatusBar.vue +++ b/src/components/StatusBar.vue @@ -22,8 +22,14 @@ UpdateStatusItem, }, - mounted() { + data() { + return { + showSettingsButton: window.heynote.isWebApp, + } + }, + mounted() { + }, computed: { @@ -90,6 +96,14 @@ :autoUpdate="autoUpdate" :allowBetaVersions="allowBetaVersions" /> +
+ +
@@ -132,6 +146,12 @@ cursor: pointer &:hover background-color: rgba(255,255,255, 0.1) + .icon + display: block + width: 14px + height: 22px + +dark-mode + opacity: 0.9 .line-number color: rgba(255, 255, 255, 0.7) .num @@ -148,14 +168,9 @@ padding-top: 0 padding-bottom: 0 .icon - display: block - width: 14px - height: 22px background-size: 14px background-repeat: no-repeat background-position: center center - +dark-mode - opacity: 0.9 &.dark background-image: url("@/assets/icons/dark-mode.png") &.light @@ -167,14 +182,18 @@ padding-top: 0 padding-bottom: 0 .icon - display: block - width: 14px - height: 22px - +dark-mode - opacity: 0.9 background-size: 16px background-repeat: no-repeat background-position: center center background-image: url("@/assets/icons/format.svg") + + .settings + padding-top: 0 + padding-bottom: 0 + .icon + background-size: 13px + background-repeat: no-repeat + background-position: center center + background-image: url("@/assets/icons/settings.svg") diff --git a/src/components/settings/Settings.vue b/src/components/settings/Settings.vue index 72bee85..a202b02 100644 --- a/src/components/settings/Settings.vue +++ b/src/components/settings/Settings.vue @@ -33,6 +33,7 @@ autoUpdate: this.initialSettings.autoUpdate, activeTab: "general", + isWebApp: window.heynote.isWebApp, } }, @@ -89,6 +90,7 @@ @click="activeTab = 'appearance'" />
-
+

Global Keyboard Shortcut

-
+

Show In

- +

Auto Update

diff --git a/src/components/settings/TabContent.vue b/src/components/settings/TabContent.vue index 917d3df..0825281 100644 --- a/src/components/settings/TabContent.vue +++ b/src/components/settings/TabContent.vue @@ -4,7 +4,7 @@ computed: { className() { - return "tab-content " + (this.tab === this.activeTab ? "active" : "") + return "tab-content tab-" + this.tab + " " + (this.tab === this.activeTab ? "active" : "") } } } diff --git a/src/components/settings/TabListItem.vue b/src/components/settings/TabListItem.vue index 68c49a1..9fc53e4 100644 --- a/src/components/settings/TabListItem.vue +++ b/src/components/settings/TabListItem.vue @@ -4,7 +4,7 @@ computed: { tabClass() { - return this.tab === this.activeTab ? "active" : "" + return "tab-" + this.tab + " " + (this.tab === this.activeTab ? "active" : "") } } } diff --git a/tests/basic-editing.spec.js b/tests/basic-editing.spec.js index 797a6fd..b5bdff5 100644 --- a/tests/basic-editing.spec.js +++ b/tests/basic-editing.spec.js @@ -4,7 +4,6 @@ import { HeynotePage } from "./test-utils.js"; let heynotePage test.beforeEach(async ({ page }) => { - console.log("beforeEach") heynotePage = new HeynotePage(page) await heynotePage.goto() }); diff --git a/tests/formatting.spec.js b/tests/formatting.spec.js index 76d91ae..5b5bbac 100644 --- a/tests/formatting.spec.js +++ b/tests/formatting.spec.js @@ -4,7 +4,6 @@ import { HeynotePage } from "./test-utils.js"; let heynotePage test.beforeEach(async ({ page }) => { - console.log("beforeEach") heynotePage = new HeynotePage(page) await heynotePage.goto() }) diff --git a/tests/language-detection.spec.js b/tests/language-detection.spec.js index 6d5868d..3f07418 100644 --- a/tests/language-detection.spec.js +++ b/tests/language-detection.spec.js @@ -4,7 +4,6 @@ import { HeynotePage } from "./test-utils.js"; let heynotePage test.beforeEach(async ({ page }) => { - console.log("beforeEach") heynotePage = new HeynotePage(page) await heynotePage.goto() }) diff --git a/tests/markdown.spec.js b/tests/markdown.spec.js index d174c13..38b2b1f 100644 --- a/tests/markdown.spec.js +++ b/tests/markdown.spec.js @@ -4,7 +4,6 @@ import { HeynotePage } from "./test-utils.js"; let heynotePage test.beforeEach(async ({ page }) => { - console.log("beforeEach") heynotePage = new HeynotePage(page) await heynotePage.goto() }); diff --git a/tests/math.spec.js b/tests/math.spec.js index d6913e5..8f69d72 100644 --- a/tests/math.spec.js +++ b/tests/math.spec.js @@ -4,7 +4,6 @@ import { HeynotePage } from "./test-utils.js"; let heynotePage test.beforeEach(async ({ page }) => { - console.log("beforeEach") heynotePage = new HeynotePage(page) await heynotePage.goto() }); diff --git a/tests/settings.spec.js b/tests/settings.spec.js new file mode 100644 index 0000000..67f2232 --- /dev/null +++ b/tests/settings.spec.js @@ -0,0 +1,40 @@ +import { test, expect } from "@playwright/test"; +import { HeynotePage } from "./test-utils.js"; + +let heynotePage + +test.beforeEach(async ({ page }) => { + heynotePage = new HeynotePage(page) + await heynotePage.goto() +}); + + +test("test open settings dialog", async ({ page }) => { + await page.locator("css=.status-block.settings").click() + await expect(page.locator("css=.overlay .settings .dialog")).toBeVisible() +}) + +test("test close settings dialog", async ({ page }) => { + await page.locator("css=.status-block.settings").click() + await page.locator("css=.overlay .settings .dialog .bottom-bar .close").click() + await expect(page.locator("css=.overlay .settings .dialog")).not.toBeVisible() +}) + +test("test close settings dialog with escape", async ({ page }) => { + await page.locator("css=.status-block.settings").click() + await page.locator("body").press("Escape") + await expect(page.locator("css=.overlay .settings .dialog")).not.toBeVisible() +}) + +test("test change line gutter setting", async ({ page }) => { + await expect(page.locator("css=.cm-lineNumbers")).toBeVisible() + await page.locator("css=.status-block.settings").click() + await page.locator("css=.overlay .settings .dialog .sidebar li.tab-appearance").click() + await expect(page.locator("css=.settings .tab-content.tab-appearance")).toBeVisible() + await page.getByLabel("Show line numbers").click() + await expect(page.locator("css=.cm-lineNumbers")).toBeHidden() + expect((await heynotePage.getStoredSettings()).showLineNumberGutter).toBe(false) + await page.getByLabel("Show line numbers").click() + await expect(page.locator("css=.cm-lineNumbers")).toBeVisible() + expect((await heynotePage.getStoredSettings()).showLineNumberGutter).toBe(true) +}) diff --git a/tests/test-utils.js b/tests/test-utils.js index 93a29ae..d249170 100644 --- a/tests/test-utils.js +++ b/tests/test-utils.js @@ -42,4 +42,8 @@ export class HeynotePage { const block = blocks[blockIndex] return content.slice(block.content.from, block.content.to) } + + async getStoredSettings() { + return await this.page.evaluate(() => JSON.parse(window.localStorage.getItem("settings"))) + } } diff --git a/webapp/bridge.js b/webapp/bridge.js index 0183e69..3ce14d1 100644 --- a/webapp/bridge.js +++ b/webapp/bridge.js @@ -1,3 +1,5 @@ +import { SETTINGS_CHANGE_EVENT, OPEN_SETTINGS_EVENT } from "../electron/constants"; + const mediaMatch = window.matchMedia('(prefers-color-scheme: dark)') let themeCallback = null mediaMatch.addEventListener("change", async (event) => { @@ -31,8 +33,46 @@ if (uaPlatform.indexOf("Win") !== -1) { } } + +class IpcRenderer { + constructor() { + this.callbacks = {} + } + + on(event, callback) { + if (!this.callbacks[event]) { + this.callbacks[event] = [] + } + this.callbacks[event].push(callback) + } + + send(event, ...args) { + if (this.callbacks[event]) { + for (const callback of this.callbacks[event]) { + callback(null, ...args) + } + } + } +} + +const ipcRenderer = new IpcRenderer() + +// get initial settings +let settingsData = localStorage.getItem("settings") +let initialSettings = { + keymap: "default", + emacsMetaKey: "meta", + showLineNumberGutter: true, + showFoldGutter: true, +} +if (settingsData !== null) { + initialSettings = Object.assign(initialSettings, JSON.parse(settingsData)) +} + + const Heynote = { platform: platform, + isWebApp: true, buffer: { async load() { @@ -57,12 +97,19 @@ const Heynote = { //ipcRenderer.on(WINDOW_CLOSE_EVENT, callback) }, + settings: initialSettings, + onOpenSettings(callback) { - //ipcRenderer.on(OPEN_SETTINGS_EVENT, callback) + ipcRenderer.on(OPEN_SETTINGS_EVENT, callback) }, onSettingsChange(callback) { - //ipcRenderer.on(SETTINGS_CHANGE_EVENT, (event, settings) => callback(settings)) + ipcRenderer.on(SETTINGS_CHANGE_EVENT, (event, settings) => callback(settings)) + }, + + setSettings(settings) { + localStorage.setItem("settings", JSON.stringify(settings)) + ipcRenderer.send(SETTINGS_CHANGE_EVENT, settings) }, themeMode: { @@ -88,10 +135,6 @@ const Heynote = { initial: localStorage.getItem("theme") || "system", }, - settings: { - keymap: "default", - }, - getCurrencyData: async () => { if (currencyData !== null) { return currencyData @@ -102,4 +145,4 @@ const Heynote = { }, } -export default Heynote +export { Heynote, ipcRenderer} diff --git a/webapp/index.html b/webapp/index.html index 9f88204..dba49a6 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -11,8 +11,9 @@