achat-maison-albi-fr/src/pages/fr/products/[...slug].astro
Emil Gulamov d1c619bb9e Refactor language switching logic for blog posts, insights and products
- Ensure URLs maintain correct structure without duplicating language prefixes
- Update script to dynamically reconstruct URLs when switching languages
- Improve logic for adding and removing language prefixes based on current path
2024-09-08 14:53:53 +04:00

391 lines
12 KiB
Text

---
// Import section components
import MainLayout from "@/layouts/MainLayout.astro";
import ProductTabBtn from "@components/ui/buttons/ProductTabBtn.astro";
import PrimaryCTA from "@components/ui/buttons/PrimaryCTA.astro";
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
import { SITE } from "@data/constants";
// Global declaration for gsap animation library
declare global {
interface Window {
gsap: any;
}
}
// This gets the static paths for all the unique products
export async function getStaticPaths() {
const productEntries = await getCollection("products", ({ id }) =>
id.startsWith("fr/")
);
return productEntries.map((product) => {
const slugWithoutLang = product.slug.replace(/^fr\//, ""); // Remove the "fr/" prefix
return {
params: { lang: "fr", slug: slugWithoutLang },
props: { product },
};
});
}
const { product } = Astro.props;
const pageTitle: string = `${product.data.title} | ${SITE.title}`;
---
<MainLayout title={pageTitle}>
<div id="overlay" class="fixed inset-0 bg-neutral-200 dark:bg-neutral-800">
</div>
<section
class="mx-auto flex max-w-[85rem] flex-col px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div>
<p
id="fadeText"
class="mb-8 max-w-prose text-pretty font-light text-neutral-700 dark:text-neutral-300 sm:text-xl"
>
{product.data.main.content}
</p>
</div>
<div
class="flex flex-col items-center justify-between space-y-4 sm:flex-row sm:space-y-0"
>
<div id="fadeInUp">
<h1
class="block text-4xl font-bold tracking-tighter text-neutral-800 dark:text-neutral-200 sm:text-5xl md:text-6xl lg:text-7xl"
>
{product.data.title}
</h1>
<p class="text-lg text-neutral-600 dark:text-neutral-400">
{product.data.description}
</p>
</div>
<div>
<Image
id="fadeInMoveRight"
src={product.data.main.imgMain}
class="w-[600px]"
alt={product.data.main.imgAlt}
format={"avif"}
loading={"eager"}
/>
</div>
</div>
</section>
<div class="mx-auto max-w-[85rem] px-4 pt-10 sm:px-6 lg:px-8 lg:pt-14">
<nav
class="mx-auto grid max-w-6xl gap-y-px sm:flex sm:gap-x-4 sm:gap-y-0"
aria-label="Tabs"
role="tablist"
>
{
product.data.tabs.map((tab, index) => (
<ProductTabBtn
title={tab.title}
id={tab.id}
dataTab={tab.dataTab}
first={index === 0}
/>
))
}
</nav>
<div class="mt-12 md:mt-16">
<div id="tabs-with-card-1" role="tabpanel">
<div class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14">
<div class="grid gap-12 md:grid-cols-2">
<div class="lg:w-3/4">
<h2
class="text-balance text-3xl font-bold tracking-tight text-neutral-800 dark:text-neutral-200 md:leading-tight lg:text-4xl"
>
{product.data.longDescription.title}
</h2>
<p
class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400"
>
{product.data.longDescription.subTitle}
</p>
<p class="mt-5">
<PrimaryCTA
title={product.data.longDescription.btnTitle}
url={product.data.longDescription.btnURL}
/>
</p>
</div>
<div class="space-y-6 lg:space-y-10">
{
product.data.descriptionList.map((list) => (
<div class="flex">
<div>
<h3 class="text-base font-bold text-neutral-800 dark:text-neutral-200 sm:text-lg">
{list.title}
</h3>
<p class="mt-1 text-neutral-600 dark:text-neutral-400">
{list.subTitle}
</p>
</div>
</div>
))
}
</div>
</div>
</div>
</div>
<div id="tabs-with-card-2" class="hidden" role="tabpanel">
<div class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14">
<div class="grid w-full grid-cols-1 gap-x-16 md:grid-cols-2">
<div class="max-w-md space-y-6">
{
product.data.specificationsLeft.map((spec) => (
<div>
<h3 class="block font-bold text-neutral-800 dark:text-neutral-200">
{spec.title}
</h3>
<p class="text-neutral-600 dark:text-neutral-400">
{spec.subTitle}
</p>
</div>
))
}
</div>
{
product.data.specificationsRight ? (
<div class="mt-6 max-w-md space-y-6 md:ml-auto md:mt-0">
{product.data.specificationsRight?.map((spec) => (
<div>
<h3 class="block font-bold text-neutral-800 dark:text-neutral-200">
{spec.title}
</h3>
<p class="text-neutral-600 dark:text-neutral-400">
{spec.subTitle}
</p>
</div>
))}
</div>
) : product.data.tableData ? (
<div class="mt-6 space-y-6 md:ml-auto md:mt-0">
<div class="flex flex-col">
<div class="-m-1.5 overflow-x-auto">
<div class="inline-block min-w-full p-1.5 align-middle">
<div class="overflow-hidden">
<table class="min-w-full divide-y divide-neutral-300 dark:divide-neutral-700">
<thead>
<tr>
{product.data.tableData?.[0].feature?.map(
(header) => (
<th
scope="col"
class="px-6 py-3 text-start text-xs font-medium uppercase text-neutral-500 dark:text-neutral-500"
>
{header}
</th>
)
)}
</tr>
</thead>
<tbody class="divide-y divide-neutral-300 dark:divide-neutral-700">
{product.data.tableData?.map((row) =>
// Wrap each row's content in a separate <tr> element
row.description.map((rowData) => (
<tr>
{/* Iterate through each cell value in the row's description array */}
{rowData.map((cellValue) => (
// Render each cell value in its own <td> element
<td class="whitespace-nowrap px-6 py-4 text-sm font-medium text-neutral-600 dark:text-neutral-400">
{cellValue}
</td>
))}
</tr>
))
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
) : null
}
</div>
</div>
</div>
</div>
</div>
<div id="tabs-with-card-3" class="hidden" role="tabpanel">
<div class="mx-auto mb-20 flex w-full md:mb-28 2xl:w-4/5">
<div
class="relative left-12 top-12 z-10 overflow-hidden rounded-xl shadow-lg md:left-12 md:top-16 md:-ml-12 lg:ml-0"
>
{
product.data.blueprints.first && (
<Image
src={product.data.blueprints.first}
class="h-full w-full object-cover object-center"
alt="Blueprint Illustration"
format={"avif"}
/>
)
}
</div>
<div class="relative right-12 overflow-hidden rounded-xl shadow-xl">
{
product.data.blueprints.second && (
<Image
src={product.data.blueprints.second}
class="h-full w-full object-cover object-center"
alt="Blueprint Illustration"
format={"avif"}
/>
)
}
</div>
</div>
</div>
</MainLayout>
<script>
import { gsap } from "gsap";
type AnimationSettings = {
autoAlpha?: number;
y?: number;
x?: number;
willChange?: string;
};
function setElementAnimationDefaults(
id: string,
settings: AnimationSettings
) {
gsap.set(id, settings);
}
setElementAnimationDefaults("#fadeText", {
autoAlpha: 0,
y: 50,
willChange: "transform, opacity",
});
setElementAnimationDefaults("#fadeInUp", {
autoAlpha: 0,
y: 50,
willChange: "transform, opacity",
});
setElementAnimationDefaults("#fadeInMoveRight", {
autoAlpha: 0,
x: 300,
willChange: "transform, opacity",
});
let timeline = gsap.timeline({ defaults: { overwrite: "auto" } });
timeline.to("#fadeText", {
duration: 1.5,
autoAlpha: 1,
y: 0,
delay: 1,
ease: "power2.out",
});
timeline.to(
"#fadeInUp",
{ duration: 1.5, autoAlpha: 1, y: 0, ease: "power2.out" },
"-=1.2"
);
timeline.to(
"#fadeInMoveRight",
{ duration: 1.5, autoAlpha: 1, x: 0, ease: "power2.inOut" },
"-=1.4"
);
timeline.to("#overlay", { duration: 1, autoAlpha: 0, delay: 0.2 });
</script>
<script>
document.addEventListener("DOMContentLoaded", function () {
function setButtonInactive(btn: any, activeButton: any) {
if (btn !== activeButton) {
btn.classList.remove(
"active",
"bg-neutral-100",
"hover:border-transparent",
"dark:bg-white/[.05]"
);
const tabId = btn.getAttribute("data-target");
if (tabId) {
const contentElement = document.querySelector(tabId);
if (contentElement) {
contentElement.classList.add("hidden");
}
}
changeHeadingStyle(
btn,
["text-neutral-800", "dark:text-neutral-200"],
["text-orange-400", "dark:text-orange-300"]
);
}
}
function activateButton(button: any) {
button.classList.add(
"active",
"bg-neutral-100",
",hover:border-transparent",
"dark:bg-white/[.05]"
);
const tabId = button.getAttribute("data-target");
if (tabId) {
const contentElementToShow = document.querySelector(tabId);
if (contentElementToShow) {
contentElementToShow.classList.remove("hidden");
}
}
changeHeadingStyle(
button,
["text-orange-400", "dark:text-orange-300"],
["text-neutral-800", "dark:text-neutral-200"]
);
}
function changeHeadingStyle(
button: any,
addClasses: any,
removeClasses: any
) {
let heading = button.querySelector("span");
if (heading) {
heading.classList.remove(...removeClasses);
heading.classList.add(...addClasses);
}
}
const tabButtons = document.querySelectorAll("[data-target]");
if (tabButtons.length > 0) {
changeHeadingStyle(
tabButtons[0],
["text-orange-400", "dark:text-orange-300"],
[]
);
}
tabButtons.forEach((button) => {
button.addEventListener("click", () => {
tabButtons.forEach((btn) => setButtonInactive(btn, button));
activateButton(button);
});
});
});
</script>