diff --git a/src/common/interfaces/ClientUiMenu.interface.ts b/src/common/interfaces/ClientUiMenu.interface.ts index c472a2c..53521ad 100644 --- a/src/common/interfaces/ClientUiMenu.interface.ts +++ b/src/common/interfaces/ClientUiMenu.interface.ts @@ -5,19 +5,20 @@ export interface MenuItemConfig { customHTML?: HTMLElement; } -export type MenuAnchor = - | "LeftCenter" - | "RightCenter" - | "TopCenter" - | "BottomCenter" - | "TopLeft" - | "TopRight" - | "BottomLeft" - | "BottomRight"; +export enum MenuPosition { + TopLeft = 'top-left', + Left = 'left', + BottomLeft = 'bottom-left', + Top = 'top', + Bottom = 'bottom', + TopRight = 'top-right', + Right = 'right', + BottomRight = 'bottom-right', +} export interface MenuConfig { isGlobal?: boolean; - anchor: MenuAnchor; - activationRadius: number; + menuPosition: MenuPosition; + activationRadius?: number; items: MenuItemConfig[]; } diff --git a/src/ext/lib/uwui/ClientMenu.ts b/src/ext/lib/uwui/ClientMenu.ts index 8d3c004..e15bbca 100644 --- a/src/ext/lib/uwui/ClientMenu.ts +++ b/src/ext/lib/uwui/ClientMenu.ts @@ -1,4 +1,4 @@ -import { MenuConfig, MenuItemConfig } from '@src/common/interfaces/ClientUiMenu.interface'; +import { MenuPosition, MenuConfig, MenuItemConfig } from '@src/common/interfaces/ClientUiMenu.interface'; import extensionCss from '@src/main.css?inline'; export class ClientMenu { @@ -8,9 +8,12 @@ export class ClientMenu { private root!: HTMLDivElement; private visible = false; + private menuPositionClasses: string[] = []; + constructor(private config: MenuConfig) {} mount(anchorElement: HTMLElement) { + this.buildMenuPositionClassList(); this.createHost(); this.createShadow(); this.createMenu(); @@ -76,7 +79,6 @@ export class ClientMenu { this.shadow.appendChild(style); } - private createHost() { this.host = document.createElement("div"); this.host.classList.add('uw-ultrawidify-container-root'); @@ -90,7 +92,6 @@ export class ClientMenu { height: "100%", zIndex: this.config.isGlobal ? "2147483647" : "2147483640", // pointerEvents: "none", - backgroundColor: "#00000099", }); console.log('UI host created:', this.host); @@ -101,30 +102,74 @@ export class ClientMenu { this.injectStyles(); } + /** + * + * @returns + */ + private buildMenuPositionClassList() { + let classList; + switch (this.config.menuPosition) { + case MenuPosition.TopLeft: + classList = ['uw-menu-left','uw-menu-top']; + break; + case MenuPosition.Left: + classList = ['uw-menu-left','uw-menu-ycenter']; + break; + case MenuPosition.BottomLeft: + classList = ['uw-menu-left','uw-menu-bottom']; + break; + case MenuPosition.Top: + classList = ['uw-menu-center','uw-menu-top']; + break; + case MenuPosition.Bottom: + classList = ['uw-menu-center', 'uw-menu-bottom']; + break; + case MenuPosition.TopRight: + classList = ['uw-menu-right', 'uw-menu-top']; + break; + case MenuPosition.Right: + classList = ['uw-menu-right', 'uw-menu-ycenter']; + break; + case MenuPosition.BottomRight: + classList = ['uw-menu-right', 'uw-menu-bottom']; + break; + default: // left-center is our default position + classList = ['uw-menu-left', 'uw-menu-ycenter']; + break; + } + + this.menuPositionClasses = classList; + } + private createMenu() { this.root = document.createElement("div"); this.root.className = "uw-menu-root font-mono"; const trigger = document.createElement("div"); - trigger.className = "uw-menu-trigger"; - trigger.textContent = "☰"; + trigger.classList = "uw-menu-trigger uw-trigger"; + trigger.textContent = "Ultrawidify"; const submenu = this.buildSubmenu(this.config.items); trigger.addEventListener("mouseenter", () => this.show()); this.root.addEventListener("mouseleave", () => this.hide()); - this.root.append(trigger, submenu); + console.log('menu position classes:', this.menuPositionClasses) + this.root.classList.add(...this.menuPositionClasses); + + trigger.appendChild(submenu); + this.root.append(trigger); this.shadow.appendChild(this.root); } private buildSubmenu(items: MenuItemConfig[]): HTMLDivElement { const menu = document.createElement("div"); - menu.className = "uw-submenu"; + menu.classList = "uw-submenu"; + menu.classList.add(...this.menuPositionClasses); for (const item of items) { const el = document.createElement("div"); - el.className = "uw-menu-item"; + el.className = `uw-menu-item uw-trigger`; if (item.customHTML) { el.appendChild(item.customHTML); @@ -151,8 +196,11 @@ export class ClientMenu { } private position(anchorEl: HTMLElement) { - const rect = anchorEl.getBoundingClientRect(); - const r = this.root.style; + let appendClassList: string[] = []; + + + + anchorEl.classList.add(...appendClassList); // switch (this.config.anchor) { // case "LeftCenter": @@ -188,14 +236,15 @@ export class ClientMenu { private show() { if (!this.visible) { this.visible = true; - this.root.classList.add("visible"); + this.root.classList.add("uw-visible"); + this.root.classList.remove("uw-hidden"); } } private hide() { if (this.visible) { this.visible = false; - this.root.classList.remove("visible"); + this.root.classList.remove("uw-visible"); } } } diff --git a/src/ext/lib/uwui/UI.ts b/src/ext/lib/uwui/UI.ts index 20ee39b..8cf2d9d 100644 --- a/src/ext/lib/uwui/UI.ts +++ b/src/ext/lib/uwui/UI.ts @@ -3,6 +3,7 @@ import { ClientMenu } from './ClientMenu'; import EventBus from '../EventBus'; import PlayerData from '../video-data/PlayerData'; import { SiteSettings } from '../settings/SiteSettings'; +import { MenuPosition as MenuPosition } from '../../../common/interfaces/ClientUiMenu.interface'; if (process.env.CHANNEL !== 'stable'){ console.info("Loading: UI"); @@ -118,7 +119,14 @@ class UI { const uwid = `uw-ultrawidify-${this.interfaceId}-root-${random}` if (this.uiConfig.parentElement) { - const uwMenu = new ClientMenu({isGlobal: this.isGlobal, anchor: "LeftCenter", items: [{label: 'test'}]}); + const uwMenu = new ClientMenu({ + isGlobal: this.isGlobal, + menuPosition: MenuPosition.Left, + items: [ + {label: 'test'}, + {label: 'test nested', subitems: [{label: 'sub test'}, {label: 'sub test 2'}]} + ] + }); uwMenu.mount(this.uiConfig.parentElement); } return; diff --git a/src/ui/res/styles/player-menu.css b/src/ui/res/styles/player-menu.css index 7bf9c31..d078a6a 100644 --- a/src/ui/res/styles/player-menu.css +++ b/src/ui/res/styles/player-menu.css @@ -2,9 +2,92 @@ @import "tailwindcss/utilities"; .uw-menu-root { - @apply h-full w-full font-mono text-stone-200 text-[16px]; + @apply h-full w-full font-mono text-stone-200 text-[16px] flex flex-row; + + &.uw-menu-left { + @apply justify-start; + } + &.uw-menu-right { + @apply justify-end; + } + + &.uw-menu-left, &.uw-menu-right { + &.uw-menu-top { + @apply items-start; + } + &.uw-menu-ycenter { + @apply items-center; + } + &.uw-menu-bottom { + @apply items-end; + } + } + + &.uw-menu-center { + @apply flex-col items-center; + + &.uw-menu-top { + @apply justify-start; + } + &.uw-menu-bottom { + @apply justify-end; + } + } * { @apply font-mono text-stone-200 text-[1em]; } } + +.uw-menu-trigger { + +} + +.uw-submenu { + @apply absolute flex flex-col gap-0; + + &.uw-menu-left { + @apply left-full; + } + &.uw-menu-right { + @apply right-full; + } + + &.uw-menu-left, &.uw-menu-right { + &.uw-menu-top { + @apply top-1/2 -translate-y-1/2; + } + &.uw-menu-ycenter { + @apply top-0; + } + &.uw-menu-bottom { + @apply bottom-0; + } + } + + &.uw-menu-center { + @apply left-1/2 -translate-x-1/2 flex-row; + + &.uw-menu-top { + @apply bottom-0; + } + &.uw-menu-bottom { + @apply top-0; + } + } + + * { + @apply font-mono text-stone-200 text-[1em]; + } +} + +.uw-trigger { + @apply p-4 relative block + bg-stone-950/75 backdrop-blur-[1em] backdrop-brightness-75 backdrop-saturate-50 + text-nowrap + ; + + &:hover { + @apply text-primary-200 bg-stone-800/75; + } +}