Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
5.3 KiB
171 lines
5.3 KiB
import { findUpTag, whichChild } from "../lib/utils"; |
|
|
|
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, width: number, toRight: boolean) { |
|
const elements = [tabContent, prevTabContent]; |
|
if(toRight) elements.reverse(); |
|
elements[0].style.filter = `brightness(80%)`; |
|
elements[0].style.transform = `translate3d(${-width * .25}px, 0, 0)`; |
|
elements[1].style.transform = `translate3d(${width}px, 0, 0)`; |
|
|
|
tabContent.classList.add('active'); |
|
void tabContent.offsetWidth; // reflow |
|
|
|
tabContent.style.transform = ''; |
|
tabContent.style.filter = ''; |
|
} |
|
|
|
function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, width: number, toRight: boolean) { |
|
const elements = [tabContent, prevTabContent]; |
|
if(toRight) elements.reverse(); |
|
elements[0].style.transform = `translate3d(${-width}px, 0, 0)`; |
|
elements[1].style.transform = `translate3d(${width}px, 0, 0)`; |
|
|
|
tabContent.classList.add('active'); |
|
void tabContent.offsetWidth; // reflow |
|
|
|
tabContent.style.transform = ''; |
|
} |
|
|
|
export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 250) { |
|
const hideTimeouts: {[id: number]: number} = {}; |
|
let transitionEndTimeout: number; |
|
let prevTabContent: HTMLElement = null; |
|
let prevId = -1; |
|
|
|
const selectTab = (id: number, animate = true) => { |
|
if(id == prevId) return false; |
|
|
|
//console.log('selectTab id:', id); |
|
|
|
const p = prevTabContent; |
|
const tabContent = content.children[id] as HTMLElement; |
|
|
|
// * means animation isn't needed |
|
if(content.dataset.slider == 'none' || !animate) { |
|
if(p) { |
|
p.classList.remove('active'); |
|
} |
|
|
|
tabContent.classList.add('active'); |
|
|
|
prevId = id; |
|
prevTabContent = tabContent; |
|
|
|
if(onTransitionEnd) onTransitionEnd(); |
|
return; |
|
} |
|
|
|
if(prevTabContent) { |
|
prevTabContent.classList.remove('to'); |
|
} |
|
|
|
const toRight = prevId < id; |
|
if(!tabContent) { |
|
//prevTabContent.classList.remove('active'); |
|
} else if(prevId != -1) { |
|
const width = prevTabContent.getBoundingClientRect().width; |
|
|
|
if(tabs || content.dataset.slider == 'tabs') { |
|
slideTabs(tabContent, prevTabContent, width, toRight); |
|
} else { |
|
slideNavigation(tabContent, prevTabContent, width, toRight); |
|
} |
|
|
|
tabContent.classList.add('to'); |
|
} else { |
|
tabContent.classList.add('active'); |
|
} |
|
|
|
const _prevId = prevId; |
|
if(hideTimeouts.hasOwnProperty(id)) clearTimeout(hideTimeouts[id]); |
|
if(p/* && false */) { |
|
hideTimeouts[_prevId] = window.setTimeout(() => { |
|
p.style.transform = ''; |
|
p.style.filter = ''; |
|
p.classList.remove('active'); |
|
|
|
if(tabContent) { |
|
tabContent.classList.remove('to'); |
|
} |
|
|
|
delete hideTimeouts[_prevId]; |
|
}, /* 420 */transitionTime); |
|
|
|
if(onTransitionEnd) { |
|
if(transitionEndTimeout) clearTimeout(transitionEndTimeout); |
|
transitionEndTimeout = window.setTimeout(() => { |
|
onTransitionEnd(); |
|
transitionEndTimeout = 0; |
|
}, transitionTime); |
|
} |
|
} |
|
|
|
prevId = id; |
|
prevTabContent = tabContent; |
|
}; |
|
|
|
if(tabs) { |
|
const useStripe = !tabs.classList.contains('no-stripe'); |
|
|
|
const tagName = 'LI';//tabs.firstElementChild.tagName; |
|
tabs.addEventListener('click', function(e) { |
|
let target = e.target as HTMLElement; |
|
|
|
if(target.tagName != tagName) { |
|
target = findUpTag(target, tagName); |
|
} |
|
|
|
//console.log('tabs click:', target); |
|
|
|
if(!target) return false; |
|
|
|
let id: number; |
|
if(target.dataset.tab) { |
|
id = +target.dataset.tab; |
|
if(id == -1) { |
|
return false; |
|
} |
|
} else { |
|
id = whichChild(target); |
|
} |
|
|
|
const tabContent = content.children[id] as HTMLDivElement; |
|
|
|
if(onClick) onClick(id, tabContent); |
|
if(target.classList.contains('active') || id == prevId) { |
|
return false; |
|
} |
|
|
|
const prev = tabs.querySelector(tagName.toLowerCase() + '.active') as HTMLElement; |
|
prev && prev.classList.remove('active'); |
|
|
|
// stripe from ZINCHUK |
|
if(useStripe && prevId != -1) { |
|
const indicator = target.querySelector('i')!; |
|
const currentIndicator = target.parentElement.children[prevId].querySelector('i')!; |
|
|
|
currentIndicator.classList.remove('animate'); |
|
indicator.classList.remove('animate'); |
|
|
|
// We move and resize our indicator so it repeats the position and size of the previous one. |
|
const shiftLeft = currentIndicator.parentElement.parentElement.offsetLeft - indicator.parentElement.parentElement.offsetLeft; |
|
const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth; |
|
indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`; |
|
|
|
//console.log(`translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`); |
|
|
|
requestAnimationFrame(() => { |
|
// Now we remove the transform to let it animate to its own position and size. |
|
indicator.classList.add('animate'); |
|
indicator.style.transform = 'none'; |
|
}); |
|
} |
|
// stripe END |
|
|
|
target.classList.add('active'); |
|
selectTab(id); |
|
}); |
|
} |
|
|
|
return selectTab; |
|
} |