diff --git a/packages/docs-gesture-handler/src/components/HandIcon/index.tsx b/packages/docs-gesture-handler/src/components/HandIcon/index.tsx new file mode 100644 index 0000000000..df23b0c72e --- /dev/null +++ b/packages/docs-gesture-handler/src/components/HandIcon/index.tsx @@ -0,0 +1,23 @@ +import type React from 'react'; + +interface Props extends React.SVGProps { + children?: React.ReactNode; +} + +function HandIcon({ children, ...props }: Props) { + return ( + + + {children} + + ); +} + +export default HandIcon; diff --git a/packages/docs-gesture-handler/src/components/TopPromoRotator/index.tsx b/packages/docs-gesture-handler/src/components/TopPromoRotator/index.tsx new file mode 100644 index 0000000000..faf7ac203d --- /dev/null +++ b/packages/docs-gesture-handler/src/components/TopPromoRotator/index.tsx @@ -0,0 +1,97 @@ +import clsx from 'clsx'; +import React, { type ReactNode, useEffect, useMemo, useState } from 'react'; + +import HandIcon from '../HandIcon'; +import styles from './styles.module.css'; + +type Promo = { + key: string; + href: string; + bg: string; + buttonLabel: string; + label: ReactNode; +}; + +const PROMOS: readonly Promo[] = [ + { + key: 'appjs', + href: 'https://appjs.co?origin=swmansion_bar', + bg: '#C7CEF5', + buttonLabel: 'Get your tickets', + label: ( + <> + App.js Conf 2026 + + {' '} + is just around the corner! + + + ), + }, + { + key: 'paradise', + href: 'https://paradise.swmansion.com?origin=swmansion_bar', + bg: '#FFF4C0', + buttonLabel: 'Learn more', + label: ( + <> + React Native Paradise + + {' '} + - a week of advanced RN workshops in Croatia! + + + ), + }, +]; + +export default function TopPromoRotator() { + const promos = useMemo(() => PROMOS, []); + + const [index, setIndex] = useState(0); + + useEffect(() => { + const id = window.setInterval(() => { + setIndex(i => (i + 1) % promos.length); + }, 5_000); + + return () => window.clearInterval(id); + }, [promos.length]); + + const active = promos[index]; + + const barHeight = 50; + const translateY = `translateY(-${index * barHeight}px)`; + + return ( +
+
+ {promos.map(p => ( + + {p.label} + + ))} +
+ + {typeof active.label === 'string' ? active.label : ''} + +
+ ); +} diff --git a/packages/docs-gesture-handler/src/components/TopPromoRotator/styles.module.css b/packages/docs-gesture-handler/src/components/TopPromoRotator/styles.module.css new file mode 100644 index 0000000000..78a5c2c43d --- /dev/null +++ b/packages/docs-gesture-handler/src/components/TopPromoRotator/styles.module.css @@ -0,0 +1,77 @@ +.wrapper { + position: relative; + height: 50px; + min-height: 50px; + max-height: 50px; + width: 100%; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + font-size: 1rem; + font-weight: 500; +} + +.slider { + position: absolute; + inset: 0; + will-change: transform; +} + +.banner { + display: flex; + height: 50px; + min-height: 50px; + width: 100%; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0 0.75rem; + font-size: 1rem; + font-weight: 500; + line-height: 1; + color: #001a72; + text-align: center; + text-decoration: none; + transition: background-color 300ms ease-out; + white-space: nowrap; + box-sizing: border-box; +} + +.banner:hover { + color: #001a72 !important; + text-decoration: none !important; + background-color: rgba(0, 0, 0, 0.05); +} + +.banner:hover * { + text-decoration: none !important; +} + +.banner:hover .underline { + text-decoration: underline !important; + text-underline-offset: 2px; +} + +.hiddenOnMobile { + display: inline; +} + +@media (max-width: 768px) { + .hiddenOnMobile { + display: none; + } +} + +.icon { + flex-shrink: 0; + width: 28px; + height: 28px; + transform: rotate(-90deg); + display: block; +} + +.underline { + text-decoration: underline; + text-underline-offset: 2px; +} diff --git a/packages/docs-gesture-handler/src/theme/Navbar/index.js b/packages/docs-gesture-handler/src/theme/Navbar/index.js index d8e869034b..19483b5ab7 100644 --- a/packages/docs-gesture-handler/src/theme/Navbar/index.js +++ b/packages/docs-gesture-handler/src/theme/Navbar/index.js @@ -1,6 +1,7 @@ import React from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; import { Navbar } from '@swmansion/t-rex-ui'; +import TopPromoRotator from '@site/src/components/TopPromoRotator'; export default function NavbarWrapper(props) { const titleImages = { @@ -12,6 +13,9 @@ export default function NavbarWrapper(props) { logo: useBaseUrl('/img/logo-hero.svg'), }; return ( - +
+ + +
); }