diff --git a/package.json b/package.json index 0545f7a..16ec736 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "ngu-web-app", + "name": "figma-make-app", "private": true, "version": "1.0.0", "type": "module", @@ -13,7 +13,8 @@ "@fontsource/montserrat": "^5.3.0", "@fontsource/poppins": "^5.3.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router-dom": "^7.18.4" }, "devDependencies": { "@tailwindcss/vite": "^4.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ac6c0d..51fa4dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.2.4(react@19.2.4) + react-router-dom: + specifier: ^7.18.4 + version: 7.18.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) devDependencies: '@tailwindcss/vite': specifier: ^4.0.0 @@ -340,6 +343,10 @@ packages: babel-plugin-react-compiler: optional: true + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -471,6 +478,23 @@ packages: peerDependencies: react: ^19.2.4 + react-router-dom@7.18.4: + resolution: {integrity: sha512-yrfmJHIpDG7taCpqKjT1G5B6q3O2K+RN8/fgNf0lTjCwiPbQ0ei6vXX9ZjQR+7ld8Tr7Z5xmyMnZ8YJrphWQUw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.18.4: + resolution: {integrity: sha512-PUPQcMhMGRAslLcvtlPz/kmzBEWPhLdgLFrL7pLNepBL6dX0lWj4WD2cUYVgYCuT3jxvghYFg81cDTj44DhetQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -483,6 +507,9 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -767,6 +794,8 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.7 vite: 8.0.5(@types/node@22.19.17)(jiti@2.6.1) + cookie@1.1.1: {} + csstype@3.2.3: {} detect-libc@2.1.2: {} @@ -868,6 +897,20 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 + react-router-dom@7.18.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-router: 7.18.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + react-router@7.18.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + cookie: 1.1.1 + react: 19.2.4 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.4(react@19.2.4) + react@19.2.4: {} rolldown@1.0.0-rc.12: @@ -893,6 +936,8 @@ snapshots: scheduler@0.27.0: {} + set-cookie-parser@2.7.2: {} + source-map-js@1.2.1: {} tailwindcss@4.2.2: {} diff --git a/src/App.tsx b/src/App.tsx index 9f0dc69..d0e8d61 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import nguLogo from "@/NGU_Logo.svg"; import fallLogo from "@/Fall Logo.svg"; import nguLogo_WhiteBG from "@/NGU_Logo_WhiteBG.svg"; @@ -15,13 +15,10 @@ const DoveSVG = ({ className = "" }: { className?: string }) => ( ); -const InstagramIcon = () => ( - +const InstagramIcon = ({ id = "ig-gradient" }) => ( + - + @@ -52,11 +49,22 @@ const Social_Links = [ { label: "Discord", href: "https://discord.com/invite/AtngzpqaX5", Icon: DiscordIcon }, ] -const Nav_Links = [ - { label: "About", href: "#about"}, - { label: "Events", href: "#events"}, - { label: "Connect", href: "#connect"}, -] +const PAGE_LINKS = [ + { label: "Home", tab: "main" }, + { label: "Other", tab: "other" }, + { label: "Resources", tab: "resources" }, +]; + + +const PAGE_SECTIONS = { + main: [ + { label: "#About", href: "#about" }, + { label: "#Events", href: "#events" }, + { label: "#Connect", href: "#connect" }, + ], + other: [], + resources: [], +}; const Footer_Links = [ { label: "Privacy Policy", href: "#"}, @@ -64,6 +72,99 @@ const Footer_Links = [ { label: "Contact Us", href: "mailto:info@nextgenerationofunity.org"}, ] +const EVENTS = [ + { + id: "spring-2025", + title: "Spring Retreat 2026", + theme: "Altering Intertia", + date: "March/April 2026", + location: "Unity Village, MO", + image: fallLogo, // e.g. springLogo + color: "#f1c2fe", + gradient: + "linear-gradient(150deg, rgba(240, 224, 254, 1), rgba(255, 255, 255, 0.28))", + desc_a: + "A weekend of connection, workshops, and community for young adults across the Unity movement.", + desc_b: null, + status: "past", + links: [ + ], + }, + { + id: "fall-retreat-2026", + title: "Fall Retreat 2026", + theme: "Consciousness Creates", + date: "November 12-15th, 2026", + location: "Unity Village, MO", + image: fallLogo, + color: "#b89421", + gradient: + "linear-gradient(150deg, rgba(178, 150, 42, 0.45), rgba(230, 200, 120, 0.15) 65%, rgba(255, 255, 255, 0.28))", + desc_a: + "Join us for an exciting opportunity to connect with young adults from across the country through meaningful conversations, creative workshops, and shared artistic expression. All designed to shift your focus to your highest self.", + desc_b: "Registration starting at $150, and $75 lodging cost.", + status: "upcoming", + links: [ + { label: "Register Now!", link: "https://ngu.churchcenter.com/registrations/events/3761999" }, + { label: "Scholarship Application", link: "https://ngu.churchcenter.com/people/forms/1261992" }, + { label: "Volunteer", link: "https://ngu.churchcenter.com/people/forms/1176908" }, + ], + }, + { + id: "spring-recharge-2027", + title: "Spring Recharge 2027", + theme: "TBD", + date: "March 6th, 2027", + location: "Online", + image: null, // e.g. eventLogo + color: "#138ba0", + gradient: + null, + desc_a: + "One-day online event to reconnect in the spring.", + desc_b: null, + status: "upcoming", + links: [ + ], + }, + { + id: "spring-service-2027", + title: "Service Week 2027", + theme: "Leadership & Service", + date: "April 4-9th, 2027", + location: "Unity Village, MO", + image: null, // e.g. eventLogo + color: "#138ba0", + gradient: + null, + desc_a: + "Join us at beautiful Unity Village for a week of leadership development and service projects.", + desc_b: null, + status: "upcoming", + links: [ + ], + } +]; + +const START_INDEX = (() => { + const i = EVENTS.findIndex(e => e.status === "upcoming"); + return i === -1 ? EVENTS.length - 1 : i; +})(); + +const TEAL = "#138ba0"; + +const CARD = "min(48rem, 90vw)"; // the card itself — your original max-w-3xl +const GAP = "5rem"; // space between cards ← this is your knob +const SLIDE = `calc(${CARD} + ${GAP})`; +const HALF_SLIDE = `calc(${CARD} / 2)`; +const FADE_DIST = "18rem"; + +const EDGE_FADE = `linear-gradient(to right, + transparent calc(50% - (${HALF_SLIDE} + ${FADE_DIST})), + black calc(50% - ${HALF_SLIDE}), + black calc(50% + ${HALF_SLIDE}), + transparent calc(50% + (${HALF_SLIDE} + ${FADE_DIST})))`; + {/* Functions */} function WaveText({ text, baseDelay = 0, step = 0.1 }) { return ( @@ -81,51 +182,219 @@ function WaveText({ text, baseDelay = 0, step = 0.1 }) { ); } + + export default function App() { + {/* NAV functions*/} const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [activeTab, setActiveTab] = useState("main"); + const [activeSection, setActiveSection] = useState(null); + const sections = PAGE_SECTIONS[activeTab] ?? []; + const activePage = PAGE_LINKS.find((p) => p.tab === activeTab); + const goToPage = (tab) => { + setActiveTab(tab); + setActiveSection(null); + setMobileMenuOpen(false); + window.scrollTo({ top: 0 }); + }; + + // Highlight the section currently in view, so the second tier + // visibly tracks position within the page. + useEffect(() => { + if (sections.length === 0) return; + + const targets = sections + .map((s) => document.querySelector(s.href)) + .filter(Boolean); + if (targets.length === 0) return; + + const observer = new IntersectionObserver( + (entries) => { + const visible = entries + .filter((e) => e.isIntersecting) + .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0]; + if (visible) setActiveSection(`#${visible.target.id}`); + }, + { rootMargin: "-120px 0px -60% 0px", threshold: 0 } + ); + + targets.forEach((t) => observer.observe(t)); + return () => observer.disconnect(); + }, [activeTab]); + + {/* Other useState consts and Functions*/} + const [showCalendar, setShowCalendar] = useState(false); + const [index, setIndex] = useState(START_INDEX); + + const event = EVENTS[index]; + const isPast = event.status === "past"; + const currentColor = event.color || TEAL; + + const prev = () => setIndex(i => Math.max(0, i - 1)); + const next = () => setIndex(i => Math.min(EVENTS.length - 1, i + 1)); + + const arrowStyle = enabled => ({ + border: `1px solid ${TEAL}`, + background: "rgba(255,255,255,0.6)", + color: enabled ? TEAL : "#b8c6c9", + cursor: enabled ? "pointer" : "default", + opacity: enabled ? 1 : 0.4, + }); + + {/* Start of Main Content*/} return (
{/* ── NAV ─────────────────────────────────────────────── */} - + + {/* Tier 2 — sections of the current page */} + {sections.length > 0 && ( + + )} + + + {/* Keeps page content clear of the fixed header */} +
0 ? "h-[6.75rem]" : "h-[4.5rem]"} /> + {/* Mobile menu */} {mobileMenuOpen && ( -
- - {Nav_Links.map((link) => ( - setMobileMenuOpen(false)}> - {link.label} - - ))} - setMobileMenuOpen(false)}> +
+ + +
+ {PAGE_LINKS.map((page) => { + const pageSections = PAGE_SECTIONS[page.tab] ?? []; + const isActive = activeTab === page.tab; + + return ( + + ); + })} +
+ + setMobileMenuOpen(false)} + > Give
@@ -164,7 +433,7 @@ export default function App() {
- {/* ── ABOUT/INFO ─────────────────────────────────────── */} + {/* #About ─────────────────────────────────────── */}
@@ -189,51 +458,162 @@ export default function App() {
- {/* ── EVENTS ─────────────────────────────────────────────── */} -
-
-
-

- Upcoming Events -

-
- - {/* Featured event card */} -
-
-
-
- Next Generation of Unity -

Fall Retreat 2026

-

"Consciousness Creates"

-

November 12-15th, 2026

-

Unity Village, MO

-
-
- Next Generation of Unity -
-
-

Join us for an exciting opportunity to connect with young adults from across the country through meaningful conversations, creative workshops, and shared artistic expression. All designed to shift your focus your highest self.

-

Registration starting at $150, and $75 loding cost.

- -
- {[ - { label: "Register Now!", link:"https://ngu.churchcenter.com/registrations/events/3761999"}, - { label: "Small Group Leader Application", link:"https://ngu.churchcenter.com/people/forms/1285944"}, - { label: "Scholarship Application", link:"https://ngu.churchcenter.com/people/forms/1261992"}, - ].map(item => ( - - {item.label} - - ))} -
-
-
- -

· More events coming soon, stay connected for announcements ·

+ {/* #Events ─────────────────────────────────────────────── */} +
+
+
+

+ {isPast ? "Past Events" : "Upcoming Events"} +

+
+ + {/* Carousel — full-bleed so neighbors can peek in from the screen edges */} +
+ {/* Masked viewport: everything outside the fade gradient is invisible */} +
+ {/* Sliding track */} +
+ {EVENTS.map((ev, i) => { + const active = i === index; + const past = ev.status === "past"; + const color = ev.color || TEAL; + return ( +
!active && setIndex(i)} + aria-hidden={!active} + > +
+
+
+
+ Next Generation of Unity +

{ev.title}

+ {ev.theme && ( +

"{ev.theme}"

+ )} +

{ev.date}

+

{ev.location}

+
+
+ {ev.image && ( + {ev.title} + )} +
+
+ + {ev.desc_a &&

{ev.desc_a}

} + {ev.desc_b &&

{ev.desc_b}

} + + {ev.links.length > 0 ? ( +
+ {ev.links.map(item => ( + + {item.label} + + ))} +
+ ) : ( + past ? ( +

+ This event has concluded, thank you to everyone who joined us! +

+ ) : ( + <> +

+ Registration has not opened yet, follow our instagram for more details. +

+ + + @nextgenerationunity + + + ) + )} +
+
+
+ ); + })} +
+
+ + {/* Arrows — outside the masked element so they never fade */} + + +
+ +
+ {/* Dot indicators */} +
+ {EVENTS.map((e, i) => ( +
+ +

+ · More events coming soon, stay connected for announcements · +

+
- {/* ── CONNECT / SOCIALS ─────────────────────────────────── */} + {/* #Connect -------------------------------------------- */}
@@ -263,17 +643,48 @@ export default function App() { ))}
-
- - 📅 View NGU Calendar - +
+ + 📅 View NGU Calendar + + + + + + + + +
+ + {showCalendar && ( +
+