From 9b67aa75baee7835897aa4b36ad1c21ac7bd4b89 Mon Sep 17 00:00:00 2001 From: Hy Nguyen Date: Sat, 5 Oct 2024 04:24:31 -0500 Subject: [PATCH] animate headlines and add highlight briefs --- app/components/Footer.tsx | 2 +- app/routes/_index/BriefCard.tsx | 36 ++++++++++++++++ app/routes/_index/Headlines.tsx | 54 ++++++++++++++++++++++++ app/routes/_index/index.tsx | 73 ++++++++++++++++----------------- app/routes/pay._index/index.tsx | 2 +- app/routes/store/TagsFilter.tsx | 2 +- app/tailwind.css | 10 +++-- package.json | 1 + yarn.lock | 5 +++ 9 files changed, 141 insertions(+), 44 deletions(-) create mode 100644 app/routes/_index/BriefCard.tsx create mode 100644 app/routes/_index/Headlines.tsx diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx index 2cf4028..1f08363 100644 --- a/app/components/Footer.tsx +++ b/app/components/Footer.tsx @@ -1,6 +1,6 @@ export default function Footer() { return ( -
+

© {new Date().getFullYear()} TOYSHOP

diff --git a/app/routes/_index/BriefCard.tsx b/app/routes/_index/BriefCard.tsx new file mode 100644 index 0000000..77b2563 --- /dev/null +++ b/app/routes/_index/BriefCard.tsx @@ -0,0 +1,36 @@ +import { useInView } from "react-intersection-observer"; +import { HighlightInfo } from "."; + +type Props = { + highlight: HighlightInfo; +}; + +export default function BriefCard({ highlight }: Props) { + const { ref: briefRef, inView: briefInView } = useInView({ + threshold: 0.5, // How much visible to trigger + triggerOnce: true, + }); + + return ( +
+
+

+ {highlight.headline} +

+

+ {highlight.brief.split(" ").map((word, index) => ( + +  {word} + + ))} +

+
+
+ ); +} diff --git a/app/routes/_index/Headlines.tsx b/app/routes/_index/Headlines.tsx new file mode 100644 index 0000000..742a2ea --- /dev/null +++ b/app/routes/_index/Headlines.tsx @@ -0,0 +1,54 @@ +import { HighlightInfo } from "."; +import { useEffect, useRef, useState } from "react"; + +type Props = { + highlight: HighlightInfo; +}; + +export default function Headlines({ highlight }: Props) { + const containerRef = useRef(null); + const [headlineWidth, setHeadlineWidth] = useState(0); + + // Update scrollY on scroll + useEffect(() => { + const handleScroll = () => { + if (!containerRef.current) return; + const clientRect = containerRef.current.getBoundingClientRect(); + const percentage = + (100 / clientRect.height) * + (clientRect.height - clientRect.bottom); + // add 5% to fill up sooner + setHeadlineWidth(Math.min(Math.max(percentage + 5, 0), 100)); + }; + + window.addEventListener("scroll", handleScroll); + return () => { + window.removeEventListener("scroll", handleScroll); + }; + }, []); + + return ( +
+ {/* Headline image */} +
+
+ +
+ +
+
+
+
+ ); +} diff --git a/app/routes/_index/index.tsx b/app/routes/_index/index.tsx index ec1bbce..f19645c 100644 --- a/app/routes/_index/index.tsx +++ b/app/routes/_index/index.tsx @@ -9,6 +9,8 @@ import save_outline from "~/assets/landing_page/headlines/save_outline.png"; import save_fill from "~/assets/landing_page/headlines/save_fill.png"; import share_outline from "~/assets/landing_page/headlines/share_outline.png"; import share_fill from "~/assets/landing_page/headlines/share_fill.png"; +import Headlines from "./Headlines"; +import BriefCard from "./BriefCard"; export const meta: MetaFunction = () => { return [ @@ -17,30 +19,33 @@ export const meta: MetaFunction = () => { ]; }; -export default function Index() { - const highlights: { - headline: [string, string]; // [outline, fill] - brief: string; - }[] = [ +export type HighlightInfo = { + headline: string; + headlineImages: [string, string]; // [outline, fill] + brief: string; +}; + +export default function LandingPage() { + const highlights: HighlightInfo[] = [ { - // EXPLORE - headline: [explore_outline, explore_fill], - brief: "exploreeee", + headline: "Explore", + headlineImages: [explore_outline, explore_fill], + brief: "Browse our huge selection of unique and exciting toys, from futuristic vehicles to powerful battle machines, all waiting to be explored.", }, { - // COLLECT - headline: [collect_outline, collect_fill], - brief: "colllecettt", + headline: "Collect", + headlineImages: [collect_outline, collect_fill], + brief: "Build your ultimate collection with limited editions and series designed for true enthusiasts and collectors alike.", }, { - // SAVE - headline: [save_outline, save_fill], - brief: "sassavavee", + headline: "Save", + headlineImages: [save_outline, save_fill], + brief: "Save big on every purchase! We offer unbeatable deals and exclusive discounts. Don't miss our regular flash sales for your favorite toys!", }, { - // SHARE - headline: [share_outline, share_fill], - brief: "shharrree", + headline: "Share", + headlineImages: [share_outline, share_fill], + brief: "Join the conversation! Share your experience, rate your favorites, and help others find the perfect toy by leaving your feedback and reviews.", }, ]; @@ -48,31 +53,23 @@ export default function Index() {
{/* Hero section */} -
+

Welcome

+ + {/* Headlines scrollzone */} {highlights.map((highlight, i) => ( -
-
-
- -
- -
-
-
-

- {highlight.brief} Online store for toys. Online store - for toys. Online store for toys. Online store for toys. -

-
+ ))} + + {/* Highlight briefs */} +
+
+ {highlights.map((highlight, i) => ( + + ))} +
+
); } diff --git a/app/routes/pay._index/index.tsx b/app/routes/pay._index/index.tsx index 9e86b5a..9b5cdc1 100644 --- a/app/routes/pay._index/index.tsx +++ b/app/routes/pay._index/index.tsx @@ -42,7 +42,7 @@ export default function PayPageDefault() {

Note: this is a demo project, do not enter real information. To - test payment, please enter card number: 4242 4242 4242 4242. + test payment, please enter card number 4242 4242 4242 4242 and any valid value for the rest.

diff --git a/app/routes/store/TagsFilter.tsx b/app/routes/store/TagsFilter.tsx index 854305d..3d6bd6b 100644 --- a/app/routes/store/TagsFilter.tsx +++ b/app/routes/store/TagsFilter.tsx @@ -50,7 +50,7 @@ export default function TagsFilter({ <>