diff --git a/apps/docs/features/app.providers.tsx b/apps/docs/features/app.providers.tsx index f6c2f3089b3..63b3ace9bab 100644 --- a/apps/docs/features/app.providers.tsx +++ b/apps/docs/features/app.providers.tsx @@ -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) {
+ {children} diff --git a/apps/www/components/Announcement/Announcement.tsx b/apps/www/components/Announcement/Announcement.tsx deleted file mode 100644 index 61ae468b94a..00000000000 --- a/apps/www/components/Announcement/Announcement.tsx +++ /dev/null @@ -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) => { - 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 ( -
- {!isLaunchWeekSection && ( -
- -
- )} - {children} - -
- ) - } -} - -export default Announcement diff --git a/apps/www/components/Announcement/data/Announcement.json b/apps/www/components/Announcement/data/Announcement.json deleted file mode 100644 index 7cce453492d..00000000000 --- a/apps/www/components/Announcement/data/Announcement.json +++ /dev/null @@ -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" -} diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx index e9464537bf3..b79402c9e32 100644 --- a/apps/www/components/Hero/Hero.tsx +++ b/apps/www/components/Hero/Hero.tsx @@ -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 = () => {
+
+ +

Build in a weekend Scale to millions diff --git a/apps/www/lib/constants.ts b/apps/www/lib/constants.ts index 5ae466909a6..91a222b325a 100644 --- a/apps/www/lib/constants.ts +++ b/apps/www/lib/constants.ts @@ -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` diff --git a/apps/www/pages/_app.tsx b/apps/www/pages/_app.tsx index 93020054f3e..bebf9d0b426 100644 --- a/apps/www/pages/_app.tsx +++ b/apps/www/pages/_app.tsx @@ -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) { > + diff --git a/apps/www/public/images/launchweek/14/promo-banner-bg.png b/apps/www/public/images/launchweek/14/promo-banner-bg.png new file mode 100644 index 00000000000..524db38d09e Binary files /dev/null and b/apps/www/public/images/launchweek/14/promo-banner-bg.png differ diff --git a/packages/ui-patterns/Banners/Countdown.tsx b/packages/ui-patterns/Banners/Countdown.tsx new file mode 100644 index 00000000000..77c6cde0c5a --- /dev/null +++ b/packages/ui-patterns/Banners/Countdown.tsx @@ -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 ( + + ) + } + } + + return +} + +export default CountdownComponent diff --git a/packages/ui-patterns/Banners/LW14Announcement.tsx b/packages/ui-patterns/Banners/LW14Announcement.tsx new file mode 100644 index 00000000000..69ad2dfcc7a --- /dev/null +++ b/packages/ui-patterns/Banners/LW14Announcement.tsx @@ -0,0 +1,10 @@ +import { Announcement } from 'ui/src/layout/banners' +import LW14Banner from './LW14Banner' + +export const LW14Announcement = () => { + return ( + + + + ) +} diff --git a/packages/ui/src/layout/banners/LW13CountdownBanner/LW13CountdownBanner.tsx b/packages/ui-patterns/Banners/LW14Banner.tsx similarity index 83% rename from packages/ui/src/layout/banners/LW13CountdownBanner/LW13CountdownBanner.tsx rename to packages/ui-patterns/Banners/LW14Banner.tsx index 98ce6df034c..325569c39f3 100644 --- a/packages/ui/src/layout/banners/LW13CountdownBanner/LW13CountdownBanner.tsx +++ b/packages/ui-patterns/Banners/LW14Banner.tsx @@ -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 diff --git a/packages/ui-patterns/Banners/data.json b/packages/ui-patterns/Banners/data.json new file mode 100644 index 00000000000..27667113a2d --- /dev/null +++ b/packages/ui-patterns/Banners/data.json @@ -0,0 +1,7 @@ +{ + "text": "Launch Week 14", + "launchDate": "2025-03-31T07:00:00.000-08:00", + "link": "/launch-week", + "cta": "Learn more" +} + diff --git a/packages/ui-patterns/CountdownWidget/index.tsx b/packages/ui-patterns/CountdownWidget/index.tsx index a4b178dfe18..e9a36f81f35 100644 --- a/packages/ui-patterns/CountdownWidget/index.tsx +++ b/packages/ui-patterns/CountdownWidget/index.tsx @@ -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 = () => ( - : + : ) return ( diff --git a/packages/ui-patterns/PromoToast/PromoToast.tsx b/packages/ui-patterns/PromoToast/PromoToast.tsx index dd6a2177068..58a8b1a76d8 100644 --- a/packages/ui-patterns/PromoToast/PromoToast.tsx +++ b/packages/ui-patterns/PromoToast/PromoToast.tsx @@ -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' )} > -
-
Launch Week 13
-

- 2—6 Dec +

+ 31 APR - 04 MAR / 7AM PT + +

+ Launch Week 14

-
-
- A week of new features +
-
+
) => { 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) } diff --git a/packages/ui/src/layout/banners/data/Announcement.json b/packages/ui/src/layout/banners/data/Announcement.json deleted file mode 100644 index c031ca0a95b..00000000000 --- a/packages/ui/src/layout/banners/data/Announcement.json +++ /dev/null @@ -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" -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62a25a6918a..2c32d90620a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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)