├── public └── index.html ├── src ├── components │ ├── Home.js │ ├── Footer.js │ ├── About.js │ ├── GalleryItem.js │ ├── Gallery.js │ ├── Featured.js │ ├── Navbar.js │ ├── menu.js │ ├── Hero.js │ ├── Blog.js │ └── NotFound.js ├── index.js ├── hooks │ ├── useSmoothScroll.js │ └── gsap.js ├── App.js ├── style.css └── index.css ├── .gitignore ├── README.md └── package.json /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Immemorial 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/Home.js: -------------------------------------------------------------------------------- 1 | import About from "./About"; 2 | import Featured from "./Featured"; 3 | import Gallery from "./Gallery"; 4 | import Hero from "./Hero"; 5 | 6 | const Home = () => { 7 | return ( 8 |
9 | 10 | 11 | 12 | 13 |
14 | ); 15 | }; 16 | 17 | export default Home; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { BrowserRouter } from "react-router-dom"; 4 | import App from "./App"; 5 | import "./index.css"; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById("root")); 8 | root.render( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { useFooterHeadLine } from "../hooks/gsap"; 3 | 4 | const Footer = () => { 5 | const footerRef = useRef(null); 6 | const footerHeadLine = useRef(null); 7 | 8 | useFooterHeadLine(footerHeadLine, footerRef); 9 | return ( 10 |
11 |

Bonjour

12 |

© {new Date().getFullYear()} Immemorial. Crafted by yours truly

13 |
14 | ); 15 | }; 16 | 17 | export default Footer; 18 | -------------------------------------------------------------------------------- /src/hooks/useSmoothScroll.js: -------------------------------------------------------------------------------- 1 | import Lenis from "@studio-freight/lenis"; 2 | import { useEffect } from "react"; 3 | export const useSmoothScroll = () => { 4 | const lenis = new Lenis({ 5 | duration: 1.5, 6 | easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), 7 | direction: "vertical", // vertical, horizontal 8 | smooth: true, 9 | }); 10 | 11 | useEffect(() => { 12 | function raf(time) { 13 | //raf = request animation frame 14 | lenis.raf(time); 15 | //time ta scrolling are 16 | requestAnimationFrame(raf); 17 | } 18 | 19 | requestAnimationFrame(raf); 20 | }, []); 21 | }; 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is Immemorial? 2 | Immemorial is a platform that takes users on a journey through the lost treasures and shining stars of the 1990s. It features easy filtering functionality, allowing users to find their favorite TV shows, music albums, cartoons, and more from the 90s. The platform is updated regularly with new and classic favorites from the era. 3 | 4 | What's the only era that never seems to end? The 90s! Journey through appreciating items from 90s TV, music, and art. See if you remember old toys, cartoons, or prints of such. Indulge in some nostalgia before our world falls back into the dark ages. 5 | 6 | How to use this repo? 7 | Download or clone this repo and run the following command in the terminal: 8 | 9 | npm install 10 | 11 | 12 | Tools: 13 | React.js, React Router, GSAP 14 | 15 | Thanks for visiting this repo, take care! 16 | -------------------------------------------------------------------------------- /src/components/About.js: -------------------------------------------------------------------------------- 1 | const About = () => { 2 | return ( 3 |
4 | {" "} 5 |

About

6 |

7 | Explore the lost treasures and shining stars of the 1990s! Find your 8 | favorite cartoons, TV shows, music albums, & more with easy filtering 9 | functionality. With Immemorial, stay up-to-date with all your 90s 10 | favorites while turning back time. 11 |

12 |

13 | What's the only era that never seems to end? The 90s! Journey through 14 | appreciating items from 90s TV, music, and art. See if you remember old 15 | toys, cartoons, or prints of such. Indulge in some nostalgia before our 16 | world falls back into the dark ages. 17 |

18 |
19 | ); 20 | }; 21 | 22 | export default About; 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "immemorial", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@studio-freight/lenis": "^0.2.26", 7 | "@testing-library/jest-dom": "^5.16.5", 8 | "@testing-library/react": "^13.4.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "gsap": "^3.11.3", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "react-router-dom": "^6.4.4", 14 | "react-scripts": "5.0.1", 15 | "web-vitals": "^2.1.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/components/GalleryItem.js: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { 3 | useGsapGalleryTitle, 4 | useGsapGalleryCategory, 5 | useGsapGalleryImage, 6 | } from "../hooks/gsap"; 7 | const GalleryItem = ({ image }) => { 8 | //ref create 9 | const galleryTitleRef = useRef(null); 10 | const galleryCategoryRef = useRef(null); 11 | const galleryImageRef = useRef(null); 12 | //hook create 13 | useGsapGalleryTitle(galleryTitleRef, galleryImageRef); 14 | useGsapGalleryCategory(galleryCategoryRef, galleryImageRef); 15 | useGsapGalleryImage(galleryImageRef); 16 | return ( 17 |
18 |

19 | {image.title} 20 |

21 |

22 | {image.category} 23 |

24 |
29 |
30 | ); 31 | }; 32 | 33 | export default GalleryItem; 34 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Route, Routes } from "react-router-dom"; 3 | import Home from "./components/Home"; 4 | // import Navbar from "./components/Navbar"; 5 | import Navbar from "./components/Navbar"; 6 | import Footer from "./components/Footer"; 7 | import { useSmoothScroll } from "./hooks/useSmoothScroll"; 8 | import About from "./components/About"; 9 | import Gallery from "./components/Gallery"; 10 | import Featured from "./components/Featured"; 11 | import Blog from "./components/Blog"; 12 | import NotFound from "./components/NotFound"; 13 | const App = () => { 14 | //smooth scroll are jonno lenis github use kora hoyse 15 | useSmoothScroll(); 16 | return ( 17 |
18 | 19 | 20 | } /> 21 | } /> 22 | } /> 23 | } /> 24 | } /> 25 | } /> 26 | 27 |
29 | ); 30 | }; 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /src/components/Gallery.js: -------------------------------------------------------------------------------- 1 | import GalleryItem from "./GalleryItem"; 2 | const images = [ 3 | { 4 | id: 1, 5 | src: "https://images.pexels.com/photos/4842487/pexels-photo-4842487.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1", 6 | title: "Arcade playtime for 90's kids", 7 | category: "Arcade Games", 8 | }, 9 | { 10 | id: 2, 11 | src: "https://images.pexels.com/photos/3356608/pexels-photo-3356608.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1", 12 | title: "No signal - no transmission", 13 | category: "TV", 14 | }, 15 | { 16 | id: 3, 17 | src: "https://images.pexels.com/photos/12668238/pexels-photo-12668238.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1", 18 | title: "Retro Closures", 19 | category: "Boombox", 20 | }, 21 | { 22 | id: 4, 23 | src: "https://images.pexels.com/photos/12204293/pexels-photo-12204293.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1", 24 | title: "Vinyl Loveless Happiness", 25 | category: "Vinyl Record", 26 | }, 27 | ]; 28 | 29 | const Gallery = () => { 30 | return ( 31 |
32 |

Gallery

33 |
34 | {images.map((image) => ( 35 | 36 | ))} 37 |
38 |
39 | ); 40 | }; 41 | 42 | export default Gallery; 43 | -------------------------------------------------------------------------------- /src/components/Featured.js: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { 3 | useGsapFeatureLeftShutterUnveil, 4 | useGsapFeatureRightShutterUnveil, 5 | } from "../hooks/gsap"; 6 | const Featured = () => { 7 | const featureRef = useRef(null); 8 | const featureLeftShutterRef = useRef(null); 9 | const featureRightShutterRef = useRef(null); 10 | 11 | useGsapFeatureLeftShutterUnveil(featureLeftShutterRef, featureRef); 12 | useGsapFeatureRightShutterUnveil(featureRightShutterRef, featureRef); 13 | return ( 14 |
15 |

Featured

16 |
17 |
18 | 90'S TELEPHONE 19 | 90'S TELEPHONE 23 | 27 |
28 |
29 | 90'S CASSETTE PLAYER 30 | 90'S CASSETTE PLAYER 34 | 38 |
39 |
40 |
41 | ); 42 | }; 43 | 44 | export default Featured; 45 | -------------------------------------------------------------------------------- /src/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import { useGsapDownStagger } from "../hooks/gsap"; 4 | const Navbar = () => { 5 | const li1 = useRef(null); 6 | const li2 = useRef(null); 7 | const li3 = useRef(null); 8 | const blogRef = useRef(null); 9 | const logoRef = useRef(null); 10 | 11 | const lip1 = useRef(null); 12 | const lip2 = useRef(null); 13 | const lip3 = useRef(null); 14 | const pblogRef = useRef(null); 15 | 16 | const liArrp = [lip1, lip2, lip3]; 17 | const pblogArr = [pblogRef]; 18 | 19 | const liArr = [li1, li2, li3]; 20 | const blogArr = [blogRef]; 21 | const logoArr = [logoRef]; 22 | 23 | useGsapDownStagger(liArrp, 0.9); 24 | useGsapDownStagger(pblogArr, 1.9); 25 | 26 | useGsapDownStagger(liArr, 0.9); 27 | useGsapDownStagger(logoArr, 1.5); 28 | useGsapDownStagger(blogArr, 1.9); 29 | 30 | return ( 31 | 67 | ); 68 | }; 69 | 70 | export default Navbar; 71 | -------------------------------------------------------------------------------- /src/components/menu.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import gsap from "gsap"; 3 | import "./styles.css"; // Import your CSS file 4 | import { Link } from "react-router-dom"; 5 | 6 | const Menu = () => { 7 | const [isMenuOpen, setMenuOpen] = useState(false); 8 | 9 | const toggleMenu = () => { 10 | setMenuOpen(!isMenuOpen); 11 | }; 12 | 13 | const closeMenu = () => { 14 | setMenuOpen(false); 15 | }; 16 | 17 | const animateMenu = () => { 18 | const tl = gsap.timeline({ paused: true }); 19 | tl.to(".menu", { 20 | opacity: 1, 21 | duration: 1, 22 | top: 0, 23 | ease: "Power2.easeInOut", 24 | }); 25 | tl.to( 26 | ".nav", 27 | { 28 | opacity: 1, 29 | marginBottom: 0, 30 | duration: 1, 31 | ease: "Power2.easeInOut", 32 | stagger: 0.3, 33 | }, 34 | ">-0.5" 35 | ); 36 | return tl; 37 | }; 38 | 39 | const t1 = animateMenu(); 40 | 41 | return ( 42 |
43 |
44 |
45 |
Uniqo
46 |
47 |
48 |
49 | Menu 50 |
51 |
52 |
53 | 54 | {/* Menu Stuff */} 55 |
56 |
Menu
57 |
58 | 59 |
60 |
61 |
    62 |
  • 63 | 64 | Home 01 65 | 66 |
  • 67 |
  • 68 | 69 | Blog 02 70 | 71 |
  • 72 |
  • 73 | 74 | About 03 75 | 76 |
  • 77 |
78 |
79 |
80 | {/* Your other menu content */} 81 |
82 |
83 |
84 | ); 85 | }; 86 | 87 | export default Menu; 88 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | margin: 0; 6 | padding: 0; 7 | font-family: "Poppins", Arial; 8 | } 9 | 10 | body { 11 | background-color: rgb(16, 16, 16); 12 | color: white; 13 | } 14 | 15 | ul { 16 | list-style: none; 17 | } 18 | 19 | .logo { 20 | font-size: 2rem; 21 | } 22 | 23 | .home { 24 | display: flex; 25 | justify-content: space-between; 26 | padding: 50px; 27 | } 28 | 29 | .menu-div { 30 | cursor: pointer; 31 | transition: all 0.2s ease-in-out; 32 | } 33 | 34 | .menu-div:hover { 35 | color: gray; 36 | transition: all 0.2s ease-in-out; 37 | } 38 | 39 | /* Menu Stuff */ 40 | 41 | .menu { 42 | opacity: 0.3; 43 | width: 100%; 44 | height: 100vh; 45 | display: flex; 46 | flex-direction: row; 47 | justify-content: space-between; 48 | padding: 0px 50px; 49 | position: fixed; 50 | top: -100%; 51 | align-items: center; 52 | background-color: rgb(39, 39, 39); 53 | } 54 | 55 | .nav { 56 | opacity: 0; 57 | margin-bottom: -20px; 58 | } 59 | 60 | .nav-link { 61 | color: white; 62 | text-decoration: none; 63 | font-size: 3rem; 64 | transition: all 0.2s ease-in-out; 65 | } 66 | 67 | .nav-link:hover { 68 | color: gray; 69 | transition: all 0.2s ease-in-out; 70 | } 71 | 72 | .background { 73 | position: absolute; 74 | font-size: 15rem; 75 | font-weight: 600; 76 | color: rgba(235, 235, 235, 0.04); 77 | user-select: none; 78 | z-index: 1; 79 | } 80 | 81 | .small-number { 82 | font-size: 1.2rem; 83 | } 84 | 85 | .exit { 86 | cursor: pointer; 87 | position: absolute; 88 | right: 40px; 89 | top: 40px; 90 | } 91 | 92 | .title { 93 | font-size: 2rem; 94 | color: rgb(170, 151, 126); 95 | } 96 | 97 | .right { 98 | padding-right: 100px; 99 | } 100 | 101 | .information { 102 | margin-bottom: 24px; 103 | } 104 | 105 | .menu-container { 106 | z-index: 3; 107 | } 108 | 109 | .social-medias > a { 110 | color: white; 111 | text-decoration: none; 112 | text-transform: uppercase; 113 | font-size: 0.9rem; 114 | letter-spacing: 1px; 115 | } 116 | 117 | /* Media Query */ 118 | @media screen and (max-width: 660px) { 119 | .menu { 120 | flex-direction: column; 121 | justify-content: center; 122 | } 123 | 124 | .right { 125 | display: none; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/components/Hero.js: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { 3 | useGsapShutterUnveil, 4 | useGsapPhotoDropping, 5 | useGsapPhotoLevitate, 6 | } from "../hooks/gsap"; 7 | 8 | const Hero = () => { 9 | const heroRef = useRef(null); 10 | const shutter1 = useRef(null); 11 | const shutter2 = useRef(null); 12 | 13 | const photo1Ref = useRef(null); 14 | const photo2Ref = useRef(null); 15 | const photo3Ref = useRef(null); 16 | const photo4Ref = useRef(null); 17 | const photo5Ref = useRef(null); 18 | 19 | const photoArr = [photo1Ref, photo2Ref, photo3Ref, photo4Ref, photo5Ref]; 20 | 21 | useGsapShutterUnveil(shutter1, 0, heroRef); 22 | useGsapShutterUnveil(shutter2, 0.2, heroRef); 23 | useGsapPhotoDropping(photoArr); 24 | useGsapPhotoLevitate(photoArr, heroRef); 25 | 26 | return ( 27 |
28 |

29 | Ethereal 30 |

31 |

32 | Canvas 33 |

34 |
35 |
43 | 44 |
52 | 53 |
61 | 62 |
70 |
78 |
79 |
80 | ); 81 | }; 82 | 83 | export default Hero; 84 | -------------------------------------------------------------------------------- /src/components/Blog.js: -------------------------------------------------------------------------------- 1 | const Blog = ({ needFullHight }) => { 2 | return ( 3 |
4 |

blog

5 | 6 |
7 |
14 |
21 |
28 |
35 |
42 |
49 |
56 |
57 |
58 | ); 59 | }; 60 | 61 | export default Blog; 62 | -------------------------------------------------------------------------------- /src/components/NotFound.js: -------------------------------------------------------------------------------- 1 | // const NotFound = () => { 2 | // return ( 3 | //
4 | //
5 | //
6 | //
7 | //
8 | // Lorem ipsum dolor sit amet consectetur adipisicing elit. Animi, 9 | // repudiandae! 10 | //
11 | //
12 | //
13 | // Lorem ipsum dolor sit amet consectetur adipisicing elit. Animi, 14 | // repudiandae! 15 | //
16 | //
17 | // Lorem ipsum dolor sit amet consectetur adipisicing elit. Animi, 18 | // repudiandae! 19 | //
20 | //
21 | //
22 | //
23 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum 24 | // vitae inventore incidunt eligendi soluta. Vero, laboriosam facere in 25 | // velit rerum libero repellat quidem animi nam voluptatem laborum 26 | // eveniet delectus assumenda. 27 | //
28 | //
29 | 30 | //
Lorem ipsum dolor sit amet.
31 | //
32 | //
33 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti 34 | // pariatur impedit obcaecati eos consequatur esse sequi quasi, 35 | // incidunt itaque temporibus. 36 | //
37 | //
38 | // Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti 39 | // pariatur impedit obcaecati eos consequatur esse sequi quasi, 40 | // incidunt itaque temporibus. 41 | //
42 | //
43 | //
44 | //
45 | // ); 46 | // }; 47 | 48 | // export default NotFound; 49 | 50 | import { useRef } from "react"; 51 | import { useGsapNotFoundHeadline, useGsapNotFoundImg } from "../hooks/gsap"; 52 | 53 | const NotFound = () => { 54 | const leftHeadlineRef = useRef(null); 55 | const rightHeadlineRef = useRef(null); 56 | const leftImgRef = useRef(null); 57 | const rightImgRef = useRef(null); 58 | 59 | useGsapNotFoundHeadline(leftHeadlineRef); 60 | useGsapNotFoundHeadline(rightHeadlineRef, "100vw"); 61 | useGsapNotFoundImg(leftImgRef); 62 | useGsapNotFoundImg(rightImgRef); 63 | 64 | return ( 65 |
66 |
67 | Sorry, we couldn't 68 |
69 |
70 | Woman Sitting on a Hood of an Old Volkswagen Golf Car 74 |
75 |
76 | Woman showing retro photo camera and holding blooming flower 80 |
81 |
82 | Find that page 83 |
84 |
85 | ); 86 | }; 87 | 88 | export default NotFound; 89 | -------------------------------------------------------------------------------- /src/hooks/gsap.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import gsap, { Expo } from "gsap"; 3 | import ScrollTrigger from "gsap/ScrollTrigger"; 4 | 5 | gsap.registerPlugin(ScrollTrigger); 6 | //hero likha animation 7 | export const useGsapShutterUnveil = (item, delay = 0, trigger) => { 8 | //heroRef trigger hisabe use kora hoase akhane 9 | //trigger bolte animate jayga ta bojhai....oi jayga tekhe bar hoa abar fire gele animate hoi 10 | useEffect(() => { 11 | const el = item.current; 12 | gsap.fromTo( 13 | el, 14 | { 15 | height: "100%", 16 | }, 17 | { 18 | height: 0, 19 | duration: 2, 20 | ease: Expo.easeInOut, 21 | delay: delay, 22 | scrollTrigger: { 23 | trigger: trigger.current, 24 | //view port a dhukle animation play hobe bar hole off hobe aitar jonno toggleAction 25 | toggleActions: "play reverse play reverse", 26 | }, 27 | } 28 | ); 29 | }, [item, delay, trigger]); 30 | }; 31 | 32 | //navbar animation 33 | export const useGsapDownStagger = (arr, delay = 0) => { 34 | useEffect(() => { 35 | const el = arr.map((item) => item.current); 36 | gsap.fromTo( 37 | el, 38 | { 39 | y: "-100%", 40 | opacity: 0, 41 | }, 42 | { 43 | y: 0, 44 | opacity: 1, 45 | //koto time dhore animate hobe tar jonno duration 46 | duration: 1.2, 47 | //array item gula kotokhon por por ashbe tar jonno stagger set kora hoi 48 | stagger: 0.2, 49 | ease: Expo.easeIn, 50 | delay: delay, 51 | } 52 | ); 53 | }, [arr, delay]); 54 | }; 55 | 56 | //hero Image drop animation 57 | 58 | export const useGsapPhotoDropping = (arr) => { 59 | useEffect(() => { 60 | const el = arr.map((item) => item.current); 61 | gsap.fromTo( 62 | el, 63 | { 64 | y: "-100vh", 65 | scale: 0, 66 | }, 67 | { 68 | y: 0, 69 | //pic soto tekhe boro hoar jonno scale use kora 70 | scale: 1, 71 | duration: 1.7, 72 | stagger: 0.2, 73 | ease: Expo.easeIn, 74 | delay: 2, 75 | } 76 | ); 77 | }, [arr]); 78 | }; 79 | 80 | export const useGsapPhotoLevitate = (arr, trigger) => { 81 | useEffect(() => { 82 | const el = arr.map((item) => item.current); 83 | gsap.fromTo( 84 | el, 85 | { 86 | y: 0, 87 | }, 88 | { 89 | y: "-100%", 90 | ease: Expo.easeInOut, 91 | 92 | scrollTrigger: { 93 | trigger: trigger.current, 94 | //scrub value 1 mane true 95 | scrub: 1, 96 | toggleActions: "play reverse play reverse", 97 | }, 98 | } 99 | ); 100 | }, [arr, trigger]); 101 | }; 102 | 103 | export const useGsapFeatureLeftShutterUnveil = (item, trigger) => { 104 | useEffect(() => { 105 | const el = item.current; 106 | gsap.fromTo( 107 | el, 108 | { 109 | height: "100%", 110 | }, 111 | { 112 | height: 0, 113 | duration: 1.3, 114 | ease: Expo.easeInOut, 115 | scrollTrigger: { 116 | trigger: trigger.current, 117 | start: "top center", 118 | end: "bottom center", 119 | toggleActions: "play reverse play reverse", 120 | }, 121 | } 122 | ); 123 | }, [item, trigger]); 124 | }; 125 | 126 | export const useGsapFeatureRightShutterUnveil = (item, trigger) => { 127 | useEffect(() => { 128 | const el = item.current; 129 | gsap.fromTo( 130 | el, 131 | { 132 | width: "100%", 133 | }, 134 | { 135 | width: 0, 136 | duration: 1.3, 137 | ease: Expo.easeInOut, 138 | scrollTrigger: { 139 | trigger: trigger.current, 140 | start: "top center", 141 | end: "bottom center", 142 | toggleActions: "play reverse play reverse", 143 | }, 144 | } 145 | ); 146 | }, [item, trigger]); 147 | }; 148 | 149 | export const useGsapGalleryImage = (item) => { 150 | useEffect(() => { 151 | const el = item.current; 152 | gsap.fromTo( 153 | el, 154 | { 155 | x: 0, 156 | width: 0, 157 | }, 158 | { 159 | x: "30%", 160 | width: "100%", 161 | ease: Expo.easeInOut, 162 | scrollTrigger: { 163 | trigger: el, 164 | start: "top center", 165 | end: "bottom top", 166 | toggleActions: "play reverse play reverse", 167 | }, 168 | } 169 | ); 170 | }, [item]); 171 | }; 172 | export const useGsapGalleryTitle = (item, trigger) => { 173 | useEffect(() => { 174 | const el = item.current; 175 | gsap.fromTo( 176 | el, 177 | { 178 | x: "30%", 179 | }, 180 | { 181 | x: 0, 182 | ease: Expo.easeInOut, 183 | scrollTrigger: { 184 | trigger: trigger.current, 185 | start: "top center", 186 | end: "bottom top", 187 | toggleActions: "play reverse play reverse", 188 | }, 189 | } 190 | ); 191 | }, [item, trigger]); 192 | }; 193 | 194 | export const useGsapGalleryCategory = (item, trigger) => { 195 | useEffect(() => { 196 | const el = item.current; 197 | gsap.fromTo( 198 | el, 199 | { 200 | x: "-100vw", 201 | }, 202 | { 203 | x: "0", 204 | 205 | ease: Expo.easeInOut, 206 | scrollTrigger: { 207 | trigger: trigger.current, 208 | start: "top center", 209 | end: "bottom top", 210 | toggleActions: "play reverse play reverse", 211 | }, 212 | } 213 | ); 214 | }, [item, trigger]); 215 | }; 216 | 217 | export const useFooterHeadLine = (item, trigger) => { 218 | useEffect(() => { 219 | const el = item.current; 220 | gsap.fromTo( 221 | el, 222 | { 223 | y: "-100%", 224 | }, 225 | { 226 | y: 0, 227 | duration: 1, 228 | ease: Expo.easeInOut, 229 | scrollTrigger: { 230 | trigger: trigger.current, 231 | toggleActions: "play", 232 | }, 233 | } 234 | ); 235 | }, [item, trigger]); 236 | }; 237 | 238 | export const useGsapNotFoundHeadline = (item, vw = "-100vw") => { 239 | useEffect(() => { 240 | const el = item.current; 241 | 242 | gsap.fromTo( 243 | el, 244 | { 245 | x: vw, 246 | }, 247 | { 248 | x: 0, 249 | duration: 1.5, 250 | ease: Expo.easeInOut, 251 | } 252 | ); 253 | }, [item, vw]); 254 | }; 255 | 256 | export const useGsapNotFoundImg = (item) => { 257 | useEffect(() => { 258 | const el = item.current; 259 | 260 | gsap.fromTo( 261 | el, 262 | { 263 | scale: 0, 264 | borderRadius: "50%", 265 | }, 266 | { 267 | scale: 1, 268 | borderRadius: 0, 269 | duration: 4, 270 | delay: 1, 271 | ease: "elastic", 272 | } 273 | ); 274 | }, [item]); 275 | }; 276 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | /* poppins */ 2 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap"); 3 | /* Bai Jamjuree */ 4 | @import url("https://fonts.googleapis.com/css2?family=Bai+Jamjuree:wght@200;300;400;500;600;700&display=swap"); 5 | /* Syncopate */ 6 | @import url("https://fonts.googleapis.com/css2?family=Syncopate:wght@400;700&display=swap"); 7 | /* Bodoni Moda */ 8 | @import url("https://fonts.googleapis.com/css2?family=Bodoni+Moda:wght@6400;500;600;700;800;900&display=swap"); 9 | :root { 10 | --color-primary: #d53f41; 11 | --color-dark: #0c0b0b; 12 | --color-darker: #131212; 13 | --color-light: #dbd8d6; 14 | --color-lighter: #f5f0ec; 15 | } 16 | * { 17 | margin: 0; 18 | padding: 0; 19 | list-style: none; 20 | text-decoration: none; 21 | box-sizing: border-box; 22 | } 23 | html, 24 | body { 25 | overflow-x: hidden; 26 | } 27 | html { 28 | font-size: 62.5%; 29 | } 30 | body { 31 | font-family: "poppins", sans-serif; 32 | font-size: 2rem; 33 | font-weight: 400; 34 | line-height: 1.7; 35 | letter-spacing: 1px; 36 | background-color: var(--color-lighter); 37 | } 38 | .wrapper { 39 | margin: 0 5vw; 40 | } 41 | section { 42 | padding: 8vw 0; 43 | } 44 | .section-title { 45 | font-family: "syncopate", sans-serif; 46 | font-size: 1.5rem; 47 | color: var(--color-primary); 48 | padding-bottom: 5vw; 49 | text-transform: lowercase; 50 | } 51 | .min-h-100vh { 52 | min-height: 100vh; 53 | } 54 | .navbar { 55 | display: flex; 56 | justify-content: space-between; 57 | align-items: flex-start; 58 | padding: 6rem 0; 59 | font-family: "syncopate", sans-serif; 60 | font-size: 1.5rem; 61 | text-transform: lowercase; 62 | } 63 | .phone-menu { 64 | display: none; 65 | } 66 | .links, 67 | .blog-link { 68 | font-weight: 700; 69 | display: block; 70 | } 71 | .links a, 72 | .blog-link a { 73 | color: var(--color-dark); 74 | position: relative; 75 | } 76 | .links a::after, 77 | .blog-link a::after { 78 | content: ""; 79 | width: 0; 80 | height: 0.2rem; 81 | position: absolute; 82 | top: 30%; 83 | left: 50%; 84 | transform: translate(-30%, 50%); 85 | background-color: var(--color-primary); 86 | transition: 0.5s; 87 | } 88 | .links a:hover:after, 89 | .blog-link a:hover:after { 90 | width: 120%; 91 | } 92 | 93 | .logo a { 94 | color: var(--color-darker); 95 | } 96 | .hero { 97 | font-family: "Bai Jamjuree", sans-serif; 98 | text-transform: uppercase; 99 | text-align: center; 100 | font-size: 10vw; 101 | line-height: 1.2; 102 | min-height: 100vh; 103 | color: var(--color-darker); 104 | position: relative; 105 | flex-direction: column; 106 | justify-content: center; 107 | display: flex; 108 | align-items: center; 109 | } 110 | .ethereal, 111 | .canvas { 112 | position: relative; 113 | } 114 | .ethereal span, 115 | .canvas span { 116 | position: absolute; 117 | top: 0; 118 | left: 0; 119 | right: 0; 120 | bottom: 0; 121 | width: 100%; 122 | height: 100%; 123 | background-color: var(--color-lighter); 124 | } 125 | .photos { 126 | position: absolute; 127 | top: 0; 128 | left: 0; 129 | bottom: 0; 130 | right: 0; 131 | z-index: 1; 132 | display: grid; 133 | grid-template-columns: repeat(7, 1fr); 134 | grid-template-rows: repeat(5, 1fr); 135 | } 136 | .photo { 137 | width: 100%; 138 | height: 100%; 139 | background-position: center; 140 | background-repeat: no-repeat; 141 | background-size: cover; 142 | object-fit: cover; 143 | } 144 | .photo.one { 145 | grid-column: 5; 146 | grid-row: 1; 147 | } 148 | .photo.two { 149 | grid-column: 1; 150 | grid-row: 2; 151 | } 152 | .photo.three { 153 | grid-column: 4; 154 | grid-row: 3; 155 | } 156 | .photo.four { 157 | grid-column: 7; 158 | grid-row: 4; 159 | } 160 | .photo.five { 161 | grid-column: 2; 162 | grid-row: 5; 163 | } 164 | 165 | .features { 166 | display: grid; 167 | grid-template-columns: 30% auto; 168 | align-items: center; 169 | gap: 7rem; 170 | } 171 | .features img { 172 | width: 100%; 173 | } 174 | .feature-l, 175 | .feature-r { 176 | display: flex; 177 | flex-direction: column; 178 | gap: 1rem; 179 | position: relative; 180 | } 181 | 182 | .feature-text { 183 | letter-spacing: 5px; 184 | font-weight: 500; 185 | } 186 | .feature-shutter-l, 187 | .feature-shutter-r { 188 | position: absolute; 189 | z-index: 1; 190 | width: 100%; 191 | height: 100%; 192 | background-color: var(--color-lighter); 193 | top: 0; 194 | left: 0; 195 | right: 0; 196 | bottom: 0; 197 | } 198 | 199 | .about p:last-child { 200 | margin-top: 3vw; 201 | } 202 | .about p { 203 | font-size: 3vw; 204 | line-height: 1.5; 205 | color: var(--color-darker); 206 | } 207 | .gallery > .section-title { 208 | margin-left: 5vw; 209 | } 210 | 211 | .gallery-wrapper { 212 | display: grid; 213 | grid-template-columns: 1fr; 214 | justify-items: center; 215 | gap: 10vw; 216 | padding: 10vw; 217 | background-color: var(--color-primary); 218 | } 219 | .gallery-item { 220 | position: relative; 221 | width: 50%; 222 | } 223 | .gallery-item-title { 224 | position: absolute; 225 | top: 10%; 226 | left: -50%; 227 | font-family: "Bai Jamjuree", sans-serif; 228 | font-size: 8vw; 229 | line-height: 1.2; 230 | text-transform: uppercase; 231 | color: var(--color-lighter); 232 | z-index: 1; 233 | mix-blend-mode: color-dodge; 234 | } 235 | .gallery-item-category { 236 | position: absolute; 237 | left: 0; 238 | bottom: -6%; 239 | text-transform: uppercase; 240 | color: var(--color-lighter); 241 | letter-spacing: 10px; 242 | z-index: 1; 243 | } 244 | .gallery-item-img { 245 | background-position: center; 246 | background-repeat: no-repeat; 247 | background-size: cover; 248 | width: 100%; 249 | height: 100vh; 250 | } 251 | /* not found */ 252 | .not-found { 253 | min-height: 100vh; 254 | display: grid; 255 | grid-template-columns: 1fr 1fr; 256 | align-content: flex-start; 257 | column-gap: 5vw; 258 | row-gap: 1vw; 259 | padding: 5vw 0; 260 | } 261 | 262 | .headline-1, 263 | .headline-2 { 264 | font-family: "Bai Jamjuree", sans-serif; 265 | font-size: 8vw; 266 | font-weight: 700; 267 | line-height: 1; 268 | text-transform: capitalize; 269 | } 270 | 271 | .img-1, 272 | .img-2 { 273 | width: 20vw; 274 | height: 20vw; 275 | overflow: hidden; 276 | display: flex; 277 | justify-content: center; 278 | align-items: center; 279 | z-index: 1; 280 | } 281 | 282 | .img-1 img, 283 | .img-2 img { 284 | display: block; 285 | width: 100%; 286 | } 287 | 288 | .img-2 { 289 | justify-self: self-end; 290 | } 291 | 292 | .footer { 293 | text-align: center; 294 | } 295 | .footer h1 { 296 | font-family: "Bodoni Moda", serif; 297 | font-size: 10vw; 298 | text-transform: lowercase; 299 | color: var(--color-primary); 300 | } 301 | 302 | .blog-area { 303 | display: grid; 304 | height: 100vh; 305 | grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); 306 | gap: 1rem; 307 | grid-auto-flow: dense; 308 | } 309 | .blog-image-1 { 310 | grid-column: auto / span 3; 311 | grid-row: auto / span 2; 312 | } 313 | .blog-image-2 { 314 | grid-column: auto / span 3; 315 | } 316 | .blog-image-3 { 317 | grid-column: auto / span 2; 318 | grid-row: auto / span 3; 319 | } 320 | .blog-image-4 { 321 | grid-column: auto / span 3; 322 | } 323 | .blog-image-5 { 324 | grid-column: auto / span 3; 325 | } 326 | .blog-image-6 { 327 | grid-column: auto / span 3; 328 | grid-row: auto / span 2; 329 | } 330 | .blog-image-7 { 331 | grid-column: auto / span 6; 332 | } 333 | @media only screen and (max-width: 688px) { 334 | .navbar { 335 | font-size: 1.1rem; 336 | } 337 | .links, 338 | .blog-link { 339 | display: none; 340 | } 341 | .phone-menu { 342 | display: block; 343 | } 344 | .blog-link, 345 | .phone-menu > li > a { 346 | color: var(--color-dark); 347 | font-weight: bold; 348 | } 349 | .photos { 350 | position: absolute; 351 | top: 0; 352 | left: 0; 353 | bottom: 0; 354 | right: 0; 355 | z-index: 1; 356 | display: grid; 357 | grid-template-columns: repeat(4, 1fr); 358 | grid-template-rows: repeat(5, 1fr); 359 | } 360 | .photo { 361 | width: 100%; 362 | height: 100%; 363 | background-position: center; 364 | background-repeat: no-repeat; 365 | background-size: cover; 366 | object-fit: cover; 367 | } 368 | .photo.one { 369 | grid-column: 4; 370 | grid-row: 1; 371 | } 372 | .photo.two { 373 | grid-column: 1; 374 | grid-row: 2; 375 | } 376 | .photo.three { 377 | grid-column: 3; 378 | grid-row: 3; 379 | } 380 | .photo.four { 381 | grid-column: 4; 382 | grid-row: 4; 383 | display: none; 384 | } 385 | .photo.five { 386 | grid-column: 2; 387 | grid-row: 5; 388 | } 389 | .about p { 390 | font-size: 5vw; 391 | line-height: 1.5; 392 | color: var(--color-darker); 393 | } 394 | .gallery-item-img { 395 | height: 30vh; 396 | } 397 | } 398 | @media only screen and (max-width: 400px) { 399 | .navbar { 400 | padding: 2rem 0 0 0; 401 | } 402 | .photos { 403 | position: absolute; 404 | top: 0; 405 | left: 0; 406 | bottom: 0; 407 | right: 0; 408 | z-index: 1; 409 | display: grid; 410 | grid-template-columns: repeat(3, 1fr); 411 | grid-template-rows: repeat(5, 1fr); 412 | } 413 | .photo { 414 | width: 100%; 415 | height: 100%; 416 | background-position: center; 417 | background-repeat: no-repeat; 418 | background-size: cover; 419 | object-fit: cover; 420 | } 421 | .photo.one { 422 | grid-column: 4; 423 | grid-row: 1; 424 | display: none; 425 | } 426 | .photo.two { 427 | grid-column: 1; 428 | grid-row: 2; 429 | } 430 | .photo.three { 431 | grid-column: 3; 432 | grid-row: 3; 433 | } 434 | .photo.four { 435 | grid-column: 3; 436 | grid-row: 4; 437 | display: none; 438 | } 439 | .photo.five { 440 | grid-column: 2; 441 | grid-row: 5; 442 | } 443 | } 444 | --------------------------------------------------------------------------------