Update logic for loading blog posts in different languages
The changes in this commit involve updates to the logic that drives loading of blog posts. Further changes were made to various components to pass the locale as a prop, which is then used for URL formation in these components.
This commit is contained in:
parent
2da6ae38af
commit
dc1b76b20f
9 changed files with 64 additions and 91 deletions
|
@ -25,10 +25,11 @@ import Icon from "./icons/Icon.astro";
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="hs-dropdown-menu duration mt-2 hidden rounded-lg bg-neutral-50 p-2 opacity-0 shadow-md transition-[opacity,margin] before:absolute before:-top-4 before:start-0 before:h-4 before:w-full after:absolute after:-bottom-4 after:start-0 after:h-4 after:w-full hs-dropdown-open:opacity-100 dark:divide-neutral-700 dark:border dark:border-neutral-700 dark:bg-neutral-800 !transform-none !top-[98%] !left-[20%] md:!top-[80%] md:!left-[90%]"
|
class="hs-dropdown-menu duration !left-[20%] !top-[98%] mt-2 hidden !transform-none rounded-lg bg-neutral-50 p-2 opacity-0 shadow-md transition-[opacity,margin] before:absolute before:-top-4 before:start-0 before:h-4 before:w-full after:absolute after:-bottom-4 after:start-0 after:h-4 after:w-full hs-dropdown-open:opacity-100 dark:divide-neutral-700 dark:border dark:border-neutral-700 dark:bg-neutral-800 md:!left-[90%] md:!top-[80%]"
|
||||||
aria-labelledby="hs-dropdown-hover-event"
|
aria-labelledby="hs-dropdown-hover-event"
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
// Map through the list of languages, creating a link for each language
|
||||||
Object.entries(languages).map(([lang, label]) => (
|
Object.entries(languages).map(([lang, label]) => (
|
||||||
<a
|
<a
|
||||||
class="flex items-center gap-x-3.5 rounded-lg px-3 py-2 text-sm text-neutral-800 hover:bg-neutral-100 focus:bg-neutral-100 focus:outline-none dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:bg-neutral-700"
|
class="flex items-center gap-x-3.5 rounded-lg px-3 py-2 text-sm text-neutral-800 hover:bg-neutral-100 focus:bg-neutral-100 focus:outline-none dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:bg-neutral-700"
|
||||||
|
@ -46,7 +47,9 @@ import Icon from "./icons/Icon.astro";
|
||||||
<script is:inline src="/scripts/vendor/preline/dropdown/index.js"></script>
|
<script is:inline src="/scripts/vendor/preline/dropdown/index.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Type alias for supported languages
|
||||||
type TLanguage = "en" | "fr";
|
type TLanguage = "en" | "fr";
|
||||||
|
// array of supported languages
|
||||||
const languages: TLanguage[] = ["en", "fr"];
|
const languages: TLanguage[] = ["en", "fr"];
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
@ -68,8 +71,18 @@ import Icon from "./icons/Icon.astro";
|
||||||
|
|
||||||
if (lang === url.pathname.split("/")[1]) return;
|
if (lang === url.pathname.split("/")[1]) return;
|
||||||
|
|
||||||
if (lang !== "en") {
|
if (url.pathname.includes("/post")) {
|
||||||
pathParts.unshift(lang);
|
if (url.pathname.includes("en")) {
|
||||||
|
pathParts.unshift(lang);
|
||||||
|
pathParts.splice(2, 0, lang);
|
||||||
|
} else {
|
||||||
|
pathParts.unshift(lang);
|
||||||
|
pathParts.splice(2, 0, "en");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lang !== "en") {
|
||||||
|
pathParts.unshift(lang);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url.pathname = pathParts.join("/");
|
url.pathname = pathParts.join("/");
|
||||||
|
|
|
@ -5,10 +5,11 @@ import { Image } from "astro:assets";
|
||||||
import { formatDate } from "@utils/utils";
|
import { formatDate } from "@utils/utils";
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
|
|
||||||
const { blogEntry } = Astro.props;
|
const { blogEntry, blogLocale = "" } = Astro.props;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
blogEntry: CollectionEntry<"blog">;
|
blogEntry: CollectionEntry<"blog">;
|
||||||
|
blogLocale?: string;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ interface Props {
|
||||||
which automatically prefetches the linked page to speed up navigation. -->
|
which automatically prefetches the linked page to speed up navigation. -->
|
||||||
<a
|
<a
|
||||||
class="group relative block rounded-xl outline-none ring-zinc-500 transition duration-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
|
class="group relative block rounded-xl outline-none ring-zinc-500 transition duration-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
|
||||||
href={`/blog/${blogEntry.slug}/`}
|
href={blogLocale !== "" ? `/${blogLocale}/blog/${blogEntry.slug}/` : `/blog/${blogEntry.slug}/`}
|
||||||
data-astro-prefetch
|
data-astro-prefetch
|
||||||
>
|
>
|
||||||
<!-- The container for the blog post's cover image. Uses astro:assets' Image for image source -->
|
<!-- The container for the blog post's cover image. Uses astro:assets' Image for image source -->
|
||||||
|
|
|
@ -5,10 +5,11 @@ import type { CollectionEntry } from "astro:content";
|
||||||
import AvatarBlogLarge from "@components/ui/avatars/AvatarBlogLarge.astro";
|
import AvatarBlogLarge from "@components/ui/avatars/AvatarBlogLarge.astro";
|
||||||
import PrimaryCTA from "@components/ui/buttons/PrimaryCTA.astro";
|
import PrimaryCTA from "@components/ui/buttons/PrimaryCTA.astro";
|
||||||
|
|
||||||
const { blogEntry } = Astro.props;
|
const { blogEntry, recentBlogLocale = "" } = Astro.props;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
blogEntry: CollectionEntry<"blog">;
|
blogEntry: CollectionEntry<"blog">;
|
||||||
|
recentBlogLocale?: string;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ interface Props {
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="outline-none ring-zinc-500 transition duration-300 hover:text-orange-400 focus-visible:ring dark:text-neutral-300 dark:ring-zinc-200 dark:hover:text-neutral-50 dark:focus:outline-none"
|
class="outline-none ring-zinc-500 transition duration-300 hover:text-orange-400 focus-visible:ring dark:text-neutral-300 dark:ring-zinc-200 dark:hover:text-neutral-50 dark:focus:outline-none"
|
||||||
href={`/blog/${blogEntry.slug}/`}
|
href={recentBlogLocale !== "" ? `/${recentBlogLocale}/blog/${blogEntry.slug}/` : `/blog/${blogEntry.slug}/`}
|
||||||
>
|
>
|
||||||
{blogEntry.data.description}
|
{blogEntry.data.description}
|
||||||
</a>
|
</a>
|
||||||
|
@ -56,7 +57,7 @@ interface Props {
|
||||||
<!-- Read More button which is a link to the blog post detailed page -->
|
<!-- Read More button which is a link to the blog post detailed page -->
|
||||||
<div class="mt-5">
|
<div class="mt-5">
|
||||||
<PrimaryCTA
|
<PrimaryCTA
|
||||||
url={`/blog/${blogEntry.slug}/`}
|
url={recentBlogLocale !== "" ? `/${recentBlogLocale}/blog/${blogEntry.slug}/` : `/blog/${blogEntry.slug}/`}
|
||||||
title="Read More"
|
title="Read More"
|
||||||
data-astro-prefetch
|
data-astro-prefetch
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
title: "Maximizing Efficiency with ScrewFast's Cutting-Edge Tools"
|
|
||||||
description: "Innovating Construction Efficiency with Precision Tools & Support"
|
|
||||||
author: "Jacob"
|
|
||||||
authorImage: "@/images/blog/jacob.avif"
|
|
||||||
authorImageAlt: "Avatar Description"
|
|
||||||
pubDate: 2024-02-06
|
|
||||||
cardImage: "@/images/blog/post-1.avif"
|
|
||||||
cardImageAlt: "Top view mechanical tools arrangement"
|
|
||||||
readTime: 4
|
|
||||||
tags: ["tools", "construction", "workflow" ]
|
|
||||||
contents: [
|
|
||||||
"In today's fast-paced construction industry, efficiency is key to success. At ScrewFast, we understand the importance of optimizing your project workflow to meet deadlines and stay within budget. That's why we're thrilled to introduce our cutting-edge tools designed to empower your projects like never before.",
|
|
||||||
"Our range of hardware tools combines precision engineering with user-centric design, ensuring maximum productivity on every job site. From power drills to advanced fastening solutions, ScrewFast's tools are built to withstand the rigors of construction while streamlining your workflow.",
|
|
||||||
"One of our standout offerings is our intuitive dashboards, which provide real-time insights into project progress, resource allocation, and more. With user-friendly interfaces, navigating and overseeing your projects has never been easier.",
|
|
||||||
"But efficiency isn't just about the tools you use—it's also about the support you receive. That's why ScrewFast offers comprehensive documentation and expert guidance every step of the way. Our dedicated teams are committed to your success, providing personalized assistance to ensure you get the most out of our products.",
|
|
||||||
"Join the countless industry leaders who have already experienced the difference ScrewFast tools can make. With our cutting-edge solutions, you can fast-track your projects to success and stay ahead of the competition."
|
|
||||||
]
|
|
||||||
---
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
title: "Enhancing Safety and Workmanship with ScrewFast Construction Services"
|
|
||||||
description: "Quality construction services for lasting results"
|
|
||||||
author: "Brad"
|
|
||||||
authorImage: "@/images/blog/brad.avif"
|
|
||||||
authorImageAlt: "Avatar Description"
|
|
||||||
pubDate: 2024-02-10
|
|
||||||
cardImage: "@/images/blog/post-2.avif"
|
|
||||||
cardImageAlt: "Man in black sweatpants using DEWALT circular saw and cutting a wood plank"
|
|
||||||
readTime: 5
|
|
||||||
tags: ["safety", "craftsmanship", "management" ]
|
|
||||||
contents: [
|
|
||||||
"When it comes to construction, safety and quality workmanship are non-negotiable. At ScrewFast, we're proud to offer a range of construction services that prioritize both, ensuring your projects are built to last.",
|
|
||||||
"Our team of skilled craftsmen brings precision and expertise to every job, from minor installations to large-scale structural work. With top-quality tools and materials from our extensive inventory, we guarantee the highest standards of safety and craftsmanship on every project.",
|
|
||||||
"But our commitment to excellence doesn't end there. We also provide thorough project management services to keep your build on track and within budget. From workflow coordination to stakeholder communication, ScrewFast handles the complexities so you can focus on your vision.",
|
|
||||||
"What sets ScrewFast apart is our dedication to ongoing support. We don't just finish the job and walk away—we're here for the long haul. Our maintenance services ensure that your construction remains in optimal condition, providing peace of mind for years to come.",
|
|
||||||
"For larger enterprise clients, we offer custom solutions tailored to your unique challenges. By understanding your specific needs, we engineer strategies aimed at maximizing efficiency and driving your business forward.",
|
|
||||||
"With ScrewFast construction services, you can trust that your projects are in good hands. Experience the difference today and see why so many clients choose ScrewFast for their construction needs."
|
|
||||||
]
|
|
||||||
---
|
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
title: "Simplify Procurement and Stay Within Budget with ScrewFast"
|
|
||||||
description: "Affordable, durable tools for efficient construction projects"
|
|
||||||
author: "Olga Zabegina"
|
|
||||||
role: "Strategic Marketing Manager"
|
|
||||||
authorImage: "@/images/blog/anna.avif"
|
|
||||||
authorImageAlt: "Avatar Description"
|
|
||||||
pubDate: 2024-02-18
|
|
||||||
cardImage: "@/images/blog/post-3.avif"
|
|
||||||
cardImageAlt: "Side view worker wearing gloves"
|
|
||||||
readTime: 3
|
|
||||||
tags: ["procurement", "affordable", "efficiency" ]
|
|
||||||
contents: [
|
|
||||||
"Managing a construction project can be overwhelming, especially when it comes to procurement. That's why ScrewFast is committed to simplifying the process and keeping your projects within budget.",
|
|
||||||
"With our line of affordable tools and equipment, you can find everything you need without breaking the bank. Our user-centric design ensures that our products are easy to use, saving you time and frustration on the job site.",
|
|
||||||
"But affordability doesn't mean sacrificing quality. ScrewFast products are built to last, providing reliable performance and durability when you need it most. And with our comprehensive documentation and tutorials, you can integrate our products seamlessly into your workflow, maximizing efficiency and productivity.",
|
|
||||||
"Whether you're a DIY enthusiast or a seasoned contractor, ScrewFast has the solutions you need to succeed. Experience the difference for yourself and see why ScrewFast is the trusted choice for hardware and construction needs."
|
|
||||||
]
|
|
||||||
---
|
|
|
@ -14,7 +14,9 @@ import { SITE } from "@data/constants";
|
||||||
|
|
||||||
// getStaticPaths is used to pre-render all routes based on the blog posts
|
// getStaticPaths is used to pre-render all routes based on the blog posts
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const blogPosts = await getCollection("blog");
|
const blogPosts = await getCollection("blog", ({ id }) => {
|
||||||
|
return id.startsWith("en/");
|
||||||
|
});
|
||||||
return blogPosts.map((post) => ({
|
return blogPosts.map((post) => ({
|
||||||
params: { slug: post.slug },
|
params: { slug: post.slug },
|
||||||
props: { post },
|
props: { post },
|
||||||
|
@ -24,7 +26,12 @@ export async function getStaticPaths() {
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
|
|
||||||
// Get all blog posts
|
// Get all blog posts
|
||||||
const blogPosts: CollectionEntry<"blog">[] = await getCollection("blog");
|
const blogPosts: CollectionEntry<"blog">[] = await getCollection(
|
||||||
|
"blog",
|
||||||
|
({ id }) => {
|
||||||
|
return id.startsWith("en/");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Filter out the current post to get related posts
|
// Filter out the current post to get related posts
|
||||||
// Note: This is a very basic way of choosing related posts, just for the purpose of the example.
|
// Note: This is a very basic way of choosing related posts, just for the purpose of the example.
|
||||||
|
@ -35,12 +42,9 @@ const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter(
|
||||||
);
|
);
|
||||||
|
|
||||||
const pageTitle: string = `${post.data.title} | ${SITE.title}`;
|
const pageTitle: string = `${post.data.title} | ${SITE.title}`;
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<MainLayout
|
<MainLayout title={pageTitle}>
|
||||||
title={pageTitle}
|
|
||||||
>
|
|
||||||
<section class="mx-auto max-w-3xl px-4 pb-12 pt-6 sm:px-6 lg:px-8 lg:pt-10">
|
<section class="mx-auto max-w-3xl px-4 pb-12 pt-6 sm:px-6 lg:px-8 lg:pt-10">
|
||||||
<div class="max-w-2xl">
|
<div class="max-w-2xl">
|
||||||
<div class="mb-6 flex items-center justify-between">
|
<div class="mb-6 flex items-center justify-between">
|
||||||
|
|
|
@ -8,10 +8,15 @@ import { getCollection } from "astro:content";
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { SITE } from "@data/constants";
|
import { SITE } from "@data/constants";
|
||||||
|
|
||||||
// Get all blogs post and sort them based on publish date
|
// Get all blogs post in English and sort them based on publish date
|
||||||
const blogPosts: CollectionEntry<"blog">[] = (await getCollection("blog")).sort(
|
|
||||||
|
const englishBlogEntries = await getCollection("blog", ({ id }) => {
|
||||||
|
return id.startsWith("en/");
|
||||||
|
});
|
||||||
|
|
||||||
|
const blogPosts: CollectionEntry<"blog">[] = englishBlogEntries.sort(
|
||||||
(a: CollectionEntry<"blog">, b: CollectionEntry<"blog">) =>
|
(a: CollectionEntry<"blog">, b: CollectionEntry<"blog">) =>
|
||||||
b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||||
);
|
);
|
||||||
// Get all insights posts
|
// Get all insights posts
|
||||||
const insightPosts: CollectionEntry<"insights">[] =
|
const insightPosts: CollectionEntry<"insights">[] =
|
||||||
|
@ -38,16 +43,18 @@ const pageTitle: string = `Blog | ${SITE.title}`;
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "WebPage",
|
"@type": "WebPage",
|
||||||
"@id": "https://screwfast.uk/blog",
|
"@id": "https://screwfast.uk/blog",
|
||||||
"url": "https://screwfast.uk/blog",
|
url: "https://screwfast.uk/blog",
|
||||||
"name": "Blog | ScrewFast",
|
name: "Blog | ScrewFast",
|
||||||
"description": "Stay up-to-date with the latest trends and developments in the construction industry with insights from ScrewFast's team of industry experts.",
|
description:
|
||||||
"isPartOf": {
|
"Stay up-to-date with the latest trends and developments in the construction industry with insights from ScrewFast's team of industry experts.",
|
||||||
|
isPartOf: {
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
"url": "https://screwfast.uk",
|
url: "https://screwfast.uk",
|
||||||
"name": "ScrewFast",
|
name: "ScrewFast",
|
||||||
"description": "ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs."
|
description:
|
||||||
|
"ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs.",
|
||||||
},
|
},
|
||||||
"inLanguage": "en-US"
|
inLanguage: "en-US",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
|
|
|
@ -8,8 +8,13 @@ import { getCollection } from "astro:content";
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { SITE } from "@data/constants";
|
import { SITE } from "@data/constants";
|
||||||
|
|
||||||
// Get all blogs post and sort them based on publish date
|
// Get all blogs post in French and sort them based on publish date
|
||||||
const blogPosts: CollectionEntry<"blog">[] = (await getCollection("blog")).sort(
|
|
||||||
|
const frenchBlogEntries = await getCollection("blog", ({ id }) => {
|
||||||
|
return id.startsWith("fr/");
|
||||||
|
});
|
||||||
|
|
||||||
|
const blogPosts: CollectionEntry<"blog">[] = frenchBlogEntries.sort(
|
||||||
(a: CollectionEntry<"blog">, b: CollectionEntry<"blog">) =>
|
(a: CollectionEntry<"blog">, b: CollectionEntry<"blog">) =>
|
||||||
b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||||
);
|
);
|
||||||
|
@ -22,12 +27,12 @@ const mostRecentPost: CollectionEntry<"blog"> = blogPosts[0];
|
||||||
const otherPosts: CollectionEntry<"blog">[] = blogPosts.slice(1);
|
const otherPosts: CollectionEntry<"blog">[] = blogPosts.slice(1);
|
||||||
|
|
||||||
// Define variables for page content
|
// Define variables for page content
|
||||||
const title: string = "Your Gateway to Construction Excellence";
|
const title: string = "Votre Passerelle vers l'Excellence en Construction";
|
||||||
const subTitle: string =
|
const subTitle: string =
|
||||||
"Explore the latest news, tips, and insights from ScrewFast to enhance your construction projects. From product spotlights to project management strategies, our blog is your go-to resource for all things hardware and construction.";
|
"Explorez les dernières actualités, astuces et analyses de ScrewFast pour améliorer vos projets de construction. Des mises en avant de produits aux stratégies de gestion de projet, notre blog est votre ressource incontournable pour tout ce qui concerne les outils et la construction.";
|
||||||
const secondTitle: string = "Insights";
|
const secondTitle: string = "Insights";
|
||||||
const secondSubTitle: string =
|
const secondSubTitle: string =
|
||||||
"Stay up-to-date with the latest trends and developments in the construction industry with insights from ScrewFast's team of industry experts. ";
|
"Restez à jour avec les dernières tendances et évolutions de l'industrie de la construction grâce aux analyses de l'équipe d'experts de ScrewFast.";
|
||||||
|
|
||||||
const pageTitle: string = `Blog | ${SITE.title}`;
|
const pageTitle: string = `Blog | ${SITE.title}`;
|
||||||
---
|
---
|
||||||
|
@ -47,7 +52,7 @@ const pageTitle: string = `Blog | ${SITE.title}`;
|
||||||
"name": "ScrewFast",
|
"name": "ScrewFast",
|
||||||
"description": "ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs."
|
"description": "ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs."
|
||||||
},
|
},
|
||||||
"inLanguage": "en-US"
|
"inLanguage": "fr"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
|
@ -74,14 +79,14 @@ const pageTitle: string = `Blog | ${SITE.title}`;
|
||||||
>
|
>
|
||||||
<!--Blog posts grid-->
|
<!--Blog posts grid-->
|
||||||
<div class="grid gap-6 lg:grid-cols-2">
|
<div class="grid gap-6 lg:grid-cols-2">
|
||||||
{otherPosts.map((blogEntry) => <CardBlog blogEntry={blogEntry} />)}
|
{otherPosts.map((blogEntry) => <CardBlog blogEntry={blogEntry} blogLocale="fr"/>)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<!--Most recent blog post-->
|
<!--Most recent blog post-->
|
||||||
<section
|
<section
|
||||||
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||||
>
|
>
|
||||||
<CardBlogRecent blogEntry={mostRecentPost} />
|
<CardBlogRecent blogEntry={mostRecentPost} recentBlogLocale="fr" />
|
||||||
</section>
|
</section>
|
||||||
<!--Insights section-->
|
<!--Insights section-->
|
||||||
<section
|
<section
|
||||||
|
|
Loading…
Add table
Reference in a new issue