From 574baa686011a9b9a799382e52850a780412b86d Mon Sep 17 00:00:00 2001 From: ramvignesh-b Date: Tue, 28 Apr 2026 23:22:57 +0530 Subject: [PATCH] feat: enhance homescreen with scroll motion --- frontend/bun.lock | 9 ++ frontend/package.json | 1 + frontend/src/index.css | 76 +++++------ frontend/src/pages/Home.tsx | 263 +++++++++++++++++++++++++++++++++++- 4 files changed, 308 insertions(+), 41 deletions(-) diff --git a/frontend/bun.lock b/frontend/bun.lock index d6c45c6..56066a0 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -17,6 +17,7 @@ "daisyui": "^5.5.19", "fabric": "^7.2.0", "idb": "^8.0.3", + "motion": "^12.38.0", "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.72.1", @@ -402,6 +403,8 @@ "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -526,6 +529,12 @@ "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], + + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], + + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "msw": ["msw@2.13.2", "", { "dependencies": { "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.41.2", "@open-draft/deferred-promise": "^2.2.0", "@types/statuses": "^2.0.6", "cookie": "^1.0.2", "graphql": "^16.12.0", "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", "rettime": "^0.10.1", "statuses": "^2.0.2", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.0", "type-fest": "^5.2.0", "until-async": "^3.0.2", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": ">= 4.8.x" }, "optionalPeers": ["typescript"], "bin": { "msw": "cli/index.js" } }, "sha512-go2H1TIERKkC48pXiwec5l6sbNqYuvqOk3/vHGo1Zd+pq/H63oFawDQerH+WQdUw/flJFHDG7F+QdWMwhntA/A=="], diff --git a/frontend/package.json b/frontend/package.json index 7af9d67..c240185 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,7 @@ "daisyui": "^5.5.19", "fabric": "^7.2.0", "idb": "^8.0.3", + "motion": "^12.38.0", "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.72.1", diff --git a/frontend/src/index.css b/frontend/src/index.css index 8071edf..3224478 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -2,57 +2,57 @@ @plugin "daisyui"; @plugin "daisyui/theme" { - name: "piku"; - default: true; - prefersdark: true; - color-scheme: dark; + name: "piku"; + default: true; + prefersdark: true; + color-scheme: dark; - --color-base-100: oklch(14% 0.012 35); - --color-base-200: oklch(18% 0.014 33); - --color-base-300: oklch(22% 0.016 32); - --color-base-content: oklch(82% 0.02 70); + --color-base-100: oklch(14% 0.012 35); + --color-base-200: oklch(18% 0.014 33); + --color-base-300: oklch(22% 0.016 32); + --color-base-content: oklch(82% 0.02 70); - --color-primary: oklch(67% 0.11 78); - --color-primary-content: oklch(15% 0.03 70); + --color-primary: oklch(67% 0.11 78); + --color-primary-content: oklch(15% 0.03 70); - --color-secondary: oklch(48% 0.08 305); - --color-secondary-content: oklch(92% 0.01 305); + --color-secondary: oklch(48% 0.08 305); + --color-secondary-content: oklch(92% 0.01 305); - --color-accent: oklch(55% 0.06 325); - --color-accent-content: oklch(18% 0.03 295); + --color-accent: oklch(55% 0.06 325); + --color-accent-content: oklch(18% 0.03 295); - --color-neutral: oklch(28% 0.02 45); - --color-neutral-content: oklch(80% 0.015 60); + --color-neutral: oklch(28% 0.02 45); + --color-neutral-content: oklch(80% 0.015 60); - --color-info: oklch(60% 0.07 240); - --color-info-content: oklch(95% 0.01 240); - --color-success: oklch(60% 0.08 150); - --color-success-content: oklch(16% 0.03 150); - --color-warning: oklch(68% 0.08 72); - --color-warning-content: oklch(18% 0.03 60); - --color-error: oklch(55% 0.1 22); - --color-error-content: oklch(92% 0.01 22); + --color-info: oklch(60% 0.07 240); + --color-info-content: oklch(95% 0.01 240); + --color-success: oklch(60% 0.08 150); + --color-success-content: oklch(16% 0.03 150); + --color-warning: oklch(68% 0.08 72); + --color-warning-content: oklch(18% 0.03 60); + --color-error: oklch(55% 0.1 22); + --color-error-content: oklch(92% 0.01 22); - --radius-selector: 0.5rem; - --radius-field: 0.375rem; - --radius-box: 0.5rem; + --radius-selector: 0.5rem; + --radius-field: 0.375rem; + --radius-box: 0.5rem; - --depth: 1; - --noise: 0.03; + --depth: 1; + --noise: 0.03; - --border: 1px; + --border: 1px; } @theme { - --font-display: "Playwrite HR Lijeva Variable", cursive; - --font-sans: "Jost Variable", sans-serif; - --font-serif: "Playfair Display Variable", serif; - --color-glass-bg: rgba(28, 22, 16, 0.45); - --shadow-warm: 0 20px 50px -12px rgba(30, 20, 12, 0.6); - --radius-xl: 1.5rem; - --color-paper: oklch(97% 0.008 80); + --font-display: "Playwrite HR Lijeva Variable", cursive; + --font-sans: "Jost Variable", sans-serif; + --font-serif: "Playfair Display Variable", serif; + --color-glass-bg: rgba(28, 22, 16, 0.45); + --shadow-warm: 0 20px 50px -12px rgba(30, 20, 12, 0.6); + --radius-xl: 1.5rem; + --color-paper: oklch(97% 0.008 80); } .glass-card { - @apply bg-glass-bg backdrop-blur-xl border border-white/5 shadow-warm rounded-xl; + @apply bg-glass-bg backdrop-blur-xl border border-white/5 shadow-warm rounded-xl; } diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 3db2cd9..65a532e 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,9 +1,266 @@ +import { + motion, + useMotionValueEvent, + useScroll, + useSpring, + useTransform, +} from "motion/react"; +import { useRef, useState } from "react"; import Logo from "../components/Logo"; +import { EnvelopeReveal } from "../components/reader/EnvelopeReveal"; +import { formatDate } from "../utils/dateFormat.ts"; export default function Home() { + const sectionContainer1 = useRef(null); + const { scrollYProgress: section1ScrollProgress } = useScroll({ + target: sectionContainer1, + }); + const smoothProgress = useSpring(section1ScrollProgress, { + stiffness: 100, + damping: 30, + restDelta: 0.001, + }); + const [isEnvelopeFlipped, setIsEnvelopeFlipped] = useState(true); + const [recipient, setRecipient] = useState("someone dear"); + const [ignite, setIgnite] = useState(false); + + useMotionValueEvent(section1ScrollProgress, "change", (latestScrollValue) => { + if (latestScrollValue <= 0.6) { + setIsEnvelopeFlipped(true); + } else { + setIsEnvelopeFlipped(false); + } + if (latestScrollValue > 0.68) { + setRecipient("future me"); + } else { + setRecipient("someone dear"); + } + if (latestScrollValue > 0.77) { + setIgnite(true); + } else { + setIgnite(false); + } + }); + return ( -
- -
+
+
+ +

+ You've been carrying something +

+

+ unsaid +

+
+ + +
+ and that's okay... +
+
+ + + + is a{" "} + + safe space + + ,
+ + where you can + +
+
+
+ + pen down your unsaid words into{" "} + + letters + + . + + + seal it{" "} + + secure + {" "} + and{" "} + + private + + . + + + send it to{" "} + + someone dear + + + {" "} + or{" "} + + yourself in the future + + . + + + + and even burn it to + release the burden. + +
+
+ + {}} + isFlip={isEnvelopeFlipped} + /> + + +
+
+
+
); }