achat-maison-albi-fr/src/pages/insights/[...slug].astro
Emil Gulamov e57a205784 Refactor imports to utilize absolute paths
This commit changes all project imports to use absolute paths instead of relative ones. In addition, the 'tsconfig.json' has been updated to recognize new paths, aiding in easier project navigation and improved readability. The implemented changes result in cleaner imports and a more comprehensible project structure.
2024-04-17 18:25:49 +04:00

263 lines
7.1 KiB
Text

---
// Import section components
import { SITE } from "@data/constants";
import MainLayout from "@/layouts/MainLayout.astro";
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
// Use `getStaticPaths` to generate static routes for generated pages on build
export async function getStaticPaths() {
const insightPosts = await getCollection("insights");
return insightPosts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
// Get the props for this page that define a specific insight post
const { post } = Astro.props;
const { Content } = await post.render();
const pageTitle: string = `${post.data.title} | ${SITE.title}`;
---
<MainLayout title={pageTitle}>
<section class="py-6 sm:py-8 lg:py-12">
<div class="mx-auto max-w-screen-xl px-4 md:px-8">
<div class="grid gap-8 md:grid-cols-2 lg:gap-12">
<div>
<div class="h-64 overflow-hidden rounded-lg shadow-lg md:h-auto">
<Image
class="h-full w-full object-cover object-center"
src={post.data.cardImage}
alt={post.data.cardImageAlt}
draggable={"false"}
format={"avif"}
/>
</div>
<div
id="progress-mobile"
class="fixed left-0 top-0 h-2 w-full bg-gradient-to-r from-orange-400/30 to-orange-400 md:hidden"
>
</div>
<div id="pin" class="mt-10 hidden space-y-4 md:block">
<div
class="h-px w-full overflow-hidden bg-neutral-300 dark:bg-neutral-700"
>
<div
id="progress"
class="h-px w-full bg-gradient-to-r from-orange-400/30 to-orange-400"
>
</div>
</div>
<p class="text-pretty text-sm font-light text-neutral-500">
Table of Contents:
</p>
<div id="toc" class="">
<ul
class="space-y-2 text-pretty text-base text-neutral-700 transition duration-300 dark:text-neutral-400"
>
</ul>
</div>
</div>
</div>
<div class="md:pt-8">
<h1
class="mb-4 text-balance text-center text-2xl font-bold text-neutral-800 dark:text-neutral-200 sm:text-3xl md:mb-6 md:text-left"
>
{post.data.title}
</h1>
<article
class="text-pretty text-lg text-neutral-700 dark:text-neutral-300"
>
<Content />
</article>
</div>
</div>
</div>
</section>
</MainLayout>
<style is:global>
:root {
--transition-cubic: cubic-bezier(0.165, 0.84, 0.44, 1);
}
html {
scroll-behavior: smooth;
}
article h2,
article h3,
article h4,
article h5,
article h6 {
font-weight: bold;
margin-top: 2.5rem;
scroll-margin-top: 3rem;
}
h2 {
font-size: 1.5rem;
line-height: 2rem;
}
h3 {
font-size: 1.25rem;
line-height: 1.75rem;
}
h4 {
font-size: 1.125rem;
line-height: 1.75rem;
}
p {
margin-top: 1.5rem;
}
#toc li {
display: flex;
align-items: center;
opacity: 0.8;
transition: all 300ms var(--transition-cubic);
}
#toc li.selected {
opacity: 1;
}
#toc li svg {
width: 0;
height: 0;
transition:
height 400ms var(--transition-cubic),
width 400ms var(--transition-cubic);
}
#toc li.selected svg {
width: 1.25rem;
height: 1.25rem;
margin-right: 0.3rem;
}
</style>
<script>
const onScroll = (): void => {
const article = document.querySelector("article");
if (!article) return;
const articleHeight = article.offsetHeight;
const articleOffsetTop = article.offsetTop;
const scrollTop = window.scrollY || document.documentElement.scrollTop;
if (articleHeight && articleOffsetTop && scrollTop) {
const progress =
((scrollTop - articleOffsetTop) /
(articleHeight - window.innerHeight)) *
100;
const progressBar = document.getElementById("progress");
const progressBarMobile = document.getElementById("progress-mobile");
if (progressBar && progressBarMobile) {
progressBar.style.width = `${progress}%`;
progressBarMobile.style.width = `${progress}%`;
}
}
};
document.addEventListener("DOMContentLoaded", (event) => {
window.onscroll = onScroll;
// Set initial width of progress bar
const progressBar = document.getElementById("progress");
const progressBarMobile = document.getElementById("progress-mobile");
if (progressBar && progressBarMobile) {
progressBar.style.width = "0%";
progressBarMobile.style.width = "0%";
}
});
</script>
<script>
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
gsap.timeline({
scrollTrigger: {
scrub: 1,
pin: true,
trigger: "#pin",
start: "top 20%",
endTrigger: "footer",
end: "top bottom",
},
});
const SVG_HTML_STRING =
'<svg class="w-0 h-0 flex-none" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#fa5a15"><path stroke-linecap="round" stroke-linejoin="round" d="m12.75 15 3-3m0 0-3-3m3 3h-7.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"></svg>';
function setActiveLinkById(id: string | null) {
const listItems = document.querySelectorAll("#toc li");
listItems.forEach((item) => item.classList.remove("selected"));
if (!id) return;
const activeLink = document.querySelector(`#toc a[href="#${id}"]`);
if (!activeLink) return;
const listItem = activeLink.parentElement;
listItem?.classList.add("selected");
}
document.addEventListener("DOMContentLoaded", function () {
// The article element that contains the Markdown content
const article: HTMLElement | null = document.querySelector("article");
// The ToC container <ul> element
const tocList: HTMLElement | null = document.querySelector("#toc ul");
const headings: NodeListOf<HTMLElement> | [] = article
? article.querySelectorAll("h1, h2, h3, h4, h5, h6")
: [];
headings.forEach((heading, i) => {
if (heading instanceof HTMLElement) {
const listItem = document.createElement("li");
listItem.className = "toc-level-" + heading.tagName.toLowerCase();
const tempDiv = document.createElement("div");
tempDiv.innerHTML = SVG_HTML_STRING;
const svg = tempDiv.firstChild;
listItem.appendChild(svg as Node);
const link = document.createElement("a");
link.href = "#" + heading.id;
link.textContent = heading.textContent;
listItem.appendChild(link);
tocList?.appendChild(listItem);
gsap.timeline({
scrollTrigger: {
trigger: heading,
start: "top 20%",
end: () =>
`bottom top+=${i === headings.length - 1 ? 0 : (headings[i + 1] as HTMLElement).getBoundingClientRect().height}`,
onEnter: () => setActiveLinkById(heading.id),
onLeaveBack: () =>
setActiveLinkById((headings[i - 1] as HTMLElement)?.id),
},
});
}
});
});
</script>