main.js
← Back to explorer
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
document.querySelectorAll('a[href="#top"]').forEach((link) => {
link.addEventListener("click", (event) => {
event.preventDefault();
window.scrollTo({ top: 0, behavior: "smooth" });
});
});
const themeToggle = document.getElementById("theme-toggle");
const themeThumb = themeToggle.querySelector(".theme-toggle-thumb");
const root = document.documentElement;
function setThemeIcon(theme) {
themeThumb.innerHTML = theme === "dark" ? "☀" : "☽";
}
setThemeIcon(root.getAttribute("data-theme") === "dark" ? "dark" : "light");
themeToggle.addEventListener("click", () => {
const isDark = root.getAttribute("data-theme") === "dark";
if (isDark) {
root.removeAttribute("data-theme");
localStorage.setItem("theme", "light");
setThemeIcon("light");
} else {
root.setAttribute("data-theme", "dark");
localStorage.setItem("theme", "dark");
setThemeIcon("dark");
}
});
const lightbox = document.getElementById("lightbox");
const lightboxImg = lightbox.querySelector(".lightbox-img");
const lightboxClose = lightbox.querySelector(".lightbox-close");
function openLightbox(img) {
lightboxImg.src = img.src;
lightboxImg.alt = img.alt;
lightbox.hidden = false;
document.body.style.overflow = "hidden";
}
function closeLightbox() {
lightbox.hidden = true;
lightboxImg.src = "";
document.body.style.overflow = "";
}
document.querySelectorAll(".fullscreen-btn").forEach((btn) => {
btn.addEventListener("click", () => {
const img = btn.previousElementSibling;
openLightbox(img);
});
});
lightboxClose.addEventListener("click", closeLightbox);
lightbox.addEventListener("click", (event) => {
if (event.target === lightbox) {
closeLightbox();
}
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && !lightbox.hidden) {
closeLightbox();
}
});
function letterboxGap(slide) {
const img = slide.querySelector("img");
if (!img || !img.naturalWidth || !img.naturalHeight) return 0;
const cw = slide.clientWidth;
const ch = slide.clientHeight;
const scale = Math.min(cw / img.naturalWidth, ch / img.naturalHeight);
const renderedHeight = img.naturalHeight * scale;
return Math.max(0, (ch - renderedHeight) / 2);
}
function pinOverlayToImage(slide) {
const gap = letterboxGap(slide);
const btn = slide.querySelector(".fullscreen-btn");
if (btn) btn.style.bottom = gap + 10 + "px";
return gap;
}
function initCarousel(carousel) {
const track = carousel.querySelector(".carousel-track");
const slides = Array.from(track.children);
const prevBtn = carousel.querySelector(".carousel-arrow--prev");
const nextBtn = carousel.querySelector(".carousel-arrow--next");
const dotsWrap = carousel.querySelector(".carousel-dots");
if (slides.length <= 1) {
prevBtn.hidden = true;
nextBtn.hidden = true;
dotsWrap.hidden = true;
return;
}
const dots = slides.map((_, i) => {
const dot = document.createElement("button");
dot.type = "button";
dot.className = "carousel-dot" + (i === 0 ? " active" : "");
dot.setAttribute("aria-label", "Go to image " + (i + 1));
dot.addEventListener("click", () => scrollToSlide(i));
dotsWrap.appendChild(dot);
return dot;
});
slides.forEach((slide) => {
const img = slide.querySelector("img");
if (!img) return;
if (img.complete && img.naturalWidth) {
pinOverlayToImage(slide);
} else {
img.addEventListener("load", () => {
pinOverlayToImage(slide);
updateUI();
});
}
});
function currentIndex() {
return Math.round(track.scrollLeft / track.clientWidth);
}
function scrollToSlide(i) {
track.scrollTo({ left: slides[i].offsetLeft, behavior: "smooth" });
}
function updateUI() {
const index = currentIndex();
dots.forEach((dot, i) => dot.classList.toggle("active", i === index));
prevBtn.style.visibility = index === 0 ? "hidden" : "visible";
nextBtn.style.visibility = index === slides.length - 1 ? "hidden" : "visible";
dotsWrap.style.bottom = pinOverlayToImage(slides[index]) + 14 + "px";
}
prevBtn.addEventListener("click", () => scrollToSlide(Math.max(0, currentIndex() - 1)));
nextBtn.addEventListener("click", () => scrollToSlide(Math.min(slides.length - 1, currentIndex() + 1)));
track.addEventListener("scroll", () => window.requestAnimationFrame(updateUI));
window.addEventListener("resize", () => {
slides.forEach(pinOverlayToImage);
updateUI();
});
updateUI();
}
document.querySelectorAll("[data-carousel]").forEach(initCarousel);
async function initPriceTags() {
const tags = document.querySelectorAll(".price-tag");
if (!tags.length) return;
let usdPerInr = null;
try {
const res = await fetch("https://open.er-api.com/v6/latest/INR");
const data = await res.json();
usdPerInr = data.rates.USD;
} catch (err) {
usdPerInr = null;
}
tags.forEach((tag) => {
const tooltip = tag.querySelector(".price-tooltip");
const inr = parseFloat(tag.dataset.inr);
if (usdPerInr) {
const usd = (inr * usdPerInr).toLocaleString("en-US", {
style: "currency",
currency: "USD",
});
tooltip.textContent = "≈ " + usd;
} else {
tooltip.textContent = "Exchange rate unavailable";
}
});
}
initPriceTags();