Landing lage scroll snapping

This commit is contained in:
2026-05-12 03:59:04 +02:00
parent 9832275f45
commit bd9a01491a
2 changed files with 53 additions and 26 deletions
+16
View File
@@ -0,0 +1,16 @@
/* Force the body to never scroll */
html, body {
overflow: hidden;
height: 100%;
margin: 0;
padding: 0;
}
/* Optional: Hide scrollbar track for a cleaner UI while keeping functionality */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
+29 -18
View File
@@ -6,6 +6,8 @@ import Link from "next/link";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { motion, Variants } from "framer-motion"; import { motion, Variants } from "framer-motion";
import "./Home.css";
const MotionLink = motion(Link); const MotionLink = motion(Link);
export const mistShowcase = [ export const mistShowcase = [
@@ -140,7 +142,7 @@ function ShowSection({
return ( return (
<motion.section <motion.section
ref={ref} ref={ref}
className="h-svh p-10 md:p-20 w-full flex flex-col items-center justify-center" className="h-svh p-10 md:p-20 w-full flex flex-col items-center justify-center snap-center"
> >
<motion.div <motion.div
className="flex flex-col gap-2 items-center justify-center" className="flex flex-col gap-2 items-center justify-center"
@@ -188,22 +190,38 @@ export default function HomePage() {
const [currentText, setCurrentText] = useState(mistShowcase[0]?.code || ""); const [currentText, setCurrentText] = useState(mistShowcase[0]?.code || "");
return ( return (
<div className="flex w-full flex-col xl:flex-row"> /*
<div className="flex fixed xl:top-0 xl:right-0 w-svw xl:w-[40vw] h-svh xl:items-center mt-10 justify-center z-50 pointer-events-none"> 1. Move overflow-y-auto and snap-y to the ROOT div.
<div className="xl:w-full overflow-hidden"> Now the entire screen is the scrollable "track".
*/
<div className="h-svh overflow-y-auto snap-y snap-mandatory scroll-smooth no-scrollbar relative flex flex-col xl:flex-row">
{/*
THE RIGHT SIDE (MorphCode)
Using 'sticky' instead of 'fixed'. It will stay pinned to the
top/center while you scroll through the sections.
*/}
<div className="pointer-events-none sticky top-0 right-0 z-50 flex order-first xl:order-last w-full xl:w-[40vw] h-svh items-center justify-center p-10">
<div className="w-full max-w-2xl overflow-hidden">
<motion.div <motion.div
className="w-max h-auto border border-fd-border p-5 rounded-xl min-h-24 backdrop-blur bg-black dark:bg-black/20" className="will-change-transform transform-gpu w-full h-auto border border-fd-border p-5 rounded-xl min-h-24 backdrop-blur bg-black dark:bg-black/20 pointer-events-auto"
variants={item} variants={item}
initial="hidden" initial="hidden"
animate="show" animate="show"
> >
<MorphCode code={currentText} /> {/*
We use a key here to help React/Framer distinguish
morphing vs unmounting if needed
*/}
<MorphCode code={currentText} key="morph-code-logic" />
</motion.div> </motion.div>
</div> </div>
</div> </div>
<div className="flex-1"> {/*
<div className="mt-10 xl:mt-0"> THE SECTIONS
They now live in the main scroll flow.
*/}
<div className="flex-1 w-full xl:w-[60vw]">
{mistShowcase.map((show) => ( {mistShowcase.map((show) => (
<ShowSection <ShowSection
key={show.title} key={show.title}
@@ -212,24 +230,17 @@ export default function HomePage() {
/> />
))} ))}
</div> </div>
</div>
<div className="xl:w-[40vw]" />
{/* <div className="absolute left-1/2 bottom-1">
</div> */} {/* Scroll Indicator - Use fixed so it stays relative to screen */}
<motion.div <motion.div
initial={{ opacity: 0, y: -8 }} initial={{ opacity: 0, y: -8 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }} transition={{ duration: 0.6 }}
className="absolute bottom-8 left-1/2 -translate-x-1/2" className="fixed bottom-8 left-1/2 -translate-x-1/2 pointer-events-none z-50"
> >
<motion.div <motion.div
animate={{ y: [0, 10, 0] }} animate={{ y: [0, 10, 0] }}
transition={{ transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
duration: 1.5,
repeat: Infinity,
ease: "easeInOut",
}}
className="flex flex-col items-center gap-1 text-muted-foreground" className="flex flex-col items-center gap-1 text-muted-foreground"
> >
<ChevronsDownIcon <ChevronsDownIcon