Skip to content

Commit 042d0eb

Browse files
authored
🎉 feat: add Banner component (#435)
1 parent cc3a6ce commit 042d0eb

File tree

2 files changed

+136
-5
lines changed

2 files changed

+136
-5
lines changed

‎components/Banner.tsx‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { useState, useEffect } from 'react'
2+
3+
interface BannerProps {
4+
storageKey: string
5+
}
6+
7+
export function Banner({ storageKey }: BannerProps) {
8+
const [isVisible, setIsVisible] = useState(false)
9+
10+
useEffect(() => {
11+
const dismissed = localStorage.getItem(`nextra-banner-${storageKey}`)
12+
if (!dismissed) {
13+
setIsVisible(true)
14+
}
15+
}, [storageKey])
16+
17+
const handleDismiss = () => {
18+
localStorage.setItem(`nextra-banner-${storageKey}`, 'true')
19+
setIsVisible(false)
20+
}
21+
22+
if (!isVisible) return null
23+
24+
return (
25+
<div className="nextra-banner-container">
26+
<div className="nextra-banner-content">
27+
<div className="nextra-banner-text">
28+
LibreChat is joining <span className="clickhouse-highlight">ClickHouse</span> to power the
29+
open-source Agentic Data Stack 🎉{' '}
30+
<a
31+
href="http://clickhouse.com/blog/librechat-open-source-agentic-data-stack"
32+
target="_blank"
33+
rel="noopener noreferrer"
34+
>
35+
Learn More ↗
36+
</a>
37+
</div>
38+
<button className="nextra-banner-close" onClick={handleDismiss} aria-label="Dismiss banner">
39+
<svg
40+
xmlns="http://www.w3.org/2000/svg"
41+
width="20"
42+
height="20"
43+
viewBox="0 0 24 24"
44+
fill="none"
45+
stroke="currentColor"
46+
strokeWidth="2"
47+
strokeLinecap="round"
48+
strokeLinejoin="round"
49+
>
50+
<line x1="18" y1="6" x2="6" y2="18"></line>
51+
<line x1="6" y1="6" x2="18" y2="18"></line>
52+
</svg>
53+
</button>
54+
</div>
55+
<style jsx>{`
56+
.nextra-banner-container {
57+
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
58+
color: #ffffff;
59+
text-align: center;
60+
font-size: 14px;
61+
font-weight: 500;
62+
padding: 12px 16px;
63+
position: relative;
64+
z-index: 1000;
65+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
66+
}
67+
.nextra-banner-content {
68+
max-width: 90rem;
69+
margin: 0 auto;
70+
display: flex;
71+
align-items: center;
72+
justify-content: center;
73+
gap: 16px;
74+
position: relative;
75+
}
76+
.nextra-banner-text {
77+
flex: 1;
78+
display: flex;
79+
align-items: center;
80+
justify-content: center;
81+
gap: 8px;
82+
flex-wrap: wrap;
83+
}
84+
.nextra-banner-text :global(.clickhouse-highlight) {
85+
background-color: rgb(250, 255, 105);
86+
color: rgb(21, 21, 21);
87+
font-weight: 700;
88+
padding: 2px 6px;
89+
clip-path: polygon(5% 0%, 100% 0%, 95% 100%, 0% 100%);
90+
display: inline-block;
91+
}
92+
.nextra-banner-text :global(a) {
93+
color: #ffffff;
94+
text-decoration: underline;
95+
font-weight: 600;
96+
transition: opacity 0.2s;
97+
}
98+
.nextra-banner-text :global(a:hover) {
99+
opacity: 0.7;
100+
}
101+
.nextra-banner-close {
102+
background: transparent;
103+
border: none;
104+
cursor: pointer;
105+
padding: 4px;
106+
display: flex;
107+
align-items: center;
108+
justify-content: center;
109+
color: #ffffff;
110+
opacity: 0.7;
111+
transition: opacity 0.2s;
112+
flex-shrink: 0;
113+
}
114+
.nextra-banner-close:hover {
115+
opacity: 1;
116+
}
117+
@media (max-width: 768px) {
118+
.nextra-banner-container {
119+
font-size: 13px;
120+
padding: 10px 12px;
121+
}
122+
.nextra-banner-content {
123+
gap: 12px;
124+
}
125+
}
126+
`}</style>
127+
</div>
128+
)
129+
}

‎pages/_app.tsx‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import '../style.css'
22
import 'vidstack/styles/base.css'
33
import '../src/overrides.css'
44
// import Script from 'next/script'
5+
import posthog from 'posthog-js'
56
import { useEffect } from 'react'
67
import { useRouter } from 'next/router'
7-
import posthog from 'posthog-js'
8-
import { PostHogProvider } from 'posthog-js/react'
9-
import { CrispWidget } from '@/components/supportChat'
10-
import { Hubspot, hsPageView } from '@/components/analytics/hubspot'
118
import { GeistSans } from 'geist/font/sans'
9+
import { GeistMono } from 'geist/font/mono'
10+
import { PostHogProvider } from 'posthog-js/react'
1211
import { Analytics } from '@vercel/analytics/react'
1312
import { SpeedInsights } from '@vercel/speed-insights/next'
14-
import { GeistMono } from 'geist/font/mono'
13+
import { Hubspot, hsPageView } from '@/components/analytics/hubspot'
14+
import { CrispWidget } from '@/components/supportChat'
15+
import { Banner } from '@/components/Banner'
1516

1617
export default function App({ Component, pageProps }) {
1718
const router = useRouter()
@@ -42,6 +43,7 @@ export default function App({ Component, pageProps }) {
4243
>
4344
{/* <div className={`${GeistSans.variable}`}> */}
4445
<PostHogProvider client={posthog}>
46+
<Banner storageKey="clickhouse-announcement" />
4547
<Component {...pageProps} />
4648
<Analytics />
4749
<SpeedInsights />

0 commit comments

Comments
 (0)