Skip to content

Commit 9420a19

Browse files
authored
docs: add banner rotator (#3696)
## Description Replaces appjs banner with TopPromoRotator component in navbar. Adds paradise promo. <img width="1702" height="607" alt="Screenshot 2026-02-26 at 13 23 50" src="https://github.com/user-attachments/assets/f36d776e-dfb6-4ad9-9bff-3a0a0a7df39c" />
1 parent 41e0c63 commit 9420a19

5 files changed

Lines changed: 213 additions & 12 deletions

File tree

docs/src/components/HandIcon/index.tsx

Lines changed: 23 additions & 0 deletions
Large diffs are not rendered by default.

docs/src/components/Hero/ScreenSequence/styles.module.css

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.screens {
22
position: absolute;
3-
top: 2rem;
3+
top: calc(3rem + 50px);
44
right: 0;
55
overflow: hidden;
66
min-height: 55%;
@@ -10,41 +10,41 @@
1010

1111
@media (min-width: 2920px) {
1212
.screens {
13-
top: 3rem;
13+
top: calc(3rem + 50px);
1414
min-height: 70%;
1515
}
1616
}
1717
@media (min-width: 3000px) and (min-height: 1500px) {
1818
.screens {
19-
top: -3vh;
19+
top: calc(-3vh + 50px);
2020
min-height: 50%;
2121
}
2222
}
2323

2424
@media (min-width: 3000px) and (min-height: 2000px) {
2525
.screens {
26-
top: 3vh;
26+
top: calc(3vh + 50px);
2727
min-height: 35%;
2828
}
2929
}
3030

3131
@media (max-width: 2000px) {
3232
.screens {
33-
top: 4rem;
33+
top: calc(4rem + 50px);
3434
min-height: 70%;
3535
}
3636
}
3737

3838
@media (max-width: 1350px) {
3939
.screens {
40-
top: 9rem;
40+
top: calc(9rem + 50px);
4141
min-height: 60%;
4242
}
4343
}
4444

4545
@media (max-width: 996px) {
4646
.screens {
47-
top: 2rem;
47+
top: calc(2rem + 50px);
4848
}
4949
}
5050

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import clsx from 'clsx';
2+
import React, { type ReactNode, useEffect, useMemo, useState } from 'react';
3+
4+
import HandIcon from '../HandIcon';
5+
import styles from './styles.module.css';
6+
7+
type Promo = {
8+
key: string;
9+
href: string;
10+
bg: string;
11+
buttonLabel: string;
12+
label: ReactNode;
13+
};
14+
15+
const PROMOS: readonly Promo[] = [
16+
{
17+
key: 'appjs',
18+
href: 'https://appjs.co?origin=swmansion_bar',
19+
bg: '#C7CEF5',
20+
buttonLabel: 'Get your tickets',
21+
label: (
22+
<>
23+
<strong>App.js Conf 2026</strong>
24+
<span className={styles.hiddenOnMobile}>
25+
{' '}
26+
is just around the corner!
27+
</span>
28+
</>
29+
),
30+
},
31+
{
32+
key: 'paradise',
33+
href: 'https://paradise.swmansion.com?origin=swmansion_bar',
34+
bg: '#FFF4C0',
35+
buttonLabel: 'Learn more',
36+
label: (
37+
<>
38+
<strong>React Native Paradise</strong>
39+
<span className={styles.hiddenOnMobile}>
40+
{' '}
41+
- a week of advanced RN workshops in Croatia!
42+
</span>
43+
</>
44+
),
45+
},
46+
];
47+
48+
export default function TopPromoRotator() {
49+
const promos = useMemo(() => PROMOS, []);
50+
51+
const [index, setIndex] = useState(0);
52+
53+
useEffect(() => {
54+
const id = window.setInterval(() => {
55+
setIndex(i => (i + 1) % promos.length);
56+
}, 5_000);
57+
58+
return () => window.clearInterval(id);
59+
}, [promos.length]);
60+
61+
const active = promos[index];
62+
63+
const barHeight = 50;
64+
const translateY = `translateY(-${index * barHeight}px)`;
65+
66+
return (
67+
<div
68+
className={clsx(styles.wrapper)}
69+
style={{
70+
backgroundColor: active.bg,
71+
transition: 'background-color 600ms ease',
72+
}}>
73+
<div
74+
className={styles.slider}
75+
style={{
76+
transform: translateY,
77+
transition: 'transform 700ms cubic-bezier(0.22, 1, 0.36, 1)',
78+
}}>
79+
{promos.map(p => (
80+
<a
81+
key={p.key}
82+
href={p.href}
83+
target="_blank"
84+
rel="noopener noreferrer"
85+
className={styles.banner}>
86+
<span>{p.label}</span>
87+
<HandIcon aria-hidden="true" className={styles.icon} />
88+
<span className={styles.underline}>{p.buttonLabel}</span>
89+
</a>
90+
))}
91+
</div>
92+
<span className="sr-only">
93+
{typeof active.label === 'string' ? active.label : ''}
94+
</span>
95+
</div>
96+
);
97+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
.wrapper {
2+
position: relative;
3+
height: 50px;
4+
min-height: 50px;
5+
max-height: 50px;
6+
width: 100%;
7+
overflow: hidden;
8+
display: flex;
9+
align-items: center;
10+
justify-content: center;
11+
font-size: 1rem;
12+
font-weight: 500;
13+
}
14+
15+
.slider {
16+
position: absolute;
17+
inset: 0;
18+
will-change: transform;
19+
}
20+
21+
.banner {
22+
display: flex;
23+
height: 50px;
24+
min-height: 50px;
25+
width: 100%;
26+
align-items: center;
27+
justify-content: center;
28+
gap: 0.5rem;
29+
padding: 0 0.75rem;
30+
font-size: 1rem;
31+
font-weight: 500;
32+
line-height: 1;
33+
color: #001a72;
34+
text-align: center;
35+
text-decoration: none;
36+
transition: background-color 300ms ease-out;
37+
white-space: nowrap;
38+
box-sizing: border-box;
39+
}
40+
41+
.banner:hover {
42+
color: #001a72 !important;
43+
text-decoration: none !important;
44+
background-color: rgba(0, 0, 0, 0.05);
45+
}
46+
47+
.banner:hover * {
48+
text-decoration: none !important;
49+
}
50+
51+
.banner:hover .underline {
52+
text-decoration: underline !important;
53+
text-underline-offset: 2px;
54+
}
55+
56+
.hiddenOnMobile {
57+
display: inline;
58+
}
59+
60+
@media (max-width: 768px) {
61+
.hiddenOnMobile {
62+
display: none;
63+
}
64+
}
65+
66+
.icon {
67+
flex-shrink: 0;
68+
width: 28px;
69+
height: 28px;
70+
transform: rotate(-90deg);
71+
display: block;
72+
}
73+
74+
.underline {
75+
text-decoration: underline;
76+
text-underline-offset: 2px;
77+
}

docs/src/theme/Navbar/index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React from 'react';
22
import { Navbar } from '@swmansion/t-rex-ui';
3+
import TopPromoRotator from '@site/src/components/TopPromoRotator';
34

45
export default function NavbarWrapper(props) {
56
return (
6-
<Navbar
7-
useLandingLogoDualVariant={true}
8-
isAlgoliaActive={false}
9-
{...props}
10-
/>
7+
<div style={{ display: 'flex', flexDirection: 'column', flexShrink: 0 }}>
8+
<TopPromoRotator />
9+
<Navbar
10+
useLandingLogoDualVariant={true}
11+
isAlgoliaActive={false}
12+
{...props}
13+
/>
14+
</div>
1115
);
1216
}

0 commit comments

Comments
 (0)