refactor(ui): strip all dark: Tailwind classes (single-theme product)
All checks were successful
Build and Push Docker Image / build (push) Successful in 12m17s

Mechanical sweep of 41 files via `perl -i -pe 's{\s+dark:[\w:/\[\]\.\-]+}{}g'`.
All dark: variants were paired with light-mode counterparts already; no
elements relied on a dark:-only style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt
2026-05-22 18:45:42 +02:00
parent 6969b9c2bc
commit 5b99d6a530
41 changed files with 214 additions and 214 deletions

View File

@@ -335,20 +335,20 @@ function RoundsDndGrid({
function ConfidenceBadge({ confidence }: { confidence: number }) { function ConfidenceBadge({ confidence }: { confidence: number }) {
if (confidence > 0.8) { if (confidence > 0.8) {
return ( return (
<Badge variant="outline" className="border-emerald-300 bg-emerald-50 text-emerald-700 dark:border-emerald-700 dark:bg-emerald-950/30 dark:text-emerald-400 text-xs tabular-nums"> <Badge variant="outline" className="border-emerald-300 bg-emerald-50 text-emerald-700 text-xs tabular-nums">
{Math.round(confidence * 100)}% {Math.round(confidence * 100)}%
</Badge> </Badge>
) )
} }
if (confidence >= 0.5) { if (confidence >= 0.5) {
return ( return (
<Badge variant="outline" className="border-amber-300 bg-amber-50 text-amber-700 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-400 text-xs tabular-nums"> <Badge variant="outline" className="border-amber-300 bg-amber-50 text-amber-700 text-xs tabular-nums">
{Math.round(confidence * 100)}% {Math.round(confidence * 100)}%
</Badge> </Badge>
) )
} }
return ( return (
<Badge variant="outline" className="border-red-300 bg-red-50 text-red-700 dark:border-red-700 dark:bg-red-950/30 dark:text-red-400 text-xs tabular-nums"> <Badge variant="outline" className="border-red-300 bg-red-50 text-red-700 text-xs tabular-nums">
{Math.round(confidence * 100)}% {Math.round(confidence * 100)}%
</Badge> </Badge>
) )
@@ -897,8 +897,8 @@ export default function AwardDetailPage({
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Eligible</p> <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Eligible</p>
<p className="text-2xl font-bold tabular-nums">{award.eligibleCount}</p> <p className="text-2xl font-bold tabular-nums">{award.eligibleCount}</p>
</div> </div>
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-950/40"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-emerald-100">
<CheckCircle2 className="h-5 w-5 text-emerald-600 dark:text-emerald-400" /> <CheckCircle2 className="h-5 w-5 text-emerald-600" />
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -910,8 +910,8 @@ export default function AwardDetailPage({
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Evaluated</p> <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Evaluated</p>
<p className="text-2xl font-bold tabular-nums">{(award as any).totalAssessed ?? award._count.eligibilities}</p> <p className="text-2xl font-bold tabular-nums">{(award as any).totalAssessed ?? award._count.eligibilities}</p>
</div> </div>
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-950/40"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-blue-100">
<ListChecks className="h-5 w-5 text-blue-600 dark:text-blue-400" /> <ListChecks className="h-5 w-5 text-blue-600" />
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -923,8 +923,8 @@ export default function AwardDetailPage({
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Jurors</p> <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Jurors</p>
<p className="text-2xl font-bold tabular-nums">{award._count.jurors}</p> <p className="text-2xl font-bold tabular-nums">{award._count.jurors}</p>
</div> </div>
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-violet-100 dark:bg-violet-950/40"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-violet-100">
<Users className="h-5 w-5 text-violet-600 dark:text-violet-400" /> <Users className="h-5 w-5 text-violet-600" />
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -936,8 +936,8 @@ export default function AwardDetailPage({
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Votes</p> <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Votes</p>
<p className="text-2xl font-bold tabular-nums">{award._count.votes}</p> <p className="text-2xl font-bold tabular-nums">{award._count.votes}</p>
</div> </div>
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-amber-100 dark:bg-amber-950/40"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-amber-100">
<Vote className="h-5 w-5 text-amber-600 dark:text-amber-400" /> <Vote className="h-5 w-5 text-amber-600" />
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -1612,7 +1612,7 @@ export default function AwardDetailPage({
{/* Rounds Tab */} {/* Rounds Tab */}
<TabsContent value="rounds" className="space-y-4"> <TabsContent value="rounds" className="space-y-4">
{award.eligibilityMode !== 'SEPARATE_POOL' && ( {award.eligibilityMode !== 'SEPARATE_POOL' && (
<div className="flex items-start gap-2 rounded-md border border-blue-200 bg-blue-50 p-3 text-blue-800 dark:border-blue-800 dark:bg-blue-950/30 dark:text-blue-300"> <div className="flex items-start gap-2 rounded-md border border-blue-200 bg-blue-50 p-3 text-blue-800">
<Info className="h-4 w-4 mt-0.5 shrink-0" /> <Info className="h-4 w-4 mt-0.5 shrink-0" />
<p className="text-sm"> <p className="text-sm">
Rounds are used in <strong>Separate Pool</strong> mode to create a dedicated evaluation track for shortlisted projects. Rounds are used in <strong>Separate Pool</strong> mode to create a dedicated evaluation track for shortlisted projects.
@@ -1620,7 +1620,7 @@ export default function AwardDetailPage({
</div> </div>
)} )}
{!award.competitionId && ( {!award.competitionId && (
<div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-800 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-300"> <div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-800">
<AlertCircle className="h-4 w-4 mt-0.5 shrink-0" /> <AlertCircle className="h-4 w-4 mt-0.5 shrink-0" />
<p className="text-sm"> <p className="text-sm">
Link this award to a competition first before creating rounds. Link this award to a competition first before creating rounds.
@@ -1750,16 +1750,16 @@ export default function AwardDetailPage({
return ( return (
<TableRow <TableRow
key={r.project.id} key={r.project.id}
className={isWinner ? 'bg-amber-50/80 dark:bg-amber-950/20' : ''} className={isWinner ? 'bg-amber-50/80' : ''}
> >
<TableCell> <TableCell>
<span className={`inline-flex h-7 w-7 items-center justify-center rounded-full text-xs font-bold ${ <span className={`inline-flex h-7 w-7 items-center justify-center rounded-full text-xs font-bold ${
i === 0 i === 0
? 'bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300' ? 'bg-amber-100 text-amber-800'
: i === 1 : i === 1
? 'bg-slate-200 text-slate-700 dark:bg-slate-700 dark:text-slate-300' ? 'bg-slate-200 text-slate-700'
: i === 2 : i === 2
? 'bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-300' ? 'bg-orange-100 text-orange-800'
: 'text-muted-foreground' : 'text-muted-foreground'
}`}> }`}>
{i + 1} {i + 1}

View File

@@ -1047,7 +1047,7 @@ export default function MemberDetailPage() {
/> />
</div> </div>
<div className="flex items-center justify-between gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900 dark:border-amber-900 dark:bg-amber-950/30 dark:text-amber-100"> <div className="flex items-center justify-between gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Clock className="h-3.5 w-3.5 shrink-0" /> <Clock className="h-3.5 w-3.5 shrink-0" />
<span> <span>

View File

@@ -907,7 +907,7 @@ export default function MemberInvitePage() {
</div> </div>
{!sendInvitation && ( {!sendInvitation && (
<div className="flex items-start gap-3 rounded-lg bg-blue-500/10 p-4 text-blue-700 dark:text-blue-400"> <div className="flex items-start gap-3 rounded-lg bg-blue-500/10 p-4 text-blue-700">
<MailX className="h-5 w-5 shrink-0 mt-0.5" /> <MailX className="h-5 w-5 shrink-0 mt-0.5" />
<div> <div>
<p className="font-medium">No invitations will be sent</p> <p className="font-medium">No invitations will be sent</p>

View File

@@ -473,7 +473,7 @@ function MentorAssignmentContent({ projectId }: { projectId: string }) {
<TabsContent value="ai" className="space-y-4"> <TabsContent value="ai" className="space-y-4">
{aiSource === 'fallback' && ( {aiSource === 'fallback' && (
<div className="flex items-start gap-3 rounded-md border border-amber-300 bg-amber-50 p-3 text-sm dark:border-amber-700 dark:bg-amber-950/40"> <div className="flex items-start gap-3 rounded-md border border-amber-300 bg-amber-50 p-3 text-sm">
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" /> <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" />
<div> <div>
<p className="font-medium">AI matching unavailable</p> <p className="font-medium">AI matching unavailable</p>
@@ -693,7 +693,7 @@ function PendingChangeRequestsPanel({ projectId }: { projectId: string }) {
return ( return (
<> <>
<Card className="border-amber-300 dark:border-amber-700"> <Card className="border-amber-300">
<CardHeader> <CardHeader>
<CardTitle className="text-lg flex items-center gap-2"> <CardTitle className="text-lg flex items-center gap-2">
<Inbox className="h-5 w-5 text-amber-600" /> <Inbox className="h-5 w-5 text-amber-600" />

View File

@@ -462,7 +462,7 @@ export default function BulkUploadPage() {
return ( return (
<TableRow <TableRow
key={row.project.id} key={row.project.id}
className={row.isComplete ? 'bg-green-50/50 dark:bg-green-950/10' : ''} className={row.isComplete ? 'bg-green-50/50' : ''}
> >
<TableCell> <TableCell>
<Link <Link

View File

@@ -53,15 +53,15 @@ type TeamMemberEntry = {
} }
const ROLE_COLORS: Record<string, string> = { const ROLE_COLORS: Record<string, string> = {
LEAD: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400', LEAD: 'bg-red-100 text-red-700',
MEMBER: 'bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-400', MEMBER: 'bg-teal-100 text-teal-700',
ADVISOR: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', ADVISOR: 'bg-blue-100 text-blue-700',
} }
const ROLE_AVATAR_COLORS: Record<string, string> = { const ROLE_AVATAR_COLORS: Record<string, string> = {
LEAD: 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300', LEAD: 'bg-red-100 text-red-700',
MEMBER: 'bg-teal-100 text-teal-700 dark:bg-teal-900/40 dark:text-teal-300', MEMBER: 'bg-teal-100 text-teal-700',
ADVISOR: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300', ADVISOR: 'bg-blue-100 text-blue-700',
} }
const ROLE_LABELS: Record<string, string> = { const ROLE_LABELS: Record<string, string> = {

View File

@@ -679,7 +679,7 @@ export default function ProjectsPage() {
<Button <Button
variant="outline" variant="outline"
onClick={() => setAiTagDialogOpen(true)} onClick={() => setAiTagDialogOpen(true)}
className={taggingInProgress ? 'border-amber-400 bg-amber-50 dark:bg-amber-950/20' : ''} className={taggingInProgress ? 'border-amber-400 bg-amber-50' : ''}
> >
{taggingInProgress ? ( {taggingInProgress ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin text-amber-600" /> <Loader2 className="mr-2 h-4 w-4 animate-spin text-amber-600" />
@@ -1716,15 +1716,15 @@ export default function ProjectsPage() {
<div className="space-y-6 py-4"> <div className="space-y-6 py-4">
{/* Progress Indicator (when running) */} {/* Progress Indicator (when running) */}
{taggingInProgress && ( {taggingInProgress && (
<div className="p-4 rounded-lg bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-900"> <div className="p-4 rounded-lg bg-blue-50 border border-blue-200">
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Loader2 className="h-5 w-5 animate-spin text-blue-600" /> <Loader2 className="h-5 w-5 animate-spin text-blue-600" />
<div className="flex-1"> <div className="flex-1">
<p className="font-medium text-blue-900 dark:text-blue-100"> <p className="font-medium text-blue-900">
AI Tagging in Progress AI Tagging in Progress
</p> </p>
<p className="text-sm text-blue-700 dark:text-blue-300"> <p className="text-sm text-blue-700">
{jobStatus?.status === 'PENDING' {jobStatus?.status === 'PENDING'
? 'Initializing...' ? 'Initializing...'
: `Processing ${jobStatus?.totalProjects || 0} projects with AI...`} : `Processing ${jobStatus?.totalProjects || 0} projects with AI...`}
@@ -1739,12 +1739,12 @@ export default function ProjectsPage() {
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-blue-700 dark:text-blue-300"> <span className="text-blue-700">
{jobStatus?.processedCount || 0} of {jobStatus?.totalProjects || '?'} projects processed {jobStatus?.processedCount || 0} of {jobStatus?.totalProjects || '?'} projects processed
{jobStatus?.taggedCount ? ` (${jobStatus.taggedCount} tagged)` : ''} {jobStatus?.taggedCount ? ` (${jobStatus.taggedCount} tagged)` : ''}
</span> </span>
{jobStatus && jobStatus.totalProjects > 0 && ( {jobStatus && jobStatus.totalProjects > 0 && (
<span className="font-medium text-blue-900 dark:text-blue-100"> <span className="font-medium text-blue-900">
{taggingProgressPercent}% {taggingProgressPercent}%
</span> </span>
)} )}
@@ -1767,9 +1767,9 @@ export default function ProjectsPage() {
{taggingResult && !taggingInProgress && ( {taggingResult && !taggingInProgress && (
<div className={`p-4 rounded-lg border ${ <div className={`p-4 rounded-lg border ${
taggingResult.failed > 0 taggingResult.failed > 0
? 'bg-amber-50 dark:bg-amber-950/20 border-amber-200 dark:border-amber-900' ? 'bg-amber-50 border-amber-200'
: taggingResult.processed > 0 : taggingResult.processed > 0
? 'bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-900' ? 'bg-green-50 border-green-200'
: 'bg-muted border-border' : 'bg-muted border-border'
}`}> }`}>
<div className="flex items-center gap-3 mb-3"> <div className="flex items-center gap-3 mb-3">
@@ -1804,12 +1804,12 @@ export default function ProjectsPage() {
</div> </div>
{taggingResult.errors.length > 0 && ( {taggingResult.errors.length > 0 && (
<div className="mt-3 space-y-2"> <div className="mt-3 space-y-2">
<p className="text-sm font-medium text-amber-700 dark:text-amber-300"> <p className="text-sm font-medium text-amber-700">
{taggingResult.errors.length} project{taggingResult.errors.length > 1 ? 's' : ''} failed: {taggingResult.errors.length} project{taggingResult.errors.length > 1 ? 's' : ''} failed:
</p> </p>
<div className="max-h-32 overflow-y-auto rounded bg-background/50 p-2 text-xs space-y-1"> <div className="max-h-32 overflow-y-auto rounded bg-background/50 p-2 text-xs space-y-1">
{taggingResult.errors.map((error, i) => ( {taggingResult.errors.map((error, i) => (
<p key={i} className="text-amber-700 dark:text-amber-300"> <p key={i} className="text-amber-700">
{error} {error}
</p> </p>
))} ))}

View File

@@ -394,7 +394,7 @@ export default function AdminProxyEvaluatePage({ params: paramsPromise }: PagePr
</Link> </Link>
</Button> </Button>
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
{isReadOnly ? 'Submitted Evaluation' : 'Fill In Evaluation'} {isReadOnly ? 'Submitted Evaluation' : 'Fill In Evaluation'}
</h1> </h1>
<div className="flex items-center gap-2 mt-1 flex-wrap"> <div className="flex items-center gap-2 mt-1 flex-wrap">
@@ -404,8 +404,8 @@ export default function AdminProxyEvaluatePage({ params: paramsPromise }: PagePr
variant="secondary" variant="secondary"
className={ className={
project.competitionCategory === 'STARTUP' project.competitionCategory === 'STARTUP'
? 'bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-950 dark:text-violet-300' ? 'bg-violet-100 text-violet-700 border-violet-200'
: 'bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-950 dark:text-sky-300' : 'bg-sky-100 text-sky-700 border-sky-200'
} }
> >
{project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'} {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'}
@@ -415,7 +415,7 @@ export default function AdminProxyEvaluatePage({ params: paramsPromise }: PagePr
</div> </div>
</div> </div>
<Card className="border-l-4 border-l-amber-500 bg-amber-50/40 dark:bg-amber-950/10"> <Card className="border-l-4 border-l-amber-500 bg-amber-50/40">
<CardContent className="flex items-start gap-3 p-4"> <CardContent className="flex items-start gap-3 p-4">
<UserCheck className="h-5 w-5 text-amber-600 shrink-0 mt-0.5" /> <UserCheck className="h-5 w-5 text-amber-600 shrink-0 mt-0.5" />
<div className="flex-1 text-sm"> <div className="flex-1 text-sm">
@@ -431,7 +431,7 @@ export default function AdminProxyEvaluatePage({ params: paramsPromise }: PagePr
</Card> </Card>
{isReadOnly && ( {isReadOnly && (
<Card className="border-l-4 border-l-blue-500 bg-blue-50/50 dark:bg-blue-950/20"> <Card className="border-l-4 border-l-blue-500 bg-blue-50/50">
<CardContent className="flex items-start gap-3 p-4"> <CardContent className="flex items-start gap-3 p-4">
<Lock className="h-5 w-5 text-blue-600 shrink-0 mt-0.5" /> <Lock className="h-5 w-5 text-blue-600 shrink-0 mt-0.5" />
<div className="flex-1"> <div className="flex-1">
@@ -446,7 +446,7 @@ export default function AdminProxyEvaluatePage({ params: paramsPromise }: PagePr
)} )}
{hasCOI && !isReadOnly && ( {hasCOI && !isReadOnly && (
<Card className="border-l-4 border-l-red-500 bg-red-50/40 dark:bg-red-950/10"> <Card className="border-l-4 border-l-red-500 bg-red-50/40">
<CardContent className="flex items-start gap-3 p-4"> <CardContent className="flex items-start gap-3 p-4">
<Lock className="h-5 w-5 text-red-600 shrink-0 mt-0.5" /> <Lock className="h-5 w-5 text-red-600 shrink-0 mt-0.5" />
<div className="flex-1 text-sm"> <div className="flex-1 text-sm">

View File

@@ -55,7 +55,7 @@ export default function AdminJurorProxyEvaluatePage({ params: paramsPromise }: P
</Link> </Link>
</Button> </Button>
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
Proxy Evaluations Proxy Evaluations
</h1> </h1>
<p className="text-muted-foreground mt-1"> <p className="text-muted-foreground mt-1">
@@ -205,8 +205,8 @@ function AssignmentRow({ roundId, userId, assignment, mode }: AssignmentRowProps
className={cn( className={cn(
'shrink-0', 'shrink-0',
project.competitionCategory === 'STARTUP' project.competitionCategory === 'STARTUP'
? 'bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-950 dark:text-violet-300' ? 'bg-violet-100 text-violet-700 border-violet-200'
: 'bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-950 dark:text-sky-300', : 'bg-sky-100 text-sky-700 border-sky-200',
)} )}
> >
{project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'} {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'}

View File

@@ -2074,39 +2074,39 @@ export default function RoundDetailPage() {
</p> </p>
)} )}
{aiAssignmentMutation.isPending && ( {aiAssignmentMutation.isPending && (
<div className="flex items-center gap-3 p-3 rounded-lg bg-violet-50 border border-violet-200 dark:bg-violet-950/20 dark:border-violet-800"> <div className="flex items-center gap-3 p-3 rounded-lg bg-violet-50 border border-violet-200">
<div className="relative"> <div className="relative">
<div className="h-8 w-8 rounded-full border-2 border-violet-300 border-t-violet-600 animate-spin" /> <div className="h-8 w-8 rounded-full border-2 border-violet-300 border-t-violet-600 animate-spin" />
</div> </div>
<div> <div>
<p className="text-sm font-medium text-violet-800 dark:text-violet-200">AI is analyzing projects and jurors...</p> <p className="text-sm font-medium text-violet-800">AI is analyzing projects and jurors...</p>
<p className="text-xs text-violet-600 dark:text-violet-400"> <p className="text-xs text-violet-600">
Matching expertise, reviewing bios, and balancing workloads Matching expertise, reviewing bios, and balancing workloads
</p> </p>
</div> </div>
</div> </div>
)} )}
{aiAssignmentMutation.error && !aiAssignmentMutation.isPending && ( {aiAssignmentMutation.error && !aiAssignmentMutation.isPending && (
<div className="flex items-center gap-3 p-3 rounded-lg bg-red-50 border border-red-200 dark:bg-red-950/20 dark:border-red-800"> <div className="flex items-center gap-3 p-3 rounded-lg bg-red-50 border border-red-200">
<AlertTriangle className="h-5 w-5 text-red-600 shrink-0" /> <AlertTriangle className="h-5 w-5 text-red-600 shrink-0" />
<div className="flex-1"> <div className="flex-1">
<p className="text-sm font-medium text-red-800 dark:text-red-200"> <p className="text-sm font-medium text-red-800">
AI generation failed AI generation failed
</p> </p>
<p className="text-xs text-red-600 dark:text-red-400"> <p className="text-xs text-red-600">
{aiAssignmentMutation.error.message} {aiAssignmentMutation.error.message}
</p> </p>
</div> </div>
</div> </div>
)} )}
{aiAssignmentMutation.data && !aiAssignmentMutation.isPending && ( {aiAssignmentMutation.data && !aiAssignmentMutation.isPending && (
<div className="flex items-center gap-3 p-3 rounded-lg bg-emerald-50 border border-emerald-200 dark:bg-emerald-950/20 dark:border-emerald-800"> <div className="flex items-center gap-3 p-3 rounded-lg bg-emerald-50 border border-emerald-200">
<CheckCircle2 className="h-5 w-5 text-emerald-600 shrink-0" /> <CheckCircle2 className="h-5 w-5 text-emerald-600 shrink-0" />
<div className="flex-1"> <div className="flex-1">
<p className="text-sm font-medium text-emerald-800 dark:text-emerald-200"> <p className="text-sm font-medium text-emerald-800">
{aiAssignmentMutation.data.stats.assignmentsGenerated} assignments generated {aiAssignmentMutation.data.stats.assignmentsGenerated} assignments generated
</p> </p>
<p className="text-xs text-emerald-600 dark:text-emerald-400"> <p className="text-xs text-emerald-600">
{aiAssignmentMutation.data.stats.totalJurors} jurors, {aiAssignmentMutation.data.stats.totalProjects} projects {aiAssignmentMutation.data.stats.totalJurors} jurors, {aiAssignmentMutation.data.stats.totalProjects} projects
{aiAssignmentMutation.data.fallbackUsed && ' (algorithm fallback)'} {aiAssignmentMutation.data.fallbackUsed && ' (algorithm fallback)'}
</p> </p>
@@ -2588,9 +2588,9 @@ export default function RoundDetailPage() {
{/* Autosave error bar — only shows when save fails */} {/* Autosave error bar — only shows when save fails */}
{autosaveStatus === 'error' && ( {autosaveStatus === 'error' && (
<div className="fixed bottom-0 left-0 right-0 z-50 border-t bg-red-50 dark:bg-red-950/50 shadow-[0_-4px_12px_rgba(0,0,0,0.1)]"> <div className="fixed bottom-0 left-0 right-0 z-50 border-t bg-red-50 shadow-[0_-4px_12px_rgba(0,0,0,0.1)]">
<div className="container flex items-center justify-between py-3 px-4 max-w-5xl mx-auto"> <div className="container flex items-center justify-between py-3 px-4 max-w-5xl mx-auto">
<div className="flex items-center gap-2 text-sm text-red-700 dark:text-red-300"> <div className="flex items-center gap-2 text-sm text-red-700">
<AlertTriangle className="h-4 w-4" /> <AlertTriangle className="h-4 w-4" />
<span>Auto-save failed</span> <span>Auto-save failed</span>
</div> </div>

View File

@@ -219,12 +219,12 @@ export default function ApplicantDashboardPage() {
key={round.id} key={round.id}
className={`flex flex-col sm:flex-row items-start sm:items-center gap-3 rounded-lg border px-4 py-3 ${ className={`flex flex-col sm:flex-row items-start sm:items-center gap-3 rounded-lg border px-4 py-3 ${
isUrgent isUrgent
? 'border-amber-500/50 bg-amber-50 dark:bg-amber-950/20' ? 'border-amber-500/50 bg-amber-50'
: 'border-primary/20 bg-primary/5' : 'border-primary/20 bg-primary/5'
}`} }`}
> >
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
<Clock className={`h-4 w-4 shrink-0 ${isUrgent ? 'text-amber-600 dark:text-amber-400' : 'text-primary'}`} /> <Clock className={`h-4 w-4 shrink-0 ${isUrgent ? 'text-amber-600' : 'text-primary'}`} />
<span className="font-medium text-sm truncate">{round.name}</span> <span className="font-medium text-sm truncate">{round.name}</span>
<Badge variant={isUrgent ? 'warning' : 'default'} className="shrink-0"> <Badge variant={isUrgent ? 'warning' : 'default'} className="shrink-0">
{remaining > 0 ? formatCountdown(remaining) + ' left' : 'Closed'} {remaining > 0 ? formatCountdown(remaining) + ' left' : 'Closed'}

View File

@@ -427,10 +427,10 @@ function ProjectDetails({ project }: { project: ProjectData }) {
return ( return (
<div className="px-4 pb-4 pt-2 space-y-4 border-t mt-2"> <div className="px-4 pb-4 pt-2 space-y-4 border-t mt-2">
{project.evaluationScore && ( {project.evaluationScore && (
<div className="flex items-center gap-2 rounded-md bg-blue-50/50 dark:bg-blue-950/20 px-3 py-2"> <div className="flex items-center gap-2 rounded-md bg-blue-50/50 px-3 py-2">
<Star className="h-4 w-4 text-blue-600 dark:text-blue-400 shrink-0" /> <Star className="h-4 w-4 text-blue-600 shrink-0" />
<div className="text-sm"> <div className="text-sm">
<span className="font-semibold text-blue-700 dark:text-blue-300"> <span className="font-semibold text-blue-700">
{project.evaluationScore.avg.toFixed(1)} / 10 {project.evaluationScore.avg.toFixed(1)} / 10
</span> </span>
<span className="text-muted-foreground ml-2"> <span className="text-muted-foreground ml-2">
@@ -518,7 +518,7 @@ function ProjectCard({
isExpanded && 'rotate-180' isExpanded && 'rotate-180'
)} /> )} />
<div className="min-w-0"> <div className="min-w-0">
<h3 className="font-semibold text-sm group-hover:text-brand-blue dark:group-hover:text-brand-teal transition-colors"> <h3 className="font-semibold text-sm group-hover:text-brand-blue transition-colors">
{project.title} {project.title}
</h3> </h3>
<p className="text-xs text-muted-foreground mt-0.5"> <p className="text-xs text-muted-foreground mt-0.5">
@@ -587,7 +587,7 @@ function ChairPanel({
const isClosed = award.status === 'CLOSED' const isClosed = award.status === 'CLOSED'
return ( return (
<Card className="border-amber-200 dark:border-amber-900"> <Card className="border-amber-200">
<CardHeader> <CardHeader>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Gavel className="h-5 w-5 text-amber-600" /> <Gavel className="h-5 w-5 text-amber-600" />

View File

@@ -44,7 +44,7 @@ export default function JuryRoundDetailPage() {
Back Back
</Button> </Button>
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
{round?.name || 'Round Details'} {round?.name || 'Round Details'}
</h1> </h1>
<p className="text-muted-foreground mt-1"> <p className="text-muted-foreground mt-1">

View File

@@ -460,7 +460,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</div> </div>
<Card className="border-l-4 border-l-amber-500"> <Card className="border-l-4 border-l-amber-500">
<CardContent className="flex items-start gap-4 p-6"> <CardContent className="flex items-start gap-4 p-6">
<div className="rounded-xl bg-amber-50 dark:bg-amber-950/40 p-3"> <div className="rounded-xl bg-amber-50 p-3">
<Clock className="h-6 w-6 text-amber-600" /> <Clock className="h-6 w-6 text-amber-600" />
</div> </div>
<div> <div>
@@ -495,7 +495,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</Link> </Link>
</Button> </Button>
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
Evaluate Project Evaluate Project
</h1> </h1>
<p className="text-muted-foreground mt-1">{project.title}</p> <p className="text-muted-foreground mt-1">{project.title}</p>
@@ -526,7 +526,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</Link> </Link>
</Button> </Button>
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
Evaluate Project Evaluate Project
</h1> </h1>
<p className="text-muted-foreground mt-1">{project.title}</p> <p className="text-muted-foreground mt-1">{project.title}</p>
@@ -534,7 +534,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</div> </div>
<Card className="border-l-4 border-l-amber-500"> <Card className="border-l-4 border-l-amber-500">
<CardContent className="flex items-start gap-4 p-6"> <CardContent className="flex items-start gap-4 p-6">
<div className="rounded-xl bg-amber-50 dark:bg-amber-950/40 p-3"> <div className="rounded-xl bg-amber-50 p-3">
<ShieldAlert className="h-6 w-6 text-amber-600" /> <ShieldAlert className="h-6 w-6 text-amber-600" />
</div> </div>
<div> <div>
@@ -573,7 +573,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</Button> </Button>
)} )}
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
{isReadOnly ? 'Submitted Evaluation' : 'Evaluate Project'} {isReadOnly ? 'Submitted Evaluation' : 'Evaluate Project'}
</h1> </h1>
<div className="flex items-center gap-2 mt-1"> <div className="flex items-center gap-2 mt-1">
@@ -583,8 +583,8 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
variant="secondary" variant="secondary"
className={ className={
project.competitionCategory === 'STARTUP' project.competitionCategory === 'STARTUP'
? 'bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-950 dark:text-violet-300' ? 'bg-violet-100 text-violet-700 border-violet-200'
: 'bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-950 dark:text-sky-300' : 'bg-sky-100 text-sky-700 border-sky-200'
} }
> >
{project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'} {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'}
@@ -595,7 +595,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
</div> </div>
{isReadOnly && ( {isReadOnly && (
<Card className="border-l-4 border-l-blue-500 bg-blue-50/50 dark:bg-blue-950/20"> <Card className="border-l-4 border-l-blue-500 bg-blue-50/50">
<CardContent className="flex items-start gap-3 p-4"> <CardContent className="flex items-start gap-3 p-4">
<Lock className="h-5 w-5 text-blue-600 shrink-0 mt-0.5" /> <Lock className="h-5 w-5 text-blue-600 shrink-0 mt-0.5" />
<div className="flex-1"> <div className="flex-1">

View File

@@ -98,8 +98,8 @@ export default function JuryProjectDetailPage() {
variant="secondary" variant="secondary"
className={ className={
project.competitionCategory === 'STARTUP' project.competitionCategory === 'STARTUP'
? 'bg-violet-100 text-violet-700 border-violet-200 dark:bg-violet-950 dark:text-violet-300' ? 'bg-violet-100 text-violet-700 border-violet-200'
: 'bg-sky-100 text-sky-700 border-sky-200 dark:bg-sky-950 dark:text-sky-300' : 'bg-sky-100 text-sky-700 border-sky-200'
} }
> >
{project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'} {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'}

View File

@@ -54,7 +54,7 @@ export default function JuryAssignmentsPage() {
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
My Assignments My Assignments
</h1> </h1>
<p className="text-muted-foreground mt-1"> <p className="text-muted-foreground mt-1">

View File

@@ -262,7 +262,7 @@ async function JuryDashboardContent() {
<div className="h-1 w-full bg-gradient-to-r from-brand-teal/40 via-brand-blue/40 to-brand-teal/40" /> <div className="h-1 w-full bg-gradient-to-r from-brand-teal/40 via-brand-blue/40 to-brand-teal/40" />
<CardContent className="py-8 px-6"> <CardContent className="py-8 px-6">
<div className="flex flex-col items-center text-center mb-6"> <div className="flex flex-col items-center text-center mb-6">
<div className="rounded-2xl bg-gradient-to-br from-brand-teal/10 to-brand-blue/10 p-4 mb-3 dark:from-brand-teal/20 dark:to-brand-blue/20"> <div className="rounded-2xl bg-gradient-to-br from-brand-teal/10 to-brand-blue/10 p-4 mb-3">
<ClipboardList className="h-8 w-8 text-brand-teal/60" /> <ClipboardList className="h-8 w-8 text-brand-teal/60" />
</div> </div>
<p className="text-lg font-semibold">No assignments yet</p> <p className="text-lg font-semibold">No assignments yet</p>
@@ -273,13 +273,13 @@ async function JuryDashboardContent() {
<div className={`grid gap-3 max-w-md mx-auto ${juryCompareEnabled ? 'sm:grid-cols-2' : ''}`}> <div className={`grid gap-3 max-w-md mx-auto ${juryCompareEnabled ? 'sm:grid-cols-2' : ''}`}>
<Link <Link
href="/jury/competitions" href="/jury/competitions"
className="group flex items-center gap-3 rounded-xl border border-border/60 p-3 transition-all duration-200 hover:border-brand-blue/30 hover:bg-brand-blue/5 hover:-translate-y-0.5 hover:shadow-md dark:hover:border-brand-teal/30 dark:hover:bg-brand-teal/5" className="group flex items-center gap-3 rounded-xl border border-border/60 p-3 transition-all duration-200 hover:border-brand-blue/30 hover:bg-brand-blue/5 hover:-translate-y-0.5 hover:shadow-md"
> >
<div className="rounded-lg bg-blue-50 p-2 transition-colors group-hover:bg-blue-100 dark:bg-blue-950/40"> <div className="rounded-lg bg-blue-50 p-2 transition-colors group-hover:bg-blue-100">
<ClipboardList className="h-4 w-4 text-blue-600 dark:text-blue-400" /> <ClipboardList className="h-4 w-4 text-blue-600" />
</div> </div>
<div className="text-left"> <div className="text-left">
<p className="font-semibold text-sm group-hover:text-brand-blue dark:group-hover:text-brand-teal transition-colors">All Assignments</p> <p className="font-semibold text-sm group-hover:text-brand-blue transition-colors">All Assignments</p>
<p className="text-xs text-muted-foreground">View evaluations</p> <p className="text-xs text-muted-foreground">View evaluations</p>
</div> </div>
</Link> </Link>
@@ -288,7 +288,7 @@ async function JuryDashboardContent() {
href="/jury/competitions" href="/jury/competitions"
className="group flex items-center gap-3 rounded-xl border border-border/60 p-3 transition-all duration-200 hover:border-brand-teal/30 hover:bg-brand-teal/5 hover:-translate-y-0.5 hover:shadow-md" className="group flex items-center gap-3 rounded-xl border border-border/60 p-3 transition-all duration-200 hover:border-brand-teal/30 hover:bg-brand-teal/5 hover:-translate-y-0.5 hover:shadow-md"
> >
<div className="rounded-lg bg-teal-50 p-2 transition-colors group-hover:bg-teal-100 dark:bg-teal-950/40"> <div className="rounded-lg bg-teal-50 p-2 transition-colors group-hover:bg-teal-100">
<GitCompare className="h-4 w-4 text-brand-teal" /> <GitCompare className="h-4 w-4 text-brand-teal" />
</div> </div>
<div className="text-left"> <div className="text-left">
@@ -314,8 +314,8 @@ async function JuryDashboardContent() {
<div className="rounded-[7px] bg-background"> <div className="rounded-[7px] bg-background">
<CardHeader className="pb-2 pt-4 px-5"> <CardHeader className="pb-2 pt-4 px-5">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="rounded-lg bg-amber-100 p-1.5 dark:bg-amber-900/40"> <div className="rounded-lg bg-amber-100 p-1.5">
<Trophy className="h-4 w-4 text-amber-600 dark:text-amber-400" /> <Trophy className="h-4 w-4 text-amber-600" />
</div> </div>
<CardTitle className="text-lg">Special Awards Voting Open</CardTitle> <CardTitle className="text-lg">Special Awards Voting Open</CardTitle>
</div> </div>
@@ -333,27 +333,27 @@ async function JuryDashboardContent() {
className={cn( className={cn(
'rounded-xl border p-4 space-y-3 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md', 'rounded-xl border p-4 space-y-3 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md',
hasVoted hasVoted
? 'border-green-200/60 bg-green-50/30 dark:border-green-800/40 dark:bg-green-950/10' ? 'border-green-200/60 bg-green-50/30'
: isUrgent : isUrgent
? 'border-red-200 bg-red-50/50 dark:border-red-900 dark:bg-red-950/20' ? 'border-red-200 bg-red-50/50'
: 'border-amber-200/60 bg-amber-50/30 dark:border-amber-800/40 dark:bg-amber-950/10' : 'border-amber-200/60 bg-amber-50/30'
)} )}
> >
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div> <div>
<h3 className={cn('font-semibold', hasVoted ? 'text-green-700 dark:text-green-400' : 'text-amber-700 dark:text-amber-400')}>{award.name}</h3> <h3 className={cn('font-semibold', hasVoted ? 'text-green-700' : 'text-amber-700')}>{award.name}</h3>
<p className="text-xs text-muted-foreground mt-0.5"> <p className="text-xs text-muted-foreground mt-0.5">
{award._count.eligibilities} project{award._count.eligibilities !== 1 ? 's' : ''} to review {award._count.eligibilities} project{award._count.eligibilities !== 1 ? 's' : ''} to review
{record.isChair && ' · You are the Chair'} {record.isChair && ' · You are the Chair'}
</p> </p>
</div> </div>
{hasVoted ? ( {hasVoted ? (
<Badge className="bg-green-100 text-green-800 border-green-300 dark:bg-green-950 dark:text-green-300 dark:border-green-700"> <Badge className="bg-green-100 text-green-800 border-green-300">
<CheckCircle2 className="mr-1 h-3 w-3" /> <CheckCircle2 className="mr-1 h-3 w-3" />
Submitted Submitted
</Badge> </Badge>
) : ( ) : (
<Badge className="bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-950 dark:text-amber-300 dark:border-amber-700"> <Badge className="bg-amber-100 text-amber-800 border-amber-300">
Vote Now Vote Now
</Badge> </Badge>
)} )}
@@ -452,8 +452,8 @@ async function JuryDashboardContent() {
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="rounded-lg bg-brand-blue/10 p-1.5 dark:bg-brand-blue/20"> <div className="rounded-lg bg-brand-blue/10 p-1.5">
<ClipboardList className="h-4 w-4 text-brand-blue dark:text-brand-teal" /> <ClipboardList className="h-4 w-4 text-brand-blue" />
</div> </div>
<CardTitle className="text-lg">My Assignments</CardTitle> <CardTitle className="text-lg">My Assignments</CardTitle>
</div> </div>
@@ -487,14 +487,14 @@ async function JuryDashboardContent() {
href={`/jury/competitions/${assignment.round.id}/projects/${assignment.project.id}`} href={`/jury/competitions/${assignment.round.id}/projects/${assignment.project.id}`}
className="flex-1 min-w-0 group" className="flex-1 min-w-0 group"
> >
<p className="text-sm font-medium truncate group-hover:text-brand-blue dark:group-hover:text-brand-teal transition-colors"> <p className="text-sm font-medium truncate group-hover:text-brand-blue transition-colors">
{assignment.project.title} {assignment.project.title}
</p> </p>
<div className="flex items-center gap-2 mt-1"> <div className="flex items-center gap-2 mt-1">
<span className="text-xs text-muted-foreground truncate"> <span className="text-xs text-muted-foreground truncate">
{assignment.project.teamName} {assignment.project.teamName}
</span> </span>
<Badge variant="secondary" className="text-[10px] px-1.5 py-0 bg-brand-blue/5 text-brand-blue/80 dark:bg-brand-teal/10 dark:text-brand-teal/80 border-0"> <Badge variant="secondary" className="text-[10px] px-1.5 py-0 bg-brand-blue/5 text-brand-blue/80 border-0">
{assignment.round.name} {assignment.round.name}
</Badge> </Badge>
</div> </div>
@@ -506,7 +506,7 @@ async function JuryDashboardContent() {
Done Done
</Badge> </Badge>
) : isDraft && isVotingOpen ? ( ) : isDraft && isVotingOpen ? (
<Badge className="text-xs bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-950 dark:text-amber-300 dark:border-amber-700 animate-pulse"> <Badge className="text-xs bg-amber-100 text-amber-800 border-amber-300 animate-pulse">
<Send className="mr-1 h-3 w-3" /> <Send className="mr-1 h-3 w-3" />
Ready to submit Ready to submit
</Badge> </Badge>
@@ -571,7 +571,7 @@ async function JuryDashboardContent() {
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="rounded-lg bg-brand-teal/10 p-1.5 dark:bg-brand-teal/20"> <div className="rounded-lg bg-brand-teal/10 p-1.5">
<Zap className="h-4 w-4 text-brand-teal" /> <Zap className="h-4 w-4 text-brand-teal" />
</div> </div>
<CardTitle className="text-lg">Quick Actions</CardTitle> <CardTitle className="text-lg">Quick Actions</CardTitle>
@@ -581,13 +581,13 @@ async function JuryDashboardContent() {
<div className={`grid gap-3 ${juryCompareEnabled ? 'sm:grid-cols-2' : ''}`}> <div className={`grid gap-3 ${juryCompareEnabled ? 'sm:grid-cols-2' : ''}`}>
<Link <Link
href="/jury/competitions" href="/jury/competitions"
className="group flex items-center gap-4 rounded-xl border border-border/60 p-4 transition-all duration-200 hover:border-brand-blue/30 hover:bg-brand-blue/5 hover:-translate-y-0.5 hover:shadow-md dark:hover:border-brand-teal/30 dark:hover:bg-brand-teal/5" className="group flex items-center gap-4 rounded-xl border border-border/60 p-4 transition-all duration-200 hover:border-brand-blue/30 hover:bg-brand-blue/5 hover:-translate-y-0.5 hover:shadow-md"
> >
<div className="rounded-xl bg-blue-50 p-3 transition-colors group-hover:bg-blue-100 dark:bg-blue-950/40 dark:group-hover:bg-blue-950/60"> <div className="rounded-xl bg-blue-50 p-3 transition-colors group-hover:bg-blue-100">
<ClipboardList className="h-5 w-5 text-blue-600 dark:text-blue-400" /> <ClipboardList className="h-5 w-5 text-blue-600" />
</div> </div>
<div className="text-left"> <div className="text-left">
<p className="font-semibold text-sm group-hover:text-brand-blue dark:group-hover:text-brand-teal transition-colors">All Assignments</p> <p className="font-semibold text-sm group-hover:text-brand-blue transition-colors">All Assignments</p>
<p className="text-xs text-muted-foreground mt-0.5">View and manage evaluations</p> <p className="text-xs text-muted-foreground mt-0.5">View and manage evaluations</p>
</div> </div>
</Link> </Link>
@@ -596,7 +596,7 @@ async function JuryDashboardContent() {
href="/jury/competitions" href="/jury/competitions"
className="group flex items-center gap-4 rounded-xl border border-border/60 p-4 transition-all duration-200 hover:border-brand-teal/30 hover:bg-brand-teal/5 hover:-translate-y-0.5 hover:shadow-md" className="group flex items-center gap-4 rounded-xl border border-border/60 p-4 transition-all duration-200 hover:border-brand-teal/30 hover:bg-brand-teal/5 hover:-translate-y-0.5 hover:shadow-md"
> >
<div className="rounded-xl bg-teal-50 p-3 transition-colors group-hover:bg-teal-100 dark:bg-teal-950/40 dark:group-hover:bg-teal-950/60"> <div className="rounded-xl bg-teal-50 p-3 transition-colors group-hover:bg-teal-100">
<GitCompare className="h-5 w-5 text-brand-teal" /> <GitCompare className="h-5 w-5 text-brand-teal" />
</div> </div>
<div className="text-left"> <div className="text-left">
@@ -620,8 +620,8 @@ async function JuryDashboardContent() {
<div className="h-1 w-full bg-gradient-to-r from-brand-blue via-brand-teal to-brand-blue" /> <div className="h-1 w-full bg-gradient-to-r from-brand-blue via-brand-teal to-brand-blue" />
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="rounded-lg bg-brand-blue/10 p-1.5 dark:bg-brand-blue/20"> <div className="rounded-lg bg-brand-blue/10 p-1.5">
<Waves className="h-4 w-4 text-brand-blue dark:text-brand-teal" /> <Waves className="h-4 w-4 text-brand-blue" />
</div> </div>
<div> <div>
<CardTitle className="text-lg">Active Voting Stages</CardTitle> <CardTitle className="text-lg">Active Voting Stages</CardTitle>
@@ -650,13 +650,13 @@ async function JuryDashboardContent() {
className={cn( className={cn(
'rounded-xl border p-4 space-y-3 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md', 'rounded-xl border p-4 space-y-3 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md',
isUrgent isUrgent
? 'border-red-200 bg-red-50/50 dark:border-red-900 dark:bg-red-950/20' ? 'border-red-200 bg-red-50/50'
: 'border-border/60 bg-muted/20 dark:bg-muted/10' : 'border-border/60 bg-muted/20'
)} )}
> >
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div> <div>
<h3 className="font-semibold text-brand-blue dark:text-brand-teal">{round.name}</h3> <h3 className="font-semibold text-brand-blue">{round.name}</h3>
<p className="text-xs text-muted-foreground mt-0.5"> <p className="text-xs text-muted-foreground mt-0.5">
{program.name} &middot; {program.year} {program.name} &middot; {program.year}
</p> </p>
@@ -716,7 +716,7 @@ async function JuryDashboardContent() {
<AnimatedCard index={8}> <AnimatedCard index={8}>
<Card> <Card>
<CardContent className="flex flex-col items-center justify-center py-6 text-center"> <CardContent className="flex flex-col items-center justify-center py-6 text-center">
<div className="rounded-2xl bg-brand-teal/10 p-3 mb-2 dark:bg-brand-teal/20"> <div className="rounded-2xl bg-brand-teal/10 p-3 mb-2">
<Clock className="h-6 w-6 text-brand-teal/70" /> <Clock className="h-6 w-6 text-brand-teal/70" />
</div> </div>
<p className="font-semibold text-sm">No active voting stages</p> <p className="font-semibold text-sm">No active voting stages</p>
@@ -734,7 +734,7 @@ async function JuryDashboardContent() {
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="rounded-lg bg-brand-teal/10 p-1.5 dark:bg-brand-teal/20"> <div className="rounded-lg bg-brand-teal/10 p-1.5">
<BarChart3 className="h-4 w-4 text-brand-teal" /> <BarChart3 className="h-4 w-4 text-brand-teal" />
</div> </div>
<CardTitle className="text-lg">Round Summary</CardTitle> <CardTitle className="text-lg">Round Summary</CardTitle>
@@ -750,7 +750,7 @@ async function JuryDashboardContent() {
<div className="flex items-center justify-between text-sm"> <div className="flex items-center justify-between text-sm">
<span className="font-medium truncate">{round.name}</span> <span className="font-medium truncate">{round.name}</span>
<div className="flex items-baseline gap-1 shrink-0 ml-2"> <div className="flex items-baseline gap-1 shrink-0 ml-2">
<span className="font-bold tabular-nums text-brand-blue dark:text-brand-teal">{pct}%</span> <span className="font-bold tabular-nums text-brand-blue">{pct}%</span>
<span className="text-xs text-muted-foreground">({done}/{total})</span> <span className="text-xs text-muted-foreground">({done}/{total})</span>
</div> </div>
</div> </div>
@@ -852,7 +852,7 @@ export default async function JuryDashboardPage() {
<div className="space-y-4"> <div className="space-y-4">
{/* Header */} {/* Header */}
<div> <div>
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground"> <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
{getGreeting()}, {session?.user?.name || 'Juror'} {getGreeting()}, {session?.user?.name || 'Juror'}
</h1> </h1>
<p className="text-muted-foreground mt-0.5"> <p className="text-muted-foreground mt-0.5">

View File

@@ -596,7 +596,7 @@ function MilestonesSection({
<div <div
key={milestone.id} key={milestone.id}
className={`flex items-start gap-3 p-3 rounded-lg border transition-all duration-200 hover:-translate-y-0.5 hover:shadow-sm ${ className={`flex items-start gap-3 p-3 rounded-lg border transition-all duration-200 hover:-translate-y-0.5 hover:shadow-sm ${
isCompleted ? 'bg-green-50/50 border-green-200 dark:bg-green-950/20 dark:border-green-900' : '' isCompleted ? 'bg-green-50/50 border-green-200' : ''
}`} }`}
> >
<Checkbox <Checkbox

View File

@@ -280,7 +280,7 @@ function FinalistConfirmContent({ token }: { token: string }) {
Your project <strong>{data.project.title}</strong> is a finalist for the Monaco Ocean Your project <strong>{data.project.title}</strong> is a finalist for the Monaco Ocean
Protection Challenge grand finale. Protection Challenge grand finale.
</p> </p>
<div className="bg-background border-amber-300 mt-3 rounded-md border-l-4 p-3 dark:border-amber-700"> <div className="bg-background border-amber-300 mt-3 rounded-md border-l-4 p-3">
<p className="text-sm"> <p className="text-sm">
<strong>Confirm by {formatDeadline(deadline)}.</strong> <strong>Confirm by {formatDeadline(deadline)}.</strong>
</p> </p>

View File

@@ -437,7 +437,7 @@ export function AssignmentPreviewSheet({
{mode === 'ai' && !aiResult && !isAIGenerating && ( {mode === 'ai' && !aiResult && !isAIGenerating && (
<Card className="border-dashed"> <Card className="border-dashed">
<CardContent className="flex flex-col items-center justify-center py-8 gap-3"> <CardContent className="flex flex-col items-center justify-center py-8 gap-3">
<div className="h-12 w-12 rounded-full bg-violet-100 dark:bg-violet-950 flex items-center justify-center"> <div className="h-12 w-12 rounded-full bg-violet-100 flex items-center justify-center">
<Sparkles className="h-6 w-6 text-violet-600" /> <Sparkles className="h-6 w-6 text-violet-600" />
</div> </div>
<div className="text-center space-y-1"> <div className="text-center space-y-1">
@@ -463,7 +463,7 @@ export function AssignmentPreviewSheet({
{isLoading ? ( {isLoading ? (
<div className="space-y-3"> <div className="space-y-3">
{mode === 'ai' && ( {mode === 'ai' && (
<Card className="border-violet-200 bg-violet-50/50 dark:bg-violet-950/20"> <Card className="border-violet-200 bg-violet-50/50">
<CardContent className="flex items-center gap-3 py-4"> <CardContent className="flex items-center gap-3 py-4">
<div className="relative"> <div className="relative">
<div className="h-6 w-6 rounded-full border-2 border-violet-300 border-t-violet-600 animate-spin" /> <div className="h-6 w-6 rounded-full border-2 border-violet-300 border-t-violet-600 animate-spin" />
@@ -567,13 +567,13 @@ export function AssignmentPreviewSheet({
{/* ── Warnings ── */} {/* ── Warnings ── */}
{preview.warnings && preview.warnings.length > 0 && ( {preview.warnings && preview.warnings.length > 0 && (
<Card className="border-amber-300 bg-amber-50/50 dark:bg-amber-950/20"> <Card className="border-amber-300 bg-amber-50/50">
<CardContent className="p-3"> <CardContent className="p-3">
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
<AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5 shrink-0" /> <AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5 shrink-0" />
<div className="space-y-1"> <div className="space-y-1">
{preview.warnings.map((w: string, idx: number) => ( {preview.warnings.map((w: string, idx: number) => (
<p key={idx} className="text-xs text-amber-800 dark:text-amber-200"> <p key={idx} className="text-xs text-amber-800">
{w} {w}
</p> </p>
))} ))}

View File

@@ -259,7 +259,7 @@ export function AwardShortlist({
} }
</p> </p>
{eligibilityMode === 'SEPARATE_POOL' && !hasAwardRounds && ( {eligibilityMode === 'SEPARATE_POOL' && !hasAwardRounds && (
<div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-800 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-300"> <div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-800">
<AlertTriangle className="h-4 w-4 mt-0.5 shrink-0" /> <AlertTriangle className="h-4 w-4 mt-0.5 shrink-0" />
<p className="text-sm"> <p className="text-sm">
No award rounds have been created yet. Projects will be confirmed but <strong>not routed</strong> to an evaluation track. Create rounds on the award page first. No award rounds have been created yet. Projects will be confirmed but <strong>not routed</strong> to an evaluation track. Create rounds on the award page first.

View File

@@ -328,13 +328,13 @@ export function FinalizationTab({ roundId, roundStatus }: FinalizationTabProps)
<div className="space-y-6"> <div className="space-y-6">
{/* Grace Period Banner */} {/* Grace Period Banner */}
{summary.isGracePeriodActive && ( {summary.isGracePeriodActive && (
<Card className="border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950/20"> <Card className="border-amber-200 bg-amber-50">
<CardContent className="flex items-center justify-between py-4"> <CardContent className="flex items-center justify-between py-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Clock className="h-5 w-5 text-amber-600" /> <Clock className="h-5 w-5 text-amber-600" />
<div> <div>
<p className="font-medium text-amber-800 dark:text-amber-200">Grace Period Active</p> <p className="font-medium text-amber-800">Grace Period Active</p>
<p className="text-sm text-amber-600 dark:text-amber-400"> <p className="text-sm text-amber-600">
Applicants can still submit until{' '} Applicants can still submit until{' '}
{summary.gracePeriodEndsAt {summary.gracePeriodEndsAt
? new Date(summary.gracePeriodEndsAt).toLocaleString() ? new Date(summary.gracePeriodEndsAt).toLocaleString()
@@ -358,12 +358,12 @@ export function FinalizationTab({ roundId, roundStatus }: FinalizationTabProps)
{/* Finalized Banner */} {/* Finalized Banner */}
{summary.isFinalized && ( {summary.isFinalized && (
<Card className="border-green-200 bg-green-50 dark:border-green-800 dark:bg-green-950/20"> <Card className="border-green-200 bg-green-50">
<CardContent className="flex items-center gap-3 py-4"> <CardContent className="flex items-center gap-3 py-4">
<CheckCircle2 className="h-5 w-5 text-green-600" /> <CheckCircle2 className="h-5 w-5 text-green-600" />
<div> <div>
<p className="font-medium text-green-800 dark:text-green-200">Round Finalized</p> <p className="font-medium text-green-800">Round Finalized</p>
<p className="text-sm text-green-600 dark:text-green-400"> <p className="text-sm text-green-600">
Finalized on{' '} Finalized on{' '}
{summary.finalizedAt {summary.finalizedAt
? new Date(summary.finalizedAt).toLocaleString() ? new Date(summary.finalizedAt).toLocaleString()
@@ -376,13 +376,13 @@ export function FinalizationTab({ roundId, roundStatus }: FinalizationTabProps)
{/* Needs Processing Banner */} {/* Needs Processing Banner */}
{!summary.isFinalized && !summary.isGracePeriodActive && summary.projects.length > 0 && summary.projects.every((p) => !p.proposedOutcome) && ( {!summary.isFinalized && !summary.isGracePeriodActive && summary.projects.length > 0 && summary.projects.every((p) => !p.proposedOutcome) && (
<Card className="border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/20"> <Card className="border-blue-200 bg-blue-50">
<CardContent className="flex items-center justify-between py-4"> <CardContent className="flex items-center justify-between py-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<AlertTriangle className="h-5 w-5 text-blue-600" /> <AlertTriangle className="h-5 w-5 text-blue-600" />
<div> <div>
<p className="font-medium text-blue-800 dark:text-blue-200">Projects Need Processing</p> <p className="font-medium text-blue-800">Projects Need Processing</p>
<p className="text-sm text-blue-600 dark:text-blue-400"> <p className="text-sm text-blue-600">
{summary.projects.length} project{summary.projects.length !== 1 ? 's' : ''} in this round have no proposed outcome. {summary.projects.length} project{summary.projects.length !== 1 ? 's' : ''} in this round have no proposed outcome.
Click &quot;Process&quot; to auto-assign outcomes based on round type and project activity. Click &quot;Process&quot; to auto-assign outcomes based on round type and project activity.
</p> </p>

View File

@@ -124,7 +124,7 @@ export function MentoringRoundOverview({ roundId }: Props) {
<p className="text-muted-foreground mt-1 text-xs"> <p className="text-muted-foreground mt-1 text-xs">
{assignedPct}% of round{' '} {assignedPct}% of round{' '}
{stats.awaitingAssignment > 0 && ( {stats.awaitingAssignment > 0 && (
<span className="text-amber-700 dark:text-amber-400"> <span className="text-amber-700">
· {stats.awaitingAssignment} awaiting · {stats.awaitingAssignment} awaiting
</span> </span>
)} )}
@@ -189,7 +189,7 @@ export function MentoringRoundOverview({ roundId }: Props) {
<Card <Card
className={`md:col-span-2 xl:col-span-4 ${ className={`md:col-span-2 xl:col-span-4 ${
pendingCount > 0 ? 'border-amber-300 dark:border-amber-700' : '' pendingCount > 0 ? 'border-amber-300' : ''
}`} }`}
> >
<CardContent className="flex items-center justify-between py-4"> <CardContent className="flex items-center justify-between py-4">

View File

@@ -290,8 +290,8 @@ export function ProjectStatesTable({ competitionId, roundId, roundStatus, compet
<div className="space-y-4"> <div className="space-y-4">
{/* Finalization hint for closed rounds */} {/* Finalization hint for closed rounds */}
{(roundStatus === 'ROUND_CLOSED' || roundStatus === 'ROUND_ARCHIVED') && ( {(roundStatus === 'ROUND_CLOSED' || roundStatus === 'ROUND_ARCHIVED') && (
<div className="flex items-center gap-2 rounded-lg border border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/20 px-4 py-3 text-sm"> <div className="flex items-center gap-2 rounded-lg border border-blue-200 bg-blue-50 px-4 py-3 text-sm">
<span className="text-blue-700 dark:text-blue-300"> <span className="text-blue-700">
This round is closed. Use the <strong>Finalization</strong> tab to review proposed outcomes and confirm advancement. This round is closed. Use the <strong>Finalization</strong> tab to review proposed outcomes and confirm advancement.
</span> </span>
</div> </div>

View File

@@ -699,7 +699,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
This may take a minute. You can continue working results will appear automatically. This may take a minute. You can continue working results will appear automatically.
</p> </p>
</div> </div>
<div className="h-2 w-48 rounded-full bg-blue-100 dark:bg-blue-900 overflow-hidden"> <div className="h-2 w-48 rounded-full bg-blue-100 overflow-hidden">
<div className="h-full w-full rounded-full bg-blue-500 animate-pulse" /> <div className="h-full w-full rounded-full bg-blue-500 animate-pulse" />
</div> </div>
</> </>
@@ -962,18 +962,18 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
{/* Ranking in-progress banner */} {/* Ranking in-progress banner */}
{rankingInProgress && ( {rankingInProgress && (
<Card className="border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/30"> <Card className="border-blue-200 bg-blue-50">
<CardContent className="flex items-center gap-3 py-4"> <CardContent className="flex items-center gap-3 py-4">
<Loader2 className="h-5 w-5 animate-spin text-blue-600 dark:text-blue-400 flex-shrink-0" /> <Loader2 className="h-5 w-5 animate-spin text-blue-600 flex-shrink-0" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-blue-900 dark:text-blue-200"> <p className="text-sm font-medium text-blue-900">
Ranking in progress&hellip; Ranking in progress&hellip;
</p> </p>
<p className="text-xs text-blue-700 dark:text-blue-400"> <p className="text-xs text-blue-700">
This may take a minute. You can continue working results will appear automatically. This may take a minute. You can continue working results will appear automatically.
</p> </p>
</div> </div>
<div className="h-1.5 w-32 rounded-full bg-blue-200 dark:bg-blue-800 overflow-hidden flex-shrink-0"> <div className="h-1.5 w-32 rounded-full bg-blue-200 overflow-hidden flex-shrink-0">
<div className="h-full w-full rounded-full bg-blue-500 animate-pulse" /> <div className="h-full w-full rounded-full bg-blue-500 animate-pulse" />
</div> </div>
</CardContent> </CardContent>
@@ -1097,7 +1097,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }} exit={{ opacity: 0, y: -20 }}
className={isAdvancing className={isAdvancing
? 'rounded-lg bg-emerald-50 border-l-4 border-emerald-400 dark:bg-emerald-950/20 dark:border-emerald-600' ? 'rounded-lg bg-emerald-50 border-l-4 border-emerald-400'
: ''} : ''}
> >
<SortableProjectRow <SortableProjectRow
@@ -1120,7 +1120,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
{isCutoffRow && ( {isCutoffRow && (
<div className="flex items-center gap-2 py-1"> <div className="flex items-center gap-2 py-1">
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" /> <div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400 whitespace-nowrap"> <span className="text-xs font-medium text-emerald-600 whitespace-nowrap">
Advancement cutoff {isThresholdMode ? `Score ≥ ${threshold}` : `Top ${advanceCount}`} Advancement cutoff {isThresholdMode ? `Score ≥ ${threshold}` : `Top ${advanceCount}`}
</span> </span>
<div className="flex-1 border-t-2 border-dashed border-emerald-400/60" /> <div className="flex-1 border-t-2 border-dashed border-emerald-400/60" />

View File

@@ -33,19 +33,19 @@ const severityConfig = {
critical: { critical: {
icon: AlertTriangle, icon: AlertTriangle,
iconClass: 'text-red-600', iconClass: 'text-red-600',
bgClass: 'bg-red-50 dark:bg-red-950/30', bgClass: 'bg-red-50',
borderClass: 'border-l-red-500', borderClass: 'border-l-red-500',
}, },
warning: { warning: {
icon: AlertCircle, icon: AlertCircle,
iconClass: 'text-amber-600', iconClass: 'text-amber-600',
bgClass: 'bg-amber-50 dark:bg-amber-950/30', bgClass: 'bg-amber-50',
borderClass: 'border-l-amber-500', borderClass: 'border-l-amber-500',
}, },
info: { info: {
icon: Info, icon: Info,
iconClass: 'text-blue-600', iconClass: 'text-blue-600',
bgClass: 'bg-blue-50 dark:bg-blue-950/30', bgClass: 'bg-blue-50',
borderClass: 'border-l-blue-500', borderClass: 'border-l-blue-500',
}, },
} }
@@ -54,8 +54,8 @@ export function SmartActions({ actions }: SmartActionsProps) {
return ( return (
<Card> <Card>
<CardHeader className="flex flex-row items-center gap-3 space-y-0 pb-4"> <CardHeader className="flex flex-row items-center gap-3 space-y-0 pb-4">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-amber-100 dark:bg-amber-900/40"> <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-amber-100">
<Zap className="h-5 w-5 text-amber-600 dark:text-amber-400" /> <Zap className="h-5 w-5 text-amber-600" />
</div> </div>
<CardTitle className="flex-1">Action Required</CardTitle> <CardTitle className="flex-1">Action Required</CardTitle>
{actions.length > 0 && ( {actions.length > 0 && (
@@ -65,8 +65,8 @@ export function SmartActions({ actions }: SmartActionsProps) {
<CardContent> <CardContent>
{actions.length === 0 ? ( {actions.length === 0 ? (
<div className="flex flex-col items-center justify-center py-8 text-center"> <div className="flex flex-col items-center justify-center py-8 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-900/40"> <div className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-100">
<CheckCircle2 className="h-6 w-6 text-emerald-600 dark:text-emerald-400" /> <CheckCircle2 className="h-6 w-6 text-emerald-600" />
</div> </div>
<p className="mt-3 text-sm font-medium text-muted-foreground"> <p className="mt-3 text-sm font-medium text-muted-foreground">
All caught up! All caught up!

View File

@@ -207,7 +207,7 @@ export function EvaluationFormFields({
className={cn( className={cn(
'flex-1 h-12 rounded-lg border-2 flex items-center justify-center text-sm font-medium transition-all', 'flex-1 h-12 rounded-lg border-2 flex items-center justify-center text-sm font-medium transition-all',
currentValue === true currentValue === true
? 'border-emerald-500 bg-emerald-50 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-400' ? 'border-emerald-500 bg-emerald-50 text-emerald-700'
: 'border-border hover:border-emerald-300 hover:bg-emerald-50/50', : 'border-border hover:border-emerald-300 hover:bg-emerald-50/50',
isReadOnly && 'opacity-60 cursor-default', isReadOnly && 'opacity-60 cursor-default',
)} )}
@@ -222,7 +222,7 @@ export function EvaluationFormFields({
className={cn( className={cn(
'flex-1 h-12 rounded-lg border-2 flex items-center justify-center text-sm font-medium transition-all', 'flex-1 h-12 rounded-lg border-2 flex items-center justify-center text-sm font-medium transition-all',
currentValue === false currentValue === false
? 'border-red-500 bg-red-50 text-red-700 dark:bg-red-950/40 dark:text-red-400' ? 'border-red-500 bg-red-50 text-red-700'
: 'border-border hover:border-red-300 hover:bg-red-50/50', : 'border-border hover:border-red-300 hover:bg-red-50/50',
isReadOnly && 'opacity-60 cursor-default', isReadOnly && 'opacity-60 cursor-default',
)} )}

View File

@@ -83,10 +83,10 @@ export function EvaluationFormWithCOI({
<CardContent className="flex items-center gap-3 py-6"> <CardContent className="flex items-center gap-3 py-6">
<ShieldAlert className="h-6 w-6 text-amber-600 shrink-0" /> <ShieldAlert className="h-6 w-6 text-amber-600 shrink-0" />
<div> <div>
<p className="font-medium text-amber-800 dark:text-amber-200"> <p className="font-medium text-amber-800">
Conflict of Interest Declared Conflict of Interest Declared
</p> </p>
<p className="text-sm text-amber-700 dark:text-amber-300 mt-1"> <p className="text-sm text-amber-700 mt-1">
You declared a conflict of interest for this project. An admin will You declared a conflict of interest for this project. An admin will
review your declaration. You cannot evaluate this project while the review your declaration. You cannot evaluate this project while the
conflict is under review. conflict is under review.

View File

@@ -62,7 +62,7 @@ export function JuryPreferencesBanner() {
if (isLoading || unconfirmed.length === 0) return null if (isLoading || unconfirmed.length === 0) return null
return ( return (
<Card className="border-amber-300 bg-amber-50/50 dark:border-amber-800 dark:bg-amber-950/20"> <Card className="border-amber-300 bg-amber-50/50">
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Scale className="h-5 w-5 text-amber-600" /> <Scale className="h-5 w-5 text-amber-600" />

View File

@@ -9,10 +9,10 @@ import { Radio, Users, Trophy, Eye, EyeOff } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
const SESSION_STATUS_CONFIG: Record<string, { label: string; color: string; bg: string; pulse?: boolean }> = { const SESSION_STATUS_CONFIG: Record<string, { label: string; color: string; bg: string; pulse?: boolean }> = {
NOT_STARTED: { label: 'Not Started', color: 'text-slate-500', bg: 'bg-slate-100 dark:bg-slate-800' }, NOT_STARTED: { label: 'Not Started', color: 'text-slate-500', bg: 'bg-slate-100' },
IN_PROGRESS: { label: 'In Progress', color: 'text-emerald-600', bg: 'bg-emerald-50 dark:bg-emerald-900/20', pulse: true }, IN_PROGRESS: { label: 'In Progress', color: 'text-emerald-600', bg: 'bg-emerald-50', pulse: true },
PAUSED: { label: 'Paused', color: 'text-amber-600', bg: 'bg-amber-50 dark:bg-amber-900/20' }, PAUSED: { label: 'Paused', color: 'text-amber-600', bg: 'bg-amber-50' },
COMPLETED: { label: 'Completed', color: 'text-blue-600', bg: 'bg-blue-50 dark:bg-blue-900/20' }, COMPLETED: { label: 'Completed', color: 'text-blue-600', bg: 'bg-blue-50' },
} }
export function LiveFinalPanel({ roundId }: { roundId: string }) { export function LiveFinalPanel({ roundId }: { roundId: string }) {

View File

@@ -52,7 +52,7 @@ export function PreviousRoundSection({ currentRoundId }: { currentRoundId: strin
{!collapsed && ( {!collapsed && (
<CardContent className="space-y-4"> <CardContent className="space-y-4">
{/* Headline Stat */} {/* Headline Stat */}
<div className="flex items-center gap-3 rounded-lg bg-rose-50 dark:bg-rose-950/20 p-4"> <div className="flex items-center gap-3 rounded-lg bg-rose-50 p-4">
<ArrowDown className="h-6 w-6 text-rose-500 shrink-0" /> <ArrowDown className="h-6 w-6 text-rose-500 shrink-0" />
<div> <div>
<p className="text-lg font-semibold"> <p className="text-lg font-semibold">
@@ -85,7 +85,7 @@ export function PreviousRoundSection({ currentRoundId }: { currentRoundId: strin
</div> </div>
<div className="relative h-2.5 rounded-full bg-muted overflow-hidden"> <div className="relative h-2.5 rounded-full bg-muted overflow-hidden">
<div <div
className="absolute inset-y-0 left-0 rounded-full bg-slate-300 dark:bg-slate-600 transition-all" className="absolute inset-y-0 left-0 rounded-full bg-slate-300 transition-all"
style={{ width: `${prevPct}%` }} style={{ width: `${prevPct}%` }}
/> />
<div <div

View File

@@ -37,9 +37,9 @@ type OutcomeFilter = 'ALL' | 'PASSED' | 'FILTERED_OUT' | 'FLAGGED'
function outcomeTextColor(outcome: string): string { function outcomeTextColor(outcome: string): string {
switch (outcome) { switch (outcome) {
case 'PASSED': return 'text-emerald-700 dark:text-emerald-400' case 'PASSED': return 'text-emerald-700'
case 'FILTERED_OUT': return 'text-rose-700 dark:text-rose-400' case 'FILTERED_OUT': return 'text-rose-700'
case 'FLAGGED': return 'text-amber-700 dark:text-amber-400' case 'FLAGGED': return 'text-amber-700'
default: return 'text-primary' default: return 'text-primary'
} }
} }

View File

@@ -339,8 +339,8 @@ export function StorageSettingsForm({ settings }: StorageSettingsFormProps) {
)} )}
{storageProvider === 'local' && ( {storageProvider === 'local' && (
<div className="rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-900 dark:bg-amber-950"> <div className="rounded-lg border border-amber-200 bg-amber-50 p-4">
<p className="text-sm text-amber-800 dark:text-amber-200"> <p className="text-sm text-amber-800">
<strong>Warning:</strong> Local storage is not recommended for production deployments <strong>Warning:</strong> Local storage is not recommended for production deployments
with multiple servers, as files will only be accessible from the server that uploaded them. with multiple servers, as files will only be accessible from the server that uploaded them.
</p> </p>

View File

@@ -62,9 +62,9 @@ function getUrgency(totalMs: number): Urgency {
const urgencyStyles: Record<Urgency, string> = { const urgencyStyles: Record<Urgency, string> = {
expired: 'text-muted-foreground bg-muted', expired: 'text-muted-foreground bg-muted',
critical: 'text-red-700 bg-red-50 border-red-200 dark:text-red-400 dark:bg-red-950/50 dark:border-red-900', critical: 'text-red-700 bg-red-50 border-red-200',
warning: 'text-amber-700 bg-amber-50 border-amber-200 dark:text-amber-400 dark:bg-amber-950/50 dark:border-amber-900', warning: 'text-amber-700 bg-amber-50 border-amber-200',
normal: 'text-green-700 bg-green-50 border-green-200 dark:text-green-400 dark:bg-green-950/50 dark:border-green-900', normal: 'text-green-700 bg-green-50 border-green-200',
} }
export function CountdownTimer({ deadline, label, className }: CountdownTimerProps) { export function CountdownTimer({ deadline, label, className }: CountdownTimerProps) {

View File

@@ -19,18 +19,18 @@ import { useState } from 'react'
const statusConfig: Record<string, { bg: string; text: string; dot: string }> = { const statusConfig: Record<string, { bg: string; text: string; dot: string }> = {
DRAFT: { DRAFT: {
bg: 'bg-amber-50 dark:bg-amber-950/50', bg: 'bg-amber-50',
text: 'text-amber-700 dark:text-amber-400', text: 'text-amber-700',
dot: 'bg-amber-500', dot: 'bg-amber-500',
}, },
ACTIVE: { ACTIVE: {
bg: 'bg-emerald-50 dark:bg-emerald-950/50', bg: 'bg-emerald-50',
text: 'text-emerald-700 dark:text-emerald-400', text: 'text-emerald-700',
dot: 'bg-emerald-500', dot: 'bg-emerald-500',
}, },
ARCHIVED: { ARCHIVED: {
bg: 'bg-slate-100 dark:bg-slate-800/50', bg: 'bg-slate-100',
text: 'text-slate-600 dark:text-slate-400', text: 'text-slate-600',
dot: 'bg-slate-400', dot: 'bg-slate-400',
}, },
} }
@@ -95,10 +95,10 @@ export function EditionSelector() {
{/* Text */} {/* Text */}
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="truncate text-sm font-semibold text-slate-900 dark:text-slate-100"> <p className="truncate text-sm font-semibold text-slate-900">
{currentEdition ? currentEdition.year : 'Select'} {currentEdition ? currentEdition.year : 'Select'}
</p> </p>
<p className="truncate text-xs text-slate-500 dark:text-slate-400"> <p className="truncate text-xs text-slate-500">
{currentEdition?.status === 'ACTIVE' ? 'Current Edition' : currentEdition?.status?.toLowerCase()} {currentEdition?.status === 'ACTIVE' ? 'Current Edition' : currentEdition?.status?.toLowerCase()}
</p> </p>
</div> </div>
@@ -136,7 +136,7 @@ export function EditionSelector() {
}} }}
className={cn( className={cn(
'group/item flex items-center gap-3 rounded-lg px-2.5 py-2.5 cursor-pointer transition-colors', 'group/item flex items-center gap-3 rounded-lg px-2.5 py-2.5 cursor-pointer transition-colors',
isSelected ? 'bg-slate-100 dark:bg-slate-800' : 'hover:bg-slate-50 dark:hover:bg-slate-800/50' isSelected ? 'bg-slate-100' : 'hover:bg-slate-50'
)} )}
> >
{/* Year badge in dropdown */} {/* Year badge in dropdown */}
@@ -144,19 +144,19 @@ export function EditionSelector() {
'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg font-bold text-sm transition-colors', 'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg font-bold text-sm transition-colors',
isSelected isSelected
? 'bg-brand-blue text-white' ? 'bg-brand-blue text-white'
: 'bg-slate-200 text-slate-600 dark:bg-slate-700 dark:text-slate-300' : 'bg-slate-200 text-slate-600'
)}> )}>
{String(edition.year).slice(-2)} {String(edition.year).slice(-2)}
</div> </div>
{/* Edition info */} {/* Edition info */}
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="truncate text-sm font-semibold text-slate-900 dark:text-slate-100"> <p className="truncate text-sm font-semibold text-slate-900">
{edition.year} {edition.year}
</p> </p>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<div className={cn('h-1.5 w-1.5 rounded-full', editionStatus.dot)} /> <div className={cn('h-1.5 w-1.5 rounded-full', editionStatus.dot)} />
<span className="text-xs text-slate-500 dark:text-slate-400 capitalize"> <span className="text-xs text-slate-500 capitalize">
{edition.status.toLowerCase()} {edition.status.toLowerCase()}
</span> </span>
</div> </div>

View File

@@ -827,9 +827,9 @@ function RequirementChecklist({ roundId, files }: { roundId: string; files: Proj
className={cn( className={cn(
'flex items-center gap-3 rounded-lg border p-2.5 text-sm', 'flex items-center gap-3 rounded-lg border p-2.5 text-sm',
isFulfilled isFulfilled
? 'border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950' ? 'border-green-200 bg-green-50'
: req.isRequired : req.isRequired
? 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950' ? 'border-red-200 bg-red-50'
: 'border-muted' : 'border-muted'
)} )}
> >

View File

@@ -108,20 +108,20 @@ const ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
// Priority styles // Priority styles
const PRIORITY_STYLES = { const PRIORITY_STYLES = {
low: { low: {
iconBg: 'bg-slate-100 dark:bg-slate-800', iconBg: 'bg-slate-100',
iconColor: 'text-slate-500', iconColor: 'text-slate-500',
}, },
normal: { normal: {
iconBg: 'bg-blue-100 dark:bg-blue-900/30', iconBg: 'bg-blue-100',
iconColor: 'text-blue-600 dark:text-blue-400', iconColor: 'text-blue-600',
}, },
high: { high: {
iconBg: 'bg-amber-100 dark:bg-amber-900/30', iconBg: 'bg-amber-100',
iconColor: 'text-amber-600 dark:text-amber-400', iconColor: 'text-amber-600',
}, },
urgent: { urgent: {
iconBg: 'bg-red-100 dark:bg-red-900/30', iconBg: 'bg-red-100',
iconColor: 'text-red-600 dark:text-red-400', iconColor: 'text-red-600',
}, },
} }
@@ -158,7 +158,7 @@ function NotificationItem({
data-notification-id={notification.id} data-notification-id={notification.id}
className={cn( className={cn(
'flex gap-3 p-3 hover:bg-muted/50 transition-colors cursor-pointer', 'flex gap-3 p-3 hover:bg-muted/50 transition-colors cursor-pointer',
!notification.isRead && 'bg-blue-50/50 dark:bg-blue-950/20' !notification.isRead && 'bg-blue-50/50'
)} )}
onClick={onRead} onClick={onRead}
> >

View File

@@ -263,9 +263,9 @@ export function RequirementUploadSlot({
const isFulfilled = !!existingFile const isFulfilled = !!existingFile
const statusColor = isFulfilled const statusColor = isFulfilled
? 'border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950' ? 'border-green-200 bg-green-50'
: requirement.isRequired : requirement.isRequired
? 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950' ? 'border-red-200 bg-red-50'
: 'border-muted' : 'border-muted'
// Build accept string for file input // Build accept string for file input

View File

@@ -4,39 +4,39 @@ import { cn } from '@/lib/utils'
const STATUS_STYLES: Record<string, { variant: BadgeProps['variant']; className?: string }> = { const STATUS_STYLES: Record<string, { variant: BadgeProps['variant']; className?: string }> = {
// Round statuses // Round statuses
DRAFT: { variant: 'secondary' }, DRAFT: { variant: 'secondary' },
ACTIVE: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200 dark:text-blue-400' }, ACTIVE: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200' },
EVALUATION: { variant: 'default', className: 'bg-violet-500/10 text-violet-700 border-violet-200 dark:text-violet-400' }, EVALUATION: { variant: 'default', className: 'bg-violet-500/10 text-violet-700 border-violet-200' },
CLOSED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' }, CLOSED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' },
ROUND_DRAFT: { variant: 'secondary' }, ROUND_DRAFT: { variant: 'secondary' },
ROUND_ACTIVE: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200 dark:text-blue-400' }, ROUND_ACTIVE: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200' },
ROUND_CLOSED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' }, ROUND_CLOSED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' },
ROUND_ARCHIVED: { variant: 'secondary', className: 'bg-slate-400/10 text-slate-400 border-slate-200' }, ROUND_ARCHIVED: { variant: 'secondary', className: 'bg-slate-400/10 text-slate-400 border-slate-200' },
// Project statuses // Project statuses
SUBMITTED: { variant: 'secondary', className: 'bg-indigo-500/10 text-indigo-700 border-indigo-200 dark:text-indigo-400' }, SUBMITTED: { variant: 'secondary', className: 'bg-indigo-500/10 text-indigo-700 border-indigo-200' },
ELIGIBLE: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200 dark:text-emerald-400' }, ELIGIBLE: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200' },
ASSIGNED: { variant: 'default', className: 'bg-violet-500/10 text-violet-700 border-violet-200 dark:text-violet-400' }, ASSIGNED: { variant: 'default', className: 'bg-violet-500/10 text-violet-700 border-violet-200' },
UNDER_REVIEW: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200 dark:text-blue-400' }, UNDER_REVIEW: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200' },
SHORTLISTED: { variant: 'default', className: 'bg-amber-500/10 text-amber-700 border-amber-200 dark:text-amber-400' }, SHORTLISTED: { variant: 'default', className: 'bg-amber-500/10 text-amber-700 border-amber-200' },
SEMIFINALIST: { variant: 'default', className: 'bg-amber-500/10 text-amber-700 border-amber-200 dark:text-amber-400' }, SEMIFINALIST: { variant: 'default', className: 'bg-amber-500/10 text-amber-700 border-amber-200' },
FINALIST: { variant: 'default', className: 'bg-orange-500/10 text-orange-700 border-orange-200 dark:text-orange-400' }, FINALIST: { variant: 'default', className: 'bg-orange-500/10 text-orange-700 border-orange-200' },
WINNER: { variant: 'default', className: 'bg-yellow-500/10 text-yellow-800 border-yellow-300 dark:text-yellow-400' }, WINNER: { variant: 'default', className: 'bg-yellow-500/10 text-yellow-800 border-yellow-300' },
REJECTED: { variant: 'destructive' }, REJECTED: { variant: 'destructive' },
WITHDRAWN: { variant: 'secondary' }, WITHDRAWN: { variant: 'secondary' },
// Observer-derived statuses // Observer-derived statuses
NOT_REVIEWED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200 dark:text-slate-400' }, NOT_REVIEWED: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' },
REVIEWED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200 dark:text-emerald-400' }, REVIEWED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200' },
// Round state statuses // Round state statuses
PENDING: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200 dark:text-slate-400' }, PENDING: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-600 border-slate-200' },
IN_PROGRESS: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200 dark:text-blue-400' }, IN_PROGRESS: { variant: 'default', className: 'bg-blue-500/10 text-blue-700 border-blue-200' },
COMPLETED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200 dark:text-emerald-400' }, COMPLETED: { variant: 'default', className: 'bg-emerald-500/10 text-emerald-700 border-emerald-200' },
PASSED: { variant: 'default', className: 'bg-green-500/10 text-green-700 border-green-200 dark:text-green-400' }, PASSED: { variant: 'default', className: 'bg-green-500/10 text-green-700 border-green-200' },
// User statuses // User statuses
NONE: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-500 border-slate-200 dark:text-slate-400' }, NONE: { variant: 'secondary', className: 'bg-slate-500/10 text-slate-500 border-slate-200' },
INVITED: { variant: 'secondary', className: 'bg-sky-500/10 text-sky-700 border-sky-200 dark:text-sky-400' }, INVITED: { variant: 'secondary', className: 'bg-sky-500/10 text-sky-700 border-sky-200' },
INACTIVE: { variant: 'secondary' }, INACTIVE: { variant: 'secondary' },
SUSPENDED: { variant: 'destructive' }, SUSPENDED: { variant: 'destructive' },
} }

View File

@@ -9,11 +9,11 @@ const alertVariants = cva(
variant: { variant: {
default: "bg-background text-foreground", default: "bg-background text-foreground",
destructive: destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", "border-destructive/50 text-destructive [&>svg]:text-destructive",
success: success:
"border-green-500/50 text-green-700 dark:border-green-500 [&>svg]:text-green-600", "border-green-500/50 text-green-700 [&>svg]:text-green-600",
warning: warning:
"border-yellow-500/50 text-yellow-700 dark:border-yellow-500 [&>svg]:text-yellow-600", "border-yellow-500/50 text-yellow-700 [&>svg]:text-yellow-600",
}, },
}, },
defaultVariants: { defaultVariants: {

View File

@@ -15,10 +15,10 @@ const badgeVariants = cva(
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80', 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
outline: 'text-foreground', outline: 'text-foreground',
success: success:
'border-transparent bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100', 'border-transparent bg-green-100 text-green-800',
warning: warning:
'border-transparent bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100', 'border-transparent bg-amber-100 text-amber-800',
info: 'border-transparent bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-100', info: 'border-transparent bg-blue-100 text-blue-800',
}, },
}, },
defaultVariants: { defaultVariants: {