mirror of
https://github.com/FranP-code/spooky-spotify-showcase.git
synced 2025-10-13 00:02:36 +00:00
Add Swiper component and AlbumImage for enhanced album display
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"spotify-web-api-node": "^5.0.2",
|
"spotify-web-api-node": "^5.0.2",
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
|
"swiper": "^11.1.14",
|
||||||
"zod": "^3.23.3"
|
"zod": "^3.23.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
@@ -56,6 +56,9 @@ importers:
|
|||||||
superjson:
|
superjson:
|
||||||
specifier: ^2.2.1
|
specifier: ^2.2.1
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
|
swiper:
|
||||||
|
specifier: ^11.1.14
|
||||||
|
version: 11.1.14
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.23.3
|
specifier: ^3.23.3
|
||||||
version: 3.23.8
|
version: 3.23.8
|
||||||
@@ -1731,6 +1734,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
swiper@11.1.14:
|
||||||
|
resolution: {integrity: sha512-VbQLQXC04io6AoAjIUWuZwW4MSYozkcP9KjLdrsG/00Q/yiwvhz9RQyt0nHXV10hi9NVnDNy1/wv7Dzq1lkOCQ==}
|
||||||
|
engines: {node: '>= 4.7.0'}
|
||||||
|
|
||||||
tailwindcss@3.4.13:
|
tailwindcss@3.4.13:
|
||||||
resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==}
|
resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -2565,8 +2572,8 @@ snapshots:
|
|||||||
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
|
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
|
||||||
eslint-plugin-react: 7.37.1(eslint@8.57.1)
|
eslint-plugin-react: 7.37.1(eslint@8.57.1)
|
||||||
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
|
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
|
||||||
@@ -2585,37 +2592,37 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
'@nolyfill/is-core-module': 1.0.39
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
enhanced-resolve: 5.17.1
|
enhanced-resolve: 5.17.1
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.8.1
|
get-tsconfig: 4.8.1
|
||||||
is-bun-module: 1.2.1
|
is-bun-module: 1.2.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@typescript-eslint/parser'
|
- '@typescript-eslint/parser'
|
||||||
- eslint-import-resolver-node
|
- eslint-import-resolver-node
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.8
|
array-includes: 3.1.8
|
||||||
@@ -2626,7 +2633,7 @@ snapshots:
|
|||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
is-core-module: 2.15.1
|
is-core-module: 2.15.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -3635,6 +3642,8 @@ snapshots:
|
|||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
|
swiper@11.1.14: {}
|
||||||
|
|
||||||
tailwindcss@3.4.13:
|
tailwindcss@3.4.13:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
|
|||||||
98
src/app/_components/album-image.tsx
Normal file
98
src/app/_components/album-image.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tilt from "react-parallax-tilt";
|
||||||
|
|
||||||
|
interface AlbumImageProps {
|
||||||
|
showSpookyImage: boolean;
|
||||||
|
imageSource: string;
|
||||||
|
spookyImageSource: string | null;
|
||||||
|
album: { name: string };
|
||||||
|
generateSpookyImageData: string | null;
|
||||||
|
lastSpookyImageLoaded: number;
|
||||||
|
place: number;
|
||||||
|
spookyImageLoaded: boolean;
|
||||||
|
onImageLoad: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AlbumImage({
|
||||||
|
showSpookyImage,
|
||||||
|
imageSource,
|
||||||
|
spookyImageSource,
|
||||||
|
album,
|
||||||
|
generateSpookyImageData,
|
||||||
|
lastSpookyImageLoaded,
|
||||||
|
place,
|
||||||
|
spookyImageLoaded,
|
||||||
|
onImageLoad,
|
||||||
|
}: AlbumImageProps) {
|
||||||
|
return (
|
||||||
|
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
||||||
|
<img
|
||||||
|
className="h-36 w-36 cursor-pointer rounded"
|
||||||
|
style={{
|
||||||
|
display: showSpookyImage ? "none" : "block",
|
||||||
|
}}
|
||||||
|
src={imageSource}
|
||||||
|
alt={album.name}
|
||||||
|
/>
|
||||||
|
{spookyImageSource &&
|
||||||
|
(generateSpookyImageData
|
||||||
|
? lastSpookyImageLoaded >= place ||
|
||||||
|
lastSpookyImageLoaded + 1 === place
|
||||||
|
: true) && (
|
||||||
|
<img
|
||||||
|
className="h-36 w-36 cursor-pointer rounded"
|
||||||
|
style={{
|
||||||
|
display: showSpookyImage && spookyImageLoaded ? "block" : "none",
|
||||||
|
}}
|
||||||
|
src={spookyImageSource}
|
||||||
|
alt={album.name}
|
||||||
|
onLoad={onImageLoad}
|
||||||
|
onError={() => {
|
||||||
|
onImageLoad();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showSpookyImage && !spookyImageLoaded && (
|
||||||
|
<div className="flex h-36 w-36 items-center justify-center rounded bg-slate-300 bg-opacity-10">
|
||||||
|
<div>
|
||||||
|
{(() => {
|
||||||
|
if (generateSpookyImageData) {
|
||||||
|
if (lastSpookyImageLoaded < place - 1) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<l-pulsar
|
||||||
|
size="100"
|
||||||
|
speed="1.75"
|
||||||
|
color="white"
|
||||||
|
></l-pulsar>{" "}
|
||||||
|
<p className="text-center">On queue...</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<l-quantum
|
||||||
|
size="100"
|
||||||
|
speed="1.75"
|
||||||
|
color="white"
|
||||||
|
></l-quantum>
|
||||||
|
<p className="text-center">Generating...</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<l-ring-2 size="100" speed="1.75" color="white"></l-ring-2>
|
||||||
|
<p className="text-center">Getting image...</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Tilt>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AlbumImage;
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { use, useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Tilt from "react-parallax-tilt";
|
|
||||||
import { TrackByAlbum } from "./spotify-data";
|
import { TrackByAlbum } from "./spotify-data";
|
||||||
import { api } from "@/trpc/react";
|
import { api } from "@/trpc/react";
|
||||||
import { quantum } from "ldrs";
|
import { quantum } from "ldrs";
|
||||||
import { ring2 } from "ldrs";
|
import { ring2 } from "ldrs";
|
||||||
import { pulsar } from "ldrs";
|
import { pulsar } from "ldrs";
|
||||||
|
import Swiper from "./swiper";
|
||||||
|
import { SwiperSlide } from "swiper/react";
|
||||||
|
import AlbumImage from "./album-image";
|
||||||
|
|
||||||
pulsar.register();
|
pulsar.register();
|
||||||
ring2.register();
|
ring2.register();
|
||||||
@@ -104,80 +106,36 @@ export default function AlbumShowcase({
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer *:select-none"
|
||||||
>
|
>
|
||||||
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
<Swiper>
|
||||||
<img
|
<SwiperSlide>
|
||||||
className="h-36 w-36 cursor-pointer rounded"
|
<AlbumImage
|
||||||
style={{
|
showSpookyImage={showSpookyImage}
|
||||||
display: showSpookyImage ? "none" : "block",
|
imageSource={imageSource}
|
||||||
}}
|
spookyImageSource={spookyImageSource}
|
||||||
src={imageSource}
|
album={album}
|
||||||
alt={album.name}
|
generateSpookyImageData={generateSpookyImage.data as string}
|
||||||
/>
|
lastSpookyImageLoaded={lastSpookyImageLoaded}
|
||||||
{spookyImageSource &&
|
place={place}
|
||||||
(generateSpookyImage.data
|
spookyImageLoaded={spookyImageLoaded}
|
||||||
? lastSpookyImageLoaded >= place ||
|
onImageLoad={onImageLoad}
|
||||||
lastSpookyImageLoaded + 1 === place
|
/>
|
||||||
: true) && (
|
</SwiperSlide>
|
||||||
<img
|
<SwiperSlide>
|
||||||
className="h-36 w-36 cursor-pointer rounded"
|
<AlbumImage
|
||||||
style={{
|
showSpookyImage={showSpookyImage}
|
||||||
display:
|
imageSource={imageSource}
|
||||||
showSpookyImage && spookyImageLoaded ? "block" : "none",
|
spookyImageSource={spookyImageSource}
|
||||||
}}
|
album={album}
|
||||||
src={spookyImageSource}
|
generateSpookyImageData={generateSpookyImage.data as string}
|
||||||
alt={album.name}
|
lastSpookyImageLoaded={lastSpookyImageLoaded}
|
||||||
onLoad={onImageLoad}
|
place={place}
|
||||||
onError={() => {
|
spookyImageLoaded={spookyImageLoaded}
|
||||||
onImageLoad();
|
onImageLoad={onImageLoad}
|
||||||
}}
|
/>
|
||||||
/>
|
</SwiperSlide>
|
||||||
)}
|
</Swiper>
|
||||||
{showSpookyImage && !spookyImageLoaded && (
|
|
||||||
<div className="flex h-36 w-36 items-center justify-center rounded bg-slate-300 bg-opacity-10">
|
|
||||||
<div>
|
|
||||||
{(() => {
|
|
||||||
if (generateSpookyImage.data) {
|
|
||||||
if (lastSpookyImageLoaded < place - 1) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<l-pulsar
|
|
||||||
size="100"
|
|
||||||
speed="1.75"
|
|
||||||
color="white"
|
|
||||||
></l-pulsar>{" "}
|
|
||||||
<p className="text-center">On queue...</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<l-quantum
|
|
||||||
size="100"
|
|
||||||
speed="1.75"
|
|
||||||
color="white"
|
|
||||||
></l-quantum>
|
|
||||||
<p className="text-center">Generating...</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<l-ring-2
|
|
||||||
size="100"
|
|
||||||
speed="1.75"
|
|
||||||
color="white"
|
|
||||||
></l-ring-2>
|
|
||||||
<p className="text-center">Getting image...</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Tilt>
|
|
||||||
</div>
|
</div>
|
||||||
<section className="flex h-36 flex-grow flex-col">
|
<section className="flex h-36 flex-grow flex-col">
|
||||||
<h4 className="mb-2 text-lg font-semibold leading-none">
|
<h4 className="mb-2 text-lg font-semibold leading-none">
|
||||||
|
|||||||
9
src/app/_components/swiper.css
Normal file
9
src/app/_components/swiper.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.swiper-slide {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 18px;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
26
src/app/_components/swiper.tsx
Normal file
26
src/app/_components/swiper.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"use client";
|
||||||
|
import React, { useRef, useState } from "react";
|
||||||
|
import { Swiper as SwiperReact, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/effect-cards";
|
||||||
|
import "./swiper.css";
|
||||||
|
import { EffectCards } from "swiper/modules";
|
||||||
|
|
||||||
|
export function Swiper({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<SwiperReact
|
||||||
|
style={{
|
||||||
|
width: "144px",
|
||||||
|
height: "144px",
|
||||||
|
}}
|
||||||
|
effect={"cards"}
|
||||||
|
grabCursor={true}
|
||||||
|
modules={[EffectCards]}
|
||||||
|
className="mySwiper"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SwiperReact>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Swiper;
|
||||||
Reference in New Issue
Block a user