mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-08-02 07:29:28 +08:00
1 line
17 KiB
JavaScript
1 line
17 KiB
JavaScript
"use strict";"require baseclass";"require ui";return baseclass.extend({__init__(){ui.menu.load().then(tree=>this.render(tree));this.initNavigationControls();this.initUciIndicator()},initUciIndicator(){const original=ui.changes?.setIndicator;if(!original)return;ui.changes.setIndicator=function(n){original.call(this,n);document.querySelector('[data-indicator="uci-changes"]')?.setAttribute("data-count",n||0)}},initNavigationControls(){const overlay=document.querySelector("#mobile-menu-overlay");const navigationToggle=document.querySelector("#navigation-toggle");if(!navigationToggle||!overlay)return;const mobileList=overlay.querySelector("#mobile-nav-list");const desktop=window.matchMedia("(min-width: 768px)");const SIDEBAR_COLLAPSED_KEY="aurora.sidebarCollapsed";const isDesktopSidebar=()=>desktop.matches&&document.body.dataset.navType==="sidebar";const updateToggleState=expanded=>{const desktopSidebar=isDesktopSidebar();navigationToggle.classList.toggle("is-expanded",expanded&&!desktop.matches);navigationToggle.setAttribute("aria-expanded",expanded?"true":"false");navigationToggle.setAttribute("aria-controls",desktopSidebar?"sidebar-panel":"mobile-menu-overlay");const label=expanded&&!desktopSidebar?_("Close"):_("Navigation");navigationToggle.setAttribute("title",label);navigationToggle.setAttribute("aria-label",label)};const closeMobileNavigation=()=>{overlay.classList.remove("mobile-menu-open");document.body.classList.remove("mobile-navigation-open");document.body.style.overflow="";this.resetNavigationGroups(mobileList)};const getNavigationExpanded=()=>{if(isDesktopSidebar()){return!document.body.classList.contains("sidebar-collapsed")}return!desktop.matches&&overlay.classList.contains("mobile-menu-open")};const setNavigationExpanded=expanded=>{if(isDesktopSidebar()){closeMobileNavigation();const collapsed=!expanded;document.body.classList.toggle("sidebar-collapsed",collapsed);localStorage.setItem(SIDEBAR_COLLAPSED_KEY,collapsed);updateToggleState(expanded);return}if(desktop.matches){closeMobileNavigation();updateToggleState(false);return}overlay.classList.toggle("mobile-menu-open",expanded);document.body.classList.toggle("mobile-navigation-open",expanded);document.body.style.overflow=expanded?"hidden":"";if(expanded)this.expandActiveNavigationGroup(mobileList);else this.resetNavigationGroups(mobileList);updateToggleState(expanded)};const toggleNavigation=()=>setNavigationExpanded(!getNavigationExpanded());const syncNavigationState=()=>{closeMobileNavigation();if(isDesktopSidebar()){const collapsed=localStorage.getItem(SIDEBAR_COLLAPSED_KEY)==="true";document.body.classList.toggle("sidebar-collapsed",collapsed);updateToggleState(!collapsed);return}updateToggleState(false)};navigationToggle.addEventListener("click",e=>{e.stopPropagation();toggleNavigation()});overlay.addEventListener("click",e=>{if(e.target===overlay)setNavigationExpanded(false)});document.addEventListener("keydown",e=>{if(e.key==="Escape"&&overlay.classList.contains("mobile-menu-open")){setNavigationExpanded(false)}});desktop.addEventListener("change",syncNavigationState);syncNavigationState();document.addEventListener("click",e=>{const destination=e.target?.closest?.(".navigation-direct, .navigation-sublink, .mobile-nav-logout");if(destination&&overlay.contains(destination)){setNavigationExpanded(false)}})},renderMobileMenu(items){const list=document.querySelector("#mobile-nav-list");const footerAction=document.querySelector("#mobile-nav-footer-action");if(list)list.innerHTML="";if(footerAction)footerAction.innerHTML="";if(!list)return;items.forEach(item=>{if(item.isLogout){if(footerAction){footerAction.appendChild(E("a",{class:"mobile-nav-logout",href:item.href},[item.title]))}return}list.appendChild(this.renderNavigationItem(item,"mobile"))});this.bindNavigationAccordion(list)},render(tree){this.renderModeMenu(tree);if(L.env.dispatchpath.length>=3){let node=tree;let url="";for(let i=0;i<3&&node;i++){const segment=L.env.dispatchpath[i];node=node.children?.[segment];url+=(url?"/":"")+segment}if(node)this.renderTabMenu(node,url)}},renderTabMenu(tree,url,level=0){const container=document.querySelector("#tabmenu");const ul=E("ul",{class:"tabs"});const children=ui.menu.getChildren(tree);let activeNode=null;children.forEach(child=>{const isActive=L.env.dispatchpath[3+level]===child.name;ul.appendChild(E("li",{class:`tabmenu-item-${child.name}${isActive?" active":""}`},[E("a",{href:L.url(url,child.name)},[_(child.title)])]));if(isActive)activeNode=child});if(!ul.children.length)return E([]);container.appendChild(ul);container.style.display="";if(activeNode){this.renderTabMenu(activeNode,`${url}/${activeNode.name}`,level+1)}return ul},renderMainMenu(tree,url,level=0,navigationItems=null){const ul=level?E("ul",{class:"desktop-nav-list"}):document.querySelector("#topmenu");const children=ui.menu.getChildren(tree);if(level>1)return E([]);if(level===0){const navType=document.body?.dataset?.navType||"mega-menu";if(navType==="sidebar"){this.renderSidebar(navigationItems||[]);return ul||E([])}if(!ul||!children.length)return E([]);if(navType==="mega-menu"){this.initMegaMenu(children,url,ul)}else{this.initDropdown(children,url,ul)}}else{if(!children.length)return E([]);children.forEach(child=>{const isActive=this.isActivePath(tree.name,child.name);const attributes={class:isActive?"is-active-page":"",href:L.url(url,child.name)};if(isActive)attributes["aria-current"]="page";ul.appendChild(E("li",{},[E("a",attributes,[_(child.title)])]))})}ul.style.display="";return ul},isActivePath(parent,page){if(L.env.dispatchpath[1]!==parent)return false;return page==null||L.env.dispatchpath[2]===page},buildNavigationModel(children,url){return children.filter(child=>child?.name).map(child=>{const pages=ui.menu.getChildren(child).filter(page=>page?.name).map(page=>({name:page.name,title:_(page.title),href:L.url(url,child.name,page.name),isActivePage:this.isActivePath(child.name,page.name)}));const hasChildren=pages.length>0;const isCurrentTopLevel=this.isActivePath(child.name);return{name:child.name,title:_(child.title),href:L.url(url,child.name),hasChildren:hasChildren,isLogout:child.name==="logout",isActiveGroup:hasChildren&&isCurrentTopLevel,isActivePage:!hasChildren&&isCurrentTopLevel,activePage:pages.find(page=>page.isActivePage)||null,pages:pages}})},navigationSubmenuId(mode,name){return`${mode}-submenu-${encodeURIComponent(String(name))}`},renderNavigationItem(item,mode){const mobile=mode==="mobile";const itemClass=mobile?"mobile-nav-item":"";const directClass=mobile?"navigation-direct mobile-nav-link":"navigation-direct nav-link";if(!item.hasChildren){const attributes={class:`${directClass}${item.isActivePage?" is-active-page":""}`,href:item.href};if(item.isActivePage)attributes["aria-current"]="page";return E("li",{class:itemClass},[E("a",attributes,[item.title])])}const submenuId=this.navigationSubmenuId(mode,item.name);const groupClasses=["navigation-group",mobile?"mobile-nav-item":"sidebar-group",item.isActiveGroup?"is-active-group":"",item.isActiveGroup?"is-expanded":""].filter(Boolean);const toggleAttributes={class:mobile?"navigation-group-toggle mobile-nav-link mobile-nav-toggle":"navigation-group-toggle nav-category",type:"button","aria-expanded":item.isActiveGroup?"true":"false","aria-controls":submenuId};if(item.isActiveGroup)toggleAttributes["aria-current"]="location";const list=E("ul",{class:mobile?"navigation-submenu-list mobile-nav-submenu-list":"navigation-submenu-list sidebar-submenu"});item.pages.forEach(page=>{const linkAttributes={class:["navigation-sublink",mobile?"mobile-nav-sublink":"",page.isActivePage?"is-active-page":""].filter(Boolean).join(" "),href:page.href};if(page.isActivePage)linkAttributes["aria-current"]="page";list.appendChild(E("li",{class:mobile?"mobile-nav-subitem":""},[E("a",linkAttributes,[page.title])]))});const regionAttributes={class:mobile?"navigation-group-region mobile-nav-submenu":"navigation-group-region sidebar-section",id:submenuId,"aria-hidden":item.isActiveGroup?"false":"true"};if(!item.isActiveGroup)regionAttributes.inert="";return E("li",{class:groupClasses.join(" ")},[E("button",toggleAttributes,[E("span",{class:"nav-category-label"},[item.title])]),E("div",regionAttributes,[list])])},setNavigationGroupExpanded(item,expanded){const toggle=item.querySelector(".navigation-group-toggle");const region=item.querySelector(".navigation-group-region");item.classList.toggle("is-expanded",expanded);toggle?.setAttribute("aria-expanded",expanded?"true":"false");region?.setAttribute("aria-hidden",expanded?"false":"true");if(expanded)region?.removeAttribute("inert");else region?.setAttribute("inert","")},setExclusiveNavigationGroupExpanded(surface,item,expanded){if(!surface||!item)return;if(expanded){surface.querySelectorAll(".navigation-group.is-expanded").forEach(expandedItem=>{if(expandedItem!==item){this.setNavigationGroupExpanded(expandedItem,false)}})}this.setNavigationGroupExpanded(item,expanded)},resetNavigationGroups(surface){surface?.querySelectorAll(".navigation-group.is-expanded").forEach(item=>this.setNavigationGroupExpanded(item,false))},expandActiveNavigationGroup(surface){const activeGroup=surface?.querySelector(".navigation-group.is-active-group");if(activeGroup){this.setExclusiveNavigationGroupExpanded(surface,activeGroup,true)}},bindNavigationAccordion(surface){if(!surface||surface.dataset.accordionBound==="true")return;surface.dataset.accordionBound="true";surface.addEventListener("click",event=>{const toggle=event.target?.closest?.(".navigation-group-toggle");const item=toggle?.closest?.(".navigation-group");if(!item||!surface.contains(item))return;event.preventDefault();event.stopPropagation();this.setExclusiveNavigationGroupExpanded(surface,item,!item.classList.contains("is-expanded"))})},renderSidebar(items){const list=document.querySelector("#sidebar-list");const footer=document.querySelector("#sidebar-footer");const crumbEl=document.querySelector("#header-crumb");if(list)list.innerHTML="";if(footer)footer.innerHTML="";if(crumbEl)crumbEl.innerHTML="";if(!list)return;const crumb=[];items.forEach(item=>{if(item.isActiveGroup||item.isActivePage){crumb.push(item.title);if(item.activePage)crumb.push(item.activePage.title)}if(item.isLogout){(footer||list).appendChild(E("a",{class:"nav-link",href:item.href},[item.title]));return}list.appendChild(this.renderNavigationItem(item,"sidebar"))});this.bindNavigationAccordion(list);crumb.forEach((title,i)=>{if(i)crumbEl?.appendChild(E("li",{class:"crumb-sep"},["/"]));crumbEl?.appendChild(E("li",{class:i===crumb.length-1?"current":""},[title]))})},buildDropdownItem(child,url,ul){const submenu=ui.menu.getChildren(child);const hasSubmenu=submenu.length>0;const li=E("li",{},[E("a",{class:"menu",href:hasSubmenu?"#":L.url(url,child.name)},[_(child.title)])]);ul.appendChild(li);const menuLink=li.querySelector("a");let nav=null;if(hasSubmenu){const list=this.renderMainMenu(child,`${url}/${child.name}`,1);const children=[list];if(document.body?.dataset?.navType==="mega-menu"){list.style.setProperty("--menu-rows",Math.max(6,Math.ceil(submenu.length/4)));children.unshift(E("div",{class:"desktop-nav-anchor"},[E("span",{class:"desktop-nav-title","data-section":child.name},[_(child.title)])]));const board=document.querySelector(".desktop-menu-container > .desktop-menu-board");if(board)children.push(board.cloneNode(true))}nav=E("div",{class:"desktop-nav"},children);li.appendChild(nav);menuLink.addEventListener("click",e=>e.preventDefault())}return{li:li,nav:nav,menuLink:menuLink,hasSubmenu:hasSubmenu}},deactivateDesktopNavExcept(nav,menuLink){document.querySelectorAll(".desktop-nav").forEach(n=>{if(n!==nav)n.classList.remove("active")});document.querySelectorAll("#topmenu a").forEach(a=>{if(a!==menuLink)a.classList.remove("menu-active")})},initMegaMenu(children,url,ul){const container=document.querySelector(".desktop-menu-container");const canvas=container?.querySelector(".desktop-menu-canvas");const overlay=document.querySelector(".desktop-menu-overlay");const header=document.querySelector("header");if(!header||!overlay)return;let showTimer=null;let hideTimer=null;let canvasHeight=0;let revealDuration=300;const applyCanvasHeight=()=>{if(!canvasHeight){header.querySelectorAll(".desktop-nav").forEach(nav=>canvasHeight=Math.max(canvasHeight,nav.offsetHeight));revealDuration=Math.min(480,Math.max(240,Math.round(canvasHeight/2)))}header.style.setProperty("--mega-menu-height",`${canvasHeight}px`);header.style.setProperty("--mega-menu-duration",`${revealDuration}ms`)};let resizeTimer=null;window.addEventListener("resize",()=>{canvasHeight=0;clearTimeout(resizeTimer);resizeTimer=setTimeout(applyCanvasHeight,150)});let agedPos={x:0,y:0};let agedAt=0;let livePos={x:0,y:0};header.addEventListener("mousemove",e=>{if(e.timeStamp-agedAt>60){agedPos=livePos;agedAt=e.timeStamp}livePos={x:e.clientX,y:e.clientY}});const isAimingIntoOpenPanel=()=>{const openNav=header.querySelector(".desktop-nav.active");if(!openNav)return false;const vx=livePos.x-agedPos.x;const vy=livePos.y-agedPos.y;if(vy<=2)return false;const rect=openNav.getBoundingClientRect();if(livePos.y>=rect.top)return true;const xAtTop=livePos.x+vx*(rect.top-livePos.y)/vy;return xAtTop>=rect.left-24&&xAtTop<=rect.right+24};children.forEach(child=>{const{li:li,nav:nav,menuLink:menuLink,hasSubmenu:hasSubmenu}=this.buildDropdownItem(child,url,ul);if(!hasSubmenu)return;if(canvas)canvas.appendChild(nav);li.addEventListener("mouseenter",()=>{if(hideTimer){clearTimeout(hideTimer);hideTimer=null}const isOpen=container?.classList.contains("active");const delay=!isOpen?100:isAimingIntoOpenPanel()?260:0;showTimer=setTimeout(()=>{const wasActive=nav.classList.contains("active");this.deactivateDesktopNavExcept(nav,menuLink);if(wasActive)return;menuLink.classList.add("menu-active");if(container){applyCanvasHeight();container.dataset.closeToken="";container.classList.add("active");container.classList.remove("closing");overlay.classList.add("active")}nav.classList.add("active")},delay)});li.addEventListener("mouseleave",()=>{if(showTimer){clearTimeout(showTimer);showTimer=null}})});const idle=window.requestIdleCallback||(fn=>setTimeout(fn,1));(document.fonts?.ready||Promise.resolve()).then(()=>idle(()=>{if(!canvasHeight)applyCanvasHeight()}));const hideMenu=()=>{if(showTimer){clearTimeout(showTimer);showTimer=null}hideTimer=setTimeout(()=>{this.hideDesktopNav()},150)};header.addEventListener("mouseleave",hideMenu);overlay.addEventListener("mouseenter",hideMenu);header.addEventListener("mouseenter",()=>{if(hideTimer){clearTimeout(hideTimer);hideTimer=null}});overlay.addEventListener("click",()=>this.hideDesktopNav())},initDropdown(children,url,ul){children.forEach(child=>{const{li:li,nav:nav,menuLink:menuLink,hasSubmenu:hasSubmenu}=this.buildDropdownItem(child,url,ul);if(!hasSubmenu)return;let showTimer=null;let hideTimer=null;li.addEventListener("mouseenter",()=>{if(hideTimer){clearTimeout(hideTimer);hideTimer=null}showTimer=setTimeout(()=>{this.deactivateDesktopNavExcept(nav,menuLink);menuLink.classList.add("menu-active");nav.classList.add("active")},100)});li.addEventListener("mouseleave",()=>{if(showTimer){clearTimeout(showTimer);showTimer=null}hideTimer=setTimeout(()=>{nav.classList.remove("active");menuLink.classList.remove("menu-active")},150)})})},hideDesktopNav(){this.deactivateDesktopNavExcept(null,null);const container=document.querySelector(".desktop-menu-container");document.querySelector(".desktop-menu-overlay")?.classList.remove("active");if(!container)return;if(!container.classList.contains("active")&&!container.classList.contains("closing"))return;container.classList.add("closing");container.classList.remove("active");const sheet=container.querySelector(".desktop-menu-sheet");const closeToken=`${Date.now()}-${Math.random()}`;container.dataset.closeToken=closeToken;let closeFallback=null;const finishClosing=event=>{if(event?.target&&event.target!==sheet)return;if(container.dataset.closeToken!==closeToken){if(closeFallback!==null){clearTimeout(closeFallback);closeFallback=null}sheet?.removeEventListener("transitionend",finishClosing);return}if(closeFallback!==null){clearTimeout(closeFallback);closeFallback=null}sheet?.removeEventListener("transitionend",finishClosing);if(!container.classList.contains("active")){container.classList.remove("closing");delete container.dataset.closeToken}};if(!sheet||window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){finishClosing();return}sheet.addEventListener("transitionend",finishClosing);const duration=parseInt(document.querySelector("header")?.style.getPropertyValue("--mega-menu-duration"))||300;closeFallback=setTimeout(finishClosing,duration+50)},renderModeMenu(tree){const ul=document.querySelector("#modemenu");const children=ui.menu.getChildren(tree);let activeChild=null;children.forEach((child,index)=>{const isActive=L.env.requestpath.length?child.name===L.env.requestpath[0]:index===0;if(ul){ul.appendChild(E("li",{class:isActive?"active":""},[E("a",{href:L.url(child.name)},[_(child.title)])]))}if(isActive)activeChild=child});if(activeChild){const navigationItems=this.buildNavigationModel(ui.menu.getChildren(activeChild),activeChild.name);this.renderMainMenu(activeChild,activeChild.name,0,navigationItems);this.renderMobileMenu(navigationItems)}if(ul?.children.length>1){ul.style.display=""}}}); |