nx/nx-dev/ui-common/src/lib/live-stream-notifier.tsx

115 lines
4.2 KiB
TypeScript

'use client';
import { useState, useEffect, ReactElement } from 'react';
import { motion } from 'framer-motion';
import { MonorepoWorldIcon } from '@nx/nx-dev/ui-icons';
import { ButtonLink } from './button';
import {
PlayIcon,
XMarkIcon,
ChatBubbleLeftRightIcon,
} from '@heroicons/react/24/outline';
export function LiveStreamNotifier(): ReactElement | null {
const [isMounted, setIsMounted] = useState(false);
const [isVisible, setIsVisible] = useState<boolean>(true);
useEffect(() => {
setIsMounted(true);
const isClosedSession = localStorage.getItem('live-stream-notifier-closed');
if (isClosedSession === 'true') {
setIsVisible(false);
}
}, []);
const closeNotifier = (e: React.MouseEvent) => {
e.stopPropagation();
setIsVisible(false);
localStorage.setItem('live-stream-notifier-closed', 'true');
};
if (!isMounted || !isVisible) return null;
return (
<motion.div
layout
initial={{ y: '120%' }}
animate={{ y: 0 }}
exit={{ y: '120%' }}
transition={{
type: 'spring',
stiffness: 300,
damping: 30,
mass: 1,
}}
className="fixed bottom-0 left-0 right-0 z-30 w-full overflow-hidden bg-slate-950 text-white shadow-lg md:bottom-4 md:left-auto md:right-4 md:w-[512px] md:rounded-lg"
style={{ originY: 1 }}
>
<div className="relative p-4">
<button
onClick={closeNotifier}
className="absolute right-2 top-2 rounded-full p-1 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-white"
>
<XMarkIcon className="size-5" aria-hidden="true" />
<span className="sr-only">Close</span>
</button>
<div>
<motion.h3
layout="position"
className="flex items-center gap-2 pr-8 text-lg font-semibold"
>
<MonorepoWorldIcon
aria-hidden="true"
className="size-8 flex-shrink-0"
/>
<span>Monorepo World live replays available!</span>
</motion.h3>
<motion.div key="live-event" className="mt-4 space-y-4">
<p className="mb-2 text-sm">
Watch the replays of exciting talks on developer tooling and
monorepos! Catch all the insightful presentations from the event
on our YouTube channel.
</p>
<div className="flex flex-wrap items-center gap-1 sm:gap-4">
<a
title="Watch track 1"
href="http://go.nx.dev/MWTrack1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 rounded-lg bg-[#DDFB24] px-2 py-2 text-sm font-semibold text-black transition hover:bg-[#B2CF04] focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:text-black/70 md:px-4"
>
<PlayIcon aria-hidden="true" className="size-4" />
<span>Track 1</span>
</a>
<a
href="http://go.nx.dev/MWTrack2"
target="_blank"
title="Watch track 2"
rel="noopener noreferrer"
className="inline-flex items-center justify-center gap-2 rounded-lg bg-[#DDFB24] px-2 py-2 text-sm font-semibold text-black transition hover:bg-[#B2CF04] focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:text-black/70 md:px-4"
>
<PlayIcon aria-hidden="true" className="size-4" />
<span>Track 2</span>
</a>
<ButtonLink
variant="secondary"
size="small"
href="https://discord.gg/7yFabzBP"
target="_blank"
title="Join the discussion on Discord"
rel="noopener noreferrer"
>
<ChatBubbleLeftRightIcon
aria-hidden="true"
className="size-4"
/>
<span>#monorepo-world</span>
</ButtonLink>
</div>
</motion.div>
</div>
</div>
</motion.div>
);
}