Files
jleibl.net/src/pages/index.astro

163 lines
4.7 KiB
Plaintext

---
import Header from "../components/layout/Header.astro";
import Meta from "../components/layout/Meta.astro";
import SkipToContent from "../components/ui/SkipToContent.astro";
import Hero from "../components/sections/Hero.astro";
import About from "../components/sections/About.astro";
import Work from "../components/sections/Work.astro";
import BlogPreview from "../components/sections/BlogPreview.astro";
import Contact from "../components/sections/Contact.astro";
import Footer from "../components/layout/Footer.astro";
import "../styles/global.css";
import "../styles/theme.css";
import "@fontsource/dm-sans/400.css";
import "@fontsource/dm-sans/500.css";
import "@fontsource/dm-sans/600.css";
import "@fontsource/dm-sans/700.css";
import "@fontsource/instrument-sans/400.css";
import "@fontsource/instrument-sans/500.css";
---
<html lang="en">
<head>
<Meta />
</head>
<body>
<SkipToContent />
<div id="app-root" class="min-h-screen theme-transition black overflow-hidden">
<Header />
<main id="main-content">
<Hero />
<About />
<Work />
<BlogPreview />
<Contact />
</main>
<Footer />
</div>
</body>
</html>
<script>
document.addEventListener("DOMContentLoaded", () => {
const appRoot = document.getElementById("app-root");
const themeButtons = document.querySelectorAll(".theme-button");
const currentTheme = localStorage.getItem("colorTheme") || "black";
if (appRoot) {
appRoot.classList.remove("black", "red", "gold");
appRoot.classList.add(currentTheme);
}
document.documentElement.setAttribute("data-theme", currentTheme);
document.getElementById(`theme-${currentTheme}`)?.classList.add("ring-1", "ring-white/20");
document.addEventListener("themeChanged", (e) => {
const customEvent = e as Event & { detail: { theme: string } };
const newTheme = customEvent.detail.theme;
if (appRoot && newTheme) {
appRoot.classList.remove("black", "red", "gold");
appRoot.classList.add(newTheme);
localStorage.setItem("colorTheme", newTheme);
}
});
});
</script>
<script>
import Lenis from "lenis";
document.addEventListener("DOMContentLoaded", () => {
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
smoothWheel: true,
wheelMultiplier: 1,
touchMultiplier: 2,
infinite: false,
});
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach((link) => {
link.addEventListener("click", (e) => {
e.preventDefault();
const targetId = link.getAttribute("href");
if (targetId && targetId !== "#") {
const targetElement = document.querySelector(targetId);
if (targetElement) {
lenis.scrollTo(targetElement as HTMLElement, {
offset: 0,
duration: 1.2,
immediate: false,
});
}
}
});
});
let animationId: number;
function raf(time: number) {
lenis.raf(time);
animationId = requestAnimationFrame(raf);
}
animationId = requestAnimationFrame(raf);
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
cancelAnimationFrame(animationId);
} else {
animationId = requestAnimationFrame(raf);
}
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", () => {
if ("loading" in HTMLImageElement.prototype) {
const lazyImages = document.querySelectorAll("img[data-src]");
lazyImages.forEach((img) => {
const imgElement = img as HTMLImageElement;
imgElement.src = imgElement.dataset.src || "";
imgElement.removeAttribute("data-src");
});
} else {
const lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const lazyImage = entry.target as HTMLImageElement;
if (lazyImage.dataset.src) {
lazyImage.src = lazyImage.dataset.src;
lazyImage.removeAttribute("data-src");
}
lazyImageObserver.unobserve(lazyImage);
}
});
});
document.querySelectorAll("img[data-src]").forEach((image) => {
lazyImageObserver.observe(image);
});
}
});
</script>
<script>
if ("serviceWorker" in navigator && import.meta.env.PROD) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/service-worker.js").catch((error) => {
console.error("Service worker registration failed:", error);
});
});
}
</script>