From f031618cf5611354a1d292248707252560a6fe52 Mon Sep 17 00:00:00 2001 From: aniket Date: Tue, 10 Feb 2026 20:35:03 +0530 Subject: [PATCH 1/2] fix: testimonials carousel swipe navigation stuck on mobile (#1667) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add touchEventsTarget='container' to Swiper so touch listeners attach to container instead of wrapper - Add grabCursor for visual drag feedback on desktop - Fix className bug: home && 'h-32' → home ? 'h-32' : '' to prevent 'false' string in DOM - Add touchAction: 'pan-y' on blockquote to allow horizontal swipes to pass through to Swiper Closes #1667 --- src/common/Testimonial/TestimonialCard.jsx | 5 ++++- src/common/Testimonial/TestimonialSection.jsx | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/Testimonial/TestimonialCard.jsx b/src/common/Testimonial/TestimonialCard.jsx index 099961a016..c2e0c29ce0 100644 --- a/src/common/Testimonial/TestimonialCard.jsx +++ b/src/common/Testimonial/TestimonialCard.jsx @@ -53,7 +53,10 @@ const TestimonialCard = ({ home, quote, name, avatarUrl, category, created_at, e
-
+

{testimonials && testimonials.map((testimonial) => ( From 845da22f31e723624352780c2f8b04939304e8b8 Mon Sep 17 00:00:00 2001 From: aniket Date: Wed, 11 Feb 2026 15:06:53 +0530 Subject: [PATCH 2/2] fix: mobile drawer, navbar layout, testimonials error handling, leaderboard UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix mobile drawer not closing on outside click (useRef + click-outside listener) - Fix CSS transform creating containing block issue (translateY(0) → none) - Add global padding-top for fixed navbar offset (64px, excluding footer) - Add extra home hero padding for activity banner - Add try/catch error handling in testimonial fetches - Fix ESLint jsx-sort-props (shorthand booleans first) - Center leaderboard loading spinner - Remove overflow-hidden from leaderboard page - Import leaderBoard.css in LeaderBoard component --- package.json | 2 +- src/common/Testimonial/TestimonialSection.jsx | 11 ++++++--- src/common/Testimonial/Testimonials.jsx | 9 ++++++-- src/common/header/HeaderNav.jsx | 23 ++++++++++++++++++- src/common/header/header.css | 7 +++++- src/common/home/home.css | 1 + src/common/playleaderboard/LeaderBoard.jsx | 3 ++- src/common/playleaderboard/leaderBoard.css | 7 ++++++ 8 files changed, 54 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index b93fd03b76..3452393ee8 100644 --- a/package.json +++ b/package.json @@ -157,6 +157,6 @@ "react-snap": "^1.23.0", "tailwind-scrollbar": "^2.1.0", "tailwindcss": "^3.4.1", - "typescript": "^5.3.3" + "typescript": "^5.9.3" } } diff --git a/src/common/Testimonial/TestimonialSection.jsx b/src/common/Testimonial/TestimonialSection.jsx index 5404f01419..6740015d6e 100644 --- a/src/common/Testimonial/TestimonialSection.jsx +++ b/src/common/Testimonial/TestimonialSection.jsx @@ -18,8 +18,13 @@ function TestimonialSection() { const [testimonials, setTestimonials] = useState([]); const fetchTestimonials = async () => { - const res = await submit(fetchTestimonialsHomePage()); - setTestimonials(res); + try { + const res = await submit(fetchTestimonialsHomePage()); + setTestimonials(res || []); + } catch (error) { + console.warn('Failed to fetch testimonials:', error.message); + setTestimonials([]); + } }; useEffect(() => { @@ -30,8 +35,8 @@ function TestimonialSection() { <>

{ const isAuthenticated = useAuthenticated(); const fetchTestimonials = async () => { - const res = await submit(fetchAllTestimonials()); - setTestimonials(res); + try { + const res = await submit(fetchAllTestimonials()); + setTestimonials(res || []); + } catch (error) { + console.warn('Failed to fetch testimonials:', error.message); + setTestimonials([]); + } }; const handleLogin = (value) => { diff --git a/src/common/header/HeaderNav.jsx b/src/common/header/HeaderNav.jsx index 3952f8af71..dadcf16a68 100644 --- a/src/common/header/HeaderNav.jsx +++ b/src/common/header/HeaderNav.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { Link } from 'react-router-dom'; import { BsGithub, BsTrophyFill } from 'react-icons/bs'; import { FaLightbulb } from 'react-icons/fa'; @@ -16,6 +16,26 @@ const HeaderNav = ({ showBrowse }) => { const { showShareModal, setShowShareModal } = useSearchContext(); const [showToggleMenu, setShowToggleMenu] = useState(false); + const menuRef = useRef(null); + + // Close drawer when clicking outside the menu panel + useEffect(() => { + if (!showToggleMenu) return; + + const handleClickOutside = (event) => { + if (menuRef.current && !menuRef.current.contains(event.target)) { + setShowToggleMenu(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('touchstart', handleClickOutside); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('touchstart', handleClickOutside); + }; + }, [showToggleMenu]); const [anchorEl, setAnchorEl] = useState(null); @@ -129,6 +149,7 @@ const HeaderNav = ({ showBrowse }) => {
    e.stopPropagation()} >
  • diff --git a/src/common/header/header.css b/src/common/header/header.css index 75f9a7edba..af27735658 100644 --- a/src/common/header/header.css +++ b/src/common/header/header.css @@ -29,7 +29,12 @@ } .nav--visible { - transform: translateY(0); + transform: none; +} + +/* Push page content below the fixed header, but not the footer */ +.nav-wrapper ~ *:not(footer) { + padding-top: 64px; } diff --git a/src/common/home/home.css b/src/common/home/home.css index 359d036884..3a12a3df95 100644 --- a/src/common/home/home.css +++ b/src/common/home/home.css @@ -13,6 +13,7 @@ width: 100%; overflow-x: hidden; min-height: 100vh; + padding-top: 32px; /* extra offset for activity banner on home page */ } .app-home-body .app-home-body-content { diff --git a/src/common/playleaderboard/LeaderBoard.jsx b/src/common/playleaderboard/LeaderBoard.jsx index 32856f0706..9c38583321 100644 --- a/src/common/playleaderboard/LeaderBoard.jsx +++ b/src/common/playleaderboard/LeaderBoard.jsx @@ -6,6 +6,7 @@ import TopPlayCreators from './TopPlayCreators'; import { Watch } from 'react-loader-spinner'; import { groupBy } from 'lodash'; import { format, lastDayOfMonth } from 'date-fns'; +import './leaderBoard.css'; const LeaderBoard = () => { const [top10Contributors, updateTop10Contributors] = useState([]); @@ -69,7 +70,7 @@ const LeaderBoard = () => { }, [publishedPlays]); return ( -
    +
    {publishedPlays.length && (topContributorOfTheMonth || top10Contributors) ? (
    {topContributorOfTheMonth && ( diff --git a/src/common/playleaderboard/leaderBoard.css b/src/common/playleaderboard/leaderBoard.css index bab6f4799f..3342155873 100644 --- a/src/common/playleaderboard/leaderBoard.css +++ b/src/common/playleaderboard/leaderBoard.css @@ -38,6 +38,13 @@ height: 100vh; } */ +.leaderboard-loader { + display: flex; + align-items: center; + justify-content: center; + min-height: calc(100vh - 160px); +} + .leaderboard-wrapper { background-color: #ffffff; border-radius: 16px;