export ready
							parent
							
								
									3ec0a3c486
								
							
						
					
					
						commit
						924faf2afd
					
				| 
						 | 
					@ -7,7 +7,9 @@
 | 
				
			||||||
	"customizations": {
 | 
						"customizations": {
 | 
				
			||||||
		"vscode": {
 | 
							"vscode": {
 | 
				
			||||||
			"extensions": [
 | 
								"extensions": [
 | 
				
			||||||
				"bradlc.vscode-tailwindcss"
 | 
									"bradlc.vscode-tailwindcss",
 | 
				
			||||||
 | 
									"GitHub.copilot",
 | 
				
			||||||
 | 
									"esbenp.prettier-vscode"
 | 
				
			||||||
			]
 | 
								]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,9 +13,9 @@ const config = {
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @see https://github.com/vercel/next.js/issues/41980
 | 
					   * @see https://github.com/vercel/next.js/issues/41980
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  i18n: {
 | 
					  output: 'export',
 | 
				
			||||||
    locales: ["en"],
 | 
					  images: {
 | 
				
			||||||
    defaultLocale: "en",
 | 
					    unoptimized: true,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons';
 | 
					import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
 | 
				
			||||||
import React, { useRef, useCallback } from 'react';
 | 
					import React, { useRef, useCallback } from "react";
 | 
				
			||||||
import HTMLFlipBook from 'react-pageflip';
 | 
					import HTMLFlipBook from "react-pageflip";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FlipbookProps {
 | 
					interface FlipbookProps {
 | 
				
			||||||
  children: React.ReactNode[];
 | 
					  children: React.ReactNode[];
 | 
				
			||||||
  width: number;
 | 
					  width: number;
 | 
				
			||||||
  height: number;
 | 
					  height: number;
 | 
				
			||||||
  className?: React.ComponentProps<'div'>['className'];
 | 
					  className?: React.ComponentProps<"div">["className"];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface PageFlip {
 | 
					interface PageFlip {
 | 
				
			||||||
| 
						 | 
					@ -21,53 +21,64 @@ export default function Flipbook(props: FlipbookProps) {
 | 
				
			||||||
  const flipbook = useRef<{ pageFlip(): PageFlip } | null>(null);
 | 
					  const flipbook = useRef<{ pageFlip(): PageFlip } | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Function to flip pages
 | 
					  // Function to flip pages
 | 
				
			||||||
  const flipPage = useCallback((direction: 'next' | 'prev') => {
 | 
					  const flipPage = useCallback(
 | 
				
			||||||
    const flipbookCurrent = flipbook.current;
 | 
					    (direction: "next" | "prev") => {
 | 
				
			||||||
    if (flipbookCurrent) {
 | 
					      const flipbookCurrent = flipbook.current;
 | 
				
			||||||
      const pageFlipObj = flipbookCurrent.pageFlip();
 | 
					      if (flipbookCurrent) {
 | 
				
			||||||
      const currentPageIndex = pageFlipObj.getCurrentPageIndex();
 | 
					        const pageFlipObj = flipbookCurrent.pageFlip();
 | 
				
			||||||
      const pageCount = pageFlipObj.getPageCount();
 | 
					        const currentPageIndex = pageFlipObj.getCurrentPageIndex();
 | 
				
			||||||
 | 
					        const pageCount = pageFlipObj.getPageCount();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (direction === 'next') {
 | 
					        if (direction === "next") {
 | 
				
			||||||
        if (currentPageIndex + 2 === pageCount) {
 | 
					          if (currentPageIndex + 2 === pageCount) {
 | 
				
			||||||
          pageFlipObj.flip(0);
 | 
					            pageFlipObj.flip(0);
 | 
				
			||||||
        } else {
 | 
					          } else {
 | 
				
			||||||
          pageFlipObj.flipNext();
 | 
					            pageFlipObj.flipNext();
 | 
				
			||||||
        }
 | 
					          }
 | 
				
			||||||
      } else if (direction === 'prev') {
 | 
					        } else if (direction === "prev") {
 | 
				
			||||||
        if (currentPageIndex === 0) {
 | 
					          if (currentPageIndex === 0) {
 | 
				
			||||||
          pageFlipObj.flip(pageCount - 1);
 | 
					            pageFlipObj.flip(pageCount - 1);
 | 
				
			||||||
        } else {
 | 
					          } else {
 | 
				
			||||||
          pageFlipObj.flipPrev(); // Add this method to handle the previous page flip
 | 
					            pageFlipObj.flipPrev(); // Add this method to handle the previous page flip
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
  }, [flipbook]);
 | 
					    [flipbook],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Handler for the next button
 | 
					  // Handler for the next button
 | 
				
			||||||
  const nextButtonClick = useCallback(() => {
 | 
					  const nextButtonClick = useCallback(() => {
 | 
				
			||||||
    flipPage('next');
 | 
					    flipPage("next");
 | 
				
			||||||
  }, [flipPage]);
 | 
					  }, [flipPage]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Handler for the previous button
 | 
					  // Handler for the previous button
 | 
				
			||||||
  const prevButtonClick = useCallback(() => {
 | 
					  const prevButtonClick = useCallback(() => {
 | 
				
			||||||
    flipPage('prev');
 | 
					    flipPage("prev");
 | 
				
			||||||
  }, [flipPage]);
 | 
					  }, [flipPage]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={`flex justify-center items-center ${props.className}`}>
 | 
					    <div className={`flex items-center justify-center ${props.className}`}>
 | 
				
			||||||
      <button  onClick={prevButtonClick}>
 | 
					      <button onClick={prevButtonClick}>
 | 
				
			||||||
        <ChevronLeftIcon height={50} width={50}/>
 | 
					        <ChevronLeftIcon
 | 
				
			||||||
 | 
					          height={50}
 | 
				
			||||||
 | 
					          width={50}
 | 
				
			||||||
 | 
					          className="max-h-[7vw] max-w-[7vw]"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
      <HTMLFlipBook
 | 
					      <HTMLFlipBook
 | 
				
			||||||
        usePortrait={false}
 | 
					        usePortrait={false}
 | 
				
			||||||
        className="text-black"
 | 
					        className="text-black"
 | 
				
			||||||
        width={props.width} height={props.height}
 | 
					        width={props.width}
 | 
				
			||||||
 | 
					        height={props.height}
 | 
				
			||||||
        size="fixed"
 | 
					        size="fixed"
 | 
				
			||||||
        style={{}}
 | 
					        style={{}}
 | 
				
			||||||
        minHeight={100} maxHeight={500}
 | 
					        minHeight={100}
 | 
				
			||||||
        minWidth={100} maxWidth={500}
 | 
					        maxHeight={500}
 | 
				
			||||||
        startPage={0} startZIndex={0}
 | 
					        minWidth={100}
 | 
				
			||||||
 | 
					        maxWidth={500}
 | 
				
			||||||
 | 
					        startPage={0}
 | 
				
			||||||
 | 
					        startZIndex={0}
 | 
				
			||||||
        drawShadow
 | 
					        drawShadow
 | 
				
			||||||
        flippingTime={1000}
 | 
					        flippingTime={1000}
 | 
				
			||||||
        autoSize
 | 
					        autoSize
 | 
				
			||||||
| 
						 | 
					@ -84,7 +95,11 @@ export default function Flipbook(props: FlipbookProps) {
 | 
				
			||||||
        {props.children}
 | 
					        {props.children}
 | 
				
			||||||
      </HTMLFlipBook>
 | 
					      </HTMLFlipBook>
 | 
				
			||||||
      <button onClick={nextButtonClick}>
 | 
					      <button onClick={nextButtonClick}>
 | 
				
			||||||
      <ChevronRightIcon height={50} width={50}/>
 | 
					        <ChevronRightIcon
 | 
				
			||||||
 | 
					          height={50}
 | 
				
			||||||
 | 
					          width={50}
 | 
				
			||||||
 | 
					          className="max-h-[7vw] max-w-[7vw]"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,83 +0,0 @@
 | 
				
			||||||
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
 | 
					 | 
				
			||||||
import { useKeenSlider } from "keen-slider/react";
 | 
					 | 
				
			||||||
import { useState, type MouseEvent } from "react";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface SliderProps {
 | 
					 | 
				
			||||||
  className?: React.ComponentProps<'div'>['className'];
 | 
					 | 
				
			||||||
  children?: React.ReactNode;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function Slider({ className, children }: SliderProps) {
 | 
					 | 
				
			||||||
  const [currentSlide, setCurrentSlide] = useState(0);
 | 
					 | 
				
			||||||
  const [loaded, setLoaded] = useState(false);
 | 
					 | 
				
			||||||
  const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>({
 | 
					 | 
				
			||||||
    initial: 0,
 | 
					 | 
				
			||||||
    slideChanged(slider) {
 | 
					 | 
				
			||||||
      setCurrentSlide(slider.track.details.rel);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    created() {
 | 
					 | 
				
			||||||
      setLoaded(true);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const goPrev = (e: MouseEvent<unknown>) => {
 | 
					 | 
				
			||||||
    e.stopPropagation();
 | 
					 | 
				
			||||||
    if (currentSlide !== 0) {
 | 
					 | 
				
			||||||
      instanceRef.current?.prev();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const goNext = (e: MouseEvent<unknown>) => {
 | 
					 | 
				
			||||||
    e.stopPropagation();
 | 
					 | 
				
			||||||
    if (instanceRef.current && currentSlide !== instanceRef.current.track.details.slides.length - 1) {
 | 
					 | 
				
			||||||
      instanceRef.current.next();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className={`${className} relative`}>
 | 
					 | 
				
			||||||
      <div>
 | 
					 | 
				
			||||||
        <div ref={sliderRef} className="flex overflow-hidden relative w-full">
 | 
					 | 
				
			||||||
          {children}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        {loaded && instanceRef.current && (
 | 
					 | 
				
			||||||
          <>
 | 
					 | 
				
			||||||
            <Arrow left onClick={goPrev} disabled={currentSlide === 0} />
 | 
					 | 
				
			||||||
            <Arrow onClick={goNext} disabled={instanceRef.current ? currentSlide === instanceRef.current.track.details.slides.length - 1 : true} />
 | 
					 | 
				
			||||||
          </>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      {loaded && instanceRef.current && (
 | 
					 | 
				
			||||||
        <div className="flex justify-center py-2">
 | 
					 | 
				
			||||||
          {Array.from({ length: instanceRef.current.track.details.slides.length }, (_, idx) => (
 | 
					 | 
				
			||||||
            <button
 | 
					 | 
				
			||||||
              key={idx}
 | 
					 | 
				
			||||||
              onClick={() => instanceRef.current?.moveToIdx(idx)}
 | 
					 | 
				
			||||||
              className={`w-2.5 h-2.5 bg-white rounded-full m-1 cursor-pointer ${currentSlide === idx ? "opacity-30" : ""}`}
 | 
					 | 
				
			||||||
            ></button>
 | 
					 | 
				
			||||||
          ))}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface ArrowProps {
 | 
					 | 
				
			||||||
  disabled: boolean;
 | 
					 | 
				
			||||||
  left?: boolean;
 | 
					 | 
				
			||||||
  onClick: (e: MouseEvent<unknown>) => void;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function Arrow({ disabled, left, onClick }: ArrowProps) {
 | 
					 | 
				
			||||||
  const Icon = left ? ChevronLeftIcon : ChevronRightIcon;
 | 
					 | 
				
			||||||
  const position = left ? '-left-10' : 'left-auto -right-10';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Icon
 | 
					 | 
				
			||||||
      onClick={onClick}
 | 
					 | 
				
			||||||
      height={50}
 | 
					 | 
				
			||||||
      width={50}
 | 
					 | 
				
			||||||
      className={`absolute ${position} top-1/2 cursor-pointer -translate-y-1/2 ${disabled ? "opacity-30" : ""}`}
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,18 @@
 | 
				
			||||||
 | 
					import React, { useRef, useState, useEffect } from 'react';
 | 
				
			||||||
import Head from "next/head";
 | 
					import Head from "next/head";
 | 
				
			||||||
import Image from "next/image";
 | 
					import Image from "next/image";
 | 
				
			||||||
import Flipbook from "~/components/Flipbook";
 | 
					import Flipbook from "~/components/Flipbook";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Home() {
 | 
					export default function Home() {
 | 
				
			||||||
 | 
					  const mainRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					  const [mainWidth, setMainWidth] = useState(350);  // default value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (mainRef.current) {
 | 
				
			||||||
 | 
					      setMainWidth(mainRef.current.offsetWidth/2.3);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <Head>
 | 
					      <Head>
 | 
				
			||||||
| 
						 | 
					@ -10,22 +20,22 @@ export default function Home() {
 | 
				
			||||||
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
					        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
				
			||||||
        <link rel="icon" href="/favicon.ico" />
 | 
					        <link rel="icon" href="/favicon.ico" />
 | 
				
			||||||
      </Head>
 | 
					      </Head>
 | 
				
			||||||
      <main className="">
 | 
					      <main className="" ref={mainRef}>
 | 
				
			||||||
      <Flipbook className="" width={350} height={460}>
 | 
					        <Flipbook className="" width={mainWidth} height={mainWidth*460/350}>
 | 
				
			||||||
        <div className="bg-gray-300">
 | 
					          <div className="bg-gray-300">
 | 
				
			||||||
          <div className="flex justify-center items-center h-full">
 | 
					            <div className="flex justify-center items-center h-full">
 | 
				
			||||||
            <a href="/download/GabrielDalle_Magazine.pdf" target="_blank" className="border-my-red border-[3px] p-4 rounded-full flex gap-2 cursor-pointer hover:border-black hover:bg-white font-mono font-bold text-sm tracking-wide">
 | 
					              <a href="/download/GabrielDalle_Magazine.pdf" target="_blank" className="border-my-red border-[3px] p-4 rounded-full flex gap-2 cursor-pointer hover:border-black hover:bg-white font-mono font-bold text-sm tracking-wide">
 | 
				
			||||||
              PDF DOWNLOAD
 | 
					                PDF DOWNLOAD
 | 
				
			||||||
            </a>
 | 
					              </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					          {Array.from(Array(24), (_, i) => (
 | 
				
			||||||
        {Array.from(Array(24), (_, i) => (
 | 
					            <div className="bg-white" key={i}>
 | 
				
			||||||
          <div className="bg-white" key={i}>
 | 
					              <Image key={i} alt="pdf page" height={468} width={mainWidth} src={`/projects/fizik/pdf/page${i + 1}.png`} />
 | 
				
			||||||
            <Image key={i} alt="pdf page" height={468} width={350} src={`/projects/fizik/pdf/page${i + 1}.png`} />
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          ))}
 | 
				
			||||||
        ))}
 | 
					          <div className="bg-gray-300" />
 | 
				
			||||||
        <div className="bg-gray-300" />
 | 
					        </Flipbook>
 | 
				
			||||||
      </Flipbook>
 | 
					 | 
				
			||||||
      </main>
 | 
					      </main>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue