diff --git a/app/components/ScrollRevealWrapper.tsx b/app/components/ScrollRevealWrapper.tsx index a258086..214891c 100644 --- a/app/components/ScrollRevealWrapper.tsx +++ b/app/components/ScrollRevealWrapper.tsx @@ -14,31 +14,36 @@ export default function ScrollRevealWrapper({ children, instant = false }: Scrol useEffect(() => { if (instant) return; + const current = domRef.current; + if (!current) return; + const observer = new IntersectionObserver( ([entry]) => { - setIsVisible(entry.isIntersecting); + if (entry.isIntersecting) { + setIsVisible(true); + observer.unobserve(entry.target); + } }, { - threshold: 0.05, - rootMargin: "-6% 0px -6% 0px", + threshold: 0.02, + rootMargin: "0px 0px -50px 0px", } ); - const current = domRef.current; - if (current) observer.observe(current); + observer.observe(current); return () => { - if (current) observer.unobserve(current); + observer.disconnect(); }; }, [instant]); return (
{children} diff --git a/app/globals.css b/app/globals.css index 8dd5450..02dcbfb 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1255,6 +1255,7 @@ main>div { animation-delay: 0.5s; opacity: 0; } + /* ─── Signed-in avatar in the navbar ──────────────────────────────── * Replaces the Login pill once a session is restored, matching what the * previous navbar did. Sized to the pill's height so swapping between the @@ -1316,9 +1317,15 @@ main>div { * Applies only below the tablet breakpoint, so the compact desktop styling of * the admin forms is untouched. */ @media (max-width: 768px) { + input, select, textarea { font-size: 16px; } } + +input[type="checkbox"], +input[type="radio"] { + accent-color: #ff5500; +} \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index 93e3438..204cccd 100644 --- a/next.config.ts +++ b/next.config.ts @@ -54,6 +54,19 @@ const nextConfig: NextConfig = { ]; }, + async redirects() { + return [ + // Permanent redirect for printed QR code that points to the old event. + // The QR is already in circulation so we redirect server-side (308) so + // every scanner, browser and search engine follows it automatically. + { + source: "/Events/6a74c22b4a467d7a0aac0cc6", + destination: "/Events/6a7797c26a9a4d018da54ba1", + permanent: true, + }, + ]; + }, + // Note: legacy capitalised URLs (/Events, /Team, /SignUp …) are *not* // redirected here. Next matches a redirect `source` case-insensitively, so a // rule from "/Events" to "/events" also matches "/events" and loops diff --git a/src/components/Core/Input.jsx b/src/components/Core/Input.jsx index 25cca67..971a6e4 100644 --- a/src/components/Core/Input.jsx +++ b/src/components/Core/Input.jsx @@ -143,7 +143,7 @@ const Input = (props) => { containerStyle, style, placeholder, - value, + value = "", onChange, label, options, @@ -169,6 +169,8 @@ const Input = (props) => { return currentDate.getTime() < selectedDate.getTime(); }; + const safeValue = value ?? ""; + const getInputTypes = () => { switch (type) { case "text": @@ -179,7 +181,7 @@ const Input = (props) => { type={type} style={style || {}} placeholder={placeholder} - value={value} + value={safeValue} onChange={onChange} {...rest} /> @@ -193,7 +195,7 @@ const Input = (props) => { type={type} style={style || {}} placeholder={placeholder} - value={value} + value={safeValue} onChange={onChange} {...rest} /> @@ -207,7 +209,7 @@ const Input = (props) => { type={type} style={style || {}} placeholder={placeholder} - value={value} + value={safeValue} onChange={onChange} {...rest} /> @@ -281,31 +283,20 @@ const Input = (props) => { ); case "radio": return ( -
+
@@ -313,31 +304,20 @@ const Input = (props) => { ); case "checkbox": return ( -
+
@@ -360,7 +340,7 @@ const Input = (props) => { type={showPassword ? "text" : "password"} style={style || {}} placeholder={placeholder} - value={value} + value={safeValue} onChange={onChange} {...rest} /> @@ -515,7 +495,7 @@ const Input = (props) => { type={type} style={style || {}} placeholder={placeholder} - value={value} + value={safeValue} onChange={onChange} {...rest} /> diff --git a/src/components/Core/styles/Core.module.scss b/src/components/Core/styles/Core.module.scss index 11cd791..954eb0e 100644 --- a/src/components/Core/styles/Core.module.scss +++ b/src/components/Core/styles/Core.module.scss @@ -54,10 +54,89 @@ font-weight: normal; } -.containerInput { +.checkboxWrapper { + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 12px; + margin: 12px 0; + cursor: pointer; + user-select: none; +} + +.checkboxInput { + appearance: none; + -webkit-appearance: none; + width: 20px !important; + height: 20px !important; + min-width: 20px !important; + min-height: 20px !important; + max-width: 20px !important; + max-height: 20px !important; + border-radius: 6px !important; + border: 1.5px solid rgba(255, 255, 255, 0.35) !important; + background-color: rgba(255, 255, 255, 0.05) !important; + margin: 2px 0 0 0 !important; + padding: 0 !important; + cursor: pointer; position: relative; - width: auto; + outline: none; + flex-shrink: 0; + transition: all 0.2s ease; + + &:hover { + border-color: #ff8a00 !important; + } + + &:checked { + background-color: #ff5500 !important; + border-color: #ff5500 !important; + + &::after { + content: ""; + position: absolute; + left: 6px; + top: 2px; + width: 5px; + height: 10px; + border: solid #ffffff; + border-width: 0 2.5px 2.5px 0; + transform: rotate(45deg); + } + } + + &:focus-visible { + box-shadow: 0 0 0 2px rgba(255, 138, 0, 0.4); + } +} + +:global(input[type="radio"].checkboxInput), +.checkboxInput[type="radio"] { + border-radius: 50% !important; + + &:checked::after { + content: ""; + position: absolute; + top: 5px; + left: 5px; + width: 8px; + height: 8px; + border: none; + border-radius: 50%; + background-color: #ffffff; + transform: none; + } } + +.checkboxLabel { + color: #ffffff; + font-size: 0.875rem; + line-height: 1.45; + cursor: pointer; + margin: 0; + user-select: none; +} + .input { display: flex; outline: none; diff --git a/src/features/Modals/Profile/Admin/PreviewForm.jsx b/src/features/Modals/Profile/Admin/PreviewForm.jsx index 1781dab..6381a75 100644 --- a/src/features/Modals/Profile/Admin/PreviewForm.jsx +++ b/src/features/Modals/Profile/Admin/PreviewForm.jsx @@ -654,7 +654,7 @@ const PreviewForm = ({ ₹{eventAmount}

-
+
{safeLink ? ( +