Skip to content

Commit 9b76329

Browse files
[refactor] redesign & rewrite Hackathon home page (#59)
Co-authored-by: TechQuery <shiy2008@gmail.com>
1 parent babc91a commit 9b76329

27 files changed

Lines changed: 4099 additions & 565 deletions
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
@import './theme.less';
2+
3+
.section {
4+
padding-top: clamp(3rem, 5vw, 4rem);
5+
}
6+
7+
.registerWrap {
8+
display: grid;
9+
grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
10+
align-items: start;
11+
gap: 1.5rem;
12+
13+
@media (max-width: 1199px) {
14+
grid-template-columns: 1fr;
15+
}
16+
}
17+
18+
.registerCard {
19+
;
20+
background: linear-gradient(135deg, rgba(44, 232, 255, 0.08), rgba(123, 97, 255, 0.14));
21+
}
22+
23+
.registerCardInner,
24+
.entryHub {
25+
padding: 1.55rem;
26+
}
27+
28+
.regEyebrow,
29+
.entryEyebrow {
30+
margin: 0;
31+
color: @cyan;
32+
font-weight: 700;
33+
font-size: 0.75rem;
34+
font-family: @heading;
35+
letter-spacing: 0.12em;
36+
text-transform: uppercase;
37+
}
38+
39+
.entryStep {
40+
color: @cyan;
41+
font-weight: 700;
42+
font-size: 0.72rem;
43+
font-family: @heading;
44+
letter-spacing: 0.1em;
45+
text-transform: uppercase;
46+
}
47+
48+
.regTitle,
49+
.entryTitle {
50+
margin: 0;
51+
color: #fff;
52+
font-weight: 800;
53+
font-size: clamp(1.55rem, 3vw, 2.1rem);
54+
line-height: 1.3;
55+
font-family: @heading;
56+
}
57+
58+
.regTitle {
59+
margin-top: 0;
60+
}
61+
62+
.regDesc,
63+
.entryCard p {
64+
color: @muted;
65+
line-height: 1.75;
66+
}
67+
68+
.regDesc {
69+
margin: 0;
70+
}
71+
72+
.regActions,
73+
.entryLinks {
74+
min-width: 0;
75+
}
76+
77+
.actionButton {
78+
;
79+
}
80+
81+
.actionButtonGhost {
82+
;
83+
border-color: rgba(255, 255, 255, 0.18);
84+
color: @muted;
85+
86+
&:hover {
87+
border-color: rgba(44, 232, 255, 0.36);
88+
color: @cyan;
89+
}
90+
}
91+
92+
.entryLink {
93+
border: 1px solid rgba(44, 232, 255, 0.24);
94+
border-radius: 8px;
95+
background: rgba(44, 232, 255, 0.06);
96+
padding: 0.42rem 0.85rem;
97+
color: @cyan;
98+
font-size: 0.8rem;
99+
font-family: @heading;
100+
letter-spacing: 0.06em;
101+
text-decoration: none;
102+
text-transform: uppercase;
103+
104+
&:hover {
105+
border-color: rgba(44, 232, 255, 0.48);
106+
background: rgba(44, 232, 255, 0.12);
107+
color: @cyan;
108+
text-decoration: none;
109+
}
110+
}
111+
112+
.regFacts {
113+
margin: 0;
114+
115+
li {
116+
border: 1px solid rgba(255, 255, 255, 0.1);
117+
border-radius: 999px;
118+
background: rgba(255, 255, 255, 0.05);
119+
padding: 0.44rem 0.9rem;
120+
color: @copy;
121+
font-size: 0.82rem;
122+
}
123+
}
124+
125+
.entryHubHead {
126+
margin-bottom: 0;
127+
}
128+
129+
.entryTitle {
130+
margin-top: 0;
131+
font-size: 1.55rem;
132+
}
133+
134+
.entryCard {
135+
;
136+
transition:
137+
transform 0.22s ease,
138+
border-color 0.22s ease;
139+
padding: 1.3rem;
140+
height: 100%;
141+
142+
&:hover {
143+
transform: translateY(-3px);
144+
border-color: rgba(44, 232, 255, 0.26);
145+
}
146+
}
147+
148+
.entryStep {
149+
color: @cyan;
150+
}
151+
152+
.entryCard h4 {
153+
margin: 0;
154+
color: #fff;
155+
font-size: 1.02rem;
156+
font-family: @heading;
157+
}
158+
159+
.entryCard p {
160+
margin: 0;
161+
}
162+
163+
.entryMetaRow {
164+
margin: 0;
165+
}
166+
167+
.entryMeta {
168+
border-radius: 999px;
169+
background: rgba(255, 201, 77, 0.12);
170+
padding: 0.28rem 0.7rem;
171+
color: @gold;
172+
font-weight: 700;
173+
font-size: 0.72rem;
174+
font-family: @heading;
175+
letter-spacing: 0.08em;
176+
text-transform: uppercase;
177+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import type { FC, PropsWithChildren } from 'react';
2+
import { Col, Container, Row } from 'react-bootstrap';
3+
4+
import { HackathonHeroAction } from './Hero';
5+
import styles from './ActionHub.module.less';
6+
7+
export interface HackathonActionHubEntry {
8+
count: number;
9+
description: string;
10+
eyebrow: string;
11+
links: HackathonHeroAction[];
12+
title: string;
13+
}
14+
15+
export interface HackathonActionHubProps {
16+
entries: HackathonActionHubEntry[];
17+
facts: string[];
18+
primaryAction?: HackathonHeroAction;
19+
primaryDescription: string;
20+
primaryTitle: string;
21+
subtitle: string;
22+
title: string;
23+
}
24+
25+
export const HackathonActionHubLink: FC<{
26+
action: HackathonHeroAction;
27+
variant: 'ghost' | 'primary';
28+
}> = ({ action, variant }) => (
29+
<a
30+
className={variant === 'primary' ? styles.actionButton : styles.actionButtonGhost}
31+
href={action.href}
32+
{...(action.external && { target: '_blank', rel: 'noreferrer' })}
33+
>
34+
{action.label}
35+
</a>
36+
);
37+
38+
const ActionEntryCard: FC<{ entry: HackathonActionHubEntry; step: string }> = ({ entry, step }) => (
39+
<article className={styles.entryCard}>
40+
<span className={styles.entryStep}>
41+
{step} · {entry.eyebrow}
42+
</span>
43+
<h4 className="mt-2 mb-2">{entry.title}</h4>
44+
<p>{entry.description}</p>
45+
46+
<div className={`${styles.entryMetaRow} d-flex flex-wrap gap-2 my-3`}>
47+
<span className={`${styles.entryMeta} d-inline-flex align-items-center`}>{entry.count}</span>
48+
<span className={`${styles.entryMeta} d-inline-flex align-items-center`}>
49+
{entry.eyebrow}
50+
</span>
51+
</div>
52+
53+
<nav className={`${styles.entryLinks} d-flex flex-wrap gap-3`} aria-label={entry.title}>
54+
{entry.links.map(link => (
55+
<a
56+
key={`${link.label}-${link.href}`}
57+
className={`${styles.entryLink} d-inline-flex align-items-center`}
58+
href={link.href}
59+
{...(link.external && { target: '_blank', rel: 'noreferrer' })}
60+
>
61+
{link.label}
62+
</a>
63+
))}
64+
</nav>
65+
</article>
66+
);
67+
68+
export const HackathonActionHub: FC<PropsWithChildren<HackathonActionHubProps>> = ({
69+
children,
70+
entries,
71+
facts,
72+
primaryAction,
73+
primaryDescription,
74+
primaryTitle,
75+
subtitle,
76+
title,
77+
}) => (
78+
<section id="entry-hub" className={styles.section}>
79+
<Container>
80+
<div className={styles.registerWrap}>
81+
<article className={styles.registerCard}>
82+
<div className={styles.registerCardInner}>
83+
<p className={`${styles.regEyebrow} mb-1`}>{title}</p>
84+
<h2 className={`${styles.regTitle} mt-2`}>{primaryTitle}</h2>
85+
<p className={`${styles.regDesc} mt-3 mb-4`}>{primaryDescription}</p>
86+
87+
<nav className={`${styles.regActions} d-flex flex-wrap gap-3`} aria-label={title}>
88+
{primaryAction && <HackathonActionHubLink action={primaryAction} variant="primary" />}
89+
{children}
90+
</nav>
91+
92+
<ul className={`list-unstyled ${styles.regFacts} d-flex flex-wrap gap-2 mt-4`}>
93+
{facts.map(fact => (
94+
<li key={fact}>{fact}</li>
95+
))}
96+
</ul>
97+
</div>
98+
</article>
99+
100+
<div className={styles.entryHub}>
101+
<header className={`${styles.entryHubHead} mb-4`}>
102+
<p className={`${styles.entryEyebrow} mb-1`}>{subtitle}</p>
103+
<h3 className={`${styles.entryTitle} mt-2`}>{title}</h3>
104+
</header>
105+
106+
<Row as="ol" className="list-unstyled g-3 mb-0">
107+
{entries.map((entry, index) => (
108+
<Col as="li" key={entry.title} md={6}>
109+
<ActionEntryCard entry={entry} step={String(index + 1).padStart(2, '0')} />
110+
</Col>
111+
))}
112+
</Row>
113+
</div>
114+
</div>
115+
</Container>
116+
</section>
117+
);

0 commit comments

Comments
 (0)