add banners

This commit is contained in:
Piotr Goszczyński committed 2025-03-23 13:12:47 +01:00
1 parent 400ef6f70f
commit be2c3fe8cd
18 files changed
+105 -128

No files matched your search

+2
View File
@@ -11,6 +11,7 @@ import { QueryClientProvider } from './data/queryClient.client'
import { PageTelemetry } from './telemetry/telemetry.client'
import { ScrollRestoration } from './ui/helpers.scroll.client'
import { ThemeSandbox } from './ui/theme.client'
import { PromoToast } from 'ui-patterns'
/**
* Global providers that wrap the entire app
@@ -27,6 +28,7 @@ function GlobalProviders({ children }: PropsWithChildren) {
<CommandProvider>
<div className="flex flex-col">
<SiteLayout>
<PromoToast />
{children}
<DocsCommandMenu />
</SiteLayout>
@@ -1,78 +0,0 @@
import { useEffect, useState } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { PropsWithChildren } from 'react'
import _announcement from './data/Announcement.json'
import { X } from 'lucide-react'
export interface AnnouncementProps {
show: boolean
text: string
launchDate: string
link: string
badge?: string
}
const announcement = _announcement as AnnouncementProps
interface AnnouncementComponentProps {
show?: boolean
className?: string
link?: string
}
const Announcement = ({
show = true,
className,
children,
link,
}: PropsWithChildren<AnnouncementComponentProps>) => {
const [hidden, setHidden] = useState(true)
const router = useRouter()
const isLaunchWeekSection = router.pathname.includes('launch-week')
// override to hide announcement
if (!show || !announcement.show) return null
// construct the key for the announcement, based on the title text
const announcementKey = 'announcement_' + announcement.text.replace(/ /g, '')
// window.localStorage is kept inside useEffect
// to prevent error
useEffect(function () {
if (!window.localStorage.getItem(announcementKey)) {
return setHidden(false)
}
}, [])
function handleClose(event: any) {
event.stopPropagation()
window.localStorage.setItem(announcementKey, 'hidden')
return setHidden(true)
}
// Always show if on LW section
if (!isLaunchWeekSection && hidden) {
return null
} else {
return (
<div className={['relative z-40 w-full cursor-pointer', className].join(' ')}>
{!isLaunchWeekSection && (
<div
className="absolute z-50 right-4 flex h-full items-center opacity-100 text-white transition-opacity hover:opacity-90"
onClick={handleClose}
>
<X size={16} />
</div>
)}
{children}
<Link href={link ?? announcement.link} className="absolute inset-0 z-40"></Link>
</div>
)
}
}
export default Announcement
@@ -1,7 +0,0 @@
{
"show": true,
"text": "Supabase Launch Week 13: Day 1",
"launchDate": "2023-08-07T09:00:00.000-07:00",
"link": "https://supabase.com/launch-week#day-1",
"badge": "Get your ticket"
}
+8
View File
@@ -3,6 +3,7 @@ import Link from 'next/link'
import { Button } from 'ui'
import SectionContainer from '~/components/Layouts/SectionContainer'
import { useSendTelemetryEvent } from '~/lib/telemetry'
import AnnouncementBadge from '../Announcement/Badge'
const Hero = () => {
const sendTelemetryEvent = useSendTelemetryEvent()
@@ -15,6 +16,13 @@ const Hero = () => {
<div className="mx-auto max-w-2xl lg:col-span-6 lg:flex lg:items-center justify-center text-center">
<div className="relative z-10 lg:h-auto pt-[90px] lg:pt-[90px] lg:min-h-[300px] flex flex-col items-center justify-center sm:mx-auto md:w-3/4 lg:mx-0 lg:w-full gap-4 lg:gap-8">
<div className="flex flex-col items-center">
<div className="z-40 w-full flex justify-center -mt-4 lg:-mt-12 mb-8">
<AnnouncementBadge
url="/launch-week"
badge="Launch Week 14"
announcement="Claim ticket"
/>
</div>
<h1 className="text-foreground text-4xl sm:text-5xl sm:leading-none lg:text-7xl">
<span className="block text-foreground">Build in a weekend</span>
<span className="text-brand block md:ml-0">Scale to millions</span>
+4 -2
View File
@@ -64,8 +64,10 @@ export const LW14_DATE = '31 March — 4 April / 7am PT'
export const LW14_LAUNCH_DATE = '2025-03-31T07:00:00.000-07:00'
export const LW14_LAUNCH_DATE_END = '2025-04-04T23:59:59.000-07:00'
export const LW14_TITLE = 'Launch Week 14'
export const LW14_TWEET_TEXT = 'Launch Week 14 is just around the corner at @supabase. \nClaim your ticket and stay tuned for all the announcements! \n#launchweek'
export const LW14_TWEET_TEXT_PLATINUM = 'Just conquered a platinum @supabase Launch Week 14 ticket. Share twice to get one! \n#launchweek'
export const LW14_TWEET_TEXT =
'Launch Week 14 is just around the corner at @supabase. \nClaim your ticket and stay tuned for all the announcements! \n#launchweek'
export const LW14_TWEET_TEXT_PLATINUM =
'Just conquered a platinum @supabase Launch Week 14 ticket. Share twice to get one! \n#launchweek'
export const LW14_TWEET_TEXT_SECRET = `Found the secret golden ticket for @supabase's Launch Week 14. \nCan you find it? \n#launchweek`
export const LW14_URL = `${SITE_ORIGIN}/launch-week`
+2
View File
@@ -24,6 +24,7 @@ import MetaFaviconsPagesRouter, {
import { WwwCommandMenu } from '~/components/CommandMenu'
import { API_URL, APP_NAME, DEFAULT_META_DESCRIPTION } from '~/lib/constants'
import useDarkLaunchWeeks from '../hooks/useDarkLaunchWeeks'
import { LW14Announcement } from 'ui-patterns/Banners/LW14Announcement'
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter()
@@ -93,6 +94,7 @@ export default function App({ Component, pageProps }: AppProps) {
>
<TooltipProvider delayDuration={0}>
<CommandProvider>
<LW14Announcement />
<SonnerToaster position="top-right" />
<Component {...pageProps} />
<WwwCommandMenu />
Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

@@ -0,0 +1,36 @@
import Countdown from 'react-countdown'
import { CountdownWidget } from '../CountdownWidget'
const CountdownComponent = ({
date,
showCard = true,
}: {
date: string | number | Date
showCard?: boolean
}) => {
if (!date) return null
const renderer = ({ days, hours, minutes, seconds, completed }: any) => {
if (completed) {
// Render a completed state
return null
} else {
// Render countdown
return (
<CountdownWidget
days={days}
hours={hours}
minutes={minutes}
seconds={seconds}
showCard={showCard}
className='text-emerald-400 [text-shadow:0_0_15px_rgba(52,211,153,0.8)]'
dividerClassName='text-emerald-400 [text-shadow:0_0_15px_rgba(52,211,153,0.8)]'
/>
)
}
}
return <Countdown date={new Date(date)} renderer={renderer} />
}
export default CountdownComponent
@@ -0,0 +1,10 @@
import { Announcement } from 'ui/src/layout/banners'
import LW14Banner from './LW14Banner'
export const LW14Announcement = () => {
return (
<Announcement show={true} announcementKey="announcement_lw14_countdown">
<LW14Banner />
</Announcement>
)
}
@@ -2,22 +2,21 @@
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Button } from '../../../components/Button/Button'
import { cn } from '../../../lib/utils/cn'
import announcement from '../data/Announcement.json'
import announcement from './data.json'
import Image from 'next/image'
import { useTheme } from 'next-themes'
// import Countdown from './Countdown'
import { Button } from 'ui/src/components/Button'
import { cn } from 'ui'
const LW13BGDark =
const LW14BGDark =
'https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/images/launch-week/lw13/assets/lw13-banner-dark.png?t=2024-11-22T23%3A10%3A37.646Z'
const LW13BGLight =
const LW14BGLight =
'https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/images/launch-week/lw13/assets/lw13-banner-light.png?t=2024-11-22T23%3A10%3A37.646Z'
export function LW13CountdownBanner() {
export function LW14Banner() {
const pathname = usePathname()
const { resolvedTheme } = useTheme()
const bgImage = resolvedTheme?.includes('dark') ? LW13BGDark : LW13BGLight
const bgImage = resolvedTheme?.includes('dark') ? LW14BGDark : LW14BGLight
const isHomePage = pathname === '/'
const isLaunchWeekPage =
pathname === '/launch-week' || pathname?.includes('/launch-week/tickets/')
@@ -55,4 +54,4 @@ export function LW13CountdownBanner() {
)
}
export default LW13CountdownBanner
export default LW14Banner
+7
View File
@@ -0,0 +1,7 @@
{
"text": "Launch Week 14",
"launchDate": "2025-03-31T07:00:00.000-08:00",
"link": "/launch-week",
"cta": "Learn more"
}
@@ -8,6 +8,7 @@ interface CountdownWidgetProps {
seconds?: string
showCard?: boolean
className?: string
dividerClassName?: string
size?: 'small' | 'large'
}
@@ -18,11 +19,12 @@ export function CountdownWidget({
seconds,
showCard = true,
className,
dividerClassName,
size,
}: CountdownWidgetProps) {
const isLarge = size === 'large'
const Colon = () => (
<span className={cn('text-xs mx-px text-foreground-lighter', isLarge && 'text-lg')}>:</span>
<span className={cn('text-xs mx-px text-foreground-lighter', isLarge && 'text-lg', dividerClassName)}>:</span>
)
return (
+14 -16
View File
@@ -7,17 +7,16 @@ import { cn } from 'ui/src/lib/utils/cn'
import { Button } from 'ui/src/components/Button/Button'
import { LOCAL_STORAGE_KEYS } from 'common'
import { useTheme } from 'next-themes'
import announcement from 'ui/src/layout/banners/data/Announcement.json'
import announcement from '../Banners/data.json'
import CountdownComponent from '../Banners/Countdown'
import "./styles.css"
const LW13BGDark =
'https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/images/launch-week/lw13/assets/lw13-bg-dark.png?t=2024-11-22T23%3A10%3A37.646Z'
const LW13BGLight =
'https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/images/launch-week/lw13/assets/lw13-bg-light.png?t=2024-11-22T23%3A10%3A37.646Z'
const SITE_ORIGIN = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production' || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' ? "" : "http://localhost:3000"
const LW14BG = `${SITE_ORIGIN}/images/launchweek/14/promo-banner-bg.png`
const PromoToast = () => {
const [visible, setVisible] = useState(false)
const { resolvedTheme } = useTheme()
const bgImage = resolvedTheme?.includes('dark') ? LW13BGDark : LW13BGLight
useEffect(() => {
const shouldHide =
@@ -43,20 +42,19 @@ const PromoToast = () => {
visible && 'opacity-100 translate-y-0'
)}
>
<div className="relative z-10 text-foreground-lighter leading-3 flex flex-col font-mono uppercase tracking-wide w-full text-xs">
<div className="text-foreground uppercase tracking-wider text-lg -mb-1">Launch Week 13</div>
<p className="text-foreground-lighter uppercase tracking-wider text-xl md:text-lg leading-snug">
2—6 Dec
<div className="relative z-10 text-foreground-lighter uppercase flex flex-col text-sm w-full font-mono mb-2">
<span className="mb-1">31 APR - 04 MAR / 7AM PT</span>
<p className="relative z-10 text-foreground flex flex-col text-xl w-full leading-7 font-['Departure_Mono']">
Launch Week 14
</p>
</div>
<div className="relative z-10 text-foreground-lighter flex flex-col text-sm uppercase font-mono tracking-widest w-full -mt-1">
A week of new features
<CountdownComponent date={new Date(announcement.launchDate)} showCard={false} />
</div>
<div className="relative z-10 flex items-center space-x-2 mt-2">
<div className="relative z-10 flex items-center space-x-2">
<Button asChild type="secondary">
<Link target="_blank" rel="noreferrer" href={`https://supabase.com${announcement.link}`}>
Learn more
Claim ticket
</Link>
</Button>
<Button type="default" onClick={handleHide}>
@@ -64,7 +62,7 @@ const PromoToast = () => {
</Button>
</div>
<Image
src={bgImage}
src={LW14BG}
alt=""
fill
sizes="100%"
Whitespace-only changes.
+1
View File
@@ -28,6 +28,7 @@
"monaco-editor": "*",
"next-themes": "*",
"openai": "^4.20.1",
"react-countdown": "^2.3.5",
"react-error-boundary": "^4.0.12",
"react-hook-form": "^7.45.0",
"react-intersection-observer": "^9.8.2",
@@ -5,7 +5,6 @@ import { useEffect, useState } from 'react'
import { usePathname } from 'next/navigation'
import { PropsWithChildren } from 'react'
import { cn } from '../../lib/utils/cn'
import _announcement from './data/Announcement.json'
import { X } from 'lucide-react'
export interface AnnouncementProps {
@@ -16,12 +15,11 @@ export interface AnnouncementProps {
badge?: string
}
const announcement = _announcement as AnnouncementProps
interface AnnouncementComponentProps {
show?: boolean
dismissable?: boolean
className?: string
announcementKey: `announcement_${string}`
}
const Announcement = ({
@@ -29,6 +27,7 @@ const Announcement = ({
dismissable = true,
className,
children,
announcementKey,
}: PropsWithChildren<AnnouncementComponentProps>) => {
const [hidden, setHidden] = useState(true)
@@ -36,19 +35,19 @@ const Announcement = ({
const isLaunchWeekSection = pathname?.includes('launch-week') ?? false
// override to hide announcement
if (!show || !announcement.show) return null
if (!show) return null
// construct the key for the announcement, based on the title text
const announcementKey = 'announcement_' + announcement.text.replace(/ /g, '')
const announcementKeyNoSpaces = announcementKey.replace(/ /g, '')
// window.localStorage is kept inside useEffect
// to prevent error
useEffect(function () {
if (window.localStorage.getItem(announcementKey) === 'hidden') {
if (window.localStorage.getItem(announcementKeyNoSpaces) === 'hidden') {
setHidden(true)
}
if (!window.localStorage.getItem(announcementKey)) {
if (!window.localStorage.getItem(announcementKeyNoSpaces)) {
setHidden(false)
}
}, [])
@@ -56,7 +55,7 @@ const Announcement = ({
function handleClose(event: any) {
event.stopPropagation()
window.localStorage.setItem(announcementKey, 'hidden')
window.localStorage.setItem(announcementKeyNoSpaces, 'hidden')
return setHidden(true)
}
@@ -1,7 +0,0 @@
{
"show": true,
"text": "Launch Week 13",
"launchDate": "2024-12-02T07:00:00.000-08:00",
"link": "/launch-week",
"cta": "Learn more"
}
+3
View File
@@ -2045,6 +2045,9 @@ importers:
react:
specifier: '*'
version: 18.2.0
react-countdown:
specifier: ^2.3.5
version: 2.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react-dom:
specifier: '*'
version: 18.2.0(react@18.2.0)