diff --git a/astro.config.mjs b/astro.config.mjs
index 5279626..124cd35 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -2,22 +2,40 @@ import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import { loadEnv } from "vite";
import { ALL_PRODUCTS } from './src/data/products';
-const { SITE_URL } = loadEnv(process.env.NODE_ENV, process.cwd(), "");
-
+import react from "@astrojs/react";
+const {
+ SITE_URL
+} = loadEnv(process.env.NODE_ENV, process.cwd(), "");
function generateRedirectsForAmazonProductIds() {
- let redirects = {};
- for (let p = 0; p < ALL_PRODUCTS.length; p++) {
- let product = ALL_PRODUCTS[p];
- if (product.amazonProductId && product.slug !== product.amazonProductId) {
- redirects[`/${product.amazonProductId}`] = `/${product.slug}`;
- }
+ let redirects = {};
+ for (let p = 0; p < ALL_PRODUCTS.length; p++) {
+ let product = ALL_PRODUCTS[p];
+ if (product.amazonProductId && product.slug !== product.amazonProductId) {
+ redirects[`/${product.amazonProductId}`] = `/${product.slug}`;
}
- return redirects;
+ }
+ return redirects;
}
+
// https://astro.build/config
export default defineConfig({
- site: SITE_URL||'http://localhost',
- integrations: [sitemap()],
- redirects: generateRedirectsForAmazonProductIds(),
-});
+ site: SITE_URL || 'http://localhost',
+ integrations: [sitemap(), react()],
+ redirects: generateRedirectsForAmazonProductIds()
+ // vite: {
+ // resolve: {
+ // alias: [
+ // { find: /^swiper\/(.+)/, replacement: 'swiper/$1 '},
+ // ],
+ // },
+ // },
+ // experimental: {
+ // resolveId: (id) => {
+ // if (id === 'swiper') {
+ // return './node_modules/swiper/swiper.esm.js';
+ // }
+ // return null;
+ // }
+ // }
+});
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 61b17be..87f2863 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,10 @@
"version": "0.0.1",
"dependencies": {
"@astrojs/check": "^0.8.1",
+ "@astrojs/react": "^3.6.0",
"@astrojs/sitemap": "^3.1.6",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
"astro": "^4.11.5",
"bootstrap": "^5.3.3",
"cheerio": "*",
@@ -18,7 +21,10 @@
"dotenv-expand": "^11.0.6",
"markdown-it": "^14.0.0",
"markdown-it-attrs": "^4.1.6",
- "playwright": "*"
+ "playwright": "*",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "swiper": "^11.1.4"
},
"devDependencies": {
"@apify/tsconfig": "^0.1.0",
@@ -220,6 +226,24 @@
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
}
},
+ "node_modules/@astrojs/react": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.6.0.tgz",
+ "integrity": "sha512-YGLxy5jCU9xKG/HAvYsWMcvrQVIhqVe0Sda3Z5UtP32rfXeG6B9J1xQvnx+kRSFTpIrj+7AwPSDSehLbCHJ56w==",
+ "dependencies": {
+ "@vitejs/plugin-react": "^4.3.1",
+ "ultrahtml": "^1.5.3"
+ },
+ "engines": {
+ "node": "^18.17.1 || ^20.3.0 || >=21.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.50 || ^18.0.21",
+ "@types/react-dom": "^17.0.17 || ^18.0.6",
+ "react": "^17.0.2 || ^18.0.0 || ^19.0.0-beta",
+ "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-beta"
+ }
+ },
"node_modules/@astrojs/sitemap": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.1.6.tgz",
@@ -549,6 +573,34 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz",
+ "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz",
+ "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.24.7",
"license": "MIT",
@@ -1736,6 +1788,28 @@
"undici-types": "~5.26.4"
}
},
+ "node_modules/@types/prop-types": {
+ "version": "15.7.12",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
+ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
+ },
+ "node_modules/@types/react": {
+ "version": "18.3.3",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
+ "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.3.0",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
+ "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/sax": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
@@ -1765,6 +1839,24 @@
"version": "1.2.0",
"license": "ISC"
},
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz",
+ "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==",
+ "dependencies": {
+ "@babel/core": "^7.24.5",
+ "@babel/plugin-transform-react-jsx-self": "^7.24.5",
+ "@babel/plugin-transform-react-jsx-source": "^7.24.1",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.14.2"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0"
+ }
+ },
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.0.tgz",
@@ -2876,6 +2968,11 @@
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
"license": "MIT"
},
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
"node_modules/csv-stringify": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.5.0.tgz",
@@ -4858,6 +4955,17 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
"node_modules/lowercase-keys": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
@@ -6509,6 +6617,37 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
+ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -7003,6 +7142,14 @@
"node": ">=v12.22.7"
}
},
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
"node_modules/section-matter": {
"version": "1.0.0",
"license": "MIT",
@@ -7359,6 +7506,24 @@
"node": ">=4"
}
},
+ "node_modules/swiper": {
+ "version": "11.1.4",
+ "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.4.tgz",
+ "integrity": "sha512-1n7kbYJB2dFEpUHRFszq7gys/ofIBrMNibwTiMvPHwneKND/t9kImnHt6CfGPScMHgI+dWMbGTycCKGMoOO1KA==",
+ "funding": [
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/swiperjs"
+ },
+ {
+ "type": "open_collective",
+ "url": "http://opencollective.com/swiper"
+ }
+ ],
+ "engines": {
+ "node": ">= 4.7.0"
+ }
+ },
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -7600,6 +7765,11 @@
"integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==",
"license": "ISC"
},
+ "node_modules/ultrahtml": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz",
+ "integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg=="
+ },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
diff --git a/package.json b/package.json
index 7bd1220..19b5470 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,10 @@
},
"dependencies": {
"@astrojs/check": "^0.8.1",
+ "@astrojs/react": "^3.6.0",
"@astrojs/sitemap": "^3.1.6",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
"astro": "^4.11.5",
"bootstrap": "^5.3.3",
"cheerio": "*",
@@ -20,7 +23,10 @@
"dotenv-expand": "^11.0.6",
"markdown-it": "^14.0.0",
"markdown-it-attrs": "^4.1.6",
- "playwright": "*"
+ "playwright": "*",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "swiper": "^11.1.4"
},
"devDependencies": {
"@apify/tsconfig": "^0.1.0",
diff --git a/src/components/CarouselSwiper.tsx b/src/components/CarouselSwiper.tsx
new file mode 100644
index 0000000..b5a5574
--- /dev/null
+++ b/src/components/CarouselSwiper.tsx
@@ -0,0 +1,60 @@
+import { Swiper, SwiperSlide } from 'swiper/react';
+import { A11y as SwiperA11y, Navigation as SwiperNavigation, Pagination as SwiperPagination, Scrollbar as SwiperScrollbar } from 'swiper/modules';
+import 'swiper/swiper-bundle.css';
+import { type Props, type Image } from './CarouselSwiperProps';
+import './carousel-swiper.css';
+
+export default function CarouselSwiper(props: Props) {
+ return (
+
+ {props.images?.map((image) => (
+
+ ))}
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/CarouselSwiperProps.ts b/src/components/CarouselSwiperProps.ts
new file mode 100644
index 0000000..573a921
--- /dev/null
+++ b/src/components/CarouselSwiperProps.ts
@@ -0,0 +1,10 @@
+export interface Image {
+ src: string;
+ alt?: string;
+ title?: string;
+}
+
+export interface Props {
+ images: Image[],
+ showDots?: boolean,
+}
\ No newline at end of file
diff --git a/src/components/ImageCarousel.astro b/src/components/ImageCarousel.astro
index d0dad80..14bc981 100644
--- a/src/components/ImageCarousel.astro
+++ b/src/components/ImageCarousel.astro
@@ -1,24 +1,40 @@
---
import type { Brand } from '../data/brands/brand';
-
-export interface Image {
- src: string;
- alt?: string;
- title?: string;
-}
-
-interface Props {
- images: Image[];
- showDots?: boolean;
-}
+// import { Swiper, SwiperSlide } from 'swiper/react';
+// import { Navigation as SwiperNavigation, Pagination as SwiperPagination } from 'swiper/modules';
+import CarouselSwiper from './CarouselSwiper';
+// import 'swiper/swiper-bundle.css';
+// SwiperCore.use([SwiperNavigation, SwiperPagination])
+import { type Props, type Image } from './CarouselSwiperProps';
const { images, showDots } = Astro.props;
let index = 1;
---
-
-
-
+
+
+
+
+
-