diff --git a/jsconfig.json b/jsconfig.json index b8d6842..e71b002 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,7 +1,18 @@ { "compilerOptions": { + "baseUrl": ".", + "module": "commonjs", + "target": "es2020", "paths": { - "@/*": ["./src/*"] + "@comp/*": ["components/*"], + "@styles/*": ["styles/*"], + "@assets/*": ["assets/*"], + "@ctx/*": ["Contexts/*"], + "@img/*": ["assets/images/*"], + "@layout/*": ["layout/*"], + "@plugins/*": ["plugins/*"] } - } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.js", "**/*.jsx"], + "exclude": ["node_modules"] } diff --git a/package-lock.json b/package-lock.json index 20a87da..b05f02c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,11 @@ "name": "llc", "version": "0.1.0", "dependencies": { + "framer-motion": "^12.4.2", "next": "15.1.6", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "swiper": "^11.2.2" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -2608,6 +2610,32 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/framer-motion": { + "version": "12.4.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.4.2.tgz", + "integrity": "sha512-pW307cQKjDqEuO1flEoIFf6TkuJRfKr+c7qsHAJhDo4368N/5U8/7WU8J+xhd9+gjmOgJfgp+46evxRRFM39dA==", + "dependencies": { + "motion-dom": "^12.0.0", + "motion-utils": "^12.0.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3633,6 +3661,19 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/motion-dom": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.0.0.tgz", + "integrity": "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg==", + "dependencies": { + "motion-utils": "^12.0.0" + } + }, + "node_modules/motion-utils": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.0.0.tgz", + "integrity": "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA==" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4984,6 +5025,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swiper": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.2.tgz", + "integrity": "sha512-FmAN6zACpVUbd/1prO9xQ9gKo9cc6RE2UKU/z4oXtS8fNyX4sdOW/HHT/e444WucLJs0jeMId6WjdWM2Lrs8zA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tailwindcss": { "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", diff --git a/package.json b/package.json index 68b807f..720d37c 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,17 @@ "lint": "next lint" }, "dependencies": { + "framer-motion": "^12.4.2", + "next": "15.1.6", "react": "^19.0.0", "react-dom": "^19.0.0", - "next": "15.1.6" + "swiper": "^11.2.2" }, "devDependencies": { - "postcss": "^8", - "tailwindcss": "^3.4.1", + "@eslint/eslintrc": "^3", "eslint": "^9", "eslint-config-next": "15.1.6", - "@eslint/eslintrc": "^3" + "postcss": "^8", + "tailwindcss": "^3.4.1" } } diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/src/app/favicon.ico and /dev/null differ diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index 6b717ad..0000000 --- a/src/app/globals.css +++ /dev/null @@ -1,21 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/app/layout.js b/src/app/layout.js deleted file mode 100644 index 7bf337d..0000000 --- a/src/app/layout.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata = { - title: "Create Next App", - description: "Generated by create next app", -}; - -export default function RootLayout({ children }) { - return ( - - - {children} - - - ); -} diff --git a/src/app/layout.jsx b/src/app/layout.jsx new file mode 100644 index 0000000..fc33909 --- /dev/null +++ b/src/app/layout.jsx @@ -0,0 +1,9 @@ +import "../styles/globals.css"; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} diff --git a/src/app/page.js b/src/app/page.js deleted file mode 100644 index 61edd89..0000000 --- a/src/app/page.js +++ /dev/null @@ -1,101 +0,0 @@ -import Image from "next/image"; - -export default function Home() { - return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.js - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- -
- ); -} diff --git a/src/app/page.jsx b/src/app/page.jsx new file mode 100644 index 0000000..a04732f --- /dev/null +++ b/src/app/page.jsx @@ -0,0 +1,296 @@ +"use client"; + +import CardNormal from "src/components/Cards/CardNormal/page"; +import Navbar from "../components/NavBar"; +import { Swiper, SwiperSlide } from "swiper/react"; +import ban1 from "../assets/images/ban1.jpg"; +import ban2 from "../assets/images/ban2.png"; +import logo from "../assets/images/logo.png"; +import "swiper/css"; +import Image from "next/image"; + +export default function Home() { + const data = [ + { + id: 1, + persianName: "Hydrating Cream", + englishName: "Hydrating Cream", + description: + "A deeply moisturizing cream that keeps your skin hydrated all day long.", + cost: 250000, + costWithDiscount: 200000, + hasDiscount: true, + discountPercent: 20, + stock: 5, + mainImage: "4", + }, + { + id: 2, + persianName: "Hair Strengthening Shampoo", + englishName: "Hair Strengthening Shampoo", + description: + "A nourishing shampoo that strengthens hair roots and prevents hair fall.", + cost: 180000, + costWithDiscount: 150000, + hasDiscount: true, + discountPercent: 17, + stock: 2, + mainImage: "3", + }, + { + id: 3, + persianName: "Vitamin C Serum", + englishName: "Vitamin C Serum", + description: + "An antioxidant-rich serum that brightens skin and reduces signs of aging.", + cost: 300000, + costWithDiscount: 270000, + hasDiscount: true, + discountPercent: 10, + stock: 3, + mainImage: "1", + }, + { + id: 4, + persianName: "Charcoal Face Mask", + englishName: "Charcoal Face Mask", + description: + "A detoxifying mask that removes impurities and unclogs pores for a fresh look.", + cost: 220000, + costWithDiscount: 220000, + hasDiscount: false, + discountPercent: 0, + stock: 8, + mainImage: "4", + }, + { + id: 5, + persianName: "Body Lotion", + englishName: "Body Lotion", + description: + "A lightweight body lotion that nourishes and hydrates dry skin.", + cost: 210000, + costWithDiscount: 185000, + hasDiscount: true, + discountPercent: 12, + stock: 6, + mainImage: "2", + }, + { + id: 6, + persianName: "Aloe Vera Gel", + englishName: "Aloe Vera Gel", + description: + "A soothing gel enriched with aloe vera to calm irritated skin.", + cost: 160000, + costWithDiscount: 160000, + hasDiscount: false, + discountPercent: 0, + stock: 10, + mainImage: "3", + }, + { + id: 7, + persianName: "Sunscreen SPF 50", + englishName: "Sunscreen SPF 50", + description: + "A broad-spectrum sunscreen that protects against UV rays and prevents sunburn.", + cost: 280000, + costWithDiscount: 230000, + hasDiscount: true, + discountPercent: 18, + stock: 4, + mainImage: "1", + }, + { + id: 8, + persianName: "Face Cleanser", + englishName: "Face Cleanser", + description: + "A gentle face cleanser that removes dirt and oil without stripping moisture.", + cost: 190000, + costWithDiscount: 170000, + hasDiscount: true, + discountPercent: 10, + stock: 7, + mainImage: "2", + }, + { + id: 9, + persianName: "Moisturizing Cream", + englishName: "Moisturizing Cream", + description: + "A rich cream that provides deep hydration for soft and smooth skin.", + cost: 260000, + costWithDiscount: 260000, + hasDiscount: false, + discountPercent: 0, + stock: 9, + mainImage: "4", + }, + { + id: 10, + persianName: "Eye Serum", + englishName: "Eye Serum", + description: + "A lightweight eye serum that reduces puffiness and dark circles.", + cost: 350000, + costWithDiscount: 310000, + hasDiscount: true, + discountPercent: 12, + stock: 5, + mainImage: "3", + }, + ]; + const slides = [ + { + id: 1, + image: "/images/slide1.jpg", + alt: "Slide 1", + title: "Discover the Best Products", + description: + "Find high-quality beauty and skincare items at unbeatable prices.", + }, + { + id: 2, + image: "/images/slide2.jpg", + alt: "Slide 2", + title: "Exclusive Discounts", + description: "Enjoy special deals and save big on your favorite brands.", + }, + { + id: 3, + image: "/images/slide3.jpg", + alt: "Slide 3", + title: "Fast & Secure Delivery", + description: + "Get your products delivered quickly and safely to your doorstep.", + }, + ]; + + return ( +
+ {" "} + + {/*
+
+
*/} +
+ + +
+ +
+
+ + {" "} +
+ +
+
+
+
+
+
+
+
+

+ ADVANCED HORIZON SERVICES LLC Products{" "} +

+

+ Lorem ipsum dolor sit amet +

+ +

+ Lorem ipsum dolor sit amet consectetur, adipisicing elit. + Voluptates quas, exercitationem expedita libero hic + necessitatibus et sed aliquam consequatur repellendus dolore, + molestiae earum culpa fuga nobis odit, eligendi eius dolorem! +
+
+ Lorem ipsum dolor sit amet consectetur, adipisicing elit. + Voluptates quas, exercitationem expedita libero hic + necessitatibus et sed aliquam consequatur repellendus dolore, + molestiae earum culpa fuga nobis odit, eligendi eius dolorem! + Lorem ipsum dolor sit amet consectetur, adipisicing elit. + Voluptates quas, exercitationem expedita libero hic + necessitatibus et sed aliquam consequatur repellendus dolore, + molestiae earum culpa fuga nobis odit, eligendi eius dolorem! +

+ + +
+ +
+ +
+
+
+
+
+
+
+
+

+ Lorem ipsum dolor{" "} +

+

+ Test For Fake Data +

+

500

+
+ +
+

+ Lorem ipsum dolor{" "} +

+

+ Test In Landing Page +

+ +

+ 5,523,222 +

+
+ +
+

+ Lorem ipsum dolor{" "} +

+

+ Test For Fake +

+

+ +225{" "} +

+
+
+
+
+
+
+
+

+ ADVANCED HORIZON SERVICES LLC Products{" "} +

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. + Corporis,{" "} +

+
+ +
+ {data?.map((e, index) => ( +
+ +
+ ))} +
+
+
+
+ ); +} diff --git a/src/assets/images/ban1.jpg b/src/assets/images/ban1.jpg new file mode 100644 index 0000000..4fbda00 Binary files /dev/null and b/src/assets/images/ban1.jpg differ diff --git a/src/assets/images/ban2.png b/src/assets/images/ban2.png new file mode 100644 index 0000000..96eb33b Binary files /dev/null and b/src/assets/images/ban2.png differ diff --git a/src/assets/images/ban3.png b/src/assets/images/ban3.png new file mode 100644 index 0000000..ed7ba46 Binary files /dev/null and b/src/assets/images/ban3.png differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000..391dc96 Binary files /dev/null and b/src/assets/images/logo.png differ diff --git a/src/assets/images/product/1.png b/src/assets/images/product/1.png new file mode 100644 index 0000000..8f48b03 Binary files /dev/null and b/src/assets/images/product/1.png differ diff --git a/src/assets/images/product/2.png b/src/assets/images/product/2.png new file mode 100644 index 0000000..5d1ab9f Binary files /dev/null and b/src/assets/images/product/2.png differ diff --git a/src/assets/images/product/3.png b/src/assets/images/product/3.png new file mode 100644 index 0000000..7770b94 Binary files /dev/null and b/src/assets/images/product/3.png differ diff --git a/src/assets/images/product/4.png b/src/assets/images/product/4.png new file mode 100644 index 0000000..44bb98a Binary files /dev/null and b/src/assets/images/product/4.png differ diff --git a/src/assets/images/team.jpg b/src/assets/images/team.jpg new file mode 100644 index 0000000..8e97248 Binary files /dev/null and b/src/assets/images/team.jpg differ diff --git a/src/components/Cards/CardNormal/page.jsx b/src/components/Cards/CardNormal/page.jsx new file mode 100644 index 0000000..0709ed5 --- /dev/null +++ b/src/components/Cards/CardNormal/page.jsx @@ -0,0 +1,93 @@ +"use client"; +import React, { useContext } from "react"; +import logo from "../../../assets/images/logo.png"; + +import Image from "next/image"; +import test1 from "../../../assets/images/product/1.png"; +import test2 from "../../../assets/images/product/2.png"; +import test3 from "../../../assets/images/product/3.png"; +import test4 from "../../../assets/images/product/4.png"; +import Link from "next/link"; + +const CardNormal = ({ data, priority }) => { + return ( + <> + {" "} + <> + +
+ {data.hasDiscount && ( +
+
+

+ {data.discountPercent} + % +

+
+
+ )} + +
+ {!!data.mainImage ? ( + {`${data.persianName} + ) : ( +
+ وسمه +
+ )} +
+
+

+ {data.englishName} +

+ +

+ {data.description} +

+
+
+ + +
+
+
+
+

call

+
+ +
+

see detail

+
+
+
+
+ + ); +}; + +export default CardNormal; diff --git a/src/components/NavBar/index.jsx b/src/components/NavBar/index.jsx new file mode 100644 index 0000000..2b5bb5b --- /dev/null +++ b/src/components/NavBar/index.jsx @@ -0,0 +1,466 @@ +"use client"; + +// import { useSubscriber } from "@ctx/SubscriberContext"; + +import Image from "next/image"; +import Link from "next/link"; +import { useContext, useEffect, useRef, useState } from "react"; + +import { motion } from "framer-motion"; + +import { useRouter } from "next/navigation"; + +import logo from "../../assets/images/logo.png"; + +const Navbar = ({ theme }) => { + const router = useRouter(); + + const NavBarData = [ + { + id: 1, + name: "Electronics", + children: [ + { + id: 101, + name: "Laptops", + }, + { + id: 102, + name: "Smartphones", + }, + { + id: 103, + name: "Cameras", + }, + ], + }, + { + id: 2, + name: "Fashion", + children: [ + { + id: 201, + name: "Men's Clothing", + }, + { + id: 202, + name: "Women's Clothing", + }, + { + id: 203, + name: "Accessories", + }, + ], + }, + { + id: 3, + name: "Home & Kitchen", + children: [ + { + id: 301, + name: "Furniture", + }, + { + id: 302, + name: "Decor", + }, + { + id: 303, + name: "Kitchen Appliances", + }, + ], + }, + { + id: 4, + name: "Sports", + children: [], + }, + ]; + + const [closeNavbar, setClosNavbar] = useState(false); + const [activeStepNavbar, setActiveStepNavbar] = useState(null); + + const [isScrolled, setIsScrolled] = useState(false); + // const [hoverItemNavbar, setHoverItemNavbar] = useState(-1); + + const [responsiveNavBarItemStep, setResponsiveNavBarItemStep] = + useState(false); + const ref = useRef(null); + + const handleResetFramer = () => { + setRestFramer(false); + setTimeout(() => { + setRestFramer(true); + }, 100); + }; + + const toLeft = { + visible: (custom) => ({ + opacity: ["0", "1"], + // y: ["-30%", "0%"], + transition: { delay: custom * 0.06 }, + }), + }; + + useEffect(() => { + const handleScroll = () => { + const scrollTop = window.scrollY; + setIsScrolled(scrollTop > 200); + }; + + window.addEventListener("scroll", handleScroll); + + return () => { + window.removeEventListener("scroll", handleScroll); + }; + }, []); + + return ( + <> + {/*
+

salam

+
*/} +
+ +
+ + {/* reponsive navbar */} + {/* responsive part */} + {/* responsive part */} + {/* responsive part */} + {/* responsive part */} + {/* responsive part */} + +
+
+ {/* */} +
+
+ llc +
+
+ {/* */} +
setClosNavbar(true)} + > + + + +
+
+
+ {closeNavbar && ( +
+
+
+ )} + +
+
+
+
setClosNavbar(false)} + > + + + +
+
+
+
+
+
+ {/* */} +
+ llc +
+ + {/* */} + +
+
+
+ +
+
+ {NavBarData.map((e, index) => ( + <> + + {/* */} + <> +
{ + if (e.children.length > 0) { + setResponsiveNavBarItemStep(index); + + setActiveStepNavbar(e.id); + } + }} + > + + {e.name} + + {e.children.length > 0 ? ( +
+ + + +
+ ) : ( + "" + )} +
+
+
+ + {/* {" "} */} +
+ + {responsiveNavBarItemStep === index && + e.children.length > 0 && + e.id == activeStepNavbar && ( +
+
+ {e.children.map((s, index) => ( + // +
+

{s.name}

+
+ // + ))} +
+
+ )} + + ))} +
+
+
+
+
+
+ + ); +}; + +export default Navbar; diff --git a/src/styles/globals.css b/src/styles/globals.css new file mode 100644 index 0000000..9547371 --- /dev/null +++ b/src/styles/globals.css @@ -0,0 +1,80 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer components { + .btn { + @apply py-2 px-4 rounded-xl transition-all shadow-lg border-2; + } + + .btn-primary { + @apply bg-primary-900 text-white; + } + .btn-primary:hover { + @apply bg-primary-700; + } + + .btn-outline-primary { + @apply border border-primary-900 text-primary-900 p-2; + } + .btn-outline-primary:hover { + @apply bg-primary-700 text-white; + } + + .btn-secondary { + @apply bg-secondary-900 text-white; + } + + .btn-light { + @apply bg-gray-100 text-black; + } + .btn-light:hover { + @apply bg-gray-300 text-black; + } + + .btn-outline-light { + @apply border border-gray-100 text-white; + } + .btn-outline-light:hover { + @apply bg-gray-100 text-black; + } + + .btn-secondary:hover { + @apply bg-secondary-700; + } + + .btn-info { + @apply bg-info-100 text-white; + } + .btn-info:hover { + @apply bg-info-200; + } + + .form-control { + @apply !appearance-none !border-[2px] !bg-white !border-gray-300 !rounded-lg !w-full !py-3 px-3 !text-gray-700 !leading-tight focus:!border-[2px] focus:!border-red-600 focus:!outline-none; + } +} + +.tr2 { + transition: 2s; +} + +.tr03 { + transition: 0.3s all; +} + +.rtl { + direction: rtl; +} + +.ltr { + direction: ltr; +} + +.bg-couner-data-landing { + background: linear-gradient(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.85)), + url(../assets/images/team.jpg); + background-position: bottom; + background-size: cover; + background-repeat: no-repeat; +} diff --git a/src/utils/Chapar/index.jsx b/src/utils/Chapar/index.jsx new file mode 100644 index 0000000..e60c893 --- /dev/null +++ b/src/utils/Chapar/index.jsx @@ -0,0 +1,45 @@ +import axios from "axios"; + +export const getToken = () => { + return localStorage.getItem("token"); +}; + +const Chapar = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL, + timeout: 100000, + headers: { + "Content-type": "application/json", + "Access-Control-Allow-Origin": "*", + }, +}); + +// Request interceptor to conditionally add token to headers +Chapar.interceptors.request.use( + (config) => { + const token = getToken(); + if (token && !config.isPublic) { + config.headers.Authorization = "Bearer" + " " + token; + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +// Response interceptor to handle responses +// Chapar.interceptors.response.use( +// (response) => { +// return response.data; +// }, +// (error) => { +// const status = error?.response?.status; +// if (status === 401) { +// localStorage.removeItem("token"); +// window.location.href = "/login"; +// } +// return Promise.reject({ error, status }); +// } +// ); + +export default Chapar; diff --git a/tailwind.config.mjs b/tailwind.config.mjs index d1a9803..67258cf 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -8,8 +8,80 @@ export default { theme: { extend: { colors: { - background: "var(--background)", - foreground: "var(--foreground)", + backgroundPrimary: { + 100: "#FFFBE6", + }, + primary: { + 50: "#fff5f5", + 100: "#fce8e8", + 200: "#f6caca", + 300: "#eaa9a9", + 400: "#e18c8c", + 500: "#cc7575", + 600: "#b06060", + 700: "#914e4e", + 800: "#733d3d", + 900: "#5a2f2f", + 950: "#3a1d1d", + }, + secondary: { + 50: "#f6f6f6", + 100: "#eaeaea", + 200: "#d5d5d5", + 300: "#b8b8b8", + 400: "#999999", + 500: "#7f7f7f", + 600: "#666666", + 700: "#4d4d4d", + 800: "#333333", + 900: "#1f1f1f", + 950: "#0f0f0f", + }, + textMain: { + 100: "#444444", + }, + mainDisable: { + 100: "#888888", + }, + info: { + 100: "#2B91EF", + 200: "#0061bd", + }, + danger: { + 100: "#FF2C2C", + }, + body: { + 100: "#EEEEEE", + }, + }, + }, + + screens: { + xs: "290px", + sm: "640px", + // => @media (min-width: 640px) { ... } + + md: "768px", + // => @media (min-width: 768px) { ... } + + lg: "1024px", + // => @media (min-width: 1024px) { ... } + + xl: "1440px", + // => @media (min-width: 1280px) { ... } + + "2xl": "1536px", + // => @media (min-width: 1536px) { ... } + }, + + animation: { + "infinite-scroll": "infinite-scroll 200s linear infinite", + }, + + keyframes: { + "infinite-scroll": { + from: { transform: "translateX(0)" }, + to: { transform: "translateX(-100%)" }, }, }, },