{"id":26710538,"url":"https://github.com/dev-eranda/iphone-landing-page","last_synced_at":"2026-05-09T01:11:47.877Z","repository":{"id":253613294,"uuid":"842976437","full_name":"dev-eranda/iphone-landing-page","owner":"dev-eranda","description":"Build an iPhone landing page using ReactJS + GSAP (to learn animations)","archived":false,"fork":false,"pushed_at":"2025-03-24T06:27:28.000Z","size":45232,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T06:32:47.191Z","etag":null,"topics":["animations","frontend-development","gsap","reactjs","tailwind-css"],"latest_commit_sha":null,"homepage":"https://iphone-doc-xi.vercel.app","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dev-eranda.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-15T14:11:04.000Z","updated_at":"2025-03-24T06:27:31.000Z","dependencies_parsed_at":"2025-03-24T06:43:44.008Z","dependency_job_id":null,"html_url":"https://github.com/dev-eranda/iphone-landing-page","commit_stats":null,"previous_names":["erandamadusanka/iphone-landing-page-demo","erandamadusanka/iphone-doc","erandamadusanka/iphone-15-pro-landing-page","dev-eranda/iphone-15-pro-landing-page","dev-eranda/iphone-landing-page"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-eranda%2Fiphone-landing-page","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-eranda%2Fiphone-landing-page/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-eranda%2Fiphone-landing-page/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-eranda%2Fiphone-landing-page/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dev-eranda","download_url":"https://codeload.github.com/dev-eranda/iphone-landing-page/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245815677,"owners_count":20676951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animations","frontend-development","gsap","reactjs","tailwind-css"],"created_at":"2025-03-27T09:24:48.355Z","updated_at":"2026-05-09T01:11:42.853Z","avatar_url":"https://github.com/dev-eranda.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# iPhone landing page\n\n**Web Application:** [Click here to view the demonstration application](https://iphone-doc-xi.vercel.app/)\n\u003chr /\u003e\n\n## Project Background and Overview\nThis repository is a clone of Apple's iPhone 15 Pro website, built using React and TailwindCSS. It showcases effective use of GSAP for animations and Three.js for 3D rendering, allowing users to explore iPhone 15 Pro models in various colors and shapes. This project an excellent demonstration of modern web development practices\n\u003chr /\u003e\n\n## Project Goals\nThe main objectives of this application are to:\n\n1. Create a better user experience with smooth and eye-catching animations using GSAP\n2. Check out the iPhone 15 Pro in 3D, with different colors and sizes to explore\n3. Enjoy a personalized browsing experience with an interactive video carousel built using GSAP\n4. A fully responsive design ensures easy access and great viewing on any device\n\u003chr /\u003e\n\n## Technical Details\nCore technologies used: \n\n- **React, GSAP (GreenSock Animation Platform), TailwindCSS** \n\u003chr /\u003e\n\n## Installation\n1. Clone repository:\n   ```sh\n   git clone https://github.com/dev-eranda/iphone-landing-page.git\n\n2. Install dependencies:\n   ```sh\n   npm install\n   \n3. Start development server:\n   ```sh\n   npm run dev\n   \n  - **Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.**\n\n## \u003ca name=\"snippets\"\u003eSnippets\u003c/a\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etailwind.config.js\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\n/** @type {import('tailwindcss').Config} */\nexport default {\n  content: [\"./index.html\", \"./src/**/*.{js,ts,jsx,tsx}\"],\n  theme: {\n    extend: {\n      colors: {\n        blue: \"#2997FF\",\n        gray: {\n          DEFAULT: \"#86868b\",\n          100: \"#94928d\",\n          200: \"#afafaf\",\n          300: \"#42424570\",\n        },\n        zinc: \"#101010\",\n      },\n    },\n  },\n  plugins: [],\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003econstants/index.js\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\nimport {\n  blackImg,\n  blueImg,\n  highlightFirstVideo,\n  highlightFourthVideo,\n  highlightSecondVideo,\n  highlightThirdVideo,\n  whiteImg,\n  yellowImg,\n} from \"../utils\";\n\nexport const navLists = [\"Store\", \"Mac\", \"iPhone\", \"Support\"];\n\nexport const hightlightsSlides = [\n  {\n    id: 1,\n    textLists: [\n      \"Enter A17 Pro.\",\n      \"Game‑changing chip.\",\n      \"Groundbreaking performance.\",\n    ],\n    video: highlightFirstVideo,\n    videoDuration: 4,\n  },\n  {\n    id: 2,\n    textLists: [\"Titanium.\", \"So strong. So light. So Pro.\"],\n    video: highlightSecondVideo,\n    videoDuration: 5,\n  },\n  {\n    id: 3,\n    textLists: [\n      \"iPhone 15 Pro Max has the\",\n      \"longest optical zoom in\",\n      \"iPhone ever. Far out.\",\n    ],\n    video: highlightThirdVideo,\n    videoDuration: 2,\n  },\n  {\n    id: 4,\n    textLists: [\"All-new Action button.\", \"What will yours do?.\"],\n    video: highlightFourthVideo,\n    videoDuration: 3.63,\n  },\n];\n\nexport const models = [\n  {\n    id: 1,\n    title: \"iPhone 15 Pro in Natural Titanium\",\n    color: [\"#8F8A81\", \"#ffe7b9\", \"#6f6c64\"],\n    img: yellowImg,\n  },\n  {\n    id: 2,\n    title: \"iPhone 15 Pro in Blue Titanium\",\n    color: [\"#53596E\", \"#6395ff\", \"#21242e\"],\n    img: blueImg,\n  },\n  {\n    id: 3,\n    title: \"iPhone 15 Pro in White Titanium\",\n    color: [\"#C9C8C2\", \"#ffffff\", \"#C9C8C2\"],\n    img: whiteImg,\n  },\n  {\n    id: 4,\n    title: \"iPhone 15 Pro in Black Titanium\",\n    color: [\"#454749\", \"#3b3b3b\", \"#181819\"],\n    img: blackImg,\n  },\n];\n\nexport const sizes = [\n  { label: '6.1\"', value: \"small\" },\n  { label: '6.7\"', value: \"large\" },\n];\n\nexport const footerLinks = [\n  \"Privacy Policy\",\n  \"Terms of Use\",\n  \"Sales Policy\",\n  \"Legal\",\n  \"Site Map\",\n];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eLights.jsx\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\nimport { Environment, Lightformer } from \"@react-three/drei\";\n\nconst Lights = () =\u003e {\n  return (\n    // group different lights and lightformers. We can use group to organize lights, cameras, meshes, and other objects in the scene.\n    \u003cgroup name=\"lights\"\u003e\n      {/**\n       * @description Environment is used to create a background environment for the scene\n       * https://github.com/pmndrs/drei?tab=readme-ov-file#environment\n       */}\n      \u003cEnvironment resolution={256}\u003e\n        \u003cgroup\u003e\n          {/**\n           * @description Lightformer used to create custom lights with various shapes and properties in a 3D scene.\n           * https://github.com/pmndrs/drei?tab=readme-ov-file#lightformer\n           */}\n          \u003cLightformer\n            form=\"rect\"\n            intensity={10}\n            position={[-1, 0, -10]}\n            scale={10}\n            color={\"#495057\"}\n          /\u003e\n          \u003cLightformer\n            form=\"rect\"\n            intensity={10}\n            position={[-10, 2, 1]}\n            scale={10}\n            rotation-y={Math.PI / 2}\n          /\u003e\n          \u003cLightformer\n            form=\"rect\"\n            intensity={10}\n            position={[10, 0, 1]}\n            scale={10}\n            rotation-y={Math.PI / 2}\n          /\u003e\n        \u003c/group\u003e\n      \u003c/Environment\u003e\n\n      {/**\n       * @description spotLight is used to create a light source positioned at a specific point\n       * in the scene that emits light in a specific direction.\n       * https://threejs.org/docs/#api/en/lights/SpotLight\n       */}\n      \u003cspotLight\n        position={[-2, 10, 5]}\n        angle={0.15}\n        penumbra={1} // the penumbra is the soft edge of a shadow cast by a point light\n        decay={0} // the amount the light dims as it moves away from the source\n        intensity={Math.PI * 0.2} // the light intensity\n        color={\"#f8f9fa\"}\n      /\u003e\n      \u003cspotLight\n        position={[0, -25, 10]}\n        angle={0.15}\n        penumbra={1}\n        decay={0}\n        intensity={Math.PI * 0.2}\n        color={\"#f8f9fa\"}\n      /\u003e\n      \u003cspotLight\n        position={[0, 15, 5]}\n        angle={0.15}\n        penumbra={1}\n        decay={0.1}\n        intensity={Math.PI * 3}\n      /\u003e\n    \u003c/group\u003e\n  );\n};\n\nexport default Lights;\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003ematerials\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\n    useEffect(() =\u003e {\n      Object.entries(materials).map((material) =\u003e {\n        // these are the material names that can't be changed color\n        if (\n          material[0] !== \"zFdeDaGNRwzccye\" \u0026\u0026\n          material[0] !== \"ujsvqBWRMnqdwPx\" \u0026\u0026\n          material[0] !== \"hUlRcbieVuIiOXG\" \u0026\u0026\n          material[0] !== \"jlzuBkUzuJqgiAK\" \u0026\u0026\n          material[0] !== \"xNrofRCqOXXHVZt\"\n        ) {\n          material[1].color = new THREE.Color(props.item.color[0]);\n        }\n        material[1].needsUpdate = true;\n      });\n    }, [materials, props.item]);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eVideoCarousel.jsx\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\nimport gsap from \"gsap\";\nimport { useGSAP } from \"@gsap/react\";\nimport { ScrollTrigger } from \"gsap/all\";\ngsap.registerPlugin(ScrollTrigger);\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { hightlightsSlides } from \"../constants\";\nimport { pauseImg, playImg, replayImg } from \"../utils\";\n\nconst VideoCarousel = () =\u003e {\n  const videoRef = useRef([]);\n  const videoSpanRef = useRef([]);\n  const videoDivRef = useRef([]);\n\n  // video and indicator\n  const [video, setVideo] = useState({\n    isEnd: false,\n    startPlay: false,\n    videoId: 0,\n    isLastVideo: false,\n    isPlaying: false,\n  });\n\n  const [loadedData, setLoadedData] = useState([]);\n  const { isEnd, isLastVideo, startPlay, videoId, isPlaying } = video;\n\n  useGSAP(() =\u003e {\n    // slider animation to move the video out of the screen and bring the next video in\n    gsap.to(\"#slider\", {\n      transform: `translateX(${-100 * videoId}%)`,\n      duration: 2,\n      ease: \"power2.inOut\", // show visualizer https://gsap.com/docs/v3/Eases\n    });\n\n    // video animation to play the video when it is in the view\n    gsap.to(\"#video\", {\n      scrollTrigger: {\n        trigger: \"#video\",\n        toggleActions: \"restart none none none\",\n      },\n      onComplete: () =\u003e {\n        setVideo((pre) =\u003e ({\n          ...pre,\n          startPlay: true,\n          isPlaying: true,\n        }));\n      },\n    });\n  }, [isEnd, videoId]);\n\n  useEffect(() =\u003e {\n    let currentProgress = 0;\n    let span = videoSpanRef.current;\n\n    if (span[videoId]) {\n      // animation to move the indicator\n      let anim = gsap.to(span[videoId], {\n        onUpdate: () =\u003e {\n          // get the progress of the video\n          const progress = Math.ceil(anim.progress() * 100);\n\n          if (progress != currentProgress) {\n            currentProgress = progress;\n\n            // set the width of the progress bar\n            gsap.to(videoDivRef.current[videoId], {\n              width:\n                window.innerWidth \u003c 760\n                  ? \"10vw\" // mobile\n                  : window.innerWidth \u003c 1200\n                  ? \"10vw\" // tablet\n                  : \"4vw\", // laptop\n            });\n\n            // set the background color of the progress bar\n            gsap.to(span[videoId], {\n              width: `${currentProgress}%`,\n              backgroundColor: \"white\",\n            });\n          }\n        },\n\n        // when the video is ended, replace the progress bar with the indicator and change the background color\n        onComplete: () =\u003e {\n          if (isPlaying) {\n            gsap.to(videoDivRef.current[videoId], {\n              width: \"12px\",\n            });\n            gsap.to(span[videoId], {\n              backgroundColor: \"#afafaf\",\n            });\n          }\n        },\n      });\n\n      if (videoId == 0) {\n        anim.restart();\n      }\n\n      // update the progress bar\n      const animUpdate = () =\u003e {\n        anim.progress(\n          videoRef.current[videoId].currentTime /\n            hightlightsSlides[videoId].videoDuration\n        );\n      };\n\n      if (isPlaying) {\n        // ticker to update the progress bar\n        gsap.ticker.add(animUpdate);\n      } else {\n        // remove the ticker when the video is paused (progress bar is stopped)\n        gsap.ticker.remove(animUpdate);\n      }\n    }\n  }, [videoId, startPlay]);\n\n  useEffect(() =\u003e {\n    if (loadedData.length \u003e 3) {\n      if (!isPlaying) {\n        videoRef.current[videoId].pause();\n      } else {\n        startPlay \u0026\u0026 videoRef.current[videoId].play();\n      }\n    }\n  }, [startPlay, videoId, isPlaying, loadedData]);\n\n  // vd id is the id for every video until id becomes number 3\n  const handleProcess = (type, i) =\u003e {\n    switch (type) {\n      case \"video-end\":\n        setVideo((pre) =\u003e ({ ...pre, isEnd: true, videoId: i + 1 }));\n        break;\n\n      case \"video-last\":\n        setVideo((pre) =\u003e ({ ...pre, isLastVideo: true }));\n        break;\n\n      case \"video-reset\":\n        setVideo((pre) =\u003e ({ ...pre, videoId: 0, isLastVideo: false }));\n        break;\n\n      case \"pause\":\n        setVideo((pre) =\u003e ({ ...pre, isPlaying: !pre.isPlaying }));\n        break;\n\n      case \"play\":\n        setVideo((pre) =\u003e ({ ...pre, isPlaying: !pre.isPlaying }));\n        break;\n\n      default:\n        return video;\n    }\n  };\n\n  const handleLoadedMetaData = (i, e) =\u003e setLoadedData((pre) =\u003e [...pre, e]);\n\n  return (\n    \u003c\u003e\n      \u003cdiv className=\"flex items-center\"\u003e\n        {hightlightsSlides.map((list, i) =\u003e (\n          \u003cdiv key={list.id} id=\"slider\" className=\"sm:pr-20 pr-10\"\u003e\n            \u003cdiv className=\"video-carousel_container\"\u003e\n              \u003cdiv className=\"w-full h-full flex-center rounded-3xl overflow-hidden bg-black\"\u003e\n                \u003cvideo\n                  id=\"video\"\n                  playsInline={true}\n                  className={`${\n                    list.id === 2 \u0026\u0026 \"translate-x-44\"\n                  } pointer-events-none`}\n                  preload=\"auto\"\n                  muted\n                  ref={(el) =\u003e (videoRef.current[i] = el)}\n                  onEnded={() =\u003e\n                    i !== 3\n                      ? handleProcess(\"video-end\", i)\n                      : handleProcess(\"video-last\")\n                  }\n                  onPlay={() =\u003e\n                    setVideo((pre) =\u003e ({ ...pre, isPlaying: true }))\n                  }\n                  onLoadedMetadata={(e) =\u003e handleLoadedMetaData(i, e)}\n                \u003e\n                  \u003csource src={list.video} type=\"video/mp4\" /\u003e\n                \u003c/video\u003e\n              \u003c/div\u003e\n\n              \u003cdiv className=\"absolute top-12 left-[5%] z-10\"\u003e\n                {list.textLists.map((text, i) =\u003e (\n                  \u003cp key={i} className=\"md:text-2xl text-xl font-medium\"\u003e\n                    {text}\n                  \u003c/p\u003e\n                ))}\n              \u003c/div\u003e\n            \u003c/div\u003e\n          \u003c/div\u003e\n        ))}\n      \u003c/div\u003e\n\n      \u003cdiv className=\"relative flex-center mt-10\"\u003e\n        \u003cdiv className=\"flex-center py-5 px-7 bg-gray-300 backdrop-blur rounded-full\"\u003e\n          {videoRef.current.map((_, i) =\u003e (\n            \u003cspan\n              key={i}\n              className=\"mx-2 w-3 h-3 bg-gray-200 rounded-full relative cursor-pointer\"\n              ref={(el) =\u003e (videoDivRef.current[i] = el)}\n            \u003e\n              \u003cspan\n                className=\"absolute h-full w-full rounded-full\"\n                ref={(el) =\u003e (videoSpanRef.current[i] = el)}\n              /\u003e\n            \u003c/span\u003e\n          ))}\n        \u003c/div\u003e\n\n        \u003cbutton className=\"control-btn\"\u003e\n          \u003cimg\n            src={isLastVideo ? replayImg : !isPlaying ? playImg : pauseImg}\n            alt={isLastVideo ? \"replay\" : !isPlaying ? \"play\" : \"pause\"}\n            onClick={\n              isLastVideo\n                ? () =\u003e handleProcess(\"video-reset\")\n                : !isPlaying\n                ? () =\u003e handleProcess(\"play\")\n                : () =\u003e handleProcess(\"pause\")\n            }\n          /\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/\u003e\n  );\n};\n\nexport default VideoCarousel;\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eutils/index.js\u003c/code\u003e\u003c/summary\u003e\n\n```javascript\nimport hero from \"/assets/images/hero.jpeg\";\n\nexport const heroImg = hero;\n\nimport hmv from \"/assets/videos/hero.mp4\";\nimport smallmv from \"/assets/videos/smallHero.mp4\";\nimport highlightFirstmv from \"/assets/videos/highlight-first.mp4\";\nimport highlightSectmv from \"/assets/videos/hightlight-third.mp4\";\nimport highlightThirdmv from \"/assets/videos/hightlight-sec.mp4\";\nimport highlightFourthmv from \"/assets/videos/hightlight-fourth.mp4\";\nimport exploremv from \"/assets/videos/explore.mp4\";\nimport framemv from \"/assets/videos/frame.mp4\";\n\nimport apple from \"/assets/images/apple.svg\";\nimport search from \"/assets/images/search.svg\";\nimport bag from \"/assets/images/bag.svg\";\nimport watch from \"/assets/images/watch.svg\";\nimport right from \"/assets/images/right.svg\";\nimport replay from \"/assets/images/replay.svg\";\nimport play from \"/assets/images/play.svg\";\nimport pause from \"/assets/images/pause.svg\";\n\nimport yellow from \"/assets/images/yellow.jpg\";\nimport blue from \"/assets/images/blue.jpg\";\nimport white from \"/assets/images/white.jpg\";\nimport black from \"/assets/images/black.jpg\";\nimport explore1 from \"/assets/images/explore1.jpg\";\nimport explore2 from \"/assets/images/explore2.jpg\";\nimport chip from \"/assets/images/chip.jpeg\";\nimport frame from \"/assets/images/frame.png\";\n\nexport const heroVideo = hmv;\nexport const smallHeroVideo = smallmv;\nexport const highlightFirstVideo = highlightFirstmv;\nexport const highlightSecondVideo = highlightSectmv;\nexport const highlightThirdVideo = highlightThirdmv;\nexport const highlightFourthVideo = highlightFourthmv;\nexport const exploreVideo = exploremv;\nexport const frameVideo = framemv;\n\nexport const appleImg = apple;\nexport const searchImg = search;\nexport const bagImg = bag;\nexport const watchImg = watch;\nexport const rightImg = right;\nexport const replayImg = replay;\nexport const playImg = play;\nexport const pauseImg = pause;\n\nexport const yellowImg = yellow;\nexport const blueImg = blue;\nexport const whiteImg = white;\nexport const blackImg = black;\nexport const explore1Img = explore1;\nexport const explore2Img = explore2;\nexport const chipImg = chip;\nexport const frameImg = frame;\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eindex.css\u003c/code\u003e\u003c/summary\u003e\n\n```css\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n* {\n  margin: 0;\n  padding: 0;\n  box-sizing: border-box;\n}\n\nbody {\n  color: white;\n  width: 100dvw;\n  overflow-x: hidden;\n  height: 100%;\n  background: #000;\n  border-color: #3b3b3b;\n  user-select: none;\n}\n\ncanvas {\n  touch-action: none;\n}\n\n.scrim-max-width {\n  margin-inline-start: auto;\n  margin-inline-end: auto;\n  position: relative;\n  max-width: 1120px;\n}\n\n@layer utilities {\n  .flex-center {\n    @apply flex items-center justify-center\n  }\n\n  .nav-height {\n    @apply h-[calc(100vh-60px)]\n  }\n\n  .btn {\n    @apply px-5 py-2 rounded-3xl bg-blue my-5 hover:bg-transparent border border-transparent hover:border hover:text-blue hover:border-blue\n  }\n\n  .color-container {\n    @apply flex items-center justify-center px-4 py-4 rounded-full bg-gray-300 backdrop-blur\n  }\n\n  .size-btn-container {\n    @apply flex items-center justify-center p-1 rounded-full bg-gray-300 backdrop-blur ml-3 gap-1\n  }\n\n  .size-btn {\n    @apply w-10 h-10 text-sm flex justify-center items-center bg-white text-black rounded-full transition-all\n  }\n\n  .common-padding {\n    @apply sm:py-32 py-20 sm:px-10 px-5\n  }\n\n  .section-heading {\n    @apply text-gray lg:text-6xl md:text-5xl text-3xl lg:mb-0 mb-5 font-medium opacity-0 translate-y-20\n  }\n\n  .feature-text {\n    @apply text-gray max-w-md text-lg md:text-xl font-semibold opacity-0 translate-y-[100px]\n  }\n\n  .feature-text-container {\n    @apply w-full flex-center flex-col md:flex-row mt-10 md:mt-16 gap-5\n  }\n\n  .feature-video {\n    @apply w-full h-full object-cover object-center scale-150 opacity-0\n  }\n\n  .feature-video-container {\n    @apply w-full flex flex-col md:flex-row gap-5 items-center\n  }\n\n  .link {\n    @apply text-blue hover:underline cursor-pointer flex items-center text-xl opacity-0 translate-y-20\n  }\n\n  .control-btn {\n    @apply ml-4 p-4 rounded-full bg-gray-300 backdrop-blur flex-center\n  }\n\n  .hero-title {\n    @apply text-center font-semibold text-3xl text-gray-100 opacity-0 max-md:mb-10\n  }\n\n  .hiw-title {\n    @apply text-4xl md:text-7xl font-semibold text-center\n  }\n\n  .hiw-subtitle {\n    @apply text-gray font-semibold text-xl md:text-2xl py-10 text-center\n  }\n\n  .hiw-video {\n    @apply absolute w-[95%] h-[90%] rounded-[56px] overflow-hidden\n  }\n\n  .hiw-text-container {\n    @apply flex md:flex-row flex-col justify-between items-start gap-24\n  }\n\n  .hiw-text {\n    @apply text-gray text-xl font-normal md:font-semibold\n  }\n\n  .hiw-bigtext {\n    @apply text-white text-3xl md:text-5xl font-normal md:font-semibold my-2\n  }\n\n  .video-carousel_container {\n    @apply relative sm:w-[70vw] w-[88vw] md:h-[70vh] sm:h-[50vh] h-[35vh]\n  }\n\n  .g_fadeIn {\n    @apply opacity-0 translate-y-[100px]\n  }\n}\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-eranda%2Fiphone-landing-page","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdev-eranda%2Fiphone-landing-page","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-eranda%2Fiphone-landing-page/lists"}