Add new UI components and secure headers configuration
Introduced new UI components including testimonial section, avatar, and image elements. Configured secure headers in vercel.json file to enhance security. These changes improve both the aesthetic appeal and security of the website.
This commit is contained in:
parent
a9b4e8c0dc
commit
6025dc07db
10 changed files with 287 additions and 0 deletions
56
src/components/FeaturesStats2.astro
Normal file
56
src/components/FeaturesStats2.astro
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
|
||||
import product5 from "../images/features-image.avif";
|
||||
|
||||
const title: string = "Why Choose ScrewFast?";
|
||||
|
||||
const subTitle: string =
|
||||
"Transform your ideas into tangible results with ScrewFast tools. Whether you're starting with a sketch on a napkin or diving into a comprehensive construction project, our tools are engineered to help you build with confidence.";
|
||||
|
||||
const benefits: string[] = [
|
||||
"Robust and reliable tools for long-lasting performance.",
|
||||
"Innovative solutions tailored to modern construction needs.",
|
||||
"Customer support dedicated to your project's success.",
|
||||
];
|
||||
|
||||
const ListItemMarker:string = `<svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="mt-0.5 h-6 w-6 text-[#fa5a15] dark:text-[#fb713b]"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>`;
|
||||
---
|
||||
|
||||
<div
|
||||
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||
>
|
||||
<!-- Grid -->
|
||||
<div class="lg:grid lg:grid-cols-12 lg:items-center lg:gap-16">
|
||||
<div class="lg:col-span-7">
|
||||
<Image class="rounded-xl" src={product5} alt="Mockup of floating boxes" />
|
||||
</div>
|
||||
<div class="mt-5 sm:mt-10 lg:col-span-5 lg:mt-0">
|
||||
<div class="space-y-6 sm:space-y-8">
|
||||
<div class="space-y-2 md:space-y-4">
|
||||
<h2
|
||||
class="text-balance text-3xl font-bold text-neutral-800 dark:text-neutral-200 lg:text-4xl"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<p class="text-pretty text-neutral-600 dark:text-neutral-400">
|
||||
{subTitle}
|
||||
</p>
|
||||
</div>
|
||||
<ul role="list" class="space-y-2 sm:space-y-4">
|
||||
{
|
||||
benefits.map((item) => (
|
||||
<li class="flex space-x-3">
|
||||
<Fragment set:html={ListItemMarker}/>
|
||||
|
||||
<span class="text-pretty text-sm font-medium text-neutral-600 dark:text-neutral-400 sm:text-base">
|
||||
{item}
|
||||
</span>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
94
src/components/TestimonialsSection2.astro
Normal file
94
src/components/TestimonialsSection2.astro
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
// Import the necessary dependencies from individual component files
|
||||
import AvatarTestimonialSection2 from "./ui/avatars/AvatarTestimonialSection2.astro";
|
||||
|
||||
// Variables for customization of the LoginModal Component
|
||||
// Main heading
|
||||
const title: string = "What Our Customers Say";
|
||||
|
||||
/* TypeScript type for product. */
|
||||
type Testimonial = {
|
||||
content: string;
|
||||
author: string;
|
||||
role: string;
|
||||
avatarSrc: string;
|
||||
avatarAlt: string;
|
||||
};
|
||||
|
||||
const testimonials: Testimonial[] = [
|
||||
{
|
||||
content:
|
||||
" \"Since switching to ScrewFast's hardware tools, the efficiency on our construction sites has skyrocketed. The durability of the hex bolts and precision of the machine screws are simply unmatched. It's refreshing to work with a company that truly understands the daily demands of the industry.\" ",
|
||||
author: "Jason Clark",
|
||||
role: "Site Foreman | TopBuild",
|
||||
avatarSrc:
|
||||
"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?q=80&w=1374&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=facearea&facepad=2&w=320&h=320&q=80",
|
||||
avatarAlt: "Image Description",
|
||||
},
|
||||
{
|
||||
content:
|
||||
" \"As an interior designer, I'm always looking for high-quality materials and tools that help bring my visions to life. ScrewFast's mixed screws assortment has been a game-changer for my projects, providing the perfect blend of quality and variety. The outstanding customer support was just the cherry on top!\" ",
|
||||
author: "Maria Gonzalez",
|
||||
role: "Interior Designer | Creative Spaces",
|
||||
avatarSrc:
|
||||
"https://images.unsplash.com/photo-1544005313-94ddf0286df2?q=80&w=1376&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D8&auto=format&fit=facearea&facepad=2&w=320&h=320&q=80",
|
||||
avatarAlt: "Image Description",
|
||||
},
|
||||
{
|
||||
content:
|
||||
" \"I’ve been a professional carpenter for over 15 years, and I can sincerely say that ScrewFast’s tap bolts and nuts are some of the best I've used. They grip like no other, and I have full confidence in every joint and fixture. Plus, the service is impeccable – they truly care about my project's success.\" ",
|
||||
author: "Richard Kim",
|
||||
role: "Master Carpenter | WoodWright",
|
||||
avatarSrc:
|
||||
"https://images.unsplash.com/photo-1474176857210-7287d38d27c6?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D8&auto=format&fit=facearea&facepad=2&w=320&h=320&q=80",
|
||||
avatarAlt: "Image Description",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div
|
||||
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||
id="testimonials"
|
||||
>
|
||||
<div class="mb-6 w-3/4 max-w-2xl sm:mb-10 md:mb-16 lg:w-1/2">
|
||||
<h2
|
||||
class="text-balance text-2xl font-bold text-neutral-800 dark:text-neutral-200 sm:text-3xl lg:text-4xl"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{
|
||||
testimonials.map((testimonial) => (
|
||||
<div class="flex h-auto">
|
||||
<div class="flex flex-col rounded-xl bg-neutral-50 dark:bg-neutral-700">
|
||||
<div class="flex-auto p-4 md:p-6">
|
||||
<p class="text-pretty text-base italic text-neutral-600 dark:text-neutral-300 md:text-lg">
|
||||
{testimonial.content}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-b-xl bg-neutral-300/30 p-4 dark:bg-neutral-900/30 md:px-7">
|
||||
<div class="flex items-center">
|
||||
<AvatarTestimonialSection2
|
||||
src={testimonial.avatarSrc}
|
||||
alt={testimonial.avatarAlt}
|
||||
/>
|
||||
|
||||
<div class="ms-3 grow">
|
||||
<p class="text-sm font-bold text-neutral-800 dark:text-neutral-200 sm:text-base">
|
||||
{testimonial.author}
|
||||
</p>
|
||||
<p class="text-xs text-neutral-600 dark:text-neutral-400">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
16
src/components/ui/avatars/AvatarTestimonialSection2.astro
Normal file
16
src/components/ui/avatars/AvatarTestimonialSection2.astro
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
const { src, alt } = Astro.props;
|
||||
|
||||
interface Props {
|
||||
src: string;
|
||||
alt: string;
|
||||
}
|
||||
---
|
||||
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="size-8 rounded-full sm:h-[2.875rem] sm:w-[2.875rem]"
|
||||
src={src}
|
||||
alt={alt}
|
||||
/>
|
||||
</div>
|
||||
41
src/components/ui/images/ImgSmall.astro
Normal file
41
src/components/ui/images/ImgSmall.astro
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
const { title, src, alt, url } = Astro.props;
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
src: any;
|
||||
alt: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const imageClass = "absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
|
||||
const AnchorSVG = `
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
|
||||
</svg>`;
|
||||
---
|
||||
|
||||
<a
|
||||
href={url}
|
||||
class="group relative flex h-48 items-end overflow-hidden rounded-xl shadow-lg md:h-80"
|
||||
>
|
||||
<Image
|
||||
src={src}
|
||||
alt={alt}
|
||||
class={imageClass}
|
||||
draggable={"false"}
|
||||
format={"avif"}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0 bg-gradient-to-t from-neutral-800 via-transparent to-transparent opacity-50 dark:from-neutral-700"
|
||||
>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
|
||||
>{title} <Fragment set:html={AnchorSVG} />
|
||||
</span
|
||||
>
|
||||
</a>
|
||||
39
src/components/ui/images/ImgWide.astro
Normal file
39
src/components/ui/images/ImgWide.astro
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
const { title, src, alt, url } = Astro.props;
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
src: any;
|
||||
alt: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const imageClass = "absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
|
||||
const AnchorSVG = `
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
|
||||
</svg>`;
|
||||
---
|
||||
|
||||
<a
|
||||
href={url}
|
||||
class="group relative flex h-48 items-end overflow-hidden rounded-lg shadow-xl md:col-span-2 md:h-80"
|
||||
>
|
||||
<Image
|
||||
src={src}
|
||||
alt={alt}
|
||||
draggable={"false"}
|
||||
class={imageClass}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0 bg-gradient-to-t from-neutral-800 via-transparent to-transparent opacity-50 dark:from-neutral-700"
|
||||
>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
|
||||
>{title} <Fragment set:html={AnchorSVG} /></span
|
||||
>
|
||||
</a>
|
||||
BIN
src/images/product-image-1.avif
Normal file
BIN
src/images/product-image-1.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
src/images/product-image-2.avif
Normal file
BIN
src/images/product-image-2.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
BIN
src/images/product-image-3.avif
Normal file
BIN
src/images/product-image-3.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
BIN
src/images/product-image-4.avif
Normal file
BIN
src/images/product-image-4.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
41
vercel.json
Normal file
41
vercel.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"headers": [
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Content-Security-Policy",
|
||||
"value": "default-src 'self'; base-uri 'self'; form-action 'self'; frame-src 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; upgrade-insecure-requests; block-all-mixed-content"
|
||||
},
|
||||
{
|
||||
"key": "Permissions-Policy",
|
||||
"value": "interest-cohort=()"
|
||||
},
|
||||
{
|
||||
"key": "Referrer-Policy",
|
||||
"value": "no-referrer-when-downgrade"
|
||||
},
|
||||
{
|
||||
"key": "X-Content-Type-Options",
|
||||
"value": "nosniff"
|
||||
},
|
||||
{
|
||||
"key": "X-Frame-Options",
|
||||
"value": "SAMEORIGIN"
|
||||
},
|
||||
{
|
||||
"key": "X-XSS-Protection",
|
||||
"value": "1; mode=block"
|
||||
},
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=0, must-revalidate"
|
||||
},
|
||||
{
|
||||
"key": "Strict-Transport-Security",
|
||||
"value": "max-age=31536000; includeSubDomains; preload"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue