1 import {Component} from './component';
3 export class TriLayout extends Component {
4 private container!: HTMLElement;
5 private tabs!: HTMLElement[];
6 private sidebarScrollContainers!: HTMLElement[];
8 private lastLayoutType = 'none';
9 private onDestroy: (()=>void)|null = null;
10 private scrollCache: Record<string, number> = {
14 private lastTabShown = 'content';
17 this.container = this.$refs.container;
18 this.tabs = this.$manyRefs.tab;
19 this.sidebarScrollContainers = this.$manyRefs.sidebarScrollContainer;
22 this.mobileTabClick = this.mobileTabClick.bind(this);
24 // Watch layout changes
26 window.addEventListener('resize', () => {
30 this.setupSidebarScrollHandlers();
33 updateLayout(): void {
34 let newLayout = 'tablet';
35 if (window.innerWidth <= 1000) newLayout = 'mobile';
36 if (window.innerWidth > 1400) newLayout = 'desktop';
37 if (newLayout === this.lastLayoutType) return;
41 this.onDestroy = null;
44 if (newLayout === 'desktop') {
46 } else if (newLayout === 'mobile') {
50 this.lastLayoutType = newLayout;
54 for (const tab of this.tabs) {
55 tab.addEventListener('click', this.mobileTabClick);
58 this.onDestroy = () => {
59 for (const tab of this.tabs) {
60 tab.removeEventListener('click', this.mobileTabClick);
65 setupDesktop(): void {
70 * Action to run when the mobile info toggle bar is clicked/tapped
72 mobileTabClick(event: MouseEvent): void {
73 const tab = (event.target as HTMLElement).dataset.tab || '';
78 * Show the content tab.
79 * Used by the page-display component.
82 this.showTab('content', false);
88 showTab(tabName: string, scroll: boolean = true): void {
89 this.scrollCache[this.lastTabShown] = document.documentElement.scrollTop;
92 for (const tab of this.tabs) {
93 const isActive = (tab.dataset.tab === tabName);
94 tab.setAttribute('aria-selected', isActive ? 'true' : 'false');
98 const showInfo = (tabName === 'info');
99 this.container.classList.toggle('show-info', showInfo);
101 // Set the scroll position from cache
103 const pageHeader = document.querySelector('header') as HTMLElement;
104 const defaultScrollTop = pageHeader.getBoundingClientRect().bottom;
105 document.documentElement.scrollTop = this.scrollCache[tabName] || defaultScrollTop;
107 document.documentElement.scrollTop = this.scrollCache[tabName] || defaultScrollTop;
111 this.lastTabShown = tabName;
114 setupSidebarScrollHandlers(): void {
115 for (const sidebar of this.sidebarScrollContainers) {
116 sidebar.addEventListener('scroll', () => this.handleSidebarScroll(sidebar), {
119 this.handleSidebarScroll(sidebar);
122 window.addEventListener('resize', () => {
123 for (const sidebar of this.sidebarScrollContainers) {
124 this.handleSidebarScroll(sidebar);
129 handleSidebarScroll(sidebar: HTMLElement): void {
130 const scrollable = sidebar.clientHeight !== sidebar.scrollHeight;
131 const atTop = sidebar.scrollTop === 0;
132 const atBottom = (sidebar.scrollTop + sidebar.clientHeight) === sidebar.scrollHeight;
134 if (sidebar.parentElement) {
135 sidebar.parentElement.classList.toggle('scroll-away-from-top', !atTop && scrollable);
136 sidebar.parentElement.classList.toggle('scroll-away-from-bottom', !atBottom && scrollable);