From 96ec12f2bddd8774b13968941f11865d837a2027 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Thu, 27 Nov 2025 16:36:26 +0000 Subject: [PATCH] settings: hide groups if all children are hidden only really affects the "Email" group when messages|enabled is false. --- config/config-base.yaml | 1 + css/base.css | 7 - ts/modules/settings.ts | 281 ++++++++++++++++++++++++++++------------ ts/tsconfig.json | 2 +- 4 files changed, 200 insertions(+), 91 deletions(-) diff --git a/config/config-base.yaml b/config/config-base.yaml index 53be7fd..7d486d3 100644 --- a/config/config-base.yaml +++ b/config/config-base.yaml @@ -790,6 +790,7 @@ sections: - ["smtp", "SMTP"] - ["mailgun", "Mailgun"] value: smtp + depends_true: messages|enabled description: Method of sending email to use. - setting: address name: Sent from (address) diff --git a/css/base.css b/css/base.css index 2c084c2..14de8f7 100644 --- a/css/base.css +++ b/css/base.css @@ -221,15 +221,8 @@ sup.\~critical, .text-critical { padding-bottom: 0.1rem; } -.settings-section-button { - width: 100%; - height: 2.5rem; -} - .settings-section-button:hover, .settings-section-button:focus { box-sizing: border-box; - width: 100%; - height: 2.5rem; background-color: var(--color-neutral-normal-fill); filter: brightness(var(--settings-section-button-filter)) !important; } diff --git a/ts/modules/settings.ts b/ts/modules/settings.ts index 43695f5..92b7d24 100644 --- a/ts/modules/settings.ts +++ b/ts/modules/settings.ts @@ -1,6 +1,7 @@ import { _get, _post, _delete, _download, _upload, toggleLoader, addLoader, removeLoader, insertText, toClipboard, toDateString } from "../modules/common.js"; import { Marked } from "@ts-stack/markdown"; import { stripMarkdown } from "../modules/stripmd.js"; +import { PDT } from "src/data/timezoneNames"; declare var window: GlobalWindow; @@ -176,7 +177,7 @@ class DOMSetting {
- +
@@ -191,10 +192,10 @@ class DOMSetting { // "input" variable should supply the HTML of an element with class "setting-input" this._input = this._container.querySelector(".setting-input") as HTMLInputElement; if (setting.depends_false || setting.depends_true) { - let dependant = splitDependant(section, setting.depends_true || setting.depends_false); + let [sect, dependant] = splitDependant(section, setting.depends_true || setting.depends_false); let state = true; if (setting.depends_false) { state = false; } - document.addEventListener(`settings-${dependant[0]}-${dependant[1]}`, (event: settingsChangedEvent) => { + document.addEventListener(`settings-${sect}-${dependant}`, (event: settingsChangedEvent) => { if (toBool(event.detail) !== state) { this.hide(); } else { @@ -478,9 +479,29 @@ interface Group { members: Member[]; } -class groupButton { - private _el: HTMLElement; - private _button: HTMLElement; +abstract class groupableItem { + protected _el: HTMLElement; + asElement = () => { return this._el; } + remove = () => { this._el.remove(); }; + inGroup = (): string|null => { return this._el.parentElement.getAttribute("data-group"); } + get hidden(): boolean { return this._el.classList.contains("unfocused"); } + set hidden(v: boolean) { + if (v) { + this._el.classList.add("unfocused"); + if (this.inGroup()) { + document.dispatchEvent(new CustomEvent(`settings-group-${this.inGroup()}-child-hidden`)); + } + } else { + this._el.classList.remove("unfocused"); + if (this.inGroup()) { + document.dispatchEvent(new CustomEvent(`settings-group-${this.inGroup()}-child-visible`)); + } + } + } +} + +class groupButton extends groupableItem { + button: HTMLElement; private _dropdown: HTMLElement; private _icon: HTMLElement; private _check: HTMLInputElement; @@ -489,6 +510,11 @@ class groupButton { private _parentSidebar: HTMLElement; private static readonly _margin = "ml-6"; + private _indentClasses = ["h-11", "h-10", "h-9"]; + private _indentClass = () => { + const classes = [["h-10"], ["h-9"]]; + return classes[Math.min(this.indent, classes.length-1)]; + }; asElement = () => { return this._el; }; @@ -503,8 +529,12 @@ class groupButton { append(item: HTMLElement|groupButton) { if (item instanceof groupButton) { + item.button.classList.remove(...this._indentClasses); + item.button.classList.add(...this._indentClass()); this._dropdown.appendChild(item.asElement()); } else { + item.classList.remove(...this._indentClasses); + item.classList.add(...this._indentClass()); this._dropdown.appendChild(item); } } @@ -512,14 +542,18 @@ class groupButton { get name(): string { return this._group.name; } set name(v: string) { this._group.name = v; - this._button.querySelector(".group-button-name").textContent = v; + this.button.querySelector(".group-button-name").textContent = v; } get group(): string { return this._group.group; } set group(v: string) { + document.removeEventListener(`settings-group-${this.group}-child-visible`, this._childVisible); + document.removeEventListener(`settings-group-${this.group}-child-hidden`, this._childHidden); this._group.group = v; + document.addEventListener(`settings-group-${this.group}-child-visible`, this._childVisible); + document.addEventListener(`settings-group-${this.group}-child-hidden`, this._childHidden); this._el.setAttribute("data-group", v); - this._button.setAttribute("data-group", v); + this.button.setAttribute("data-group", v); this._check.setAttribute("data-group", v); this._dropdown.setAttribute("data-group", v); } @@ -532,17 +566,14 @@ class groupButton { this._dropdown.classList.remove(groupButton._margin); this._indent = v; this._dropdown.classList.add(groupButton._margin); - } - - get hidden(): boolean { return this._el.classList.contains("unfocused"); } - set hidden(v: boolean) { - if (v) this._el.classList.add("unfocused"); - else this._el.classList.remove("unfocused"); + for (let child of this._dropdown.children) { + child.classList.remove(...this._indentClasses); + child.classList.add(...this._indentClass()); + }; } get open(): boolean { return this._check.checked; } set open(v: boolean) { - console.trace("set", v); this.openCloseWithAnimation(v); } @@ -608,20 +639,35 @@ class groupButton { } } + private _childVisible = () => { + this.hidden = false; + } + + private _childHidden = () => { + for (let el of this._dropdown.children) { + if (!(el.classList.contains("unfocused"))) { + return; + } + } + // All children are hidden, so hide ourself + this.hidden = true; + } + // Takes sidebar as we need to disable scrolling on it when animation starts. constructor(parentSidebar: HTMLElement) { + super(); this._parentSidebar = parentSidebar; this._el = document.createElement("div"); this._el.classList.add("flex", "flex-col", "gap-2"); - this._button = document.createElement("span") as HTMLSpanElement; - this._el.appendChild(this._button); - this._button.classList.add("button", "~neutral", "@low", "settings-section-button", "justify-between"); - this._button.innerHTML = ` + this.button = document.createElement("span") as HTMLSpanElement; + this._el.appendChild(this.button); + this.button.classList.add("button", "~neutral", "@low", "settings-section-button", "h-11", "justify-between"); + this.button.innerHTML = ` -