From 3953e550b15b1381b59e10077ac2451ad79b0212 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Wed, 11 Jun 2025 11:54:28 +0300 Subject: [PATCH] feat: multi-subs working --- src/app/page.tsx | 73 ++++++++++++++++++---------- src/components/Block.tsx | 12 +++-- src/components/Carousel/Carousel.tsx | 31 +++++++----- 3 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 09cc6a6..e9c8394 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,8 +7,9 @@ import { cn } from "@/utils/cn"; import { useRawInitData } from "@telegram-apps/sdk-react"; import { ChevronLeft, ChevronRight, ClipboardList } from "lucide-react"; import { QRCodeSVG } from "qrcode.react"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { getUrl } from "./actions"; +import { EmblaCarouselType } from "embla-carousel"; interface ProxySubData { url: string; @@ -22,16 +23,23 @@ export default function Home() { const [chosen, setChosen] = useState(0); const [isLoading, setIsLoading] = useState(true); const [notFound, setNotFound] = useState(false); + const carouselApi = useRef(null); const initData = useRawInitData(); + const [isCopied, setIsCopied] = useState([]); + + useEffect(() => { + if (!proxyData.length) return; + setIsCopied(Array(proxyData.length).fill(false)); + }, [proxyData]); + const onCopyClick = async (url: string) => { if (!proxyData.length) return; await navigator.clipboard.writeText(url); - setIsCopied(true); + setIsCopied((prev) => prev.map((_, i) => i === chosen)); setTimeout(() => { - setIsCopied(false); + setIsCopied((prev) => prev.map(() => false)); }, 2000); }; - const [isCopied, setIsCopied] = useState(false); useEffect(() => { const fetchData = async () => { try { @@ -66,32 +74,43 @@ export default function Home() {
{proxyData.length && ( <> - -
- setChosen(chosen - 1 < 0 ? proxyData.length - 1 : chosen - 1)} /> - - {proxyData.map((item, index) => ( -
onCopyClick(item.url)} - key={index} - > + 1 ? `Ссылка ${chosen + 1}/${proxyData.length}` : "Ссылка"}> +
+ {proxyData.length > 1 && carouselApi.current?.scrollPrev()} />} +
+ (carouselApi.current = api)} + onSelectIndex={(index) => setChosen(index)} + > + {proxyData.map((item, index) => (
onCopyClick(item.url)} + key={index} > - - Скопировано - - +
+ + Скопировано + + +
+
- -
- ))} - - setChosen(chosen + 1 > proxyData.length - 1 ? 0 : chosen + 1)} /> + ))} + +
+ {proxyData.length > 1 && carouselApi.current?.scrollNext()} />}
Нажмите на QR, чтобы скопировать! diff --git a/src/components/Block.tsx b/src/components/Block.tsx index 8754a5e..cbf41c6 100644 --- a/src/components/Block.tsx +++ b/src/components/Block.tsx @@ -1,10 +1,16 @@ +import { cn } from "@/utils/cn"; import { PropsWithChildren } from "react"; -type BlockProps = PropsWithChildren<{ name?: string }>; +type BlockProps = PropsWithChildren<{ name?: string; className?: string }>; -const Block: React.FC = ({ children, name = "" }) => { +const Block: React.FC = ({ children, name = "", className = "" }) => { return ( -
+
{name && {name}} {children}
diff --git a/src/components/Carousel/Carousel.tsx b/src/components/Carousel/Carousel.tsx index 50df042..43eabb6 100644 --- a/src/components/Carousel/Carousel.tsx +++ b/src/components/Carousel/Carousel.tsx @@ -1,24 +1,31 @@ "use client"; -import { EmblaOptionsType } from "embla-carousel"; +import { EmblaCarouselType, EmblaOptionsType } from "embla-carousel"; import useEmblaCarousel from "embla-carousel-react"; import { PropsWithChildren, useEffect, useState } from "react"; -type Props = PropsWithChildren & EmblaOptionsType; +type Props = PropsWithChildren & + EmblaOptionsType & { + setApi?: (api: EmblaCarouselType) => void; + onSelectIndex?: (index: number) => void; + }; -const Carousel: React.FC = ({ children, ...options }: Props) => { +const Carousel: React.FC = ({ children, setApi, onSelectIndex, ...options }: Props) => { const [emblaRef, emblaApi] = useEmblaCarousel(options); const [, setSelectedIndex] = useState(0); useEffect(() => { - const selectHandler = () => { - const index = emblaApi?.selectedScrollSnap(); - setSelectedIndex(index || 0); - }; - emblaApi?.on("select", selectHandler); - return () => { - emblaApi?.off("select", selectHandler); - }; - }, [emblaApi]); + if (!emblaApi) return; + if (emblaApi && setApi) setApi(emblaApi); + const selectHandler = () => { + const index = emblaApi.selectedScrollSnap(); + setSelectedIndex(index); + onSelectIndex?.(index); + }; + emblaApi.on("select", selectHandler); + return () => { + emblaApi.off("select", selectHandler); + }; + }, [emblaApi, setApi, onSelectIndex]); return ( <>