Spaces:
Running
Running
gpt-engineer-app[bot]
commited on
Commit
·
f46336a
1
Parent(s):
255baa6
Create landing page
Browse filesCreate a landing page for AI deadlines, mimicking the design of Hugging Face's daily papers.
- src/components/ConferenceCard.tsx +55 -0
- src/components/FilterBar.tsx +34 -0
- src/components/Header.tsx +24 -0
- src/index.css +13 -69
- src/pages/Index.tsx +41 -6
- tailwind.config.ts +52 -92
src/components/ConferenceCard.tsx
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import { CalendarDays, Globe, Tag } from "lucide-react";
|
3 |
+
|
4 |
+
interface ConferenceCardProps {
|
5 |
+
name: string;
|
6 |
+
date: string;
|
7 |
+
location: string;
|
8 |
+
deadline: string;
|
9 |
+
daysLeft: number;
|
10 |
+
tags: string[];
|
11 |
+
}
|
12 |
+
|
13 |
+
const ConferenceCard = ({
|
14 |
+
name,
|
15 |
+
date,
|
16 |
+
location,
|
17 |
+
deadline,
|
18 |
+
daysLeft,
|
19 |
+
tags,
|
20 |
+
}: ConferenceCardProps) => {
|
21 |
+
return (
|
22 |
+
<div className="conference-card animate-fade-in">
|
23 |
+
<div className="flex justify-between items-start mb-4">
|
24 |
+
<h3 className="text-xl font-semibold">{name}</h3>
|
25 |
+
<div className="countdown">{daysLeft}d</div>
|
26 |
+
</div>
|
27 |
+
|
28 |
+
<div className="space-y-2 mb-4">
|
29 |
+
<div className="flex items-center text-neutral">
|
30 |
+
<CalendarDays className="h-4 w-4 mr-2" />
|
31 |
+
<span className="text-sm">{date}</span>
|
32 |
+
</div>
|
33 |
+
<div className="flex items-center text-neutral">
|
34 |
+
<Globe className="h-4 w-4 mr-2" />
|
35 |
+
<span className="text-sm">{location}</span>
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
|
39 |
+
<div className="flex flex-wrap gap-2 mb-4">
|
40 |
+
{tags.map((tag) => (
|
41 |
+
<span key={tag} className="tag">
|
42 |
+
<Tag className="h-3 w-3 mr-1" />
|
43 |
+
{tag}
|
44 |
+
</span>
|
45 |
+
))}
|
46 |
+
</div>
|
47 |
+
|
48 |
+
<div className="text-sm text-neutral-dark">
|
49 |
+
Deadline: {deadline}
|
50 |
+
</div>
|
51 |
+
</div>
|
52 |
+
);
|
53 |
+
};
|
54 |
+
|
55 |
+
export default ConferenceCard;
|
src/components/FilterBar.tsx
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
const filters = [
|
3 |
+
"All",
|
4 |
+
"ML",
|
5 |
+
"CV",
|
6 |
+
"NLP",
|
7 |
+
"RO",
|
8 |
+
"SP",
|
9 |
+
"DM",
|
10 |
+
"AP",
|
11 |
+
"KR",
|
12 |
+
"HCI",
|
13 |
+
];
|
14 |
+
|
15 |
+
const FilterBar = () => {
|
16 |
+
return (
|
17 |
+
<div className="w-full py-4 overflow-x-auto bg-white border-b border-neutral-light animate-fade-in">
|
18 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
19 |
+
<div className="flex space-x-4">
|
20 |
+
{filters.map((filter) => (
|
21 |
+
<button
|
22 |
+
key={filter}
|
23 |
+
className="px-4 py-2 text-sm font-medium rounded-lg hover:bg-primary/10 hover:text-primary transition-colors"
|
24 |
+
>
|
25 |
+
{filter}
|
26 |
+
</button>
|
27 |
+
))}
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
);
|
32 |
+
};
|
33 |
+
|
34 |
+
export default FilterBar;
|
src/components/Header.tsx
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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">
|
8 |
+
<div className="flex items-center justify-between">
|
9 |
+
<h1 className="text-2xl font-bold text-primary">AI Deadlines</h1>
|
10 |
+
<div className="relative w-full max-w-md ml-4">
|
11 |
+
<input
|
12 |
+
type="text"
|
13 |
+
placeholder="Search conferences..."
|
14 |
+
className="w-full pl-10 pr-4 py-2 border border-neutral-light rounded-lg focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary"
|
15 |
+
/>
|
16 |
+
<Search className="absolute left-3 top-2.5 h-5 w-5 text-neutral" />
|
17 |
+
</div>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
</header>
|
21 |
+
);
|
22 |
+
};
|
23 |
+
|
24 |
+
export default Header;
|
src/index.css
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
@tailwind base;
|
2 |
@tailwind components;
|
3 |
@tailwind utilities;
|
@@ -6,96 +7,39 @@
|
|
6 |
:root {
|
7 |
--background: 0 0% 100%;
|
8 |
--foreground: 222.2 84% 4.9%;
|
9 |
-
|
10 |
--card: 0 0% 100%;
|
11 |
--card-foreground: 222.2 84% 4.9%;
|
12 |
-
|
13 |
--popover: 0 0% 100%;
|
14 |
--popover-foreground: 222.2 84% 4.9%;
|
15 |
-
|
16 |
--primary: 222.2 47.4% 11.2%;
|
17 |
--primary-foreground: 210 40% 98%;
|
18 |
-
|
19 |
--secondary: 210 40% 96.1%;
|
20 |
--secondary-foreground: 222.2 47.4% 11.2%;
|
21 |
-
|
22 |
--muted: 210 40% 96.1%;
|
23 |
--muted-foreground: 215.4 16.3% 46.9%;
|
24 |
-
|
25 |
--accent: 210 40% 96.1%;
|
26 |
--accent-foreground: 222.2 47.4% 11.2%;
|
27 |
-
|
28 |
--destructive: 0 84.2% 60.2%;
|
29 |
--destructive-foreground: 210 40% 98%;
|
30 |
-
|
31 |
--border: 214.3 31.8% 91.4%;
|
32 |
--input: 214.3 31.8% 91.4%;
|
33 |
--ring: 222.2 84% 4.9%;
|
34 |
-
|
35 |
--radius: 0.5rem;
|
36 |
-
|
37 |
-
--sidebar-background: 0 0% 98%;
|
38 |
-
|
39 |
-
--sidebar-foreground: 240 5.3% 26.1%;
|
40 |
-
|
41 |
-
--sidebar-primary: 240 5.9% 10%;
|
42 |
-
|
43 |
-
--sidebar-primary-foreground: 0 0% 98%;
|
44 |
-
|
45 |
-
--sidebar-accent: 240 4.8% 95.9%;
|
46 |
-
|
47 |
-
--sidebar-accent-foreground: 240 5.9% 10%;
|
48 |
-
|
49 |
-
--sidebar-border: 220 13% 91%;
|
50 |
-
|
51 |
-
--sidebar-ring: 217.2 91.2% 59.8%;
|
52 |
}
|
53 |
|
54 |
-
|
55 |
-
|
56 |
-
--foreground: 210 40% 98%;
|
57 |
-
|
58 |
-
--card: 222.2 84% 4.9%;
|
59 |
-
--card-foreground: 210 40% 98%;
|
60 |
-
|
61 |
-
--popover: 222.2 84% 4.9%;
|
62 |
-
--popover-foreground: 210 40% 98%;
|
63 |
-
|
64 |
-
--primary: 210 40% 98%;
|
65 |
-
--primary-foreground: 222.2 47.4% 11.2%;
|
66 |
-
|
67 |
-
--secondary: 217.2 32.6% 17.5%;
|
68 |
-
--secondary-foreground: 210 40% 98%;
|
69 |
-
|
70 |
-
--muted: 217.2 32.6% 17.5%;
|
71 |
-
--muted-foreground: 215 20.2% 65.1%;
|
72 |
-
|
73 |
-
--accent: 217.2 32.6% 17.5%;
|
74 |
-
--accent-foreground: 210 40% 98%;
|
75 |
-
|
76 |
-
--destructive: 0 62.8% 30.6%;
|
77 |
-
--destructive-foreground: 210 40% 98%;
|
78 |
-
|
79 |
-
--border: 217.2 32.6% 17.5%;
|
80 |
-
--input: 217.2 32.6% 17.5%;
|
81 |
-
--ring: 212.7 26.8% 83.9%;
|
82 |
-
--sidebar-background: 240 5.9% 10%;
|
83 |
-
--sidebar-foreground: 240 4.8% 95.9%;
|
84 |
-
--sidebar-primary: 224.3 76.3% 48%;
|
85 |
-
--sidebar-primary-foreground: 0 0% 100%;
|
86 |
-
--sidebar-accent: 240 3.7% 15.9%;
|
87 |
-
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
88 |
-
--sidebar-border: 240 3.7% 15.9%;
|
89 |
-
--sidebar-ring: 217.2 91.2% 59.8%;
|
90 |
}
|
91 |
}
|
92 |
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
}
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
1 |
+
|
2 |
@tailwind base;
|
3 |
@tailwind components;
|
4 |
@tailwind utilities;
|
|
|
7 |
:root {
|
8 |
--background: 0 0% 100%;
|
9 |
--foreground: 222.2 84% 4.9%;
|
|
|
10 |
--card: 0 0% 100%;
|
11 |
--card-foreground: 222.2 84% 4.9%;
|
|
|
12 |
--popover: 0 0% 100%;
|
13 |
--popover-foreground: 222.2 84% 4.9%;
|
|
|
14 |
--primary: 222.2 47.4% 11.2%;
|
15 |
--primary-foreground: 210 40% 98%;
|
|
|
16 |
--secondary: 210 40% 96.1%;
|
17 |
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
|
18 |
--muted: 210 40% 96.1%;
|
19 |
--muted-foreground: 215.4 16.3% 46.9%;
|
|
|
20 |
--accent: 210 40% 96.1%;
|
21 |
--accent-foreground: 222.2 47.4% 11.2%;
|
|
|
22 |
--destructive: 0 84.2% 60.2%;
|
23 |
--destructive-foreground: 210 40% 98%;
|
|
|
24 |
--border: 214.3 31.8% 91.4%;
|
25 |
--input: 214.3 31.8% 91.4%;
|
26 |
--ring: 222.2 84% 4.9%;
|
|
|
27 |
--radius: 0.5rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
}
|
29 |
|
30 |
+
body {
|
31 |
+
@apply bg-neutral-light text-neutral-dark antialiased;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
}
|
34 |
|
35 |
+
.conference-card {
|
36 |
+
@apply bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow duration-300 p-6;
|
37 |
+
}
|
|
|
38 |
|
39 |
+
.tag {
|
40 |
+
@apply inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-primary/10 text-primary;
|
41 |
+
}
|
42 |
+
|
43 |
+
.countdown {
|
44 |
+
@apply text-2xl font-semibold text-primary;
|
45 |
+
}
|
src/pages/Index.tsx
CHANGED
@@ -1,12 +1,47 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
const Index = () => {
|
4 |
return (
|
5 |
-
<div className="min-h-screen
|
6 |
-
<
|
7 |
-
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
10 |
</div>
|
11 |
);
|
12 |
};
|
|
|
1 |
+
|
2 |
+
import Header from "@/components/Header";
|
3 |
+
import FilterBar from "@/components/FilterBar";
|
4 |
+
import ConferenceCard from "@/components/ConferenceCard";
|
5 |
+
|
6 |
+
const conferences = [
|
7 |
+
{
|
8 |
+
name: "ICLR 2024",
|
9 |
+
date: "May 7-11, 2024",
|
10 |
+
location: "Vienna, Austria",
|
11 |
+
deadline: "Sep 28, 2023, 8:00 PM UTC",
|
12 |
+
daysLeft: 45,
|
13 |
+
tags: ["ML", "DL", "AI"],
|
14 |
+
},
|
15 |
+
{
|
16 |
+
name: "CVPR 2024",
|
17 |
+
date: "June 17-21, 2024",
|
18 |
+
location: "Seattle, USA",
|
19 |
+
deadline: "Nov 10, 2023, 11:59 PM UTC",
|
20 |
+
daysLeft: 60,
|
21 |
+
tags: ["CV", "ML", "AI"],
|
22 |
+
},
|
23 |
+
{
|
24 |
+
name: "NeurIPS 2024",
|
25 |
+
date: "December 8-14, 2024",
|
26 |
+
location: "Vancouver, Canada",
|
27 |
+
deadline: "May 17, 2024, 11:59 PM UTC",
|
28 |
+
daysLeft: 120,
|
29 |
+
tags: ["ML", "AI", "DL"],
|
30 |
+
},
|
31 |
+
];
|
32 |
|
33 |
const Index = () => {
|
34 |
return (
|
35 |
+
<div className="min-h-screen bg-neutral-light">
|
36 |
+
<Header />
|
37 |
+
<FilterBar />
|
38 |
+
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
39 |
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
40 |
+
{conferences.map((conference) => (
|
41 |
+
<ConferenceCard key={conference.name} {...conference} />
|
42 |
+
))}
|
43 |
+
</div>
|
44 |
+
</main>
|
45 |
</div>
|
46 |
);
|
47 |
};
|
tailwind.config.ts
CHANGED
@@ -1,96 +1,56 @@
|
|
|
|
1 |
import type { Config } from "tailwindcss";
|
2 |
|
3 |
export default {
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
sidebar: {
|
56 |
-
DEFAULT: 'hsl(var(--sidebar-background))',
|
57 |
-
foreground: 'hsl(var(--sidebar-foreground))',
|
58 |
-
primary: 'hsl(var(--sidebar-primary))',
|
59 |
-
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
|
60 |
-
accent: 'hsl(var(--sidebar-accent))',
|
61 |
-
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
|
62 |
-
border: 'hsl(var(--sidebar-border))',
|
63 |
-
ring: 'hsl(var(--sidebar-ring))'
|
64 |
-
}
|
65 |
-
},
|
66 |
-
borderRadius: {
|
67 |
-
lg: 'var(--radius)',
|
68 |
-
md: 'calc(var(--radius) - 2px)',
|
69 |
-
sm: 'calc(var(--radius) - 4px)'
|
70 |
-
},
|
71 |
-
keyframes: {
|
72 |
-
'accordion-down': {
|
73 |
-
from: {
|
74 |
-
height: '0'
|
75 |
-
},
|
76 |
-
to: {
|
77 |
-
height: 'var(--radix-accordion-content-height)'
|
78 |
-
}
|
79 |
-
},
|
80 |
-
'accordion-up': {
|
81 |
-
from: {
|
82 |
-
height: 'var(--radix-accordion-content-height)'
|
83 |
-
},
|
84 |
-
to: {
|
85 |
-
height: '0'
|
86 |
-
}
|
87 |
-
}
|
88 |
-
},
|
89 |
-
animation: {
|
90 |
-
'accordion-down': 'accordion-down 0.2s ease-out',
|
91 |
-
'accordion-up': 'accordion-up 0.2s ease-out'
|
92 |
-
}
|
93 |
-
}
|
94 |
-
},
|
95 |
-
plugins: [require("tailwindcss-animate")],
|
96 |
} satisfies Config;
|
|
|
1 |
+
|
2 |
import type { Config } from "tailwindcss";
|
3 |
|
4 |
export default {
|
5 |
+
darkMode: ["class"],
|
6 |
+
content: [
|
7 |
+
"./pages/**/*.{ts,tsx}",
|
8 |
+
"./components/**/*.{ts,tsx}",
|
9 |
+
"./app/**/*.{ts,tsx}",
|
10 |
+
"./src/**/*.{ts,tsx}",
|
11 |
+
],
|
12 |
+
prefix: "",
|
13 |
+
theme: {
|
14 |
+
container: {
|
15 |
+
center: true,
|
16 |
+
padding: "2rem",
|
17 |
+
screens: {
|
18 |
+
"2xl": "1400px",
|
19 |
+
},
|
20 |
+
},
|
21 |
+
extend: {
|
22 |
+
colors: {
|
23 |
+
border: "hsl(var(--border))",
|
24 |
+
input: "hsl(var(--input))",
|
25 |
+
ring: "hsl(var(--ring))",
|
26 |
+
background: "hsl(var(--background))",
|
27 |
+
foreground: "hsl(var(--foreground))",
|
28 |
+
primary: {
|
29 |
+
DEFAULT: "#9b87f5",
|
30 |
+
light: "#d6bcfa",
|
31 |
+
dark: "#7e69ab",
|
32 |
+
},
|
33 |
+
neutral: {
|
34 |
+
DEFAULT: "#8E9196",
|
35 |
+
light: "#F1F0FB",
|
36 |
+
dark: "#403E43",
|
37 |
+
},
|
38 |
+
},
|
39 |
+
keyframes: {
|
40 |
+
"fade-in": {
|
41 |
+
"0%": { opacity: "0", transform: "translateY(10px)" },
|
42 |
+
"100%": { opacity: "1", transform: "translateY(0)" },
|
43 |
+
},
|
44 |
+
"slide-in": {
|
45 |
+
"0%": { transform: "translateX(-100%)" },
|
46 |
+
"100%": { transform: "translateX(0)" },
|
47 |
+
},
|
48 |
+
},
|
49 |
+
animation: {
|
50 |
+
"fade-in": "fade-in 0.5s ease-out",
|
51 |
+
"slide-in": "slide-in 0.3s ease-out",
|
52 |
+
},
|
53 |
+
},
|
54 |
+
},
|
55 |
+
plugins: [require("tailwindcss-animate")],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
} satisfies Config;
|