Skip to content

Commit d6c1dba

Browse files
committed
Refactor hackathon detail sections
1 parent 2a5b181 commit d6c1dba

19 files changed

Lines changed: 2378 additions & 648 deletions
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
@import './theme.less';
2+
3+
.section {
4+
.section-shell();
5+
padding-top: clamp(3rem, 5vw, 4rem);
6+
}
7+
8+
.registerWrap {
9+
display: grid;
10+
grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
11+
gap: 1.5rem;
12+
align-items: start;
13+
}
14+
15+
.registerCard {
16+
.panel-card();
17+
background: linear-gradient(135deg, rgba(44, 232, 255, 0.08), rgba(123, 97, 255, 0.14));
18+
}
19+
20+
.registerCardInner,
21+
.entryHub {
22+
padding: 1.55rem;
23+
}
24+
25+
.regEyebrow,
26+
.entryEyebrow,
27+
.entryStep {
28+
.eyebrow();
29+
}
30+
31+
.regTitle,
32+
.entryTitle {
33+
margin: 0;
34+
color: #fff;
35+
font-family: @heading;
36+
font-size: clamp(1.55rem, 3vw, 2.1rem);
37+
font-weight: 800;
38+
line-height: 1.3;
39+
}
40+
41+
.regTitle {
42+
margin-top: 0.4rem;
43+
}
44+
45+
.regDesc,
46+
.entryCard p {
47+
color: @muted;
48+
line-height: 1.75;
49+
}
50+
51+
.regDesc {
52+
margin: 0.9rem 0 1.2rem;
53+
}
54+
55+
.regActions,
56+
.entryLinks {
57+
display: flex;
58+
flex-wrap: wrap;
59+
gap: 0.9rem;
60+
}
61+
62+
.actionButton {
63+
.button-primary();
64+
}
65+
66+
.actionButtonGhost,
67+
.entryLink {
68+
.button-ghost();
69+
}
70+
71+
.regFacts {
72+
display: flex;
73+
flex-wrap: wrap;
74+
gap: 0.75rem;
75+
margin: 1.3rem 0 0;
76+
77+
li {
78+
.chip();
79+
padding: 0.48rem 0.85rem;
80+
color: @copy;
81+
font-size: 0.9rem;
82+
}
83+
}
84+
85+
.entryHub {
86+
.panel-card();
87+
}
88+
89+
.entryHubHead {
90+
margin-bottom: 1.25rem;
91+
}
92+
93+
.entryTitle {
94+
margin-top: 0.35rem;
95+
font-size: 1.55rem;
96+
}
97+
98+
.entryCard {
99+
.panel-card();
100+
height: 100%;
101+
padding: 1.3rem;
102+
}
103+
104+
.entryStep {
105+
color: @cyan;
106+
}
107+
108+
.entryCard h4 {
109+
margin: 0.55rem 0 0.45rem;
110+
color: #fff;
111+
font-family: @heading;
112+
font-size: 1.02rem;
113+
}
114+
115+
.entryCard p {
116+
margin: 0;
117+
}
118+
119+
.entryMetaRow {
120+
display: flex;
121+
flex-wrap: wrap;
122+
gap: 0.6rem;
123+
margin: 1rem 0;
124+
}
125+
126+
.entryMeta {
127+
.chip();
128+
padding: 0.35rem 0.7rem;
129+
color: @gold;
130+
font-family: @heading;
131+
font-size: 0.72rem;
132+
letter-spacing: 0.06em;
133+
text-transform: uppercase;
134+
}
135+
136+
@media (max-width: 1199px) {
137+
.registerWrap {
138+
grid-template-columns: 1fr;
139+
}
140+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { FC } from 'react';
2+
import { Col, Container, Row } from 'react-bootstrap';
3+
4+
import { HackathonHeroAction } from './HackathonHero';
5+
import styles from './HackathonActionHub.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+
secondaryAction: HackathonHeroAction;
22+
subtitle: string;
23+
title: string;
24+
}
25+
26+
const ActionHubLink: FC<{ action: HackathonHeroAction; variant: 'ghost' | 'primary' }> = ({
27+
action,
28+
variant,
29+
}) => (
30+
<a
31+
className={variant === 'primary' ? styles.actionButton : styles.actionButtonGhost}
32+
href={action.href}
33+
{...(action.external && { target: '_blank', rel: 'noreferrer' })}
34+
>
35+
{action.label}
36+
</a>
37+
);
38+
39+
const ActionEntryCard: FC<{ entry: HackathonActionHubEntry; step: string }> = ({ entry, step }) => (
40+
<article className={styles.entryCard}>
41+
<span className={styles.entryStep}>
42+
{step} · {entry.eyebrow}
43+
</span>
44+
<h4>{entry.title}</h4>
45+
<p>{entry.description}</p>
46+
47+
<div className={styles.entryMetaRow}>
48+
<span className={styles.entryMeta}>{entry.count}</span>
49+
<span className={styles.entryMeta}>{entry.eyebrow}</span>
50+
</div>
51+
52+
<nav className={styles.entryLinks} aria-label={entry.title}>
53+
{entry.links.map(link => (
54+
<a
55+
key={`${link.label}-${link.href}`}
56+
className={styles.entryLink}
57+
href={link.href}
58+
{...(link.external && { target: '_blank', rel: 'noreferrer' })}
59+
>
60+
{link.label}
61+
</a>
62+
))}
63+
</nav>
64+
</article>
65+
);
66+
67+
export const HackathonActionHub: FC<HackathonActionHubProps> = ({
68+
entries,
69+
facts,
70+
primaryAction,
71+
primaryDescription,
72+
primaryTitle,
73+
secondaryAction,
74+
subtitle,
75+
title,
76+
}) => (
77+
<section id="entry-hub" className={styles.section}>
78+
<Container>
79+
<div className={styles.registerWrap}>
80+
<article className={styles.registerCard}>
81+
<div className={styles.registerCardInner}>
82+
<p className={styles.regEyebrow}>{title}</p>
83+
<h2 className={styles.regTitle}>{primaryTitle}</h2>
84+
<p className={styles.regDesc}>{primaryDescription}</p>
85+
86+
<nav className={styles.regActions} aria-label={title}>
87+
{primaryAction && <ActionHubLink action={primaryAction} variant="primary" />}
88+
<ActionHubLink action={secondaryAction} variant="ghost" />
89+
</nav>
90+
91+
<ul className={`list-unstyled ${styles.regFacts}`}>
92+
{facts.map(fact => (
93+
<li key={fact}>{fact}</li>
94+
))}
95+
</ul>
96+
</div>
97+
</article>
98+
99+
<div className={styles.entryHub}>
100+
<header className={styles.entryHubHead}>
101+
<p className={styles.entryEyebrow}>{subtitle}</p>
102+
<h3 className={styles.entryTitle}>{title}</h3>
103+
</header>
104+
105+
<Row as="ol" className="list-unstyled g-3 mb-0">
106+
{entries.map((entry, index) => (
107+
<Col as="li" key={entry.title} md={6}>
108+
<ActionEntryCard entry={entry} step={String(index + 1).padStart(2, '0')} />
109+
</Col>
110+
))}
111+
</Row>
112+
</div>
113+
</div>
114+
</Container>
115+
</section>
116+
);

0 commit comments

Comments
 (0)