Refactor multiple components, enhance comments, and rename
Refactored multiple Astro UI components, including sections, buttons, and modals, with a focus on code cleanliness and efficiency. This included revising import statements, reordering and redefining CSS classes, and updating HTML elements. Enhanced inline comments to add context and explanations, especially registering the purpose of components and properties for improved understanding. The Accordion-related functionality was removed, pointing towards a redesign of its element usage. Moreover, TestimonialsSection2 was renamed to TestimonialsSectionAlt for better semantics.
|
@ -1,16 +1,13 @@
|
|||
---
|
||||
// Import the necessary dependencies from individual component files
|
||||
// Import SecondaryCTA component for use in this module
|
||||
import SecondaryCTA from "./ui/buttons/SecondaryCTA.astro";
|
||||
|
||||
// Variables for customization of the LoginModal Component
|
||||
// Main heading
|
||||
// Set heading and sub-heading for the pricing section
|
||||
const title: string = "Simple, Transparent Pricing";
|
||||
|
||||
// Sub-heading text
|
||||
const subTitle: string =
|
||||
"Boost efficiency with ScrewFast's clear, value-driven plans.";
|
||||
|
||||
/* TypeScript type for product. */
|
||||
// Define TypeScript type for products.
|
||||
type Product = {
|
||||
name: string;
|
||||
description: string;
|
||||
|
@ -21,7 +18,7 @@ type Product = {
|
|||
purchaseBtnTitle: string;
|
||||
purchaseLink: string;
|
||||
};
|
||||
|
||||
// Define two products for display - Starter Kit and Professional Toolbox.
|
||||
const starterKit: Product = {
|
||||
name: "Starter Kit",
|
||||
description: "Best option for DIY projects",
|
||||
|
@ -57,7 +54,7 @@ const professionalToolbox: Product = {
|
|||
<div
|
||||
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||
>
|
||||
<!-- Title and description -->
|
||||
<!-- Section heading and sub-heading -->
|
||||
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
|
||||
<h2
|
||||
class="text-balance text-2xl font-bold tracking-tight text-neutral-800 dark:text-neutral-200 md:text-4xl md:leading-tight"
|
||||
|
@ -70,7 +67,7 @@ const professionalToolbox: Product = {
|
|||
</div>
|
||||
<!-- Contains two main product blocks -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 sm:gap-0">
|
||||
<!-- Block for the `starterKit` product -->
|
||||
<!-- Starter Kit product details -->
|
||||
<div
|
||||
class="w-full rounded-xl bg-gray-800 p-6 sm:w-1/2 sm:rounded-r-none sm:p-8 lg:w-1/3"
|
||||
>
|
||||
|
@ -121,7 +118,7 @@ const professionalToolbox: Product = {
|
|||
>{starterKit.purchaseBtnTitle}</a
|
||||
>
|
||||
</div>
|
||||
<!-- Block for the `professionalToolbox` product -->
|
||||
<!-- Professional Toolbox product details -->
|
||||
<div
|
||||
class="w-full rounded-xl bg-gradient-to-tr from-[#FF512F] to-[#F09819] p-6 shadow-xl sm:w-1/2 sm:p-8"
|
||||
>
|
||||
|
@ -182,7 +179,7 @@ const professionalToolbox: Product = {
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Extra CTA for enterprise solutions -->
|
||||
<!-- Call to action for Enterprise Solutions -->
|
||||
<div class="mt-8 flex items-center justify-center gap-x-3 md:mt-12">
|
||||
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
Enterprise Solutions?
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
// Import the required modules
|
||||
import { Image } from "astro:assets";
|
||||
import PrimaryCTA from "../buttons/PrimaryCTA.astro";
|
||||
|
||||
// Extract properties from Astro.props
|
||||
const {
|
||||
title,
|
||||
subTitle,
|
||||
|
@ -14,7 +15,7 @@ const {
|
|||
imgTwo,
|
||||
imgTwoAlt,
|
||||
} = Astro.props;
|
||||
|
||||
// Define TypeScript interface for the properties
|
||||
interface Props {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
|
@ -28,26 +29,31 @@ interface Props {
|
|||
imgTwoAlt?: any;
|
||||
}
|
||||
---
|
||||
|
||||
<!-- Root section of the component -->
|
||||
<section
|
||||
class="mx-auto max-w-[85rem] items-center gap-16 px-4 py-10 sm:px-6 lg:grid lg:grid-cols-2 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||
>
|
||||
<div>
|
||||
<!-- Title of the section -->
|
||||
<h2
|
||||
class="mb-4 text-balance text-4xl font-extrabold tracking-tight text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<!-- Subtitle of the section -->
|
||||
<p
|
||||
class="mb-4 max-w-prose text-pretty font-light text-neutral-600 dark:text-neutral-400 sm:text-lg"
|
||||
>
|
||||
{subTitle}
|
||||
</p>
|
||||
<!-- Conditional rendering of the Primary Call-To-Action button if 'btnExists' is true -->
|
||||
{btnExists ? <PrimaryCTA title={btnTitle} url={btnURL} /> : null}
|
||||
</div>
|
||||
<!-- Conditionally render one or two images based on 'single' property -->
|
||||
{
|
||||
single ? (
|
||||
<div class="mt-8">
|
||||
<!-- Single image -->
|
||||
<Image
|
||||
class="w-full rounded-lg"
|
||||
src={imgOne}
|
||||
|
@ -57,6 +63,7 @@ interface Props {
|
|||
</div>
|
||||
) : (
|
||||
<div class="mt-8 grid grid-cols-2 gap-4">
|
||||
<!-- First image in a two-image layout -->
|
||||
<Image
|
||||
class="w-full rounded-xl"
|
||||
src={imgOne}
|
||||
|
@ -64,6 +71,7 @@ interface Props {
|
|||
draggable={"false"}
|
||||
format={"avif"}
|
||||
/>
|
||||
<!-- Second image in a two-image layout -->
|
||||
<Image
|
||||
class="mt-4 w-full rounded-xl lg:mt-10"
|
||||
src={imgTwo}
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
---
|
||||
// Destructure the properties from Astro.props
|
||||
const { title, url, noArrow } = Astro.props;
|
||||
|
||||
// Define TypeScript interface for the properties
|
||||
interface Props {
|
||||
title?: string;
|
||||
url?: string;
|
||||
noArrow?: boolean;
|
||||
}
|
||||
|
||||
const baseClasses = "group inline-flex items-center justify-center gap-x-2 rounded-lg px-4 py-3 text-sm font-bold text-neutral-50 ring-zinc-500 transition duration-300 focus-visible:ring outline-none";
|
||||
// Define CSS classes for styling the button
|
||||
const baseClasses =
|
||||
"group inline-flex items-center justify-center gap-x-2 rounded-lg px-4 py-3 text-sm font-bold text-neutral-50 ring-zinc-500 transition duration-300 focus-visible:ring outline-none";
|
||||
const borderClasses = "border border-transparent";
|
||||
const bgColorClasses = "bg-[#fa5a15] hover:bg-[#e14d0b] active:bg-[#e14d0b] dark:focus:outline-none";
|
||||
const bgColorClasses =
|
||||
"bg-[#fa5a15] hover:bg-[#e14d0b] active:bg-[#e14d0b] dark:focus:outline-none";
|
||||
const disableClasses = "disabled:pointer-events-none disabled:opacity-50";
|
||||
const fontSizeClasses = "2xl:text-base";
|
||||
const ringClasses = "dark:ring-zinc-200";
|
||||
// SVG for an arrow icon
|
||||
const arrowSVG = `<svg
|
||||
class="h-4 w-4 flex-shrink-0 transition duration-300 group-hover:translate-x-1"
|
||||
width="24"
|
||||
|
@ -28,12 +32,14 @@ const arrowSVG = `<svg
|
|||
</svg>`;
|
||||
---
|
||||
|
||||
<!-- Link styled as a button, with dynamic title, URL, and optional arrow -->
|
||||
<a
|
||||
class={`${baseClasses} ${borderClasses} ${bgColorClasses} ${disableClasses} ${fontSizeClasses} ${ringClasses}`}
|
||||
href={url}
|
||||
>
|
||||
{title}
|
||||
{noArrow ? null :
|
||||
<Fragment set:html={arrowSVG} />
|
||||
}
|
||||
<!-- Display the arrow based on the 'noArrow' property -->
|
||||
<!-- About Fragment: https://docs.astro.build/en/basics/astro-syntax/#fragments -->
|
||||
|
||||
{noArrow ? null : <Fragment set:html={arrowSVG} />}
|
||||
</a>
|
|
@ -1,31 +1,34 @@
|
|||
---
|
||||
// Destructure the properties from Astro.props
|
||||
const { id, dataTab, title, first } = Astro.props;
|
||||
|
||||
// Define TypeScript interface for the properties
|
||||
interface Props {
|
||||
id: string;
|
||||
dataTab: string;
|
||||
title: string;
|
||||
first?: boolean;
|
||||
}
|
||||
|
||||
// Define constants for styling classes
|
||||
const BUTTON_CLASS =
|
||||
"flex w-full justify-center rounded-xl border border-transparent p-3 outline-none ring-zinc-500 transition duration-300 hover:bg-neutral-100 focus-visible:ring dark:ring-zinc-200 dark:hover:bg-neutral-700 dark:focus:outline-none md:p-5";
|
||||
|
||||
const HEADING_CLASS = "block text-center font-bold";
|
||||
const INACTIVE_HEADING_CLASS = "text-neutral-800 dark:text-neutral-200";
|
||||
const HEADING_CLASS = "block text-center font-bold";
|
||||
const INACTIVE_HEADING_CLASS = "text-neutral-800 dark:text-neutral-200";
|
||||
---
|
||||
|
||||
<!-- Tab button element -->
|
||||
<button
|
||||
type="button"
|
||||
class={`${BUTTON_CLASS} ${first ? "active bg-neutral-100 hover:border-transparent dark:bg-white/[.05]" : ""}`}
|
||||
id={id}
|
||||
data-target={dataTab}
|
||||
role="tab"
|
||||
type="button"
|
||||
class={`${BUTTON_CLASS} ${first ? "active bg-neutral-100 hover:border-transparent dark:bg-white/[.05]" : ""}`}
|
||||
id={id}
|
||||
data-target={dataTab}
|
||||
role="tab"
|
||||
>
|
||||
<h2
|
||||
<!-- Tab text -->
|
||||
<span
|
||||
class={`${HEADING_CLASS} ${first ? "text-[#fa5a15] dark:text-[#fb713b]" : INACTIVE_HEADING_CLASS}`}
|
||||
>
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
---
|
||||
// Destructure the properties from Astro.props
|
||||
const { title, url } = Astro.props;
|
||||
|
||||
// Define TypeScript interface for the properties
|
||||
interface Props {
|
||||
title?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
const baseClasses = "inline-flex items-center justify-center gap-x-2 rounded-lg px-4 py-3 text-center text-sm font-medium text-neutral-600 shadow-sm outline-none ring-zinc-500 focus-visible:ring transition duration-300";
|
||||
// Define CSS classes for the hyperlink button
|
||||
const baseClasses =
|
||||
"inline-flex items-center justify-center gap-x-2 rounded-lg px-4 py-3 text-center text-sm font-medium text-neutral-600 shadow-sm outline-none ring-zinc-500 focus-visible:ring transition duration-300";
|
||||
const borderClasses = "border border-neutral-200";
|
||||
const bgColorClasses = "bg-neutral-300";
|
||||
const hoverClasses = "hover:bg-neutral-400/50 hover:text-neutral-600 active:text-neutral-700";
|
||||
const hoverClasses =
|
||||
"hover:bg-neutral-400/50 hover:text-neutral-600 active:text-neutral-700";
|
||||
const disableClasses = "disabled:pointer-events-none disabled:opacity-50";
|
||||
const fontSizeClasses = "2xl:text-base";
|
||||
const ringClasses = "ring-zinc-500";
|
||||
|
||||
const darkClasses = "dark:border-neutral-700 dark:bg-zinc-700 dark:text-neutral-300 dark:ring-zinc-200 dark:hover:bg-zinc-600 dark:focus:outline-none";
|
||||
const darkClasses =
|
||||
"dark:border-neutral-700 dark:bg-zinc-700 dark:text-neutral-300 dark:ring-zinc-200 dark:hover:bg-zinc-600 dark:focus:outline-none";
|
||||
---
|
||||
|
||||
<!-- Styled hyperlink -->
|
||||
<a
|
||||
class={`${baseClasses} ${borderClasses} ${bgColorClasses} ${hoverClasses} ${disableClasses} ${fontSizeClasses} ${ringClasses} ${darkClasses}`}
|
||||
href={url}
|
||||
|
|
|
@ -1,45 +1,42 @@
|
|||
---
|
||||
// Import the necessary dependencies from individual component files
|
||||
// Import necessary components from individual files
|
||||
import EmailInput from "./input/EmailInput.astro";
|
||||
import AuthBtn from "../buttons/AuthBtn.astro";
|
||||
|
||||
// Config object for customization of the RecoverModal Component
|
||||
// Config object for customization of the component
|
||||
const config = {
|
||||
// Modal identifier
|
||||
id: "hs-toggle-between-modals-recover-modal",
|
||||
|
||||
// Main heading
|
||||
title: "Forgot password?",
|
||||
|
||||
// Sub-heading text
|
||||
subTitle: "Remember your password?",
|
||||
|
||||
// Text and target link for the login button
|
||||
loginBtn: "Sign in here",
|
||||
loginBtnDataHS: "#hs-toggle-between-modals-login-modal"
|
||||
id: "hs-toggle-between-modals-recover-modal", // Modal identifier
|
||||
title: "Forgot password?", // Main heading
|
||||
subTitle: "Remember your password?", // Sub-heading text
|
||||
loginBtn: "Sign in here", // Text for login button
|
||||
loginBtnDataHS: "#hs-toggle-between-modals-login-modal", // Target link for login button
|
||||
};
|
||||
---
|
||||
|
||||
<!-- Root element of the modal with id and styling -->
|
||||
<div
|
||||
id={config.id}
|
||||
class="hs-overlay absolute start-0 top-0 z-50 hidden h-full w-full hs-overlay-backdrop-open:bg-neutral-900/90"
|
||||
>
|
||||
<!-- Modal content container -->
|
||||
<div
|
||||
class="m-3 mt-0 opacity-0 transition-all ease-out hs-overlay-open:mt-7 hs-overlay-open:opacity-100 hs-overlay-open:duration-500 sm:mx-auto sm:w-full sm:max-w-lg"
|
||||
>
|
||||
<div class="mx-auto w-full max-w-md p-6">
|
||||
<!-- Actual box for the modal elements -->
|
||||
<div
|
||||
class="mt-7 rounded-xl border border-neutral-200 bg-neutral-100 shadow-sm dark:border-neutral-700 dark:bg-neutral-800"
|
||||
>
|
||||
<div class="p-4 sm:p-7">
|
||||
<div class="text-center">
|
||||
<h1
|
||||
<h2
|
||||
class="block text-2xl font-bold text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
{config.title}
|
||||
</h1>
|
||||
</h2>
|
||||
<p class="mt-2 text-sm text-neutral-600 dark:text-neutral-400">
|
||||
{config.subTitle}
|
||||
<!-- Button that, when clicked, opens the login modal -->
|
||||
<button
|
||||
class="rounded-lg p-1 font-medium text-[#fa5a15] decoration-2 outline-none ring-zinc-500 hover:underline focus-visible:ring dark:text-[#fa5a15] dark:ring-zinc-200 dark:focus:outline-none"
|
||||
data-hs-overlay={config.loginBtnDataHS}
|
||||
|
@ -50,10 +47,12 @@ const config = {
|
|||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<!-- Form -->
|
||||
<!-- The form for password recovery -->
|
||||
<form>
|
||||
<div class="grid gap-y-4">
|
||||
<!-- Email input field imported from EmailInput component -->
|
||||
<EmailInput id="recover-email" />
|
||||
<!-- Reset password button imported from AuthBtn component -->
|
||||
<AuthBtn title="Reset password" />
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,27 +1,21 @@
|
|||
---
|
||||
// Import the necessary dependencies from individual component files
|
||||
// Import necessary components from individual files
|
||||
import EmailInput from "./input/EmailInput.astro";
|
||||
import PasswordInput from "./input/PasswordInput.astro";
|
||||
import Checkbox from "./input/Checkbox.astro";
|
||||
import GoogleBtn from "../buttons/GoogleBtn.astro";
|
||||
import AuthBtn from "../buttons/AuthBtn.astro";
|
||||
|
||||
// Config object for customization of the component
|
||||
const config = {
|
||||
// Modal identifier
|
||||
id: "hs-toggle-between-modals-register-modal",
|
||||
|
||||
// Main title
|
||||
title: "Sign up",
|
||||
|
||||
// Subtitle text
|
||||
subTitle: "Already have an account?",
|
||||
|
||||
// Text and target link for the login button
|
||||
loginBtn: "Sign in here",
|
||||
loginBtnDataHS: "#hs-toggle-between-modals-login-modal"
|
||||
id: "hs-toggle-between-modals-register-modal", // Modal identifier
|
||||
title: "Sign up", // Main heading
|
||||
subTitle: "Already have an account?", // Sub-heading text
|
||||
loginBtn: "Sign in here", // Text for login button
|
||||
loginBtnDataHS: "#hs-toggle-between-modals-login-modal", // Target link for login button
|
||||
};
|
||||
---
|
||||
|
||||
<!-- Root element of the registration modal with the id and styling -->
|
||||
<div
|
||||
id={config.id}
|
||||
class="hs-overlay absolute start-0 top-0 z-50 hidden h-full w-full hs-overlay-backdrop-open:bg-neutral-900/90"
|
||||
|
@ -35,13 +29,14 @@ const config = {
|
|||
>
|
||||
<div class="p-4 sm:p-7">
|
||||
<div class="text-center">
|
||||
<h1
|
||||
<h2
|
||||
class="block text-2xl font-bold text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
{config.title}
|
||||
</h1>
|
||||
</h2>
|
||||
<p class="mt-2 text-sm text-neutral-600 dark:text-neutral-400">
|
||||
{config.subTitle}
|
||||
<!-- Button to toggle login modal -->
|
||||
<button
|
||||
class="rounded-lg p-1 font-medium text-[#fa5a15] decoration-2 outline-none ring-zinc-500 hover:underline focus-visible:ring dark:text-[#fa5a15] dark:ring-zinc-200 dark:focus:outline-none"
|
||||
data-hs-overlay={config.loginBtnDataHS}
|
||||
|
@ -50,25 +45,29 @@ const config = {
|
|||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- The form for user registration -->
|
||||
<div class="mt-5">
|
||||
<!-- Google signup button -->
|
||||
<GoogleBtn title="Sign up with Google" />
|
||||
|
||||
<!-- Dividing line with 'Or' text -->
|
||||
<div
|
||||
class="flex items-center py-3 text-xs uppercase text-neutral-400 before:me-6 before:flex-[1_1_0%] before:border-t before:border-neutral-200 after:ms-6 after:flex-[1_1_0%] after:border-t after:border-neutral-200 dark:text-neutral-500 dark:before:border-neutral-600 dark:after:border-neutral-600"
|
||||
>
|
||||
Or
|
||||
</div>
|
||||
|
||||
<!-- Registration form -->
|
||||
<form>
|
||||
<div class="grid gap-y-4">
|
||||
<!-- Email input field -->
|
||||
<EmailInput id="register-email" />
|
||||
<!-- Password input field -->
|
||||
<PasswordInput
|
||||
id="create-password"
|
||||
;
|
||||
errorId="password-error"
|
||||
errorId="register-password-error"
|
||||
content="8+ characters required"
|
||||
/>
|
||||
<!-- Password confirmation input field -->
|
||||
<PasswordInput
|
||||
label="Confirm Password"
|
||||
id="confirm-password"
|
||||
|
@ -77,14 +76,14 @@ const config = {
|
|||
aria="confirm-password-error"
|
||||
content="Password does not match the password"
|
||||
/>
|
||||
|
||||
<!-- Checkbox with a label and a link for accepting the terms and conditions -->
|
||||
<Checkbox label="I accept the " , id="terms-agree">
|
||||
<a
|
||||
class="font-medium text-[#fa5a15] decoration-2 hover:underline dark:text-[#fa5a15] dark:focus:outline-none"
|
||||
href="#">Terms and Conditions</a
|
||||
>
|
||||
</Checkbox>
|
||||
|
||||
<!-- Submit button for the registration form -->
|
||||
<AuthBtn title="Sign up" />
|
||||
</div>
|
||||
</form>
|
||||
|
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 45 KiB |
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
// Import section components
|
||||
// Import necessary components
|
||||
import MainLayout from "../layouts/MainLayout.astro";
|
||||
import MainSection from "../components/ui/blocks/MainSection.astro";
|
||||
import LeftSection from "../components/ui/blocks/LeftSection.astro";
|
||||
import RightSection from "../components/ui/blocks/RightSection.astro";
|
||||
import FeaturesStats from "../components/FeaturesStats.astro";
|
||||
|
||||
// Import necessary images
|
||||
import blueprints from "../images/blueprints-image.avif";
|
||||
import personWorking from "../images/person-working.avif";
|
||||
import beforeAfter from "../images/before-after.avif";
|
||||
|
@ -16,7 +17,12 @@ import progressBuilding from "../images/progress-building.avif";
|
|||
import underConstruction from "../images/under-construction.avif";
|
||||
---
|
||||
|
||||
<MainLayout title="Services | ScrewFast" meta="ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs. Start exploring and contact our sales team for superior quality and reliability.">
|
||||
<!--Utilizing MainLayout for the outer layout of the page, and defining meta for SEO purposes-->
|
||||
<MainLayout
|
||||
title="Services | ScrewFast"
|
||||
meta="ScrewFast offers top-tier hardware tools and expert construction services to meet all your project needs. Start exploring and contact our sales team for superior quality and reliability."
|
||||
>
|
||||
<!--MainSection is the introductory section of the page, it also contains a CTA button-->
|
||||
<MainSection
|
||||
title="Uniting Expertise with Your Vision"
|
||||
subTitle="At ScrewFast, we take pride in providing comprehensive solutions and exceptional service in the hardware and construction industry. Our experienced team is dedicated to supporting your project from inception to completion with a range of specialized services."
|
||||
|
@ -24,7 +30,14 @@ import underConstruction from "../images/under-construction.avif";
|
|||
btnTitle="Schedule a Consultation"
|
||||
btnURL="#"
|
||||
/>
|
||||
|
||||
<!-- RightSection and LeftSection contain details about various services along with pertinent imagery.
|
||||
They alternate for variety in design.
|
||||
The 'btnExists' property is used to toggle the display of a button in these sections.
|
||||
When btnExists={true}, a button is displayed.
|
||||
This can be used to link to more detailed information or related resources.
|
||||
RightSection can also conditionally render one or two images based on the 'single' property.
|
||||
If 'single' is true, it displays one image, otherwise it displays two.
|
||||
-->
|
||||
<RightSection
|
||||
title="Delivering Expert Guidance"
|
||||
subTitle="Embarking on a construction project can be overwhelming. With our professional consultation services, we guide you through every stage, ensuring you make informed decisions. Whether you are a DIY enthusiast or a skilled contractor, our experts are on hand to offer tailored advice on product selection, project scope, and compliance with local regulations."
|
||||
|
@ -67,7 +80,7 @@ import underConstruction from "../images/under-construction.avif";
|
|||
imgTwo={underConstruction}
|
||||
imgTwoAlt={"Brown and gray building under construction"}
|
||||
/>
|
||||
|
||||
<!--FeaturesStats section showcases essential stats valuable to users-->
|
||||
<FeaturesStats
|
||||
title="By the Numbers"
|
||||
subTitle="Our commitment to quality and reliability is evident in every project we undertake. At ScrewFast, we are dedicated to delivering industry-leading services that ensure your construction projects are built to last."
|
||||
|
|