From dcf86f922c768f93e02e2f736c9c8017edad40e2 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Tue, 23 Aug 2022 17:43:01 +0200 Subject: [PATCH] Use native buttons for the mobile page header --- com.woltlab.wcf/templates/pageHeaderMenu.tpl | 8 +++ com.woltlab.wcf/templates/pageHeaderUser.tpl | 22 +++++--- ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts | 30 ++++------- ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts | 51 +++++++++---------- .../files/acp/templates/pageHeaderMenu.tpl | 8 +++ .../js/WoltLabSuite/Core/Ui/Page/Menu/Main.js | 24 ++++----- .../js/WoltLabSuite/Core/Ui/Page/Menu/User.js | 41 +++++++-------- .../files/style/layout/pageHeader.scss | 36 +++++++------ wcfsetup/install/files/style/ui/pageMenu.scss | 29 ++--------- 9 files changed, 116 insertions(+), 133 deletions(-) diff --git a/com.woltlab.wcf/templates/pageHeaderMenu.tpl b/com.woltlab.wcf/templates/pageHeaderMenu.tpl index bb79215d96..c71cd3f24a 100644 --- a/com.woltlab.wcf/templates/pageHeaderMenu.tpl +++ b/com.woltlab.wcf/templates/pageHeaderMenu.tpl @@ -1 +1,9 @@ {@$__wcf->getBoxHandler()->getBoxByIdentifier('com.woltlab.wcf.MainMenu')->render()} + diff --git a/com.woltlab.wcf/templates/pageHeaderUser.tpl b/com.woltlab.wcf/templates/pageHeaderUser.tpl index 3326fa3969..586a7a5ddf 100644 --- a/com.woltlab.wcf/templates/pageHeaderUser.tpl +++ b/com.woltlab.wcf/templates/pageHeaderUser.tpl @@ -1,12 +1,4 @@ +{if $__wcf->user->userID} + +{else} + + {icon size=32 name='arrow-right-to-bracket'} + +{/if} diff --git a/ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts b/ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts index deed873a13..b96f202958 100644 --- a/ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts +++ b/ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts @@ -13,12 +13,10 @@ import * as Language from "../../../Language"; import DomUtil from "../../../Dom/Util"; import { MenuItem, PageMenuMainProvider } from "./Main/Provider"; -type CallbackOpen = (event: MouseEvent) => void; - export class PageMenuMain implements PageMenuProvider { - private readonly callbackOpen: CallbackOpen; private readonly container: PageMenuContainer; private readonly mainMenu: HTMLElement; + private readonly mainMenuButton: HTMLButtonElement; private readonly menuItemBadges = new Map(); private readonly menuItemProvider: PageMenuMainProvider; private readonly observer: MutationObserver; @@ -27,14 +25,14 @@ export class PageMenuMain implements PageMenuProvider { this.mainMenu = document.querySelector(".mainMenu")!; this.menuItemProvider = menuItemProvider; - this.container = new PageMenuContainer(this); - - this.callbackOpen = (event) => { - event.preventDefault(); + this.mainMenuButton = document.querySelector(".pageHeaderMenuMobile") as HTMLButtonElement; + this.mainMenuButton.addEventListener("click", (event) => { event.stopPropagation(); this.container.toggle(); - }; + }); + + this.container = new PageMenuContainer(this); this.observer = new MutationObserver((mutations) => { let refreshUnreadIndicator = false; @@ -54,11 +52,8 @@ export class PageMenuMain implements PageMenuProvider { } enable(): void { - this.mainMenu.setAttribute("aria-expanded", "false"); - this.mainMenu.setAttribute("aria-label", Language.get("wcf.menu.page")); - this.mainMenu.setAttribute("role", "button"); - this.mainMenu.tabIndex = 0; - this.mainMenu.addEventListener("click", this.callbackOpen); + this.mainMenuButton.setAttribute("aria-expanded", "false"); + this.mainMenuButton.querySelector("fa-icon")!.setIcon("bars"); this.refreshUnreadIndicator(); } @@ -66,11 +61,8 @@ export class PageMenuMain implements PageMenuProvider { disable(): void { this.container.close(); - this.mainMenu.removeAttribute("aria-expanded"); - this.mainMenu.removeAttribute("aria-label"); - this.mainMenu.removeAttribute("role"); - this.mainMenu.removeAttribute("tabindex"); - this.mainMenu.removeEventListener("click", this.callbackOpen); + this.mainMenuButton.setAttribute("aria-expanded", "false"); + this.mainMenuButton.querySelector("fa-icon")!.setIcon("bars"); } getContent(): DocumentFragment { @@ -98,7 +90,7 @@ export class PageMenuMain implements PageMenuProvider { } getMenuButton(): HTMLElement { - return this.mainMenu; + return this.mainMenuButton; } sleep(): void { diff --git a/ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts b/ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts index 620289ae96..b7a2dfb177 100644 --- a/ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts +++ b/ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts @@ -18,9 +18,7 @@ import { getElement as getControlPanelElement } from "../../User/Menu/ControlPan import * as EventHandler from "../../../Event/Handler"; import { on as onMediaQueryChange } from "../../Screen"; -type CallbackOpen = (event: MouseEvent) => void; - -type Tab = HTMLAnchorElement; +type Tab = HTMLButtonElement; type TabPanel = HTMLElement; type TabComponents = [Tab, TabPanel]; @@ -42,7 +40,6 @@ type LegacyUserPanelApi = { export class PageMenuUser implements PageMenuProvider { private activeTab?: Tab = undefined; - private readonly callbackOpen: CallbackOpen; private readonly container: PageMenuContainer; private readonly legacyUserPanels = new Map(); private readonly observer: MutationObserver; @@ -51,10 +48,20 @@ export class PageMenuUser implements PageMenuProvider { private readonly tabPanels = new Map(); private readonly tabs: Tab[] = []; private readonly userMenu: HTMLElement; + private readonly userMenuButton: HTMLButtonElement; constructor() { this.userMenu = document.querySelector(".userPanel")!; + this.userMenuButton = document.querySelector(".pageHeaderUserMobile") as HTMLButtonElement; + this.userMenuButton.addEventListener("click", (event) => { + event.stopPropagation(); + + // Clicking too early while the page is still loading + // causes an incomplete tab menu. + void isReady.then(() => this.container.toggle()); + }); + this.container = new PageMenuContainer(this); const isReady = new Promise((resolve) => { @@ -69,15 +76,6 @@ export class PageMenuUser implements PageMenuProvider { } }); - this.callbackOpen = (event) => { - event.preventDefault(); - event.stopPropagation(); - - // Clicking too early while the page is still loading - // causes an incomplete tab menu. - void isReady.then(() => this.container.toggle()); - }; - onMediaQueryChange("screen-lg", { match: () => this.detachViewsFromPanel(), unmatch: () => this.detachViewsFromPanel(), @@ -89,11 +87,7 @@ export class PageMenuUser implements PageMenuProvider { } enable(): void { - this.userMenu.setAttribute("aria-expanded", "false"); - this.userMenu.setAttribute("aria-label", Language.get("wcf.menu.user")); - this.userMenu.setAttribute("role", "button"); - this.userMenu.tabIndex = 0; - this.userMenu.addEventListener("click", this.callbackOpen); + this.userMenuButton.setAttribute("aria-expanded", "false"); this.refreshUnreadIndicator(); } @@ -101,11 +95,7 @@ export class PageMenuUser implements PageMenuProvider { disable(): void { this.container.close(); - this.userMenu.removeAttribute("aria-expanded"); - this.userMenu.removeAttribute("aria-label"); - this.userMenu.removeAttribute("role"); - this.userMenu.removeAttribute("tabindex"); - this.userMenu.removeEventListener("click", this.callbackOpen); + this.userMenuButton.setAttribute("aria-expanded", "false"); } getContent(): DocumentFragment { @@ -116,7 +106,7 @@ export class PageMenuUser implements PageMenuProvider { } getMenuButton(): HTMLElement { - return this.userMenu; + return this.userMenuButton; } sleep(): void { @@ -346,8 +336,14 @@ export class PageMenuUser implements PageMenuProvider { const panelButton = provider.getPanelButton(); const button = panelButton.querySelector("a")!; + let icon = button.querySelector("fa-icon")?.outerHTML; + if (icon === undefined) { + // Fallback for the upgrade to 6.0. + icon = ''; + } + const data: TabData = { - icon: button.querySelector(".icon")!.outerHTML, + icon, label: button.dataset.title || button.title, origin: panelButton.id, }; @@ -356,12 +352,11 @@ export class PageMenuUser implements PageMenuProvider { } private buildControlPanelTab(tabList: HTMLElement, tabContainer: HTMLElement): void { - const panel = document.getElementById("topMenu")!; const userMenu = document.getElementById("userMenu")!; const userMenuButton = userMenu.querySelector("a")!; const data: TabData = { - icon: panel.querySelector(".userPanelAvatar .userAvatarImage")!.outerHTML, + icon: this.userMenuButton.querySelector(".userAvatarImage")!.outerHTML, label: userMenuButton.dataset.title || userMenuButton.title, origin: userMenu.id, }; @@ -420,7 +415,7 @@ export class PageMenuUser implements PageMenuProvider { const tabId = DomUtil.getUniqueId(); const panelId = DomUtil.getUniqueId(); - const tab = document.createElement("a"); + const tab = document.createElement("button"); tab.classList.add("pageMenuUserTab"); tab.dataset.hasUnreadContent = "false"; tab.dataset.origin = data.origin; diff --git a/wcfsetup/install/files/acp/templates/pageHeaderMenu.tpl b/wcfsetup/install/files/acp/templates/pageHeaderMenu.tpl index 678f849ff0..459813bdd5 100644 --- a/wcfsetup/install/files/acp/templates/pageHeaderMenu.tpl +++ b/wcfsetup/install/files/acp/templates/pageHeaderMenu.tpl @@ -1,3 +1,11 @@ + diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Main.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Main.js index 1ed76da0a5..c42b4b6818 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Main.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Main.js @@ -18,12 +18,12 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. this.menuItemBadges = new Map(); this.mainMenu = document.querySelector(".mainMenu"); this.menuItemProvider = menuItemProvider; - this.container = new Container_1.default(this); - this.callbackOpen = (event) => { - event.preventDefault(); + this.mainMenuButton = document.querySelector(".pageHeaderMenuMobile"); + this.mainMenuButton.addEventListener("click", (event) => { event.stopPropagation(); this.container.toggle(); - }; + }); + this.container = new Container_1.default(this); this.observer = new MutationObserver((mutations) => { let refreshUnreadIndicator = false; mutations.forEach((mutation) => { @@ -38,20 +38,14 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. this.watchForChanges(); } enable() { - this.mainMenu.setAttribute("aria-expanded", "false"); - this.mainMenu.setAttribute("aria-label", Language.get("wcf.menu.page")); - this.mainMenu.setAttribute("role", "button"); - this.mainMenu.tabIndex = 0; - this.mainMenu.addEventListener("click", this.callbackOpen); + this.mainMenuButton.setAttribute("aria-expanded", "false"); + this.mainMenuButton.querySelector("fa-icon").setIcon("bars"); this.refreshUnreadIndicator(); } disable() { this.container.close(); - this.mainMenu.removeAttribute("aria-expanded"); - this.mainMenu.removeAttribute("aria-label"); - this.mainMenu.removeAttribute("role"); - this.mainMenu.removeAttribute("tabindex"); - this.mainMenu.removeEventListener("click", this.callbackOpen); + this.mainMenuButton.setAttribute("aria-expanded", "false"); + this.mainMenuButton.querySelector("fa-icon").setIcon("bars"); } getContent() { const container = document.createElement("div"); @@ -72,7 +66,7 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. return fragment; } getMenuButton() { - return this.mainMenu; + return this.mainMenuButton; } sleep() { this.watchForChanges(); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/User.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/User.js index 36f7e72e3a..4387d4a949 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/User.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/User.js @@ -24,6 +24,13 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. this.tabPanels = new Map(); this.tabs = []; this.userMenu = document.querySelector(".userPanel"); + this.userMenuButton = document.querySelector(".pageHeaderUserMobile"); + this.userMenuButton.addEventListener("click", (event) => { + event.stopPropagation(); + // Clicking too early while the page is still loading + // causes an incomplete tab menu. + void isReady.then(() => this.container.toggle()); + }); this.container = new Container_1.default(this); const isReady = new Promise((resolve) => { if (document.readyState === "complete") { @@ -37,13 +44,6 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. }); } }); - this.callbackOpen = (event) => { - event.preventDefault(); - event.stopPropagation(); - // Clicking too early while the page is still loading - // causes an incomplete tab menu. - void isReady.then(() => this.container.toggle()); - }; (0, Screen_1.on)("screen-lg", { match: () => this.detachViewsFromPanel(), unmatch: () => this.detachViewsFromPanel(), @@ -53,20 +53,12 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. }); } enable() { - this.userMenu.setAttribute("aria-expanded", "false"); - this.userMenu.setAttribute("aria-label", Language.get("wcf.menu.user")); - this.userMenu.setAttribute("role", "button"); - this.userMenu.tabIndex = 0; - this.userMenu.addEventListener("click", this.callbackOpen); + this.userMenuButton.setAttribute("aria-expanded", "false"); this.refreshUnreadIndicator(); } disable() { this.container.close(); - this.userMenu.removeAttribute("aria-expanded"); - this.userMenu.removeAttribute("aria-label"); - this.userMenu.removeAttribute("role"); - this.userMenu.removeAttribute("tabindex"); - this.userMenu.removeEventListener("click", this.callbackOpen); + this.userMenuButton.setAttribute("aria-expanded", "false"); } getContent() { const fragment = document.createDocumentFragment(); @@ -74,7 +66,7 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. return fragment; } getMenuButton() { - return this.userMenu; + return this.userMenuButton; } sleep() { if (this.activeTab) { @@ -262,21 +254,26 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. return tabContainer; } buildTab(provider) { + var _a; const panelButton = provider.getPanelButton(); const button = panelButton.querySelector("a"); + let icon = (_a = button.querySelector("fa-icon")) === null || _a === void 0 ? void 0 : _a.outerHTML; + if (icon === undefined) { + // Fallback for the upgrade to 6.0. + icon = ''; + } const data = { - icon: button.querySelector(".icon").outerHTML, + icon, label: button.dataset.title || button.title, origin: panelButton.id, }; return this.buildTabComponents(data); } buildControlPanelTab(tabList, tabContainer) { - const panel = document.getElementById("topMenu"); const userMenu = document.getElementById("userMenu"); const userMenuButton = userMenu.querySelector("a"); const data = { - icon: panel.querySelector(".userPanelAvatar .userAvatarImage").outerHTML, + icon: this.userMenuButton.querySelector(".userAvatarImage").outerHTML, label: userMenuButton.dataset.title || userMenuButton.title, origin: userMenu.id, }; @@ -318,7 +315,7 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../. buildTabComponents(data) { const tabId = Util_1.default.getUniqueId(); const panelId = Util_1.default.getUniqueId(); - const tab = document.createElement("a"); + const tab = document.createElement("button"); tab.classList.add("pageMenuUserTab"); tab.dataset.hasUnreadContent = "false"; tab.dataset.origin = data.origin; diff --git a/wcfsetup/install/files/style/layout/pageHeader.scss b/wcfsetup/install/files/style/layout/pageHeader.scss index e92b5db1e7..e6b127e0c1 100644 --- a/wcfsetup/install/files/style/layout/pageHeader.scss +++ b/wcfsetup/install/files/style/layout/pageHeader.scss @@ -265,10 +265,6 @@ } } } - - .userPanelAvatar { - display: none; - } } /* LOGO */ @@ -313,7 +309,9 @@ @include screen-lg { .pageHeaderSearchMobile, - .userPanelLoginLink { + .pageHeaderMenuMobile, + .userPanelLoginLink, + .pageHeaderUserMobile { display: none; } } @@ -450,7 +448,7 @@ .pageHeaderSearchMobile, .userPanel, - .mainMenu { + .pageHeaderMenuMobile { align-items: center; display: flex; height: 40px; @@ -473,32 +471,40 @@ grid-area: search; } - .userPanel { + .pageHeaderUserMobile { + display: flex; grid-area: user; + justify-content: center; + width: 40px; - .userPanelItems { + &[aria-expanded="false"] .pageHeaderUserMobileActive { display: none; } - .userPanelAvatar { - display: block; + &[aria-expanded="true"] .pageHeaderUserMobileInactive { + display: none; } } + .userPanel, .mainMenu { + display: none; + } + + .pageHeaderMenuMobile { grid-area: menu; - &::before { - content: $fa-var-bars; + &[aria-expanded="false"] .pageHeaderMenuMobileActive { + display: none; } - .boxContent { + &[aria-expanded="true"] .pageHeaderMenuMobileInactive { display: none; } } - .mainMenu[aria-expanded="false"], - .userPanel[aria-expanded="false"] { + .pageHeaderMenuMobile[aria-expanded="false"], + .pageHeaderUserMobile[aria-expanded="false"] { position: relative; &.pageMenuMobileButtonHasContent::after { diff --git a/wcfsetup/install/files/style/ui/pageMenu.scss b/wcfsetup/install/files/style/ui/pageMenu.scss index 5c7fd49e47..e454afb6a5 100644 --- a/wcfsetup/install/files/style/ui/pageMenu.scss +++ b/wcfsetup/install/files/style/ui/pageMenu.scss @@ -247,38 +247,15 @@ } @include screen-md-down { - .mainMenu[aria-expanded="true"]::before { - content: $fa-var-times; - } - - .userPanel.userPanelLoggedIn[aria-expanded="true"] { - &::before { - content: $fa-var-times; - color: $wcfHeaderLink; - font-family: FontAwesome; - font-size: 28px; - line-height: 32px; - padding: 5px 5px; - } - - .userPanelAvatar { - display: none; - } - } - - .mainMenu[aria-expanded="true"]::after, - .userPanel.userPanelLoggedIn[aria-expanded="true"]::after { + .pageHeaderMenuMobile[aria-expanded="true"]::after, + .pageHeaderUserMobile[aria-expanded="true"]::after { border: 8px solid transparent; border-top-width: 0; border-bottom-color: $wcfUserMenuBackground; - bottom: -5px; + bottom: 0; content: ""; position: absolute; } - - .userPanel.userPanelLoggedIn[aria-expanded="true"]::after { - bottom: 0; - } } @include screen-sm-md { -- 2.20.1