From 8644af612840af14c7248b40175bf0cf182e162e Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Wed, 26 Aug 2026 04:30:44 +0000 Subject: [PATCH] Narrow mobile settings layout fix --- .../SettingDialogue/ObsidianLiveSyncSettingTab.ts | 12 +----------- src/modules/features/SettingDialogue/PanePatches.ts | 2 +- .../SettingDialogue/PanePatches.unit.spec.ts | 2 +- .../features/SettingDialogue/PaneRemoteConfig.ts | 2 +- .../SettingDialogue/PaneRemoteConfig.unit.spec.ts | 6 +++++- styles.css | 10 +++------- test/e2e-obsidian/scripts/settings-ui.ts | 12 ------------ 7 files changed, 12 insertions(+), 34 deletions(-) diff --git a/src/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.ts b/src/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.ts index b4e7e779..38c1be92 100644 --- a/src/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.ts +++ b/src/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.ts @@ -82,14 +82,6 @@ import { isP2PMainRemote } from "@/common/remoteConfiguration.ts"; // For creating a document // const toc = new Set(); -function registerLiveSyncSettingsModal(component: Component, containerEl: HTMLElement | undefined): void { - if (!containerEl) return; - const modalEl = containerEl.closest(".modal.mod-settings"); - if (!modalEl) return; - modalEl.addClass("sls-setting-modal"); - component.register(() => modalEl.removeClass("sls-setting-modal")); -} - export class ObsidianLiveSyncSettingTab extends PluginSettingTab { plugin: ObsidianLiveSyncPlugin; private _lifetimeComponent?: Component; @@ -709,7 +701,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { private renderCustomPage(page: SettingPage, entry: SettingsPageEntry): Component { if (requireApiVersion("1.13.0")) { const component = this.beginRenderScope(() => page.display()); - registerLiveSyncSettingsModal(component, this.containerEl); this.isShown = true; page.title = entry.name(); page.containerEl.empty(); @@ -1092,9 +1083,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { private displayImperative(): void { const changeDisplay = this.changeDisplay.bind(this); // Make sure the page-owned component is loaded for markdown rendering in panes. - const component = this.beginRenderScope(() => this.displayImperative()); + this.beginRenderScope(() => this.displayImperative()); const { containerEl } = this; - registerLiveSyncSettingsModal(component, containerEl); this.screenElements = {}; if (this._editingSettings == undefined || this.initialSettings == undefined) { this.reloadAllSettings(); diff --git a/src/modules/features/SettingDialogue/PanePatches.ts b/src/modules/features/SettingDialogue/PanePatches.ts index 5b0262ce..9c813404 100644 --- a/src/modules/features/SettingDialogue/PanePatches.ts +++ b/src/modules/features/SettingDialogue/PanePatches.ts @@ -177,7 +177,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen new Setting(paneEl).autoWireToggle("disableCheckingConfigMismatch"); }); void addPanel(paneEl, "Remediation").then((paneEl) => { - const setting = new Setting(paneEl).setClass("sls-setting-mobile-wrap-controls"); + const setting = new Setting(paneEl).setClass("sls-setting-subsequent-buttons"); const dateEl = setting.controlEl.createSpan(); setting .addText((text) => { diff --git a/src/modules/features/SettingDialogue/PanePatches.unit.spec.ts b/src/modules/features/SettingDialogue/PanePatches.unit.spec.ts index 9ed2a25b..efc10bcf 100644 --- a/src/modules/features/SettingDialogue/PanePatches.unit.spec.ts +++ b/src/modules/features/SettingDialogue/PanePatches.unit.spec.ts @@ -100,6 +100,6 @@ describe("panePatches remediation setting", () => { expect(createSpan).not.toHaveBeenCalled(); expect(remediationHarness.createSpan).toHaveBeenCalledOnce(); expect(remediationHarness.dateElement.textContent).toBe("No limit configured"); - expect(remediationHarness.setClass).toHaveBeenCalledWith("sls-setting-mobile-wrap-controls"); + expect(remediationHarness.setClass).toHaveBeenCalledWith("sls-setting-subsequent-buttons"); }); }); diff --git a/src/modules/features/SettingDialogue/PaneRemoteConfig.ts b/src/modules/features/SettingDialogue/PaneRemoteConfig.ts index 5ecbabeb..a8700ea2 100644 --- a/src/modules/features/SettingDialogue/PaneRemoteConfig.ts +++ b/src/modules/features/SettingDialogue/PaneRemoteConfig.ts @@ -107,7 +107,7 @@ export function paneRemoteConfig( this.lifetimeComponent.register(() => infoPanel.destroy()); const setupButton = new Setting(paneEl) .setName("Configure E2EE") - .setClass("sls-setting-mobile-wrap-controls"); + .setClass("sls-setting-subsequent-buttons"); setupButton .addButton((button) => setButtonDestructiveState(button) diff --git a/src/modules/features/SettingDialogue/PaneRemoteConfig.unit.spec.ts b/src/modules/features/SettingDialogue/PaneRemoteConfig.unit.spec.ts index 8853fad7..5417800c 100644 --- a/src/modules/features/SettingDialogue/PaneRemoteConfig.unit.spec.ts +++ b/src/modules/features/SettingDialogue/PaneRemoteConfig.unit.spec.ts @@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from "vitest"; const runtime = vi.hoisted(() => ({ panels: [] as Array<{ destroy: ReturnType }>, + settingClasses: [] as string[], })); vi.mock("@vrtmrz/livesync-commonlib/compat/common/types", () => ({ @@ -30,7 +31,8 @@ vi.mock("./LiveSyncSetting.ts", () => ({ return this; } - setClass() { + setClass(value: string) { + runtime.settingClasses.push(value); return this; } @@ -90,6 +92,7 @@ function createPanelElement(): HTMLElement { afterEach(() => { runtime.panels.length = 0; + runtime.settingClasses.length = 0; vi.clearAllMocks(); }); @@ -109,6 +112,7 @@ describe("paneRemoteConfig", () => { paneRemoteConfig.call(host as never, {} as HTMLElement, { addPanel } as never); await vi.waitFor(() => expect(runtime.panels).toHaveLength(1)); + expect(runtime.settingClasses).toContain("sls-setting-subsequent-buttons"); lifetimeComponent.unload(); diff --git a/styles.css b/styles.css index 5dddf444..717253b1 100644 --- a/styles.css +++ b/styles.css @@ -547,24 +547,20 @@ body.is-mobile .sls-setting button { white-space: normal; } -body.is-mobile .sls-setting-mobile-wrap-controls { +body.is-mobile .sls-setting-subsequent-buttons { flex-wrap: wrap; } -body.is-mobile .sls-setting-mobile-wrap-controls .setting-item-control { +body.is-mobile .sls-setting-subsequent-buttons .setting-item-control { min-width: 0; flex: 1 1 100%; flex-wrap: wrap; } -body.is-mobile .sls-setting-mobile-wrap-controls .setting-item-control > button { +body.is-mobile .sls-setting-subsequent-buttons .setting-item-control > button { flex: 1 1 12rem; } -body.is-mobile .modal.mod-settings.sls-setting-modal .modal-header { - background-color: var(--background-primary); -} - .active-pane .sls-setting-panel-title { border: 1px solid var(--interactive-accent); } diff --git a/test/e2e-obsidian/scripts/settings-ui.ts b/test/e2e-obsidian/scripts/settings-ui.ts index 5d9a3396..dcfae599 100644 --- a/test/e2e-obsidian/scripts/settings-ui.ts +++ b/test/e2e-obsidian/scripts/settings-ui.ts @@ -241,10 +241,6 @@ async function captureDeclarativeMobileSettings(): Promise< if (infoPanel === null || infoPanel === undefined) { throw new Error("The E2EE section did not contain its information panel."); } - const modalHeader = heading.closest(".modal.mod-settings")?.querySelector(".modal-header"); - if (modalHeader === null || modalHeader === undefined) { - throw new Error("The mobile settings page did not contain its native header."); - } const headingBounds = heading.getBoundingClientRect(); const infoBounds = infoPanel.getBoundingClientRect(); return { @@ -253,7 +249,6 @@ async function captureDeclarativeMobileSettings(): Promise< headingTop: headingBounds.top, infoBottom: infoBounds.bottom, infoTop: infoBounds.top, - modalHeaderBackground: getComputedStyle(modalHeader).backgroundColor, }; }); if ( @@ -262,13 +257,6 @@ async function captureDeclarativeMobileSettings(): Promise< ) { layoutFailures.push(`the E2EE section heading overlapped its contents (${JSON.stringify(panelLayout)})`); } - if ( - panelLayout.modalHeaderBackground === "transparent" || - panelLayout.modalHeaderBackground === "rgba(0, 0, 0, 0)" - ) { - layoutFailures.push("the native mobile settings header remained transparent over scrolling content"); - } - const remotePath = `${diagnosticsDirectory}/settings-declarative-remote-mobile.png`; await settingsNavigator.dialogue.screenshot({ ...settingsScreenshotOptions, path: remotePath }); if (layoutFailures.length > 0) {