Spaces:
Running
Running
gpt-engineer-app[bot]
commited on
Commit
·
bfd3ad3
1
Parent(s):
38de65f
Add countdown and rename title
Browse filesAdds a countdown timer to each conference card. Renames the page title to "AI Conference Deadlines".
src/components/ConferenceCard.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
-
|
|
|
|
| 2 |
import { Conference } from "@/types/conference";
|
| 3 |
-
import { formatDistanceToNow, parseISO } from "date-fns";
|
| 4 |
|
| 5 |
const ConferenceCard = ({
|
| 6 |
title,
|
|
@@ -15,8 +16,17 @@ const ConferenceCard = ({
|
|
| 15 |
abstract_deadline,
|
| 16 |
}: Conference) => {
|
| 17 |
const deadlineDate = deadline && deadline !== 'TBD' ? parseISO(deadline) : null;
|
| 18 |
-
const daysLeft = deadlineDate ? formatDistanceToNow(deadlineDate, { addSuffix: true }) : 'TBD';
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
return (
|
| 21 |
<div className="conference-card">
|
| 22 |
<div className="flex justify-between items-start mb-4">
|
|
@@ -56,6 +66,12 @@ const ConferenceCard = ({
|
|
| 56 |
</span>
|
| 57 |
)}
|
| 58 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
</div>
|
| 60 |
|
| 61 |
{Array.isArray(tags) && tags.length > 0 && (
|
|
|
|
| 1 |
+
|
| 2 |
+
import { CalendarDays, Globe, Tag, Clock, AlarmClock } from "lucide-react";
|
| 3 |
import { Conference } from "@/types/conference";
|
| 4 |
+
import { formatDistanceToNow, parseISO, isValid } from "date-fns";
|
| 5 |
|
| 6 |
const ConferenceCard = ({
|
| 7 |
title,
|
|
|
|
| 16 |
abstract_deadline,
|
| 17 |
}: Conference) => {
|
| 18 |
const deadlineDate = deadline && deadline !== 'TBD' ? parseISO(deadline) : null;
|
| 19 |
+
const daysLeft = deadlineDate && isValid(deadlineDate) ? formatDistanceToNow(deadlineDate, { addSuffix: true }) : 'TBD';
|
| 20 |
|
| 21 |
+
// Determine countdown color based on days remaining
|
| 22 |
+
const getCountdownColor = () => {
|
| 23 |
+
if (!deadlineDate || !isValid(deadlineDate)) return "text-neutral-600";
|
| 24 |
+
const daysRemaining = Math.ceil((deadlineDate.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24));
|
| 25 |
+
if (daysRemaining <= 7) return "text-red-600";
|
| 26 |
+
if (daysRemaining <= 30) return "text-orange-600";
|
| 27 |
+
return "text-green-600";
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
return (
|
| 31 |
<div className="conference-card">
|
| 32 |
<div className="flex justify-between items-start mb-4">
|
|
|
|
| 66 |
</span>
|
| 67 |
)}
|
| 68 |
</div>
|
| 69 |
+
<div className="flex items-center">
|
| 70 |
+
<AlarmClock className={`h-4 w-4 mr-2 ${getCountdownColor()}`} />
|
| 71 |
+
<span className={`text-sm font-medium ${getCountdownColor()}`}>
|
| 72 |
+
{daysLeft}
|
| 73 |
+
</span>
|
| 74 |
+
</div>
|
| 75 |
</div>
|
| 76 |
|
| 77 |
{Array.isArray(tags) && tags.length > 0 && (
|
src/components/Header.tsx
CHANGED
|
@@ -1,10 +1,7 @@
|
|
| 1 |
-
import { Search } from "lucide-react";
|
| 2 |
|
| 3 |
-
|
| 4 |
-
onSearch: (query: string) => void;
|
| 5 |
-
}
|
| 6 |
|
| 7 |
-
const Header = (
|
| 8 |
return (
|
| 9 |
<header className="w-full py-6 px-4 sm:px-6 lg:px-8 bg-white shadow-sm animate-fade-in">
|
| 10 |
<div className="max-w-7xl mx-auto">
|
|
@@ -16,13 +13,12 @@ const Header = ({ onSearch }: HeaderProps) => {
|
|
| 16 |
className="h-8 w-auto"
|
| 17 |
/>
|
| 18 |
<div className="h-6 w-px bg-neutral-200 mx-2" />
|
| 19 |
-
<h1 className="text-2xl font-bold text-neutral-dark">AI Deadlines</h1>
|
| 20 |
</div>
|
| 21 |
<div className="relative w-full max-w-md ml-4">
|
| 22 |
<input
|
| 23 |
type="text"
|
| 24 |
placeholder="Search conferences..."
|
| 25 |
-
onChange={(e) => onSearch(e.target.value)}
|
| 26 |
className="w-full pl-10 pr-4 py-2 border border-neutral-200 rounded-lg focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary bg-neutral-50"
|
| 27 |
/>
|
| 28 |
<Search className="absolute left-3 top-2.5 h-5 w-5 text-neutral" />
|
|
|
|
|
|
|
| 1 |
|
| 2 |
+
import { Search } from "lucide-react";
|
|
|
|
|
|
|
| 3 |
|
| 4 |
+
const Header = () => {
|
| 5 |
return (
|
| 6 |
<header className="w-full py-6 px-4 sm:px-6 lg:px-8 bg-white shadow-sm animate-fade-in">
|
| 7 |
<div className="max-w-7xl mx-auto">
|
|
|
|
| 13 |
className="h-8 w-auto"
|
| 14 |
/>
|
| 15 |
<div className="h-6 w-px bg-neutral-200 mx-2" />
|
| 16 |
+
<h1 className="text-2xl font-bold text-neutral-dark">AI Conference Deadlines</h1>
|
| 17 |
</div>
|
| 18 |
<div className="relative w-full max-w-md ml-4">
|
| 19 |
<input
|
| 20 |
type="text"
|
| 21 |
placeholder="Search conferences..."
|
|
|
|
| 22 |
className="w-full pl-10 pr-4 py-2 border border-neutral-200 rounded-lg focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary bg-neutral-50"
|
| 23 |
/>
|
| 24 |
<Search className="absolute left-3 top-2.5 h-5 w-5 text-neutral" />
|