Files
remark42/frontend/app/profile.ts
T
2021-11-09 02:05:41 -06:00

125 lines
2.8 KiB
TypeScript

import { setAttributes, setStyles, StylesDeclaration } from 'utils/set-dom-props';
import { createIframe } from 'utils/create-iframe';
import type { Profile } from 'common/types';
let root: HTMLDivElement | null = null;
let iframe: HTMLIFrameElement | null = null;
function removeIframe() {
iframe?.parentNode?.removeChild(iframe);
}
function createElement<K extends keyof HTMLElementTagNameMap>(
tagName: K,
styles: StylesDeclaration,
attrs?: Record<string, string>
) {
const element = document.createElement(tagName);
setStyles(element, styles);
setAttributes(element, attrs);
return element;
}
function createFragment(params: Profile & Record<string, string | unknown>) {
removeIframe();
iframe = createIframe({ ...params, page: 'profile', styles: styles.iframe });
if (!root) {
root = createElement('div', styles.root);
document.body.appendChild(root);
}
root.appendChild(iframe);
setStyles(root, styles.rootShown);
setTimeout(() => iframe?.focus());
}
function animateAppear(): void {
window.requestAnimationFrame(() => {
if (!root || !iframe) {
return;
}
setStyles(root, styles.rootAppear);
});
}
function animateDisappear(): Promise<void> {
return new Promise((resolve) => {
function handleTransitionEnd() {
resolve();
if (!root) {
return;
}
setStyles(root, styles.rootHidden);
root.removeEventListener('transitionend', handleTransitionEnd);
}
window.requestAnimationFrame(() => {
if (!root || !iframe) {
return;
}
setStyles(root, styles.rootDissapear);
root.addEventListener('transitionend', handleTransitionEnd);
});
});
}
function handleKeydown(evt: KeyboardEvent) {
console.log(evt.code);
if (evt.code !== 'Escape') {
return;
}
closeProfile();
}
export function openProfile(params: Profile & Record<string, string | unknown>) {
setStyles(document.body, { overflow: 'hidden' });
createFragment(params);
animateAppear();
window.addEventListener('keydown', handleKeydown);
}
export function closeProfile() {
window.removeEventListener('keydown', handleKeydown);
animateDisappear().then(() => {
removeIframe();
document.body.style.removeProperty('overflow');
});
}
const styles = {
root: {
display: 'none',
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
width: '100%',
height: '100%',
transition: 'opacity 0.5s ease-in',
background: 'rgba(0, 0, 0, .4)',
opacity: 0,
zIndex: 99999999,
},
rootShown: {
display: 'block',
},
rootHidden: {
display: 'none',
},
rootAppear: {
opacity: '1',
},
rootDissapear: {
opacity: '0',
transition: 'opacity 0.3s ease-out',
},
iframe: {
position: 'absolute',
right: 0,
width: '100%',
height: '100%',
},
};