Migrate product content to Markdown format and add new features

Product information previously stored in JSON files has been migrated to Markdown format for efficient content management. Additionally, added a new button component for 404 pages to improve navigation and user experience. Defined a new schema for product collections and included GSAP JavaScript library for future animations.
This commit is contained in:
Emil Gulamov 2024-02-16 08:36:04 +04:00
parent e58364effb
commit 33c942f261
17 changed files with 458 additions and 205 deletions

11
public/assets/vendor/gsap/gsap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
---
const { title, id, noArrow } = Astro.props;
interface Props {
title?: string;
id?: 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";
const borderClasses = "border border-transparent";
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";
const arrowSVG = `<svg
class="h-4 w-4 flex-shrink-0 transition duration-300 group-hover:translate-x-1"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m9 18 6-6-6-6"></path>
</svg>`;
---
<button
class={`${baseClasses} ${borderClasses} ${bgColorClasses} ${disableClasses} ${fontSizeClasses} ${ringClasses}`}
id={id}
>
{title}
{noArrow ? null :
<Fragment set:html={arrowSVG} />
}
</button>

View file

@ -11,7 +11,7 @@ interface Props {
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-semibold";
const HEADING_CLASS = "block text-center font-bold";
const INACTIVE_HEADING_CLASS = "text-neutral-800 dark:text-neutral-200";
---
@ -19,7 +19,7 @@ const BUTTON_CLASS =
type="button"
class={`${BUTTON_CLASS} ${first ? "active bg-neutral-100 hover:border-transparent dark:bg-white/[.05]" : ""}`}
id={id}
data-tab-target={dataTab}
data-target={dataTab}
role="tab"
>
<h2

View file

@ -3,13 +3,22 @@ import { Image } from "astro:assets";
const { title, src, alt, url } = Astro.props;
interface Props {
title?: string;
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";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
interface Props {
product: CollectionEntry<"products">;
}
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" />
@ -17,14 +26,14 @@ const AnchorSVG = `
---
<a
href={url}
class="group relative flex h-48 outline-none dark:focus:outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 items-end overflow-hidden rounded-xl shadow-lg md:h-80"
href={"/products/" + product.slug}
class="group relative flex h-48 items-end overflow-hidden rounded-xl shadow-lg outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:h-80"
>
<Image
src={src}
alt={alt}
class={imageClass}
src={product.data.main.imgCard}
alt={product.data.main.imgAlt}
draggable={"false"}
class={imageClass}
format={"avif"}
/>
@ -35,7 +44,6 @@ const AnchorSVG = `
<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
>
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} />
</span>
</a>

View file

@ -3,13 +3,22 @@ import { Image } from "astro:assets";
const { title, src, alt, url } = Astro.props;
interface Props {
title?: string;
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";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
interface Props {
product: CollectionEntry<"products">;
}
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" />
@ -17,14 +26,15 @@ const AnchorSVG = `
---
<a
href={url}
class="group relative outline-none dark:focus:outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 flex h-48 items-end overflow-hidden rounded-lg shadow-xl md:col-span-2 md:h-80"
href={"/products/" + product.slug}
class="group relative flex h-48 items-end overflow-hidden rounded-lg shadow-xl outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:col-span-2 md:h-80"
>
<Image
src={src}
alt={alt}
src={product.data.main.imgCard}
alt={product.data.main.imgAlt}
draggable={"false"}
class={imageClass}
format={"avif"}
/>
<div
@ -34,6 +44,6 @@ const AnchorSVG = `
<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
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} /></span
>
</a>

64
src/content/config.ts Normal file
View file

@ -0,0 +1,64 @@
// https://docs.astro.build/en/guides/content-collections/#defining-collections
import { z, defineCollection } from 'astro:content';
const productCollection = defineCollection({
type: 'content',
schema: ({ image }) => z.object({
main: z.object({
id: z.number(),
title: z.string(),
subTitle: z.string(),
content: z.string(),
imgCard: image(),
imgMain: image(),
imgAlt: z.string(),
}),
tabs: z.array(
z.object({
id: z.string(),
dataTab: z.string(),
title: z.string(),
})
),
description: z.object({
title: z.string(),
subTitle: z.string(),
btnTitle: z.string(),
btnURL: z.string(),
}),
descriptionList: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
),
specificationsLeft: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
),
specificationsRight: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
).optional(),
blueprints: z.object({
first: z.string().optional(),
second: z.string().optional(),
}),
}),
});
// const blogCollection = defineCollection({
// type: 'content',
// schema: z.object({})
// });
// 3. Export a single `collections` object to register your collection(s)
export const collections = {
'products': productCollection,
// 'blog': blogCollection,
};

View file

@ -0,0 +1,56 @@
---
main:
id: 2
title: "SF-AB A765"
subTitle: "Assorted Screw Set"
content: |
Introducing the SF-AB A765 Assorted Screw Set the ultimate solution for your screw fastening needs. This comprehensive set includes a wide variety of screws meticulously curated to tackle various projects with ease and precision.
imgCard: "../../images/product-image-2.avif"
imgMain: "../../images/product-image-3-main.avif"
imgAlt: "Mockup boxes of assorted screw set"
tabs:
- id: "tabs-with-card-item-1"
dataTab: "#tabs-with-card-1"
title: "Description"
- id: "tabs-with-card-item-2"
dataTab: "#tabs-with-card-2"
title: "Specifications"
- id: "tabs-with-card-item-3"
dataTab: "#tabs-with-card-3"
title: "Blueprints"
description:
title: "Versatile Screw Fastening Solutions"
subTitle: |
The SF-AB A765 Assorted Screw Set offers unmatched versatility and convenience, making it the perfect choice for DIY enthusiasts and professionals alike. With a comprehensive selection of screws, you'll always have the right fastener for the job.
btnTitle: "Contact sales to learn more"
btnURL: "#"
descriptionList:
- title: "Wide Variety"
subTitle: "Includes a diverse range of screw types and sizes to accommodate various applications and materials."
- title: "Ease of Use"
subTitle: "Each screw is designed for effortless installation, ensuring hassle-free fastening every time."
- title: "Convenience"
subTitle: "Eliminates the need for multiple trips to the hardware store, saving time and effort on your projects."
specificationsLeft:
- title: "Material"
subTitle: "Constructed from high-quality materials such as stainless steel, ensuring durability and corrosion resistance."
- title: "Assortment"
subTitle: "Contains a generous assortment of screws, including wood screws, machine screws, and sheet metal screws."
- title: "Quantity"
subTitle: "Each set includes a sufficient quantity of screws to handle a wide range of projects and tasks."
- title: "Sizes"
subTitle: "Available in various sizes to suit different project requirements, ensuring compatibility and versatility."
specificationsRight:
- title: "Thread Design"
subTitle: "Precision-engineered threads ensure a tight and secure fit, providing reliable fastening for your projects."
- title: "Durability"
subTitle: "Designed to withstand the rigors of everyday use, delivering long-lasting performance and reliability."
- title: "Quality Assurance"
subTitle: "Manufactured to meet or exceed industry standards, guaranteeing consistent quality and performance."
- title: "Applications"
subTitle: "Suitable for a wide range of applications, including woodworking, metalworking, construction, and more."
blueprints:
first: "../../images/blueprint-1.avif"
second: "../../images/blueprint-2.avif"
slug: a765
---

View file

@ -1,63 +0,0 @@
{
"main": {
"title": "SF-BN B203",
"subTitle": "Tap Bolts and Nuts Set",
"content": "Meet the SF-BN B203 your reliable companion for professional-grade fastening. This comprehensive box set comes with a versatile selection of tap bolts and nuts, meticulously crafted to provide the strongest hold for your construction and assembly projects.",
"img": "../images/product-main.avif",
"imgAlt": "Mockup boxes of a tap bolts and nuts set"
},
"tabs": [
{
"id": "tabs-with-card-item-1",
"dataTab": "#tabs-with-card-1",
"title": "Product Description"
},
{
"id": "tabs-with-card-item-2",
"dataTab": "#tabs-with-card-2",
"title": "Specifications"
},
{
"id": "tabs-with-card-item-3",
"dataTab": "#tabs-with-card-3",
"title": "Blueprints"
}
],
"description": {
"title": "Strength Meets Precision",
"subTitle": "The SF-BN B203 Tap Bolts and Nuts Set offers robust durability and precision for construction professionals, ensuring reliable performance in every application, from house framing to machinery assembly.",
"btnTitle": "Contact sales to learn more",
"btnURL": "#"
},
"descriptionList": [
{
"title": "Corrosion Resistance",
"subTitle": "Zinc coating not only provides a polished look but also shields against corrosion, ensuring longevity."
},
{
"title": "Improved Safety",
"subTitle": "A secure fitting translates to safer structures with reduced risk of component failure."
},
{
"title": "Convenience",
"subTitle": "This all-in-one set means you have the right size on hand, cutting down on project delays and additional trips to the hardware store."
}
],
"specifications": [
{
"id": "tabs-with-card-item-1",
"dataTab": "#tabs-with-card-1",
"title": "Product Description"
},
{
"id": "tabs-with-card-item-2",
"dataTab": "#tabs-with-card-2",
"title": "Specifications"
},
{
"id": "tabs-with-card-item-3",
"dataTab": "#tabs-with-card-3",
"title": "Blueprints"
}
]
}

View file

@ -0,0 +1,56 @@
---
main:
id: 3
title: "SF-BN B203"
subTitle: "Tap Bolts and Nuts Set"
content: |
Meet the SF-BN B203 your reliable companion for professional-grade fastening. This comprehensive box set comes with a versatile selection of tap bolts and nuts, meticulously crafted to provide the strongest hold for your construction and assembly projects.
imgCard: "../../images/product-image-3.avif"
imgMain: "../../images/product-image-3-main.avif"
imgAlt: "Mockup boxes of a tap bolts and nuts set"
tabs:
- id: "tabs-with-card-item-1"
dataTab: "#tabs-with-card-1"
title: "Description"
- id: "tabs-with-card-item-2"
dataTab: "#tabs-with-card-2"
title: "Specifications"
- id: "tabs-with-card-item-3"
dataTab: "#tabs-with-card-3"
title: "Blueprints"
description:
title: "Strength Meets Precision"
subTitle: |
The SF-BN B203 Tap Bolts and Nuts Set offers robust durability and precision for construction professionals, ensuring reliable performance in every application, from house framing to machinery assembly.
btnTitle: "Contact sales to learn more"
btnURL: "#"
descriptionList:
- title: "Corrosion Resistance"
subTitle: "Zinc coating not only provides a polished look but also shields against corrosion, ensuring longevity."
- title: "Improved Safety"
subTitle: "A secure fitting translates to safer structures with reduced risk of component failure."
- title: "Convenience"
subTitle: "This all-in-one set means you have the right size on hand, cutting down on project delays and additional trips to the hardware store."
specificationsLeft:
- title: "Material Composition"
subTitle: "Manufactured from high-grade steel, delivering strength and reliability for demanding applications."
- title: "Surface Finish"
subTitle: "Protected with a zinc coating to offer enhanced corrosion resistance and longevity."
- title: "Quantity Per Set"
subTitle: "The set includes a balanced selection of 25 tap bolts and 25 matching nuts."
- title: "Size Assortment"
subTitle: "Features a comprehensive range of sizes to cater to various project requirements, ensuring compatibility and versatility."
specificationsRight:
- title: "Thread Details"
subTitle: "Engineered with precision-cut threads for a secure fit and easy installation."
- title: "Mechanical Properties"
subTitle: "Each bolt and nut is designed to meet specific load rating or strength grades, suitable for structural applications."
- title: "Standards and Certifications"
subTitle: "Complies with relevant industry standards and certifications, ensuring consistent quality and safety."
- title: "Suitable Applications"
subTitle: "Ideal for a wide array of uses, from construction environments to mechanical assemblies that demand strong and secure joints."
blueprints:
first: "../../images/blueprint-1.avif"
second: "../../images/blueprint-2.avif"
slug: b203
---

View file

@ -0,0 +1,56 @@
---
main:
id: 4
title: "SF-FN F303"
subTitle: "Hex Bolts"
content: |
Introducing the SF-FN F303 Hex Bolts the perfect choice for heavy-duty fastening applications. Crafted with precision and durability in mind, these hex bolts provide the strength and reliability you need for your toughest projects.
imgCard: "../../images/product-image-4.avif"
imgMain: "../../images/product-image-3-main.avif"
imgAlt: "Mockup boxes of hex bolts"
tabs:
- id: "tabs-with-card-item-1"
dataTab: "#tabs-with-card-1"
title: "Description"
- id: "tabs-with-card-item-2"
dataTab: "#tabs-with-card-2"
title: "Specifications"
- id: "tabs-with-card-item-3"
dataTab: "#tabs-with-card-3"
title: "Blueprints"
description:
title: "Heavy-Duty Fastening Solutions"
subTitle: |
The SF-FN F303 Hex Bolts are designed to handle the toughest fastening challenges with ease. Whether you're working on construction projects or heavy machinery, these hex bolts deliver the strength and reliability you need.
btnTitle: "Contact sales to learn more"
btnURL: "#"
descriptionList:
- title: "Strength and Durability"
subTitle: "Constructed from high-quality materials, these hex bolts are built to withstand heavy loads and tough conditions."
- title: "Precision Engineering"
subTitle: "Engineered with precision-cut threads and exact specifications, ensuring a tight and secure fit every time."
- title: "Versatility"
subTitle: "Suitable for a wide range of applications, from construction to machinery, providing versatile fastening solutions."
specificationsLeft:
- title: "Material"
subTitle: "Made from premium-grade steel or alloy, offering exceptional strength and corrosion resistance."
- title: "Thread Design"
subTitle: "Precision-cut threads ensure optimal grip and reliability, even in high-stress environments."
- title: "Quantity"
subTitle: "Each set includes a sufficient quantity of hex bolts to tackle various projects and applications."
- title: "Sizes"
subTitle: "Available in a range of sizes to accommodate different project requirements, ensuring versatility and compatibility."
specificationsRight:
- title: "Finish"
subTitle: "Finished with a protective coating to enhance corrosion resistance and extend service life."
- title: "Load Capacity"
subTitle: "Designed to meet or exceed industry standards for load-bearing capacity, ensuring reliable performance under heavy loads."
- title: "Certifications"
subTitle: "Compliant with relevant industry standards and certifications, guaranteeing quality and reliability."
- title: "Applications"
subTitle: "Ideal for use in construction, machinery, automotive, and other heavy-duty applications that demand strong and reliable fastening."
blueprints:
first: "../../images/blueprint-1.avif"
second: "../../images/blueprint-2.avif"
slug: f303
---

View file

@ -0,0 +1,56 @@
---
main:
id: 1
title: "SF-TB T845"
subTitle: "Machine Screws"
content: |
Introducing the SF-TB T845 your go-to solution for precision fastening in machinery and equipment. This comprehensive set of machine screws is meticulously crafted to meet the stringent demands of industrial applications, ensuring secure and reliable fastening.
imgCard: "../../images/product-image-1.avif"
imgMain: "../../images/product-image-3-main.avif"
imgAlt: "Mockup boxes of machine screws set"
tabs:
- id: "tabs-with-card-item-1"
dataTab: "#tabs-with-card-1"
title: "Description"
- id: "tabs-with-card-item-2"
dataTab: "#tabs-with-card-2"
title: "Specifications"
- id: "tabs-with-card-item-3"
dataTab: "#tabs-with-card-3"
title: "Blueprints"
description:
title: "Precision Fastening Solutions"
subTitle: |
The SF-TB T845 Machine Screws offer unparalleled precision and reliability for industrial applications, ensuring seamless operation and longevity for your machinery and equipment.
btnTitle: "Contact sales to learn more"
btnURL: "#"
descriptionList:
- title: "Durability"
subTitle: "Crafted from high-quality materials, these machine screws are built to withstand the rigors of industrial environments."
- title: "Precision Engineering"
subTitle: "Engineered with precision-cut threads and exact specifications, ensuring a tight and secure fit for every application."
- title: "Versatility"
subTitle: "Suitable for a wide range of machinery and equipment, providing versatile fastening solutions for various industrial needs."
specificationsLeft:
- title: "Material Composition"
subTitle: "Constructed from premium-grade steel or alloy for exceptional strength and durability."
- title: "Surface Finish"
subTitle: "Finished with a protective coating to enhance corrosion resistance and extend service life."
- title: "Quantity Per Set"
subTitle: "Each set contains a comprehensive assortment of machine screws to meet diverse industrial requirements."
- title: "Size Range"
subTitle: "Available in various sizes and lengths to accommodate different machinery and equipment specifications."
specificationsRight:
- title: "Thread Specifications"
subTitle: "Precision-engineered threads ensure optimal grip and reliability, even in high-vibration environments."
- title: "Load Capacity"
subTitle: "Designed to meet or exceed industry standards for load-bearing capacity, ensuring safe and reliable operation."
- title: "Certifications"
subTitle: "Compliant with relevant industry standards and certifications, guaranteeing quality and reliability."
- title: "Applications"
subTitle: "Ideal for use in a wide range of industrial machinery, equipment, and assemblies that demand precise and secure fastening."
blueprints:
first: "../../images/blueprint-1.avif"
second: "../../images/blueprint-2.avif"
slug: t845
---

View file

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View file

@ -27,6 +27,7 @@ interface Props {
document.documentElement.classList.remove("dark");
}
</script>
<script is:inline src="/assets/vendor/preline/preline.js"></script>
</head>
<body
class="bg-neutral-200 selection:bg-yellow-400 selection:text-neutral-700 dark:bg-neutral-800"
@ -78,6 +79,5 @@ interface Props {
requestAnimationFrame(raf);
</script>
<script is:inline src="/assets/vendor/preline/preline.js"></script>
</body>
</html>

View file

@ -1,7 +1,7 @@
---
// Import section components
import MainLayout from "../layouts/MainLayout.astro";
import PrimaryCTA from "../components/ui/buttons/PrimaryCTA.astro";
import Btn404 from "../components/ui/buttons/Btn404.astro";
---
<MainLayout
@ -28,8 +28,13 @@ import PrimaryCTA from "../components/ui/buttons/PrimaryCTA.astro";
Don't let this hiccup slow you down. Let's get you back to building
your masterpiece.
</p>
<PrimaryCTA title="Go Back" url="#" />
<Btn404 title="Go Back" id="go-back" />
</div>
</div>
</section>
</MainLayout>
<script>
document.getElementById("go-back")?.addEventListener("click", () => {
history.back();
});
</script>

View file

@ -1,7 +1,7 @@
---
// Import section components
import MainLayout from "../layouts/MainLayout.astro";
import productData from "../content/products/b203.json";
import productData from "../content/products/b203.md";
import ProductTabBtn from "../components/ui/buttons/ProductTabBtn.astro";
import PrimaryCTA from "../components/ui/buttons/PrimaryCTA.astro";
@ -28,7 +28,9 @@ import { Image } from "astro:assets";
{productData.main.content}
</p>
</div>
<div class="flex flex-col sm:flex-row space-y-4 sm:space-y-0 items-center justify-between">
<div
class="flex flex-col items-center justify-between space-y-4 sm:flex-row sm:space-y-0"
>
<div id="fadeInUp">
<h1
class="block text-4xl font-bold tracking-tighter text-neutral-800 dark:text-neutral-200 sm:text-5xl md:text-6xl lg:text-7xl"
@ -50,9 +52,9 @@ import { Image } from "astro:assets";
</div>
</div>
<!-- Features -->
<div class="mx-auto max-w-[85rem] px-4 pt-10 sm:px-6 lg:px-8 lg:pt-14">
<!-- Tab Nav -->
<nav
class="mx-auto grid max-w-6xl gap-y-px sm:flex sm:gap-x-4 sm:gap-y-0"
aria-label="Tabs"
@ -69,7 +71,7 @@ import { Image } from "astro:assets";
))
}
</nav>
<!-- End Tab Nav -->
<div class="mt-12 md:mt-16">
<div id="tabs-with-card-1" role="tabpanel">
@ -93,15 +95,15 @@ import { Image } from "astro:assets";
/>
</p>
</div>
<!-- End Col -->
<div class="space-y-6 lg:space-y-10">
<!-- Icon Block -->
{
productData.descriptionList.map((list) => (
<div class="flex">
<div class="ms-5 sm:ms-8">
<h3 class="text-base font-semibold text-gray-800 dark:text-gray-200 sm:text-lg">
<div>
<h3 class="text-base font-bold text-gray-800 dark:text-gray-200 sm:text-lg">
{list.title}
</h3>
<p class="mt-1 text-gray-600 dark:text-gray-400">
@ -117,87 +119,49 @@ import { Image } from "astro:assets";
</div>
<div id="tabs-with-card-2" class="hidden" role="tabpanel">
<!-- Icon Blocks -->
<div 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">
<div class="grid grid-cols-2 place-content-evenly gap-x-8">
<div class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14">
<div class="grid grid-cols-1 md:grid-cols-2 w-full gap-x-16">
<div class="space-y-6 max-w-md">
{
productData.specificationsLeft.map((spec) => (
<div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
<h3 class="block font-bold text-neutral-800 dark:text-neutral-200">
{spec.title}
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
<p class="text-neutral-600 dark:text-neutral-400">
{spec.subTitle}
</p>
</div>
))
}
</div>
<div class="space-y-6 max-w-md mt-6 md:ml-auto md:mt-0">
{
productData.specificationsRight.map((spec) => (
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
<h3 class="block font-bold text-neutral-800 dark:text-neutral-200">
{spec.title}
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
<p class="text-neutral-600 dark:text-neutral-400">
{spec.subTitle}
</p>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
))
}
</div>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
</div>
<div>
<h3 class="block font-bold text-gray-800 dark:text-white">
Build your portfolio
</h3>
<p class="text-gray-600 dark:text-gray-400">
The simplest way to keep your portfolio always up-to-date.
</p>
</div>
</div>
</div>
</div>
</div>
<!-- End Grid -->
</div>
</div>
<!-- End Icon Blocks -->
<div id="tabs-with-card-3" class="hidden" role="tabpanel">
<div class="mx-auto flex w-full mb-20 md:mb-28">
<div class="mx-auto mb-20 flex w-full md:mb-28 2xl:w-4/5">
<div
class="relative left-12 top-12 z-10 -ml-12 overflow-hidden rounded-xl shadow-lg md:left-12 md:top-16 lg:ml-0"
>
@ -209,7 +173,7 @@ import { Image } from "astro:assets";
/>
</div>
<div class="relative right-12 overflow-hidden rounded-lg shadow-xl">
<div class="relative right-12 overflow-hidden rounded-xl shadow-xl">
<img
src="src/images/blueprint-2.avif"
loading="lazy"
@ -220,10 +184,7 @@ import { Image } from "astro:assets";
</div>
</div>
<script
is:inline
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"
></script>
<script is:inline src="/assets/vendor/gsap/gsap.min.js"></script>
<script>
window.addEventListener("load", (event) => {
if (window.gsap) {
@ -269,7 +230,7 @@ import { Image } from "astro:assets";
"dark:bg-white/[.05]",
);
const tabId = btn.getAttribute("data-tab-target");
const tabId = btn.getAttribute("data-target");
if (tabId) {
const contentElement = document.querySelector(tabId);
if (contentElement) {
@ -293,7 +254,7 @@ import { Image } from "astro:assets";
"dark:bg-white/[.05]",
);
const tabId = button.getAttribute("data-tab-target");
const tabId = button.getAttribute("data-target");
if (tabId) {
const contentElementToShow = document.querySelector(tabId);
if (contentElementToShow) {
@ -320,7 +281,7 @@ import { Image } from "astro:assets";
}
}
const tabButtons = document.querySelectorAll("[data-tab-target]");
const tabButtons = document.querySelectorAll("[data-target]");
if (tabButtons.length > 0) {
changeHeadingStyle(

View file

@ -7,10 +7,15 @@ import ImgWide from "../../components/ui/images/ImgWide.astro";
import FeaturesStats2 from "../../components/FeaturesStats2.astro";
import TestimonialsSection2 from "../../components/TestimonialsSection2.astro";
import product1 from "../../images/product-image-1.avif";
import product2 from "../../images/product-image-2.avif";
import product3 from "../../images/product-image-3.avif";
import product4 from "../../images/product-image-4.avif";
import { getCollection } from "astro:content";
import type { CollectionEntry } from "astro:content";
const product: CollectionEntry<"products">[] = (
await getCollection("products")
).sort(
(a: CollectionEntry<"products">, b: CollectionEntry<"products">) =>
a.data.main.id - b.data.main.id,
);
const title: string = "Products";
@ -18,7 +23,10 @@ const subTitle: string =
"Explore the durability and precision of ScrewFast tools, designed for both professionals and enthusiasts. Each of our products is crafted with precision and built to last, ensuring you have the right tool for every job.";
---
<MainLayout title="Products | 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.">
<MainLayout
title="Products | 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."
>
<div
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
@ -40,30 +48,16 @@ const subTitle: string =
</div>
<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 md:gap-6 xl:gap-8">
<ImgSmall
url="#"
title="Machine Screws"
src={product1}
alt="Mockup box of machine screws"
/>
<ImgWide
url="#"
title="Assorted Screw Set"
src={product2}
alt="Mockup box of assorted screw set"
/>
<ImgWide
url="#"
title="Tap Bolts and Nuts"
src={product3}
alt="Mockup box of tap bolts and nuts"
/>
<ImgSmall
url="#"
title="Hex Bolts"
src={product4}
alt="Mockup box of hex bolts"
/>
{
product.map((product, index) => {
const position = index % 4;
if (position === 0 || position === 3) {
return <ImgSmall product={product} />;
} else {
return <ImgWide product={product} />;
}
})
}
</div>
</div>

View file

@ -5,7 +5,7 @@
"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' https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.unsplash.com; connect-src 'self'; object-src 'none'; upgrade-insecure-requests; block-all-mixed-content"
"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: https://images.unsplash.com; connect-src 'self'; object-src 'none'; upgrade-insecure-requests; block-all-mixed-content"
},
{
"key": "Permissions-Policy",