fix style

This commit is contained in:
2026-01-29 01:18:45 -05:00
parent 23a5495f67
commit 8b628822ec
3 changed files with 107 additions and 6 deletions

View File

@@ -196,6 +196,16 @@ body {
color: var(--text-muted); color: var(--text-muted);
} }
.challenge-detail-layout {
display: grid;
gap: 2rem;
grid-template-columns: minmax(0, 1fr) 300px;
}
#leaderboard-mobile {
display: none;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.nav { .nav {
flex-direction: column; flex-direction: column;
@@ -223,6 +233,19 @@ body {
.btn { .btn {
width: 100%; width: 100%;
} }
/* Show mobile leaderboard, hide desktop sidebar */
#leaderboard-mobile {
display: block;
}
.challenge-sidebar {
display: none;
}
.challenge-detail-layout {
grid-template-columns: 1fr;
}
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {

View File

@@ -196,9 +196,31 @@ export default function ChallengeDetail() {
</div> </div>
)} )}
<div style={{ display: 'grid', gap: '2rem', gridTemplateColumns: 'minmax(0, 1fr) 300px' }}> {/* Leaderboard - Desktop: Sidebar, Mobile: Top */}
<div className="card" style={{ marginBottom: '2rem' }} id="leaderboard-mobile">
<h3 style={{ marginBottom: '1rem' }}>Leaderboard</h3>
{leaderboard.length === 0 ? (
<p style={{ color: 'var(--text-muted)', fontSize: '0.875rem' }}>No points yet</p>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
{leaderboard.map((entry, index) => (
<div key={entry.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<span style={{ marginRight: '0.5rem', color: 'var(--text-muted)' }}>{index + 1}.</span>
<strong>{entry.username}</strong>
</div>
<span style={{ color: 'var(--primary)', fontWeight: 600 }}>
{entry.validated_points} pts
</span>
</div>
))}
</div>
)}
</div>
<div className="challenge-detail-layout">
{/* Main Content */} {/* Main Content */}
<div> <div className="challenge-main">
{/* New Prediction */} {/* New Prediction */}
<div className="card" style={{ marginBottom: '2rem' }}> <div className="card" style={{ marginBottom: '2rem' }}>
<h3 style={{ marginBottom: '1rem' }}>Make a Prediction</h3> <h3 style={{ marginBottom: '1rem' }}>Make a Prediction</h3>
@@ -272,8 +294,8 @@ export default function ChallengeDetail() {
)} )}
</div> </div>
{/* Sidebar - Leaderboard */} {/* Sidebar - Leaderboard (Desktop only) */}
<div> <div className="challenge-sidebar">
<div className="card"> <div className="card">
<h3 style={{ marginBottom: '1rem' }}>Leaderboard</h3> <h3 style={{ marginBottom: '1rem' }}>Leaderboard</h3>
{leaderboard.length === 0 ? ( {leaderboard.length === 0 ? (

View File

@@ -4,6 +4,7 @@ import api from '../api';
export default function ChallengeList() { export default function ChallengeList() {
const [challenges, setChallenges] = useState([]); const [challenges, setChallenges] = useState([]);
const [pendingInvites, setPendingInvites] = useState([]);
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [showResults, setShowResults] = useState([]); const [showResults, setShowResults] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -18,6 +19,10 @@ export default function ChallengeList() {
try { try {
const data = await api.getChallenges(); const data = await api.getChallenges();
setChallenges(data.challenges); setChallenges(data.challenges);
// Filter out pending invitations
const pending = data.challenges.filter(c => c.participation_status === 'pending');
setPendingInvites(pending);
} catch (err) { } catch (err) {
console.error('Failed to load challenges:', err); console.error('Failed to load challenges:', err);
} finally { } finally {
@@ -25,6 +30,15 @@ export default function ChallengeList() {
} }
}; };
const handleRespondToInvite = async (challengeId, status) => {
try {
await api.respondToChallenge(challengeId, status);
await loadChallenges();
} catch (err) {
alert('Failed to respond: ' + err.message);
}
};
const handleSearch = (query) => { const handleSearch = (query) => {
setSearchQuery(query); setSearchQuery(query);
@@ -84,6 +98,48 @@ export default function ChallengeList() {
<div className="container"> <div className="container">
<h1 style={{ marginBottom: '2rem' }}>My Challenges</h1> <h1 style={{ marginBottom: '2rem' }}>My Challenges</h1>
{/* Pending Invitations */}
{pendingInvites.length > 0 && (
<div className="card" style={{ marginBottom: '2rem', background: 'var(--bg-lighter)' }}>
<h3 style={{ marginBottom: '1rem' }}>📬 Pending Invitations</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
{pendingInvites.map(challenge => (
<div key={challenge.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }}>
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center', flex: 1 }}>
{challenge.cover_image_url && (
<img
src={challenge.cover_image_url}
alt={challenge.title}
style={{ width: '40px', height: '60px', objectFit: 'cover', borderRadius: '0.25rem' }}
/>
)}
<div>
<div style={{ fontWeight: 500 }}>{challenge.title}</div>
<div style={{ fontSize: '0.875rem', color: 'var(--text-muted)' }}>
Invited by {challenge.creator_username}
</div>
</div>
</div>
<div style={{ display: 'flex', gap: '0.5rem' }}>
<button
className="btn btn-success btn-sm"
onClick={() => handleRespondToInvite(challenge.id, 'accepted')}
>
Accept
</button>
<button
className="btn btn-danger btn-sm"
onClick={() => handleRespondToInvite(challenge.id, 'rejected')}
>
Decline
</button>
</div>
</div>
))}
</div>
</div>
)}
{/* Search/Create */} {/* Search/Create */}
<div style={{ marginBottom: '2rem', position: 'relative' }}> <div style={{ marginBottom: '2rem', position: 'relative' }}>
<input <input
@@ -141,13 +197,13 @@ export default function ChallengeList() {
</div> </div>
{/* Challenge List */} {/* Challenge List */}
{challenges.length === 0 ? ( {challenges.filter(c => c.participation_status !== 'pending').length === 0 ? (
<div className="card" style={{ textAlign: 'center', padding: '3rem' }}> <div className="card" style={{ textAlign: 'center', padding: '3rem' }}>
<p style={{ color: 'var(--text-muted)' }}>No challenges yet. Search for a show above to create one!</p> <p style={{ color: 'var(--text-muted)' }}>No challenges yet. Search for a show above to create one!</p>
</div> </div>
) : ( ) : (
<div className="grid grid-2"> <div className="grid grid-2">
{challenges.map(challenge => ( {challenges.filter(c => c.participation_status !== 'pending').map(challenge => (
<Link key={challenge.id} to={`/challenges/${challenge.id}`} style={{ textDecoration: 'none' }}> <Link key={challenge.id} to={`/challenges/${challenge.id}`} style={{ textDecoration: 'none' }}>
<div className="card" style={{ height: '100%', display: 'flex', gap: '1rem' }}> <div className="card" style={{ height: '100%', display: 'flex', gap: '1rem' }}>
{challenge.cover_image_url && ( {challenge.cover_image_url && (