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/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
+{ - 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,6 +35,7 @@ function TestimonialSection() { <>
{testimonials && testimonials.map((testimonial) => ( diff --git a/src/common/Testimonial/Testimonials.jsx b/src/common/Testimonial/Testimonials.jsx index d082f63922..cb5a8cfe25 100644 --- a/src/common/Testimonial/Testimonials.jsx +++ b/src/common/Testimonial/Testimonials.jsx @@ -15,8 +15,13 @@ const Testimonials = () => { 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;