Refactor components and update animation scripts
This commit is contained in:
parent
0cecec1424
commit
b867fbc93f
14 changed files with 216 additions and 897 deletions
11
public/scripts/vendor/gsap/ScrollTrigger.min.js
vendored
11
public/scripts/vendor/gsap/ScrollTrigger.min.js
vendored
File diff suppressed because one or more lines are too long
11
public/scripts/vendor/gsap/gsap.min.js
vendored
11
public/scripts/vendor/gsap/gsap.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,16 +0,0 @@
|
||||||
---
|
|
||||||
// Import the necessary components from their respective component files
|
|
||||||
import LoginModal from "@components/ui/forms/LoginModal.astro";
|
|
||||||
import RegisterModal from "@components/ui/forms/RegisterModal.astro";
|
|
||||||
import RecoverModal from "@components/ui/forms/RecoverModal.astro";
|
|
||||||
import LoginBtn from "@components/ui/buttons/LoginBtn.astro";
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Login Button -->
|
|
||||||
<LoginBtn />
|
|
||||||
<!-- Login Modal -->
|
|
||||||
<LoginModal />
|
|
||||||
<!-- Register Modal -->
|
|
||||||
<RegisterModal />
|
|
||||||
<!-- Password Recovery Modal -->
|
|
||||||
<RecoverModal />
|
|
|
@ -1,118 +0,0 @@
|
||||||
---
|
|
||||||
// Import the necessary dependencies.
|
|
||||||
import AuthBtn from "@components/ui/buttons/AuthBtn.astro";
|
|
||||||
import ContactIconBlock from "@components/ui/blocks/ContactIconBlock.astro";
|
|
||||||
import TextInput from "@components/ui/forms/input/TextInput.astro";
|
|
||||||
import EmailContactInput from "@components/ui/forms/input/EmailContactInput.astro";
|
|
||||||
import PhoneInput from "@components/ui/forms/input/PhoneInput.astro";
|
|
||||||
import TextAreaInput from "@components/ui/forms/input/TextAreaInput.astro";
|
|
||||||
import Icon from "@components/ui/icons/Icon.astro";
|
|
||||||
|
|
||||||
// Define the variables that will be used in this component
|
|
||||||
const title: string = "Contact us";
|
|
||||||
const subTitle: string =
|
|
||||||
"Have questions or want to discuss a project? Reach out, and let's craft the perfect solution with our tools and services.";
|
|
||||||
const formTitle: string = "Fill in the form below";
|
|
||||||
const formSubTitle: string = "We'll get back to you in 1-2 business days.";
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Contact Us -->
|
|
||||||
<section class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14">
|
|
||||||
<div class="mx-auto max-w-2xl lg:max-w-5xl">
|
|
||||||
<div class="text-center">
|
|
||||||
<h1
|
|
||||||
class="text-balance text-2xl font-bold tracking-tight text-neutral-800 dark:text-neutral-200 md:text-4xl md:leading-tight"
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
<p class="mt-1 text-pretty text-neutral-600 dark:text-neutral-400">
|
|
||||||
{subTitle}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-12 grid items-center gap-6 lg:grid-cols-2 lg:gap-16">
|
|
||||||
<div class="flex flex-col rounded-xl p-4 sm:p-6 lg:p-8">
|
|
||||||
<h2
|
|
||||||
class="mb-8 text-xl font-bold text-neutral-700 dark:text-neutral-300"
|
|
||||||
>
|
|
||||||
{formTitle}
|
|
||||||
</h2>
|
|
||||||
<!-- Form for user input with various input fields.-->
|
|
||||||
<!-- Each field utilizes a different input component for the specific type of input (text, email, phone, and textarea)-->
|
|
||||||
<form>
|
|
||||||
<div class="grid gap-4">
|
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
||||||
<TextInput
|
|
||||||
id="hs-firstname-contacts"
|
|
||||||
label="First Name"
|
|
||||||
name="hs-firstname-contacts"
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
id="hs-lastname-contacts"
|
|
||||||
label="Last Name"
|
|
||||||
name="hs-firstname-contacts"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<EmailContactInput id="hs-email-contacts" />
|
|
||||||
<PhoneInput id="hs-phone-number" />
|
|
||||||
<TextAreaInput
|
|
||||||
id="hs-about-contacts"
|
|
||||||
label="Details"
|
|
||||||
name="hs-about-contacts"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4 grid">
|
|
||||||
<AuthBtn title="Send Message" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-3 text-center">
|
|
||||||
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
|
||||||
{formSubTitle}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--ContactIconBlocks are used to display different methods of contacting, including visiting office, email, browsing knowledgebase, and FAQ.-->
|
|
||||||
<div class="divide-y divide-neutral-300 dark:divide-neutral-700">
|
|
||||||
<ContactIconBlock
|
|
||||||
heading="Knowledgebase"
|
|
||||||
content="Browse through all of our knowledgebase articles."
|
|
||||||
isLinkVisible={true}
|
|
||||||
linkTitle="Visit guides & tutorials"
|
|
||||||
linkURL="#"
|
|
||||||
isArrowVisible={true}
|
|
||||||
><Icon name="question" />
|
|
||||||
</ContactIconBlock>
|
|
||||||
|
|
||||||
<ContactIconBlock
|
|
||||||
heading="FAQ"
|
|
||||||
content="Explore our FAQ for quick, clear answers to common queries."
|
|
||||||
isLinkVisible={true}
|
|
||||||
linkTitle="Visit FAQ"
|
|
||||||
linkURL="#"
|
|
||||||
isArrowVisible={true}
|
|
||||||
><Icon name="chatBubble" />
|
|
||||||
</ContactIconBlock>
|
|
||||||
|
|
||||||
<ContactIconBlock
|
|
||||||
heading="Visit our office"
|
|
||||||
content="UK ScrewFast"
|
|
||||||
isAddressVisible={true}
|
|
||||||
addressContent="72 Union Terrace, E10 4PE London"
|
|
||||||
><Icon name="mapPin" />
|
|
||||||
</ContactIconBlock>
|
|
||||||
|
|
||||||
<ContactIconBlock
|
|
||||||
heading="Contact us by email"
|
|
||||||
content="Prefer the written word? Drop us an email at"
|
|
||||||
isLinkVisible={true}
|
|
||||||
linkTitle="support@screwfast.uk"
|
|
||||||
linkURL="#"
|
|
||||||
><Icon name="envelopeOpen" />
|
|
||||||
</ContactIconBlock>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
|
@ -1,79 +0,0 @@
|
||||||
---
|
|
||||||
// Import the necessary AccordionItem component and JSON data
|
|
||||||
import AccordionItem from "@components/ui/blocks/AccordionItem.astro";
|
|
||||||
|
|
||||||
// Define props from Astro
|
|
||||||
const { title, faqs } = Astro.props;
|
|
||||||
|
|
||||||
// Define TypeScript interface for props
|
|
||||||
interface Faq {
|
|
||||||
question: string;
|
|
||||||
answer: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FaqGroup {
|
|
||||||
subTitle?: string;
|
|
||||||
faqs: Faq[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
faqs: FaqGroup;
|
|
||||||
}
|
|
||||||
// Define a helper function to generate ids dynamically.
|
|
||||||
const makeId = (base: any, index: any) => `${base}${index + 1}`;
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Main container that holds all content. Customized for different viewport sizes. -->
|
|
||||||
<section
|
|
||||||
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
|
||||||
>
|
|
||||||
<div class="grid gap-10 md:grid-cols-5">
|
|
||||||
<div class="md:col-span-2">
|
|
||||||
<div class="max-w-xs">
|
|
||||||
<h2
|
|
||||||
class="text-2xl font-bold text-neutral-800 dark:text-neutral-200 md:text-4xl md:leading-tight"
|
|
||||||
>
|
|
||||||
<Fragment set:html={title} />
|
|
||||||
</h2>
|
|
||||||
<p class="mt-1 hidden text-neutral-600 dark:text-neutral-400 md:block">
|
|
||||||
{faqs.subTitle}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- FAQ accordion items -->
|
|
||||||
<div class="md:col-span-3">
|
|
||||||
<div
|
|
||||||
class="hs-accordion-group divide-y divide-neutral-200 dark:divide-neutral-700"
|
|
||||||
>
|
|
||||||
{
|
|
||||||
faqs.faqs.map((question, i) => {
|
|
||||||
// Generate ids dynamically for each FAQ accordion item.
|
|
||||||
let id = makeId(
|
|
||||||
"hs-basic-with-title-and-arrow-stretched-heading-",
|
|
||||||
i
|
|
||||||
);
|
|
||||||
let collapseId = makeId(
|
|
||||||
"hs-basic-with-title-and-arrow-stretched-collapse",
|
|
||||||
i
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AccordionItem
|
|
||||||
{...question}
|
|
||||||
id={id}
|
|
||||||
collapseId={collapseId}
|
|
||||||
first={i === 0}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<!--Import the necessary Accordion plugin-->
|
|
||||||
<!--https://preline.co/plugins/html/accordion.html-->
|
|
||||||
<script>
|
|
||||||
import "@preline/accordion/index.js";
|
|
||||||
</script>
|
|
|
@ -1,117 +0,0 @@
|
||||||
---
|
|
||||||
// Import the necessary dependencies
|
|
||||||
import FooterSocialLink from "@components/ui/links/FooterSocialLink.astro";
|
|
||||||
import EmailFooterInput from "@components/ui/forms/input/EmailFooterInput.astro";
|
|
||||||
import enStrings from "@utils/navigation.ts";
|
|
||||||
import frStrings from "@utils/fr/navigation.ts";
|
|
||||||
import Icon from "@components/ui/icons/Icon.astro";
|
|
||||||
import BrandLogo from "@components/BrandLogo.astro";
|
|
||||||
import { SITE } from "@data/constants";
|
|
||||||
|
|
||||||
// Select the correct translation based on the page's lang prop:
|
|
||||||
const strings = Astro.currentLocale === "fr" ? frStrings : enStrings;
|
|
||||||
|
|
||||||
// Define the variables that will be used in this component
|
|
||||||
const sectionThreeTitle: string = Astro.currentLocale === "fr" ? "Rester à jour" : "Stay up to date";
|
|
||||||
const sectionThreeContent: string = Astro.currentLocale === "fr" ? "Restez informé des derniers outils et des offres exclusives." :
|
|
||||||
"Stay updated with the latest tools and exclusive deals.";
|
|
||||||
const crafted: string = Astro.currentLocale === "fr" ? "Fabriqué par" : "Crafted by";
|
|
||||||
---
|
|
||||||
|
|
||||||
<footer class="w-full bg-neutral-300 dark:bg-neutral-900">
|
|
||||||
<div
|
|
||||||
class="mx-auto w-full max-w-[85rem] px-4 py-10 sm:px-6 lg:px-16 lg:pt-20 2xl:max-w-screen-2xl"
|
|
||||||
>
|
|
||||||
<div class="grid grid-cols-2 gap-6 md:grid-cols-4 lg:grid-cols-5">
|
|
||||||
<div class="col-span-full lg:col-span-1">
|
|
||||||
<!-- Brand Logo -->
|
|
||||||
<BrandLogo class="h-auto w-32" />
|
|
||||||
</div>
|
|
||||||
<!-- An array of links for Product and Company sections -->
|
|
||||||
{
|
|
||||||
strings.footerLinks.map((section) => (
|
|
||||||
<div class="col-span-1">
|
|
||||||
<h3 class="font-bold text-neutral-800 dark:text-neutral-200">
|
|
||||||
{section.section}
|
|
||||||
</h3>
|
|
||||||
<ul class="mt-3 grid space-y-3">
|
|
||||||
{section.links.map((link, index) => (
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href={link.url}
|
|
||||||
class="inline-flex gap-x-2 rounded-lg text-neutral-600 outline-none ring-zinc-500 transition duration-300 hover:text-neutral-500 focus-visible:ring dark:text-neutral-400 dark:ring-zinc-200 dark:hover:text-neutral-300 dark:focus:outline-none"
|
|
||||||
>
|
|
||||||
{link.name}
|
|
||||||
</a>
|
|
||||||
{section.section === "Company" && index === 2 ? (
|
|
||||||
<span class="ms-1 inline rounded-lg bg-orange-500 px-2 py-1 text-xs font-bold text-neutral-50">
|
|
||||||
We're hiring!
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="col-span-2">
|
|
||||||
<h3 class="font-bold text-neutral-800 dark:text-neutral-200">
|
|
||||||
{sectionThreeTitle}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<form>
|
|
||||||
<EmailFooterInput />
|
|
||||||
<p class="mt-3 text-sm text-neutral-600 dark:text-neutral-400">
|
|
||||||
{sectionThreeContent}
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="mt-9 grid gap-y-2 sm:mt-12 sm:flex sm:items-center sm:justify-between sm:gap-y-0"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
|
||||||
© <span id="current-year"></span> {SITE.title}. {crafted}
|
|
||||||
<a
|
|
||||||
class="rounded-lg font-medium underline underline-offset-2 outline-none ring-zinc-500 transition duration-300 hover:text-neutral-700 hover:decoration-dashed focus:outline-none focus-visible:ring dark:ring-zinc-200 dark:hover:text-neutral-300"
|
|
||||||
href="https://sobstvennoai.dev"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer">sobstvennoAI</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Social Brands -->
|
|
||||||
<div>
|
|
||||||
<FooterSocialLink url={strings.socialLinks.facebook}
|
|
||||||
><Icon name="facebookFooter" />
|
|
||||||
</FooterSocialLink>
|
|
||||||
|
|
||||||
<FooterSocialLink url={strings.socialLinks.x}
|
|
||||||
><Icon name="xFooter" /></FooterSocialLink
|
|
||||||
>
|
|
||||||
|
|
||||||
<FooterSocialLink url={strings.socialLinks.github}
|
|
||||||
><Icon name="githubFooter" />
|
|
||||||
</FooterSocialLink>
|
|
||||||
|
|
||||||
<FooterSocialLink url={strings.socialLinks.google}
|
|
||||||
><Icon name="googleFooter" />
|
|
||||||
</FooterSocialLink>
|
|
||||||
|
|
||||||
<FooterSocialLink url={strings.socialLinks.slack}
|
|
||||||
><Icon name="slackFooter" />
|
|
||||||
</FooterSocialLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const year = new Date().getFullYear();
|
|
||||||
const element = document.getElementById("current-year");
|
|
||||||
element!.innerText = year.toString();
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
|
@ -1,214 +0,0 @@
|
||||||
---
|
|
||||||
//Import relevant dependencies
|
|
||||||
import ThemeIcon from "@components/ThemeIcon.astro";
|
|
||||||
import NavLink from "@components/ui/links/NavLink.astro";
|
|
||||||
import Authentication from "./Authentication.astro";
|
|
||||||
import enStrings from "@utils/navigation.ts";
|
|
||||||
import frStrings from "@utils/fr/navigation.ts";
|
|
||||||
import BrandLogo from "@components/BrandLogo.astro";
|
|
||||||
import LanguagePicker from "@components/ui/LanguagePicker.astro";
|
|
||||||
|
|
||||||
// Select the correct translation based on the page's lang prop:
|
|
||||||
const strings = Astro.currentLocale === "fr" ? frStrings : enStrings;
|
|
||||||
const homeUrl = Astro.currentLocale === "fr" ? "/fr" : "/";
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Main header component -->
|
|
||||||
<header
|
|
||||||
class="sticky inset-x-0 top-4 z-50 flex w-full flex-wrap text-sm md:flex-nowrap md:justify-start"
|
|
||||||
>
|
|
||||||
<!-- Navigation container -->
|
|
||||||
<nav
|
|
||||||
class="relative mx-2 w-full rounded-[36px] border border-yellow-100/40 bg-yellow-50/60 px-4 py-3 backdrop-blur-md dark:border-neutral-700/40 dark:bg-neutral-800/80 dark:backdrop-blur-md md:flex md:items-center md:justify-between md:px-6 md:py-0 lg:px-8 xl:mx-auto"
|
|
||||||
aria-label="Global"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<!-- Brand logo -->
|
|
||||||
<a
|
|
||||||
class="flex-none rounded-lg text-xl font-bold outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
|
|
||||||
href={homeUrl}
|
|
||||||
aria-label="Brand"
|
|
||||||
>
|
|
||||||
<BrandLogo class="h-auto w-24" />
|
|
||||||
</a>
|
|
||||||
<!-- Collapse toggle for smaller screens -->
|
|
||||||
<div class="ml-auto mr-5 md:hidden">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="hs-collapse-toggle flex h-8 w-8 items-center justify-center rounded-full text-sm font-bold text-neutral-600 transition duration-300 hover:bg-neutral-200 disabled:pointer-events-none disabled:opacity-50 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:focus:outline-none"
|
|
||||||
data-hs-collapse="#navbar-collapse-with-animation"
|
|
||||||
aria-controls="navbar-collapse-with-animation"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="h-[1.25rem] w-[1.25rem] flex-shrink-0 hs-collapse-open:hidden"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<line x1="3" x2="21" y1="6" y2="6"></line>
|
|
||||||
<line x1="3" x2="21" y1="12" y2="12"></line>
|
|
||||||
<line x1="3" x2="21" y1="18" y2="18"></line>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
class="hidden h-[1.25rem] w-[1.25rem] flex-shrink-0 hs-collapse-open:block"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M18 6 6 18"></path>
|
|
||||||
<path d="m6 6 12 12"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<!-- ThemeIcon component specifically for smaller screens -->
|
|
||||||
<span class="inline-block md:hidden">
|
|
||||||
<ThemeIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<!-- Contains navigation links -->
|
|
||||||
<div
|
|
||||||
id="navbar-collapse-with-animation"
|
|
||||||
class="hs-collapse hidden grow basis-full overflow-hidden transition-all duration-300 md:block"
|
|
||||||
>
|
|
||||||
<!-- Navigation links container -->
|
|
||||||
<div
|
|
||||||
class="mt-5 flex flex-col gap-x-0 gap-y-4 md:mt-0 md:flex-row md:items-center md:justify-end md:gap-x-4 lg:gap-x-7 md:gap-y-0 md:ps-7"
|
|
||||||
>
|
|
||||||
<!-- Navigation links and Authentication component -->
|
|
||||||
{strings.navBarLinks.map(link => (
|
|
||||||
<NavLink url={link.url} name={link.name} />
|
|
||||||
))}
|
|
||||||
|
|
||||||
<Authentication />
|
|
||||||
<LanguagePicker />
|
|
||||||
<!-- ThemeIcon component specifically for larger screens -->
|
|
||||||
<span class="hidden md:inline-block">
|
|
||||||
<ThemeIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<!-- Theme Appearance script to manage light/dark modes -->
|
|
||||||
<script is:inline>
|
|
||||||
const HSThemeAppearance = {
|
|
||||||
init() {
|
|
||||||
const defaultTheme = "default";
|
|
||||||
let theme = localStorage.getItem("hs_theme") || defaultTheme;
|
|
||||||
|
|
||||||
if (document.querySelector("html").classList.contains("dark")) return;
|
|
||||||
this.setAppearance(theme);
|
|
||||||
},
|
|
||||||
_resetStylesOnLoad() {
|
|
||||||
const $resetStyles = document.createElement("style");
|
|
||||||
$resetStyles.innerText = `*{transition: unset !important;}`;
|
|
||||||
$resetStyles.setAttribute("data-hs-appearance-onload-styles", "");
|
|
||||||
document.head.appendChild($resetStyles);
|
|
||||||
return $resetStyles;
|
|
||||||
},
|
|
||||||
setAppearance(theme, saveInStore = true, dispatchEvent = true) {
|
|
||||||
const $resetStylesEl = this._resetStylesOnLoad();
|
|
||||||
|
|
||||||
if (saveInStore) {
|
|
||||||
localStorage.setItem("hs_theme", theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theme === "auto") {
|
|
||||||
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
||||||
? "dark"
|
|
||||||
: "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector("html").classList.remove("dark");
|
|
||||||
document.querySelector("html").classList.remove("default");
|
|
||||||
document.querySelector("html").classList.remove("auto");
|
|
||||||
|
|
||||||
document
|
|
||||||
.querySelector("html")
|
|
||||||
.classList.add(this.getOriginalAppearance());
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
$resetStylesEl.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dispatchEvent) {
|
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("on-hs-appearance-change", { detail: theme }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getAppearance() {
|
|
||||||
let theme = this.getOriginalAppearance();
|
|
||||||
if (theme === "auto") {
|
|
||||||
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
||||||
? "dark"
|
|
||||||
: "default";
|
|
||||||
}
|
|
||||||
return theme;
|
|
||||||
},
|
|
||||||
getOriginalAppearance() {
|
|
||||||
const defaultTheme = "default";
|
|
||||||
return localStorage.getItem("hs_theme") || defaultTheme;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
HSThemeAppearance.init();
|
|
||||||
|
|
||||||
window
|
|
||||||
.matchMedia("(prefers-color-scheme: dark)")
|
|
||||||
.addEventListener("change", () => {
|
|
||||||
if (HSThemeAppearance.getOriginalAppearance() === "auto") {
|
|
||||||
HSThemeAppearance.setAppearance("auto", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
|
||||||
const $clickableThemes = document.querySelectorAll(
|
|
||||||
"[data-hs-theme-click-value]",
|
|
||||||
);
|
|
||||||
const $switchableThemes = document.querySelectorAll(
|
|
||||||
"[data-hs-theme-switch]",
|
|
||||||
);
|
|
||||||
|
|
||||||
$clickableThemes.forEach(($item) => {
|
|
||||||
$item.addEventListener("click", () =>
|
|
||||||
HSThemeAppearance.setAppearance(
|
|
||||||
$item.getAttribute("data-hs-theme-click-value"),
|
|
||||||
true,
|
|
||||||
$item,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$switchableThemes.forEach(($item) => {
|
|
||||||
$item.addEventListener("change", (e) => {
|
|
||||||
HSThemeAppearance.setAppearance(e.target.checked ? "dark" : "default");
|
|
||||||
});
|
|
||||||
|
|
||||||
$item.checked = HSThemeAppearance.getAppearance() === "dark";
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("on-hs-appearance-change", (e) => {
|
|
||||||
$switchableThemes.forEach(($item) => {
|
|
||||||
$item.checked = e.detail === "dark";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<!--Import the necessary Collapse and Overlay plugins-->
|
|
||||||
<!--https://preline.co/plugins/html/collapse.html-->
|
|
||||||
<!--https://preline.co/plugins/html/overlay.html-->
|
|
||||||
<script>
|
|
||||||
import "@preline/collapse/index.js";
|
|
||||||
import "@preline/overlay/index.js";
|
|
||||||
</script>
|
|
|
@ -1,223 +0,0 @@
|
||||||
---
|
|
||||||
//Import relevant dependencies
|
|
||||||
import ThemeIcon from "@components/ThemeIcon.astro";
|
|
||||||
import NavLink from "@components/ui/links/NavLink.astro";
|
|
||||||
import MegaMenuLink from "@components/ui/links/MegaMenuLink.astro";
|
|
||||||
import Authentication from "./Authentication.astro";
|
|
||||||
import enStrings from "@utils/navigation.ts";
|
|
||||||
import frStrings from "@utils/fr/navigation.ts";
|
|
||||||
import BrandLogo from "@components/BrandLogo.astro";
|
|
||||||
import LanguagePicker from "@components/ui/LanguagePicker.astro";
|
|
||||||
|
|
||||||
// Select the correct translation based on the page's lang prop:
|
|
||||||
const strings = Astro.currentLocale === "fr" ? frStrings : enStrings;
|
|
||||||
const homeUrl = Astro.currentLocale === "fr" ? "/fr" : "/";
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Main header component -->
|
|
||||||
<header
|
|
||||||
class="sticky inset-x-0 top-4 z-50 flex w-full flex-wrap text-sm md:flex-nowrap md:justify-start"
|
|
||||||
>
|
|
||||||
<!-- Navigation container -->
|
|
||||||
<nav
|
|
||||||
class="relative mx-2 w-full rounded-[36px] border border-yellow-100/40 bg-yellow-50/60 px-4 py-3 backdrop-blur-md dark:border-neutral-700/40 dark:bg-neutral-800/80 dark:backdrop-blur-md md:flex md:items-center md:justify-between md:px-6 md:py-0 lg:px-8 xl:mx-auto"
|
|
||||||
aria-label="Global"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<!-- Brand logo -->
|
|
||||||
<a
|
|
||||||
class="flex-none rounded-lg text-xl font-bold outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
|
|
||||||
href={homeUrl}
|
|
||||||
aria-label="Brand"
|
|
||||||
>
|
|
||||||
<BrandLogo class="h-auto w-24" />
|
|
||||||
</a>
|
|
||||||
<!-- Collapse toggle for smaller screens -->
|
|
||||||
<div class="ml-auto mr-5 md:hidden">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="hs-collapse-toggle flex h-8 w-8 items-center justify-center rounded-full text-sm font-bold text-neutral-600 transition duration-300 hover:bg-neutral-200 disabled:pointer-events-none disabled:opacity-50 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:focus:outline-none"
|
|
||||||
data-hs-collapse="#navbar-collapse-with-animation"
|
|
||||||
aria-controls="navbar-collapse-with-animation"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="h-[1.25rem] w-[1.25rem] flex-shrink-0 hs-collapse-open:hidden"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<line x1="3" x2="21" y1="6" y2="6"></line>
|
|
||||||
<line x1="3" x2="21" y1="12" y2="12"></line>
|
|
||||||
<line x1="3" x2="21" y1="18" y2="18"></line>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
class="hidden h-[1.25rem] w-[1.25rem] flex-shrink-0 hs-collapse-open:block"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M18 6 6 18"></path>
|
|
||||||
<path d="m6 6 12 12"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<!-- ThemeIcon component specifically for smaller screens -->
|
|
||||||
<span class="inline-block md:hidden">
|
|
||||||
<ThemeIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<!-- Contains navigation links -->
|
|
||||||
<div
|
|
||||||
id="navbar-collapse-with-animation"
|
|
||||||
class="hs-collapse hidden grow basis-full overflow-hidden transition-all duration-300 md:block"
|
|
||||||
>
|
|
||||||
<!-- Navigation links container -->
|
|
||||||
<div
|
|
||||||
class="mt-5 flex flex-col gap-x-0 gap-y-4 md:mt-0 md:flex-row md:items-center md:justify-end md:gap-x-4 md:gap-y-0 md:ps-7 lg:gap-x-7"
|
|
||||||
>
|
|
||||||
<!-- Navigation links and Authentication component -->
|
|
||||||
{
|
|
||||||
strings.navBarLinks.map((link) => {
|
|
||||||
if (link.name === "Services") {
|
|
||||||
return <MegaMenuLink />;
|
|
||||||
} else {
|
|
||||||
return <NavLink url={link.url} name={link.name} />;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
<Authentication />
|
|
||||||
<LanguagePicker />
|
|
||||||
<!-- ThemeIcon component specifically for larger screens -->
|
|
||||||
<span class="hidden md:inline-block">
|
|
||||||
<ThemeIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<!-- Theme Appearance script to manage light/dark modes -->
|
|
||||||
<script is:inline>
|
|
||||||
const HSThemeAppearance = {
|
|
||||||
init() {
|
|
||||||
const defaultTheme = "default";
|
|
||||||
let theme = localStorage.getItem("hs_theme") || defaultTheme;
|
|
||||||
|
|
||||||
if (document.querySelector("html").classList.contains("dark")) return;
|
|
||||||
this.setAppearance(theme);
|
|
||||||
},
|
|
||||||
_resetStylesOnLoad() {
|
|
||||||
const $resetStyles = document.createElement("style");
|
|
||||||
$resetStyles.innerText = `*{transition: unset !important;}`;
|
|
||||||
$resetStyles.setAttribute("data-hs-appearance-onload-styles", "");
|
|
||||||
document.head.appendChild($resetStyles);
|
|
||||||
return $resetStyles;
|
|
||||||
},
|
|
||||||
setAppearance(theme, saveInStore = true, dispatchEvent = true) {
|
|
||||||
const $resetStylesEl = this._resetStylesOnLoad();
|
|
||||||
|
|
||||||
if (saveInStore) {
|
|
||||||
localStorage.setItem("hs_theme", theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theme === "auto") {
|
|
||||||
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
||||||
? "dark"
|
|
||||||
: "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector("html").classList.remove("dark");
|
|
||||||
document.querySelector("html").classList.remove("default");
|
|
||||||
document.querySelector("html").classList.remove("auto");
|
|
||||||
|
|
||||||
document
|
|
||||||
.querySelector("html")
|
|
||||||
.classList.add(this.getOriginalAppearance());
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
$resetStylesEl.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dispatchEvent) {
|
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("on-hs-appearance-change", { detail: theme })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getAppearance() {
|
|
||||||
let theme = this.getOriginalAppearance();
|
|
||||||
if (theme === "auto") {
|
|
||||||
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
||||||
? "dark"
|
|
||||||
: "default";
|
|
||||||
}
|
|
||||||
return theme;
|
|
||||||
},
|
|
||||||
getOriginalAppearance() {
|
|
||||||
const defaultTheme = "default";
|
|
||||||
return localStorage.getItem("hs_theme") || defaultTheme;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
HSThemeAppearance.init();
|
|
||||||
|
|
||||||
window
|
|
||||||
.matchMedia("(prefers-color-scheme: dark)")
|
|
||||||
.addEventListener("change", () => {
|
|
||||||
if (HSThemeAppearance.getOriginalAppearance() === "auto") {
|
|
||||||
HSThemeAppearance.setAppearance("auto", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
|
||||||
const $clickableThemes = document.querySelectorAll(
|
|
||||||
"[data-hs-theme-click-value]"
|
|
||||||
);
|
|
||||||
const $switchableThemes = document.querySelectorAll(
|
|
||||||
"[data-hs-theme-switch]"
|
|
||||||
);
|
|
||||||
|
|
||||||
$clickableThemes.forEach(($item) => {
|
|
||||||
$item.addEventListener("click", () =>
|
|
||||||
HSThemeAppearance.setAppearance(
|
|
||||||
$item.getAttribute("data-hs-theme-click-value"),
|
|
||||||
true,
|
|
||||||
$item
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$switchableThemes.forEach(($item) => {
|
|
||||||
$item.addEventListener("change", (e) => {
|
|
||||||
HSThemeAppearance.setAppearance(e.target.checked ? "dark" : "default");
|
|
||||||
});
|
|
||||||
|
|
||||||
$item.checked = HSThemeAppearance.getAppearance() === "dark";
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("on-hs-appearance-change", (e) => {
|
|
||||||
$switchableThemes.forEach(($item) => {
|
|
||||||
$item.checked = e.detail === "dark";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<!--Import the necessary Collapse and Overlay plugins-->
|
|
||||||
<!--https://preline.co/plugins/html/collapse.html-->
|
|
||||||
<!--https://preline.co/plugins/html/overlay.html-->
|
|
||||||
<!--https://preline.co/plugins/html/dropdown.html-->
|
|
||||||
<script>
|
|
||||||
import "@preline/collapse/index.js";
|
|
||||||
import "@preline/overlay/index.js";
|
|
||||||
import "@preline/dropdown/index.js";
|
|
||||||
</script>
|
|
|
@ -417,8 +417,105 @@ export const Icons = {
|
||||||
d: "m20.893 13.393-1.135-1.135a2.252 2.252 0 0 1-.421-.585l-1.08-2.16a.414.414 0 0 0-.663-.107.827.827 0 0 1-.812.21l-1.273-.363a.89.89 0 0 0-.738 1.595l.587.39c.59.395.674 1.23.172 1.732l-.2.2c-.212.212-.33.498-.33.796v.41c0 .409-.11.809-.32 1.158l-1.315 2.191a2.11 2.11 0 0 1-1.81 1.025 1.055 1.055 0 0 1-1.055-1.055v-1.172c0-.92-.56-1.747-1.414-2.089l-.655-.261a2.25 2.25 0 0 1-1.383-2.46l.007-.042a2.25 2.25 0 0 1 .29-.787l.09-.15a2.25 2.25 0 0 1 2.37-1.048l1.178.236a1.125 1.125 0 0 0 1.302-.795l.208-.73a1.125 1.125 0 0 0-.578-1.315l-.665-.332-.091.091a2.25 2.25 0 0 1-1.591.659h-.18c-.249 0-.487.1-.662.274a.931.931 0 0 1-1.458-1.137l1.411-2.353a2.25 2.25 0 0 0 .286-.76m11.928 9.869A9 9 0 0 0 8.965 3.525m11.928 9.868A9 9 0 1 1 8.965 3.525",
|
d: "m20.893 13.393-1.135-1.135a2.252 2.252 0 0 1-.421-.585l-1.08-2.16a.414.414 0 0 0-.663-.107.827.827 0 0 1-.812.21l-1.273-.363a.89.89 0 0 0-.738 1.595l.587.39c.59.395.674 1.23.172 1.732l-.2.2c-.212.212-.33.498-.33.796v.41c0 .409-.11.809-.32 1.158l-1.315 2.191a2.11 2.11 0 0 1-1.81 1.025 1.055 1.055 0 0 1-1.055-1.055v-1.172c0-.92-.56-1.747-1.414-2.089l-.655-.261a2.25 2.25 0 0 1-1.383-2.46l.007-.042a2.25 2.25 0 0 1 .29-.787l.09-.15a2.25 2.25 0 0 1 2.37-1.048l1.178.236a1.125 1.125 0 0 0 1.302-.795l.208-.73a1.125 1.125 0 0 0-.578-1.315l-.665-.332-.091.091a2.25 2.25 0 0 1-1.591.659h-.18c-.249 0-.487.1-.662.274a.931.931 0 0 1-1.458-1.137l1.411-2.353a2.25 2.25 0 0 0 .286-.76m11.928 9.869A9 9 0 0 0 8.965 3.525m11.928 9.868A9 9 0 1 1 8.965 3.525",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
class:
|
class: "w-4 h-4 flex-shrink-0",
|
||||||
"w-4 h-4 flex-shrink-0",
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
guides: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
puzzle: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M2.25 7.125C2.25 6.504 2.754 6 3.375 6h6c.621 0 1.125.504 1.125 1.125v3.75c0 .621-.504 1.125-1.125 1.125h-6a1.125 1.125 0 0 1-1.125-1.125v-3.75ZM14.25 8.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v8.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 0 1-1.125-1.125v-8.25ZM3.75 16.125c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v2.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 0 1-1.125-1.125v-2.25Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
rocket: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M15.59 14.37a6 6 0 0 1-5.84 7.38v-4.8m5.84-2.58a14.98 14.98 0 0 0 6.16-12.12A14.98 14.98 0 0 0 9.631 8.41m5.96 5.96a14.926 14.926 0 0 1-5.841 2.58m-.119-8.54a6 6 0 0 0-7.381 5.84h4.8m2.581-5.84a14.927 14.927 0 0 0-2.58 5.84m2.699 2.7c-.103.021-.207.041-.311.06a15.09 15.09 0 0 1-2.448-2.448 14.9 14.9 0 0 1 .06-.312m-2.24 2.39a4.493 4.493 0 0 0-1.757 4.306 4.493 4.493 0 0 0 4.306-1.758M16.5 9a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
hammer: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437 1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
sparks: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.894 20.567 16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
community: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "mt-1 size-5 flex-shrink-0",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
strokeWidth: "1.5",
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
stroke: "currentColor",
|
||||||
|
},
|
||||||
|
chevronDown: {
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
d: "m19.5 8.25-7.5 7.5-7.5-7.5",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class: "ms-2 size-4 flex-shrink-0",
|
||||||
viewBox: "0 0 24 24",
|
viewBox: "0 0 24 24",
|
||||||
fill: "none",
|
fill: "none",
|
||||||
strokeWidth: "1.5",
|
strokeWidth: "1.5",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
// Importing necessary components
|
// Importing necessary components
|
||||||
import Meta from "@components/Meta.astro";
|
import Meta from "@components/Meta.astro";
|
||||||
import Navbar from "@components/sections/Navbar.astro";
|
import Navbar from "@components/sections/navbar&footer/NavbarMegaMenu.astro";
|
||||||
import FooterSection from "@components/sections/FooterSection.astro";
|
import FooterSection from "@components/sections/navbar&footer/FooterSection.astro";
|
||||||
import { SITE } from "@data/constants";
|
import { SITE } from "@data/constants";
|
||||||
|
|
||||||
// Setting expected props
|
// Setting expected props
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
// Import the necessary components
|
// Import the necessary components
|
||||||
import MainLayout from "@/layouts/MainLayout.astro";
|
import MainLayout from "@/layouts/MainLayout.astro";
|
||||||
import ContactSection from "@components/sections/ContactSection.astro";
|
import ContactSection from "@components/sections/misc/ContactSection.astro";
|
||||||
import { SITE } from "@data/constants";
|
import { SITE } from "@data/constants";
|
||||||
|
|
||||||
const pageTitle: string = `Contact | ${SITE.title}`;
|
const pageTitle: string = `Contact | ${SITE.title}`;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import FeaturesGeneral from "@components/sections/features/FeaturesGeneral.astro
|
||||||
import FeaturesNavs from "@components/sections/features/FeaturesNavs.astro";
|
import FeaturesNavs from "@components/sections/features/FeaturesNavs.astro";
|
||||||
import TestimonialsSection from "@components/sections/testimonials/TestimonialsSection.astro";
|
import TestimonialsSection from "@components/sections/testimonials/TestimonialsSection.astro";
|
||||||
import PricingSection from "@components/sections/pricing/PricingSection.astro";
|
import PricingSection from "@components/sections/pricing/PricingSection.astro";
|
||||||
import FAQ from "@components/sections/FAQ.astro";
|
import FAQ from "@components/sections/misc/FAQ.astro";
|
||||||
import AnnouncementBanner from "@components/ui/banners/AnnouncementBanner.astro";
|
import AnnouncementBanner from "@components/ui/banners/AnnouncementBanner.astro";
|
||||||
import heroImage from "@images/hero-image.avif";
|
import heroImage from "@images/hero-image.avif";
|
||||||
import faqs from "@data/fr/faqs.json";
|
import faqs from "@data/fr/faqs.json";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import FeaturesGeneral from "@components/sections/features/FeaturesGeneral.astro
|
||||||
import FeaturesNavs from "@components/sections/features/FeaturesNavs.astro";
|
import FeaturesNavs from "@components/sections/features/FeaturesNavs.astro";
|
||||||
import TestimonialsSection from "@components/sections/testimonials/TestimonialsSection.astro";
|
import TestimonialsSection from "@components/sections/testimonials/TestimonialsSection.astro";
|
||||||
import PricingSection from "@components/sections/pricing/PricingSection.astro";
|
import PricingSection from "@components/sections/pricing/PricingSection.astro";
|
||||||
import FAQ from "@components/sections/FAQ.astro";
|
import FAQ from "@components/sections/misc/FAQ.astro";
|
||||||
import AnnouncementBanner from "@components/ui/banners/AnnouncementBanner.astro";
|
import AnnouncementBanner from "@components/ui/banners/AnnouncementBanner.astro";
|
||||||
import heroImage from "@images/hero-image.avif";
|
import heroImage from "@images/hero-image.avif";
|
||||||
import faqs from "@data/faqs.json";
|
import faqs from "@data/faqs.json";
|
||||||
|
|
|
@ -27,9 +27,7 @@ const { product } = Astro.props;
|
||||||
const pageTitle: string = `${product.data.title} | ${SITE.title}`;
|
const pageTitle: string = `${product.data.title} | ${SITE.title}`;
|
||||||
---
|
---
|
||||||
|
|
||||||
<MainLayout
|
<MainLayout title={pageTitle}>
|
||||||
title={pageTitle}
|
|
||||||
>
|
|
||||||
<div id="overlay" class="fixed inset-0 bg-neutral-200 dark:bg-neutral-800">
|
<div id="overlay" class="fixed inset-0 bg-neutral-200 dark:bg-neutral-800">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -245,130 +243,143 @@ const pageTitle: string = `${product.data.title} | ${SITE.title}`;
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
<script is:inline src="/scripts/vendor/gsap/gsap.min.js"></script>
|
|
||||||
<script>
|
|
||||||
window.addEventListener("load", () => {
|
|
||||||
if (window.gsap) {
|
|
||||||
const gsap = window.gsap;
|
|
||||||
gsap.set("#fadeText", {
|
|
||||||
autoAlpha: 0,
|
|
||||||
y: 50,
|
|
||||||
willChange: "transform, opacity",
|
|
||||||
});
|
|
||||||
gsap.set("#fadeInUp", {
|
|
||||||
autoAlpha: 0,
|
|
||||||
y: 50,
|
|
||||||
willChange: "transform, opacity",
|
|
||||||
});
|
|
||||||
gsap.set("#fadeInMoveRight", {
|
|
||||||
autoAlpha: 0,
|
|
||||||
x: 300,
|
|
||||||
willChange: "transform, opacity",
|
|
||||||
});
|
|
||||||
|
|
||||||
let timeline = gsap.timeline({ defaults: { overwrite: "auto" } });
|
<script>
|
||||||
|
import { gsap } from "gsap";
|
||||||
|
|
||||||
timeline.to("#fadeText", {
|
type AnimationSettings = {
|
||||||
duration: 1.5,
|
autoAlpha?: number;
|
||||||
autoAlpha: 1,
|
y?: number;
|
||||||
y: 0,
|
x?: number;
|
||||||
delay: 1,
|
willChange?: string;
|
||||||
ease: "power2.out",
|
};
|
||||||
});
|
|
||||||
|
|
||||||
timeline.to(
|
function setElementAnimationDefaults(
|
||||||
"#fadeInUp",
|
id: string,
|
||||||
{ duration: 1.5, autoAlpha: 1, y: 0, ease: "power2.out" },
|
settings: AnimationSettings
|
||||||
"-=1.2",
|
) {
|
||||||
);
|
gsap.set(id, settings);
|
||||||
|
}
|
||||||
|
|
||||||
timeline.to(
|
setElementAnimationDefaults("#fadeText", {
|
||||||
"#fadeInMoveRight",
|
autoAlpha: 0,
|
||||||
{ duration: 1.5, autoAlpha: 1, x: 0, ease: "power2.inOut" },
|
y: 50,
|
||||||
"-=1.4",
|
willChange: "transform, opacity",
|
||||||
);
|
});
|
||||||
|
|
||||||
timeline.to("#overlay", { duration: 1, autoAlpha: 0, delay: 0.2 });
|
setElementAnimationDefaults("#fadeInUp", {
|
||||||
}
|
autoAlpha: 0,
|
||||||
});
|
y: 50,
|
||||||
</script>
|
willChange: "transform, opacity",
|
||||||
<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");
|
setElementAnimationDefaults("#fadeInMoveRight", {
|
||||||
if (tabId) {
|
autoAlpha: 0,
|
||||||
const contentElement = document.querySelector(tabId);
|
x: 300,
|
||||||
if (contentElement) {
|
willChange: "transform, opacity",
|
||||||
contentElement.classList.add("hidden");
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeHeadingStyle(
|
let timeline = gsap.timeline({ defaults: { overwrite: "auto" } });
|
||||||
btn,
|
|
||||||
["text-neutral-800", "dark:text-neutral-200"],
|
|
||||||
["text-orange-400", "dark:text-orange-300"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function activateButton(button: any) {
|
timeline.to("#fadeText", {
|
||||||
button.classList.add(
|
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",
|
"active",
|
||||||
"bg-neutral-100",
|
"bg-neutral-100",
|
||||||
",hover:border-transparent",
|
"hover:border-transparent",
|
||||||
"dark:bg-white/[.05]",
|
"dark:bg-white/[.05]"
|
||||||
);
|
);
|
||||||
|
|
||||||
const tabId = button.getAttribute("data-target");
|
const tabId = btn.getAttribute("data-target");
|
||||||
if (tabId) {
|
if (tabId) {
|
||||||
const contentElementToShow = document.querySelector(tabId);
|
const contentElement = document.querySelector(tabId);
|
||||||
if (contentElementToShow) {
|
if (contentElement) {
|
||||||
contentElementToShow.classList.remove("hidden");
|
contentElement.classList.add("hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeHeadingStyle(
|
changeHeadingStyle(
|
||||||
button,
|
btn,
|
||||||
["text-orange-400", "dark:text-orange-300"],
|
|
||||||
["text-neutral-800", "dark:text-neutral-200"],
|
["text-neutral-800", "dark:text-neutral-200"],
|
||||||
|
["text-orange-400", "dark:text-orange-300"]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function changeHeadingStyle(
|
function activateButton(button: any) {
|
||||||
button: any,
|
button.classList.add(
|
||||||
addClasses: any,
|
"active",
|
||||||
removeClasses: any,
|
"bg-neutral-100",
|
||||||
) {
|
",hover:border-transparent",
|
||||||
let heading = button.querySelector("span");
|
"dark:bg-white/[.05]"
|
||||||
if (heading) {
|
);
|
||||||
heading.classList.remove(...removeClasses);
|
|
||||||
heading.classList.add(...addClasses);
|
const tabId = button.getAttribute("data-target");
|
||||||
|
if (tabId) {
|
||||||
|
const contentElementToShow = document.querySelector(tabId);
|
||||||
|
if (contentElementToShow) {
|
||||||
|
contentElementToShow.classList.remove("hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabButtons = document.querySelectorAll("[data-target]");
|
changeHeadingStyle(
|
||||||
|
button,
|
||||||
|
["text-orange-400", "dark:text-orange-300"],
|
||||||
|
["text-neutral-800", "dark:text-neutral-200"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (tabButtons.length > 0) {
|
function changeHeadingStyle(
|
||||||
changeHeadingStyle(
|
button: any,
|
||||||
tabButtons[0],
|
addClasses: any,
|
||||||
["text-orange-400", "dark:text-orange-300"],
|
removeClasses: any
|
||||||
[],
|
) {
|
||||||
);
|
let heading = button.querySelector("span");
|
||||||
|
if (heading) {
|
||||||
|
heading.classList.remove(...removeClasses);
|
||||||
|
heading.classList.add(...addClasses);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tabButtons.forEach((button) => {
|
const tabButtons = document.querySelectorAll("[data-target]");
|
||||||
button.addEventListener("click", () => {
|
|
||||||
tabButtons.forEach((btn) => setButtonInactive(btn, button));
|
if (tabButtons.length > 0) {
|
||||||
activateButton(button);
|
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>
|
});
|
||||||
|
</script>
|
||||||
|
|
Loading…
Add table
Reference in a new issue