{@$__wcf->getBoxHandler()->getBoxByIdentifier('com.woltlab.wcf.MainMenu')->render()}
+<button class="pageHeaderMenuMobile" aria-expanded="false" aria-label="{lang}wcf.menu.page{/lang}">
+ <span class="pageHeaderMenuMobileInactive">
+ {icon size=32 name='bars'}
+ </span>
+ <span class="pageHeaderMenuMobileActive">
+ {icon size=32 name='xmark'}
+ </span>
+</button>
<nav id="topMenu" class="userPanel{if $__wcf->user->userID} userPanelLoggedIn{/if}">
- {if $__wcf->user->userID}
- <span class="userPanelAvatar" aria-hidden="true">{@$__wcf->getUserProfileHandler()->getAvatar()->getImageTag(32, false)}</span>
- {else}
- <a href="{link controller='Login' url=$__wcf->getRequestURI()}{/link}" class="userPanelLoginLink jsTooltip" title="{lang}wcf.user.loginOrRegister{/lang}">
- {icon size=32 name='arrow-right-to-bracket'}
- </a>
- {/if}
-
<ul class="userPanelItems">
{if $__wcf->user->userID}
<!-- user menu -->
</li>
</ul>
</nav>
+{if $__wcf->user->userID}
+ <button class="pageHeaderUserMobile" aria-expanded="false" aria-label="{lang}wcf.menu.user{/lang}">
+ <span class="pageHeaderUserMobileInactive">
+ {@$__wcf->getUserProfileHandler()->getAvatar()->getImageTag(32, false)}
+ </span>
+ <span class="pageHeaderUserMobileActive">
+ {icon size=32 name='xmark'}
+ </span>
+ </button>
+{else}
+ <a href="{link controller='Login' url=$__wcf->getRequestURI()}{/link}" class="userPanelLoginLink jsTooltip" title="{lang}wcf.user.loginOrRegister{/lang}">
+ {icon size=32 name='arrow-right-to-bracket'}
+ </a>
+{/if}
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<string, HTMLElement>();
private readonly menuItemProvider: PageMenuMainProvider;
private readonly observer: MutationObserver;
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;
}
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();
}
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 {
}
getMenuButton(): HTMLElement {
- return this.mainMenu;
+ return this.mainMenuButton;
}
sleep(): void {
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];
export class PageMenuUser implements PageMenuProvider {
private activeTab?: Tab = undefined;
- private readonly callbackOpen: CallbackOpen;
private readonly container: PageMenuContainer;
private readonly legacyUserPanels = new Map<Tab, LegacyUserPanelApi>();
private readonly observer: MutationObserver;
private readonly tabPanels = new Map<Tab, HTMLElement>();
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<void>((resolve) => {
}
});
- 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(),
}
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();
}
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 {
}
getMenuButton(): HTMLElement {
- return this.userMenu;
+ return this.userMenuButton;
}
sleep(): void {
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 = '<fa-icon size="32" name="question"></fa-icon>';
+ }
+
const data: TabData = {
- icon: button.querySelector(".icon")!.outerHTML,
+ icon,
label: button.dataset.title || button.title,
origin: panelButton.id,
};
}
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,
};
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;
<div id="mainMenu" class="mainMenu">
<!-- Placeholder for the mobile UI. -->
</div>
+<button class="pageHeaderMenuMobile" aria-expanded="false" aria-label="{lang}wcf.menu.page{/lang}">
+ <span class="pageHeaderMenuMobileInactive">
+ {icon size=32 name='bars'}
+ </span>
+ <span class="pageHeaderMenuMobileActive">
+ {icon size=32 name='xmark'}
+ </span>
+</button>
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) => {
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");
return fragment;
}
getMenuButton() {
- return this.mainMenu;
+ return this.mainMenuButton;
}
sleep() {
this.watchForChanges();
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") {
});
}
});
- 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(),
});
}
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();
return fragment;
}
getMenuButton() {
- return this.userMenu;
+ return this.userMenuButton;
}
sleep() {
if (this.activeTab) {
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 = '<fa-icon size="32" name="question"></fa-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,
};
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;
}
}
}
-
- .userPanelAvatar {
- display: none;
- }
}
/* LOGO */
@include screen-lg {
.pageHeaderSearchMobile,
- .userPanelLoginLink {
+ .pageHeaderMenuMobile,
+ .userPanelLoginLink,
+ .pageHeaderUserMobile {
display: none;
}
}
.pageHeaderSearchMobile,
.userPanel,
- .mainMenu {
+ .pageHeaderMenuMobile {
align-items: center;
display: flex;
height: 40px;
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 {
}
@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 {