achat-maison-albi-fr/src/pages/insights/[...slug].astro
Emil Gulamov c92a067040 Replace color hex codes with Tailwind color palette
Replaced all custom color hex codes used in various component classes with their corresponding color names from the expanded Tailwind color palette. This ensures consistent styling across components and enhances readability and maintainability of the code.
2024-04-07 18:23:16 +04:00

263 lines
7.1 KiB
Text

---
// 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="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" 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>