Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ const FindTeam = () => {
</div>
) : teams.length > 0 ? (
<>
<div className='grid grid-cols-1 gap-6 lg:grid-cols-2'>
<div className='grid grid-cols-1 gap-6'>
{teams.map(team => (
<TeamCard
key={team.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useState } from 'react';
import Link from 'next/link';
import { useParams, useRouter } from 'next/navigation';
import { useQueryClient } from '@tanstack/react-query';
import { LayoutGrid, Loader2, Pencil, Trash2 } from 'lucide-react';
Expand Down Expand Up @@ -142,7 +143,24 @@ const SubmissionCard = ({ submission }: SubmissionCardProps) => {
<div className='flex items-center justify-between gap-2 border-t border-white/5 pt-5'>
<div className='flex items-center gap-3'>
{isTeam ? (
<GroupAvatar members={teamMembers.map(m => m.avatar ?? '')} />
<GroupAvatar
members={teamMembers.map(m => m.avatar ?? '')}
usernames={teamMembers.map(m => m.username)}
/>
) : participant?.username ? (
<Link
href={`/profile/${participant.username}`}
target='_blank'
rel='noopener noreferrer'
aria-label={`View @${participant.username} profile`}
className='hover:opacity-90'
>
<BasicAvatar
image={submitterAvatar}
name={submitterName}
username={participant.username}
/>
</Link>
) : (
<BasicAvatar
image={submitterAvatar}
Expand Down
38 changes: 29 additions & 9 deletions components/avatars/GroupAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Link from 'next/link';
import {
Avatar,
AvatarFallback,
Expand All @@ -8,24 +9,43 @@ import {

interface GroupAvatarProps {
members: string[];
usernames?: (string | undefined)[];
}

const GroupAvatar = ({ members }: GroupAvatarProps) => {
const GroupAvatar = ({ members, usernames }: GroupAvatarProps) => {
const showCount = members.length > 3;
const maxVisible = showCount ? 3 : members.length;
const visibleMembers = members.slice(0, maxVisible);
const remainingCount = members.length - maxVisible;

return (
<AvatarGroup>
{visibleMembers.map((member, index) => (
<Avatar key={index} className='size-8 border-none! sm:size-6'>
<AvatarImage src={member} alt={`Member ${index + 1}`} />
<AvatarFallback className='bg-[#1E2329] text-[10px] text-white'>
{member.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
))}
{visibleMembers.map((member, index) => {
const username = usernames?.[index];
const avatar = (
<Avatar className='size-8 border-none! sm:size-6'>
<AvatarImage src={member} alt={`Member ${index + 1}`} />
<AvatarFallback className='bg-[#1E2329] text-[10px] text-white'>
{member.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
);
if (username) {
return (
<Link
key={index}
href={`/profile/${username}`}
target='_blank'
rel='noopener noreferrer'
aria-label={`View @${username} profile`}
className='hover:ring-primary/40 rounded-full transition-all hover:ring-2'
>
{avatar}
</Link>
);
}
return <div key={index}>{avatar}</div>;
})}
{remainingCount > 0 && (
<AvatarGroupCount className='bg-background text-foreground ring-border size-8 text-xs font-bold ring-2 sm:size-6 sm:text-xs'>
+{remainingCount}
Expand Down
100 changes: 47 additions & 53 deletions components/ui/pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React from 'react';
import { BoundlessButton } from '../buttons';
import {
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
} from 'lucide-react';
import { Button } from '@/components/ui/button';

interface PaginationProps {
currentPage: number;
Expand All @@ -18,64 +24,52 @@ const Pagination: React.FC<PaginationProps> = ({
return null;
}

const canPrev = currentPage > 1;
const canNext = currentPage < totalPages;

return (
<div className={`mt-6 w-full border-t border-[#2B2B2B] pt-4 ${className}`}>
<div className='flex items-center justify-between'>
<span className='text-sm text-gray-400'>
<div className={`flex items-center justify-end px-2 ${className}`}>
<div className='flex items-center space-x-6 lg:space-x-8'>
<div className='flex w-[100px] items-center justify-center text-sm font-medium text-white'>
Page {currentPage} of {totalPages}
</span>

<div className='flex gap-2'>
<BoundlessButton
</div>
<div className='flex items-center space-x-2'>
<Button
size='icon'
className='bg-primary text-primary-foreground hover:bg-primary/90 hidden size-8 lg:flex'
onClick={() => onPageChange(1)}
disabled={!canPrev}
>
<span className='sr-only'>Go to first page</span>
<ChevronsLeft />
</Button>
<Button
size='icon'
className='bg-primary text-primary-foreground hover:bg-primary/90 size-8'
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
size='sm'
variant='outline'
className=''
disabled={!canPrev}
>
Previous
</BoundlessButton>

{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => {
if (
page === 1 ||
page === totalPages ||
Math.abs(page - currentPage) <= 1
) {
return (
<BoundlessButton
key={page}
onClick={() => onPageChange(page)}
size='sm'
variant={currentPage === page ? 'default' : 'outline'}
className={
currentPage === page
? 'bg-blue-600'
: 'border-[#2B2B2B] text-white hover:bg-[#2B2B2B]'
}
>
{page}
</BoundlessButton>
);
} else if (page === currentPage - 2 || page === currentPage + 2) {
return (
<span key={page} className='px-2 text-gray-500'>
...
</span>
);
}
return null;
})}

<BoundlessButton
<span className='sr-only'>Go to previous page</span>
<ChevronLeft />
</Button>
<Button
size='icon'
className='bg-primary text-primary-foreground hover:bg-primary/90 size-8'
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
size='sm'
variant='outline'
className='border-[#2B2B2B] text-white'
disabled={!canNext}
>
<span className='sr-only'>Go to next page</span>
<ChevronRight />
</Button>
<Button
size='icon'
className='bg-primary text-primary-foreground hover:bg-primary/90 hidden size-8 lg:flex'
onClick={() => onPageChange(totalPages)}
disabled={!canNext}
>
Next
</BoundlessButton>
<span className='sr-only'>Go to last page</span>
<ChevronsRight />
</Button>
</div>
</div>
</div>
Expand Down
Loading