ranchimall/assets/js/index.js
2023-04-02 04:10:08 +05:30

944 lines
29 KiB
JavaScript

"use strict";
// Global variables
const { html, render: renderElem } = uhtml;
//Checks for internet connection status
if (!navigator.onLine)
floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error')
window.addEventListener('offline', () => {
floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error')
})
window.addEventListener('online', () => {
getRef('notification_drawer').remove(floGlobals.connectionErrorNotification)
notify('We are back online.', 'success')
})
const domRefs = {};
function getRef(elementId) {
if (!domRefs.hasOwnProperty(elementId)) {
domRefs[elementId] = {
count: 1,
ref: null,
};
return document.getElementById(elementId);
} else {
if (domRefs[elementId].count < 3) {
domRefs[elementId].count = domRefs[elementId].count + 1;
return document.getElementById(elementId);
} else {
if (!domRefs[elementId].ref)
domRefs[elementId].ref = document.getElementById(elementId);
return domRefs[elementId].ref;
}
}
}
function create(tagName, obj) {
const { className, text } = obj
const elem = document.createElement(tagName)
elem.className = className
elem.textContent = text
return elem
}
function setAttributes(el, attrs) {
for (key in attrs) {
el.setAttribute(key, attrs[key]);
}
}
function randomHsl(saturation = 80, lightness = 80) {
let hue = Math.random() * 360;
let color = {
primary: `hsla( ${hue}, ${saturation}%, ${lightness}%, 1)`,
light: `hsla( ${hue}, ${saturation}%, 90%, 0.6)`,
};
return color;
}
const selectedColors = [
"#FF1744",
"#F50057",
"#8E24AA",
"#5E35B1",
"#3F51B5",
"#3D5AFE",
"#00B0FF",
"#00BCD4",
"#16c79a",
"#66BB6A",
"#8BC34A",
"#11698e",
"#FF6F00",
"#FF9100",
"#FF3D00",
];
function randomColor() {
return selectedColors[Math.floor(Math.random() * selectedColors.length)];
}
//Function for displaying toast notifications. pass in error for mode param if you want to show an error.
function notify(message, mode, options = {}) {
let icon
switch (mode) {
case 'success':
icon = `<svg class="icon icon--success" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"/></svg>`
break;
case 'error':
icon = `<svg class="icon icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>`
options.pinned = true
break;
}
if (mode === 'error') {
console.error(message)
}
return getRef("notification_drawer").push(message, { icon, ...options });
}
const currentYear = new Date().getFullYear();
function getFormatedTime(time, relative) {
try {
if (String(time).indexOf("_")) time = String(time).split("_")[0];
const intTime = parseInt(time);
if (String(intTime).length < 13) time *= 1000;
let timeFrag = new Date(intTime).toString().split(" "),
day = timeFrag[0],
month = timeFrag[1],
date = timeFrag[2],
year = timeFrag[3],
minutes = new Date(intTime).getMinutes(),
hours = new Date(intTime).getHours(),
currentTime = new Date().toString().split(" ");
minutes = minutes < 10 ? `0${minutes}` : minutes;
let finalHours = ``;
if (hours > 12) finalHours = `${hours - 12}:${minutes}`;
else if (hours === 0) finalHours = `12:${minutes}`;
else finalHours = `${hours}:${minutes}`;
finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`;
if (relative) {
return `${date} ${month} ${year}`;
} else return `${finalHours} ${month} ${date} ${year}`;
} catch (e) {
console.error(e);
return time;
}
}
window.addEventListener("load", () => {
document.addEventListener("keyup", (e) => {
if (e.code === "Escape") {
if (isSiteMapOpen) {
hideSiteMap();
}
else if (isRoomOpen) {
hideRoom()
}
}
});
document.addEventListener("pointerdown", (e) => {
if (e.target.closest("button, sm-button:not([disable]), .interact")) {
createRipple(e, e.target.closest("button, sm-button, .interact"));
}
});
if (window.location.hash !== '')
showRoom(window.location.hash, false)
});
function createRipple(event, target) {
const circle = document.createElement("span");
const diameter = Math.max(target.clientWidth, target.clientHeight);
const radius = diameter / 2;
const targetDimensions = target.getBoundingClientRect();
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`;
circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`;
circle.classList.add("ripple");
const rippleAnimation = circle.animate(
[
{
transform: "scale(3)",
opacity: 0,
},
],
{
duration: 1000,
fill: "forwards",
easing: "ease-out",
}
);
target.append(circle);
rippleAnimation.onfinish = () => {
circle.remove();
};
}
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this,
args = arguments;
let later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
let callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
let timerId;
function throttle(func, delay) {
// If setTimeout is already scheduled, no need to do anything
if (timerId) {
return;
}
// Schedule a setTimeout after delay seconds
timerId = setTimeout(function () {
func();
// Once setTimeout function execution is finished, timerId = undefined so that in
// the next scroll event function execution can be scheduled by the setTimeout
timerId = undefined;
}, delay);
}
const siteMap = [
{
floor: "Current Products",
brief: ``,
outlets: [
{
name: "Bitcoin Bonds",
outletLinks: [
{
label: "Explore",
url: "bitcoinbonds.html",
}
],
brief: `Bondholders get a minimum guarantee of 13% interest per annum during the lock-in period or 50% of all Bitcoin price gains whichever is higher. It offers full capital protection if
Bitcoin prices fall below acquisition price.`,
status: `We are servicing current customers only. A new Blockchain-based version of Bitcoin Bonds will be available soon.`
},
{
name: `Bob's Fund`,
outletLinks: [
{
label: "Explore",
url: "bob'sfund.html",
}
],
brief: `Bobs Fund is a 20 year long term Bitcoin price linked product. Investors are entitled to 100% of Bitcoin price gains, but they must hold for 20 years.`,
status: `We are servicing current customers only. A new Blockchain-based version of Bob's Fund will be available soon.`
},
{
name: "Initial Coin Offering",
outletLinks: [
{
label: "Explore",
url: "ico.html",
},
{
label: "Buy",
url: "ico.html#purchase_room",
},
],
brief: `The Initial Coin Offering (ICO) of RanchiMall was launched in 2017. It was envisioned to sell 21 million tokens over 14 phases over 3 years.`,
},
],
},
/* {
floor: "Blockchain Contracts",
brief: `Blockchain Contracts are one of RanchiMall's flagship innovations.
We believe each blockchain contract will be transformational in its area and will add
tremendously to our enterprise value.`,
outlets: [
{
name: "Incorporation Blockchain Contract",
url: "incorporationblockchaincontract",
brief: `RanchiMall is incorporated on the blockchain and structured as Incorporation Blockchain Contract. Incorporation Blockchain Contract owns all the other blockchain contracts of RanchiMall.`
},
{
name: `Internship Blockchain Contract`,
url: `internshipblockchaincontract`,
brief: `Internship Blockchain Contract tokenizes all our internship initiatives. This is owned by Incorporation Blockchain Contract.`
},
{
name: "FLO Blockchain Contract",
url: "floblockchaincontract",
brief: `FLO Blockchain contract consists of all projects RanchiMall performs on FLO Blockchain (previously called Florincoin).`
}
],
},
{
floor: 'Blockchain Apps',
brief: ``,
outlets: [
{
name: "Web Wallet",
brief: `Purely web-based blockchain wallet.`,
url: 'webwallet'
},
{
name: `FLO Messenger`,
url: `flomessenger`,
},
{
name: "Content Collaboration",
brief: `A way for anonymous users across the Internet to collaborate and create beautiful articles.`,
url: "contentcollaboration",
},
{
name: "Ranchimall Times",
brief: `Article publication platform of RanchiMall`,
url: "ranchimalltimes",
},
],
},
{
floor: 'Experimental Ideas',
brief: ``,
outlets: [
{
name: "Blockchain Cloud",
url: "blockchaincloud",
},
{
name: `UPI On Blockchain`,
url: `upionblockchain`,
},
{
name: "E-Commerce On Blockchain",
url: "e-commerceonblockchain"
}
],
},
{
floor: 'Statistics and Administration',
brief: ``,
outlets: [
{
name: "Incorporation",
url: "incorporation",
},
{
name: `Team`,
url: `team`,
},
{
name: "Operational Statistic",
url: "operationalstatistic",
}
],
}, */
{
floor: 'Internship',
brief: ``,
outlets: [
{
name: "RanchiMall Internship Blockchain contract",
brief: `This outlet has the list of all active projects being executed through our internship program. Interns can apply or they can join active projects here.`,
outletLinks: [
{
label: "Explore",
url: "https://ranchimall.github.io/ribc/",
outbound: true,
}
],
},
{
name: `Certificates`,
brief: `This outlet has access to blockchain verification to all of RanchiMall issued Internship & Employment certificates`,
outletLinks: [
{
label: "Certificate list",
url: "https://www.ranchimall.net/certify/",
outbound: true,
},
{
label: "Verify Certificate",
url: "verify.html",
},
{
label: "See Intern Payments",
url: "https://ranchimall.github.io/ribcpayments/",
outbound: true,
},
],
}
],
},
];
function formatAmount(amount, currency = 'USD') {
return amount.toLocaleString(currency === 'USD' ? 'en-US' : 'en-IN', { style: 'currency', currency });
}
const render = {
bitBondRow(obj) {
const { series, currentValue, timeElapsed, percentGain } = obj;
return html`
<div class="bit-bond-series__row grid">
<div class="grid">
<h5 class="label color-0-8 weight-500">Series</h5>
<h3 class="value original-value">${formatAmount(series)}</h3>
</div>
<div class="flex align-center space-between">
<div class="grid">
<h5 class="label color-0-8 weight-500">Invested</h5>
<h3 class="value">$100</h3>
</div>
<div class="grid justify-right text-align-right">
<h5 class="label color-0-8 weight-500">Current value</h5>
<h3 class="value current-value" style="color: var(--green)">${formatAmount(currentValue)}</h3>
<div class="flex align-center">
<svg class="icon up-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M13 7.828V20h-2V7.828l-5.364 5.364-1.414-1.414L12 4l7.778 7.778-1.414 1.414L13 7.828z"/></svg>
<span class="percent-gain">${`${percentGain}%`}</span>
<span class="time-elapsed">${`In last ${timeElapsed} years`}</span>
</div>
</div>
</div>
</div>
`;
},
bobFundRow(obj) {
console.log(obj);
const { invested, floId, currentValue, timeElapsed, gain } = obj;
return html`
<div class="bob-fund__row grid">
<div class="grid">
<h5 class="label color-0-8 weight-500">FLO ID</h5>
<h3 class="person__name breakable">${floId}</h3>
</div>
<div class="flex">
<div class="grid">
<h5 class="label color-0-8 weight-500">Invested</h5>
<h3 class="value original-value">${formatAmount(invested, 'INR')}</h3>
</div>
<div class="grid justify-right text-align-right">
<h4 class="label color-0-8 weight-500">Current value</h4>
<h3 class="value current-value" style="color: var(--green)">${formatAmount(currentValue, 'INR')}</h3>
<div class="flex align-center">
<svg class="icon up-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M13 7.828V20h-2V7.828l-5.364 5.364-1.414-1.414L12 4l7.778 7.778-1.414 1.414L13 7.828z"/></svg>
<span class="percent-gain">${`${gain}%`}</span>
<span class="time-elapsed">${`In last ${timeElapsed} years`}</span>
</div>
</div>
</div>
</div>
`;
},
icoInvestorRow(obj, options) {
const { extension, investorName, bio, contribution } = obj;
const { thumbnail } = options;
const folder = thumbnail ? "investors-thumbnail" : "investors";
return html`
<div class=${`person-card investor-card grid gap-1-5 ${thumbnail ? 'person-card--small' : 'person-card--big'}`} >
<img class="person__image" src=${`assets/${folder}/${investorName}.${extension}`} alt=${`${investorName} profile picture`} loading="lazy">
<div class="grid">
<h3 class="person__name value capitalize">${investorName}</h3>
<p class="investor__bio color-0-8">${bio}</p>
</div>
<div class="grid investor__contribution-container">
<p class="investor__contribution weight-700">${contribution}</p>
</div>
</div>
`;
},
// internCard(obj) {
// const { extension, internName, level, floId, project } = obj;
// const card = getRef("intern_card_template").content.cloneNode(true).firstElementChild;
// const investorImage = card.querySelector(".person__image");
// investorImage.src = `assets/interns/${internName}.${extension}`;
// investorImage.setAttribute("alt", `${internName} profile picture`);
// card.querySelector(".intern__level").classList.add(level.toLowerCase())
// card.querySelector(".intern__level").textContent = level;
// card.querySelector(".person__name").textContent = internName;
// card.querySelector(".intern-flo-id").textContent = floId;
// card.querySelector(".intern__project").textContent = project;
// return card;
// },
floorLabel(floorNumber, offsetTop) {
return html`
<div class="floor-label interact" style=${`top: ${offsetTop}px`} data-target=${`floor_${floorNumber}`}>
<span class="floor-circle"></span>
</div>
`;
},
outletListItem(outletObj) {
const { name, brief, outletLinks } = outletObj
return html`
<li class="outlet-list__item interact">
<a href=${outletLinks[0].url} class="grid align-center flow-column gap-1 justify-start">
<div>
<h4 class="outlet-title">${name}</h4>
${brief ? html`<p class="outlet-brief">${brief}</p>` : ''}
</div>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z"/></svg>
</a>
</li>
`;
},
floorListItem(floorObj, index) {
const { floor, outlets } = floorObj
const li = html`
<li class="floor_list__item">
<button class="floor_list__header floor__button" data-target=${`floor_${index + 1}`}>
<h2 class="h2 floor-num">${`floor ${index + 1}`}</h2>
<h3 class="h3 accent-color">${floor}</h3>
</button>
<ul class="outlet-list grid">
<h3 class="h3 weight-900 floor-list__outlet">Outlets</h3>
${outlets.map(outlet => render.outletListItem(outlet))}
</ul>
</li>
`;
return li
},
outletSwitcherButton(outletObj, activeOutlet) {
const { name, outletLinks } = outletObj
const button = document.createElement('a')
button.classList.add('outlet_switcher__button')
if (activeOutlet === outletLinks[0].url) {
button.classList.add('outlet_switcher__button--active')
}
button.href = outletLinks[0].url
button.textContent = name
return button;
},
statusBanner(bannerMsg) {
return html.node`
<section class="banner">
<p class="banner__text">${bannerMsg}</p>
<button class="close-button" onclick="this.parentNode.remove()">
<svg class="icon icon-only close-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
</button>
</section>
`
}
};
const floors = [
"Current Products",
"Blockchain Contracts",
"Blockchain Applications",
"Experimental Ideas",
"Statistics and Administration",
];
/*
Animations
*/
const fadeIn = [{ opacity: 0 }, { opacity: 1 }];
const fadeOut = [{ opacity: 1 }, { opacity: 0 }];
// Slide animations
const slideInLeft = [
{
transform: "translateX(1rem)",
opacity: 0,
},
{
transform: "translateX(0)",
opacity: 1,
},
];
const slideInRight = [
{
transform: "translateX(-1rem)",
opacity: 0,
},
{
transform: "translateX(0)",
opacity: 1,
},
];
const slideOutLeft = [
{
transform: "translateX(0)",
opacity: 1,
},
{
transform: "translateX(-1rem)",
opacity: 0,
},
];
const slideOutRight = [
{
transform: "translateX(0)",
opacity: 1,
},
{
transform: "translateX(1rem)",
opacity: 0,
},
];
const slideInDown = [
{
transform: "translateY(-1rem)",
opacity: 0,
},
{
transform: "translateY(0)",
opacity: 1,
},
];
const slideInUp = [
{
transform: "translateY(1rem)",
opacity: 0,
},
{
transform: "translateY(0)",
opacity: 1,
},
];
const slideOutUp = [
{
transform: "translateY(0)",
opacity: 1,
},
{
transform: "translateY(-1rem)",
opacity: 0,
},
];
const slideOutDown = [
{
transform: "translateY(0)",
opacity: 1,
},
{
transform: "translateY(1rem)",
opacity: 0,
},
];
// eases
const easeInOvershoot = `cubic-bezier(0.6, -0.28, 0.735, 0.045)`;
const easeOutOvershoot = `cubic-bezier(0.175, 0.885, 0.32, 1.275)`;
//////////////////
document.addEventListener('click', e => {
if (e.target.closest('.floor-label, .floor__button')) {
const label = e.target.closest('.floor-label, .floor__button')
const target = label.dataset.target
window.open(`index.html#${target}`, '_self')
if (isSiteMapOpen) {
hideSiteMap()
}
}
})
const outletObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.querySelector("sm-carousel").startAutoPlay();
} else {
entry.target.querySelector("sm-carousel").stopAutoPlay();
}
});
},
{
threshold: 0.6,
}
);
/* document
.querySelectorAll(".carousel-container")
.forEach((outlet) => outletObserver.observe(outlet)); */
let isOutletSwitcherOpen = false;
document.addEventListener("click", (e) => {
if (isOutletSwitcherOpen) {
hideOutletSwitcher();
} else {
if (e.target.closest(".outlet-label")) {
clearTimeout(mouseOverTimeout);
showOutletSwitcher(e.target.closest(".outlet-label"));
}
}
});
let mouseOverTimeout;
document.querySelectorAll(".outlet-label").forEach((label) => {
label.addEventListener("mouseenter", (e) => {
mouseOverTimeout = setTimeout(() => {
showOutletSwitcher(e.target);
}, 300);
});
});
document.querySelectorAll(".outlet-label").forEach((label) => {
label.addEventListener("mouseleave", (e) => {
clearTimeout(mouseOverTimeout);
});
});
function showOutletSwitcher(button) {
if (isOutletSwitcherOpen) return;
isOutletSwitcherOpen = true;
const buttonDimensions = button.getBoundingClientRect();
getRef("outlet_switcher").setAttribute(
"style",
`top: ${buttonDimensions.top + document.documentElement.scrollTop
}px; left: ${buttonDimensions.left}px;`
);
getRef("outlet_switcher").classList.remove("hide-completely");
getRef("outlet_switcher").animate(slideInDown, {
duration: 300,
easing: easeOutOvershoot,
fill: "forwards",
});
getRef("outlet_switcher").setAttribute('tabindex', '-1')
getRef("outlet_switcher").focus()
}
function hideOutletSwitcher() {
if (!isOutletSwitcherOpen) return;
getRef("outlet_switcher").animate(slideOutUp, {
duration: 200,
easing: easeInOvershoot,
fill: "forwards",
}).onfinish = () => {
getRef("outlet_switcher").classList.add("hide-completely");
isOutletSwitcherOpen = false;
};
}
let currentPage
function renderSiteMap() {
getRef('floor_list').append(html.node`${siteMap.map((floor, index) => render.floorListItem(floor, index))}`)
const pathArray = location.pathname.split('/')
siteMap.forEach((floor) => {
const matchedOutlet = floor.outlets.find(outlet => pathArray[pathArray.length - 1].includes(outlet.outletLinks[0].url))
if (matchedOutlet)
renderFloorOutlets(floor, matchedOutlet.outletLinks[0].url)
})
}
renderSiteMap()
function renderFloorOutlets(floorObj, activeOutlet) {
const { floor, outlets } = floorObj
const frag = document.createDocumentFragment()
outlets.forEach(outlet => frag.append(render.outletSwitcherButton(outlet, activeOutlet)))
getRef('outlet_switcher__outlet_container').append(frag)
getRef('outlet_switcher__floor_num').textContent = floor
const outletNum = outlets.findIndex(o => o.outletLinks[0].url === activeOutlet)
document.querySelector('.outlet-label__no').textContent = outletNum + 1
document.querySelector('.outlet-label__no').dataset.number = outletNum + 1
if (outlets[outletNum].hasOwnProperty('status')) {
getRef('main_header').after(render.statusBanner(outlets[outletNum].status))
}
}
let isSiteMapOpen = false;
const animeOptions = {
duration: 600,
fill: "forwards",
easing: "ease",
};
const siteMapTimeline = gsap.timeline({
defaults: { ease: "power3" },
onReverseComplete: resumeScrolling,
paused: true,
});
siteMapTimeline
.from("#elevator_popup", { duration: 0.3, opacity: 0 })
.from(".floor_list__item", { opacity: 0, y: 16, stagger: 0.1 });
function showSiteMap() {
document.querySelectorAll(".page").forEach((page) => {
page.setAttribute("aria-hidden", "true");
});
isSiteMapOpen = true;
pauseScrolling()
getRef("elevator_popup").classList.remove("hide-completely");
siteMapTimeline.duration(0.9).play();
}
function hideSiteMap() {
const scrollY = document.body.style.top;
window.scrollTo(0, parseInt(scrollY || "0") * -1);
siteMapTimeline.duration(0.4).reverse();
document.querySelectorAll(".page").forEach((page) => {
page.removeAttribute("aria-hidden");
});
}
function pauseScrolling() {
document.body.style.overflow = "hidden";
document.body.style.top = `-${window.scrollY}px`;
}
function resumeScrolling() {
document.body.style.overflow = "auto";
document.body.style.top = "initial";
isSiteMapOpen = false;
getRef("elevator_popup").classList.add("hide-completely");
}
let tile, tileParent, tileDimensions, tileParentDimensions, currentRoomId
const animeInOptions = {
duration: 300,
fill: 'forwards',
easing: 'ease'
}
const animeOutOption = {
duration: 300,
fill: 'forwards',
easing: 'ease'
}
window.addEventListener('hashchange', e => {
if (allRooms.length) {
if (window.location.hash !== '') {
showRoom(window.location.hash, true)
renderRoomShorcuts()
}
else {
hideRoom()
}
}
})
let isRoomOpen = false
function showRoom(roomId, animate = false) {
if (roomId === '') return
pauseScrolling()
currentRoomId = roomId.split('#').pop()
tile = document.querySelector(`[href="${roomId}"]`)
tileParent = tile.parentNode
tileDimensions = tile.getBoundingClientRect()
tileParentDimensions = tileParent.getBoundingClientRect()
getRef('expanding_tile').classList.remove('hide-completely')
if (animate && !isRoomOpen) {
getRef('expanding_tile').animate([
{
height: `${tileDimensions.height}px`,
width: `${tileDimensions.width}px`,
transform: `translate(${tileDimensions.left - tileParentDimensions.left}px, ${tileDimensions.top - tileParentDimensions.top - window.pageYOffset}px)`
},
{
height: `${window.innerHeight}px`,
width: `${document.querySelector('main').getBoundingClientRect().width}px`,
transform: `translate(${- tileParentDimensions.left}px, ${- tileParentDimensions.top - window.pageYOffset}px)`
},
],
animeInOptions)
.onfinish = () => {
revealRoom(animate)
}
}
else {
revealRoom(animate)
}
function revealRoom(animate) {
const roomContainer = document.querySelector('.room-container')
roomContainer.querySelectorAll('.room').forEach(child => child.classList.add('hide-completely'))
document.querySelector(roomId).classList.remove('hide-completely')
getRef('room_title').textContent = tile.querySelector('.room-tile__title').textContent
getRef('hero_title').textContent = tile.querySelector('.room-tile__title').textContent
roomContainer.classList.remove('hide-completely')
if (animate && !isRoomOpen) {
roomContainer.animate(slideInDown, animeInOptions)
.onfinish = () => {
getRef('expanding_tile').classList.add('hide-completely')
isRoomOpen = true
}
}
else {
isRoomOpen = true
}
}
}
function hideRoom() {
history.replaceState(null, null, ' ');
const roomContainer = document.querySelector('.room-container')
roomContainer.animate(fadeOut, animeOutOption)
.onfinish = () => {
roomContainer.classList.add('hide-completely')
}
getRef('expanding_tile').classList.remove('hide-completely')
getRef('expanding_tile').animate([
{
height: `${window.innerHeight}px`,
width: `${document.querySelector('main').getBoundingClientRect().width}px`,
transform: `translate(${- tileParentDimensions.left}px, ${- tileParentDimensions.top - window.pageYOffset}px)`
},
{
height: `${tileDimensions.height}px`,
width: `${tileDimensions.width}px`,
transform: `translate(${tileDimensions.left - tileParentDimensions.left}px, ${tileDimensions.top - tileParentDimensions.top - window.pageYOffset}px)`
},
], animeOutOption)
.onfinish = () => {
getRef('expanding_tile').classList.add('hide-completely')
resumeScrolling()
isRoomOpen = false
}
}
const allRooms = document.querySelectorAll('.room-tile')
function renderRoomShorcuts() {
getRef('room_switcher').innerHTML = ''
const frag = document.createDocumentFragment()
allRooms.forEach(room => {
if (room.href.split('#').pop() !== window.location.hash.split('#').pop()) {
const clone = room.cloneNode(true)
clone.classList.remove('room-tile', 'room-tile--main')
if (clone.querySelector('img, svg, #performance_preview'))
clone.querySelectorAll('img, svg, #performance_preview').forEach(elem => elem.remove())
clone.classList.add('room-shortcut')
frag.append(clone)
}
})
getRef('room_switcher').append(frag)
}
if (allRooms.length) {
renderRoomShorcuts()
}
const heroTitleObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
getRef('room_title').animate(slideOutDown, animeInOptions)
.onfinish = () => {
getRef('room_title').classList.add('hide-completely')
}
}
else {
if (isRoomOpen)
getRef('room_title').classList.remove('hide-completely')
getRef('room_title').animate(slideInUp, animeInOptions)
}
})
},
{
threshold: 1
}
)
if (getRef('hero_title')) {
heroTitleObserver.observe(getRef('hero_title'))
}
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}