achat-maison-albi-fr/src/pages/insights/[...slug].astro

216 lines
5.8 KiB
Text
Raw Normal View History

---
// Import section components
import { SITE } from "@/data_files/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="pin" class="mt-10 hidden space-y-4 md:block">
<div class="h-px w-full bg-neutral-300 dark:bg-neutral-700">
<div
id="progress"
class="h-px w-full bg-gradient-to-r from-[#fa5a15]/30 to-[#fa5a15]"
>
</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;
}
@keyframes grow-progress {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
#progress {
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: scroll(block root);
}
#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>
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",
},
});
// Function to create and add an item to the ToC list
function addToC(heading, tocList) {
const li = document.createElement("li");
li.className = "toc-level-" + heading.tagName.toLowerCase();
li.innerHTML =`
<svg class="w-0 h-0" 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">
</path>
</svg>
<a href="#${heading.id}">${heading.textContent}</a>`;
tocList?.appendChild(li);
return li;
}
function setActiveLink(id) {
document.querySelectorAll("#toc li").forEach((li) => {
li.classList.remove("selected");
});
const activeLink = document.querySelector(`#toc a[href="#${id}"]`);
if (activeLink) {
const li: HTMLElement | null = activeLink.parentElement;
li?.classList.add("selected");
}
}
function generateToC(article, tocList) {
// Observe headings and add them to the ToC
let headings: NodeListOf<HTMLElement> | [] = article
? article.querySelectorAll("h1, h2, h3, h4, h5, h6")
: [];
headings.forEach((heading: Element, i: number) => {
if (heading instanceof HTMLElement) {
addToC(heading, tocList);
gsap.timeline({
scrollTrigger: {
trigger: heading,
start: "top 20%",
end: () =>
`bottom top+=${i === headings.length - 1 ? 0 : headings[i + 1].getBoundingClientRect().height}`,
onEnter: () => setActiveLink(heading.id),
},
});
}
});
}
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");
generateToC(article, tocList);
});
</script>