Skip to content

Commit

Permalink
Merge pull request #744 from hirosystems/feat/add-banner
Browse files Browse the repository at this point in the history
feat: add banner component
  • Loading branch information
ryanwaits authored Aug 22, 2024
2 parents 79de455 + e7b525a commit 875c7fe
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 2 deletions.
1 change: 0 additions & 1 deletion app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { DocsLayout, type DocsLayoutProps } from "fumadocs-ui/layout";
import type { ReactNode } from "react";
import { ArrowUpRight } from "lucide-react";
import { utils } from "@/utils/source";
import { create } from "@/components/ui/icon";
import { DocsLogo } from "@/components/ui/icon";
import { Body, NavChildren, SidebarBanner } from "./layout.client";

Expand Down
2 changes: 2 additions & 0 deletions app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
--code: 0 0% 100%;
--highlight: 40 13% 91%;
--content: 32.31 11.93% 78.63%;
--dark: 20 14.3% 4.1%;
}

.dark {
Expand Down Expand Up @@ -60,6 +61,7 @@
--code: 0 7.7% 5.1%;
--highlight: 12 6.2% 15.9%;
--content: 40 5.33% 33.14%;
--dark: 20 14.3% 4.1%;
}

.bitcoin {
Expand Down
10 changes: 10 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Viewport } from "next";
import { baseUrl, createMetadata } from "@/utils/metadata";
import { Provider } from "./provider";
import { GoogleTagManager } from "@next/third-parties/google";
import { Banner } from "@/components/ui/banner";
import { Discord, Github, HiroSVG, Youtube, X } from "@/components/ui/icon";

const GTM_ID = process.env.NEXT_PUBLIC_GTM_ID as string;
Expand Down Expand Up @@ -39,6 +40,15 @@ export default function RootLayout({
<GoogleTagManager gtmId={GTM_ID} />
<body className="flex min-h-screen flex-col">
<Provider>
<Banner
id="master-of-clarity"
cta="Compete and find out"
url="https://hirosystems.mmm.page/masterofclarity"
startDate="2024-08-21"
endDate="2024-08-28"
>
Are you a Master of Clarity?
</Banner>
{children}
<Footer />
</Provider>
Expand Down
122 changes: 122 additions & 0 deletions components/ui/banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"use client";

import { type HTMLAttributes, useCallback, useEffect, useState } from "react";
import { Button } from "./button";
import Link from "next/link";
import { X } from "lucide-react";
import { cn } from "@/utils/cn";
import { cva } from "class-variance-authority";
import { isWithinInterval, parseISO } from "date-fns";

export const buttonVariants = cva(
"bg-[#CEEFD0] inline-flex items-center justify-center rounded-md p-2 text-sm text-primary font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
color: {
outline: "border hover:bg-accent hover:text-accent-foreground",
ghost: "hover:bg-accent hover:text-accent-foreground",
secondary:
"border bg-secondary text-secondary-foreground hover:bg-accent hover:text-accent-foreground",
},
size: {
sm: "gap-1 p-0.5 text-xs",
icon: "p-1.5 [&_svg]:size-5",
},
},
}
);

export function Banner({
id,
cta = "Call to Action",
url = "/",
startDate,
endDate,
...props
}: HTMLAttributes<HTMLDivElement> & {
cta?: string;
url?: string;
startDate?: string;
endDate?: string;
}): React.ReactElement | null {
const [open, setOpen] = useState(true);
const [isWithinDateRange, setIsWithinDateRange] = useState(false);

useEffect(() => {
const now = new Date();
if (startDate && endDate) {
const start = parseISO(startDate);
const end = parseISO(endDate);
setIsWithinDateRange(isWithinInterval(now, { start, end }));
} else {
setIsWithinDateRange(true);
}

if (id) setOpen(localStorage.getItem(`nd-banner-${id}`) !== "true");
}, [id, startDate, endDate]);

useEffect(() => {
if (id) setOpen(localStorage.getItem(`nd-banner-${id}`) !== "true");
}, [id]);

const onClick = useCallback(() => {
setOpen(false);
if (id) localStorage.setItem(`nd-banner-${id}`, "true");
}, [id]);

if (!isWithinDateRange) return null;

return (
<div
id={id}
{...props}
className={cn(
"relative flex h-12 flex-row items-center justify-center bg-[#CEEFD0] px-4 text-center text-sm text-[hsl(var(--dark))] font-medium font-aeonik",
!open && "hidden",
props.className
)}
suppressHydrationWarning
>
{id ? (
<script
dangerouslySetInnerHTML={{
__html: `const ndBannerItem = localStorage.getItem('nd-banner-${id}');
if (ndBannerItem === 'true') {
document.getElementById('${id}').style.display = 'none';
}`,
}}
/>
) : null}
<div className="flex items-center justify-center space-x-4 text-inverted">
<div>{props.children}</div>
{cta && (
<Button
size="sm"
asChild
className="bg-[hsl(var(--dark))] text-[#CEEFD0] font-aeonik hover:bg-[hsl(var(--dark))] hover:text-white"
>
<a href={url} target="_blank" rel="noopener noreferrer">
{cta}
</a>
</Button>
)}
</div>
{id ? (
<button
type="button"
aria-label="Close Banner"
onClick={onClick}
className={cn(
buttonVariants({
className:
"absolute end-2 top-1/2 -translate-y-1/2 text-muted-foreground",
size: "icon",
})
)}
>
<X />
</button>
) : null}
</div>
);
}
2 changes: 1 addition & 1 deletion components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const buttonVariants = cva(
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
sm: "h-8 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
Expand Down

0 comments on commit 875c7fe

Please sign in to comment.