Skip to content

Commit 12377ee

Browse files
authored
Merge pull request #79 from Boring-Software-Inc/feat/closed-beta-banner
add closed beta banner
2 parents a93c0a8 + a65d35a commit 12377ee

2 files changed

Lines changed: 84 additions & 2 deletions

File tree

apps/web/src/components/layout/app/shell/app-shell.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Outlet, useRouterState } from "@tanstack/react-router"
22
import { AuthProvider } from "@tripwire/auth/components"
33
import { TopNav } from "#/components/layout/app/shell/top-nav"
4+
import { BetaBanner } from "#/components/layout/app/shell/beta-banner"
45
import { WorkspaceRedirect } from "#/components/layout/app/shell/workspace-redirect"
56
import { InstallGitHubPrompt } from "#/components/layout/app/shell/install-github-prompt"
67
import { AskSidePanel } from "#/components/layout/app/chat/ask-side-panel"
@@ -55,8 +56,11 @@ function AppShellInner() {
5556
isChatRoute ? undefined : { boxShadow: "#00000008 0px 1px 4px" }
5657
}
5758
>
58-
<div className="absolute inset-0 overflow-auto">
59-
{needsInstall ? <InstallGitHubPrompt /> : <Outlet />}
59+
<div className="absolute inset-0 flex flex-col">
60+
<BetaBanner />
61+
<div className="min-h-0 flex-1 overflow-auto">
62+
{needsInstall ? <InstallGitHubPrompt /> : <Outlet />}
63+
</div>
6064
</div>
6165
</div>
6266

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { useState, useSyncExternalStore } from "react"
2+
import { Button } from "@tripwire/ui/button"
3+
import { CloseIcon } from "@tripwire/ui/icons/close-icon"
4+
import { cn } from "@tripwire/ui/utils"
5+
6+
const STORAGE_KEY = "tripwire:beta-banner:dismissed"
7+
const EVENT_NAME = "tripwire:beta-banner-dismissed"
8+
9+
function subscribe(callback: () => void): () => void {
10+
window.addEventListener(EVENT_NAME, callback)
11+
return () => window.removeEventListener(EVENT_NAME, callback)
12+
}
13+
14+
function getSnapshot(): boolean {
15+
return window.localStorage.getItem(STORAGE_KEY) === "true"
16+
}
17+
18+
function getServerSnapshot(): boolean {
19+
return true
20+
}
21+
22+
function dismiss(): void {
23+
window.localStorage.setItem(STORAGE_KEY, "true")
24+
window.dispatchEvent(new Event(EVENT_NAME))
25+
}
26+
27+
export function BetaBanner() {
28+
const dismissed = useSyncExternalStore(
29+
subscribe,
30+
getSnapshot,
31+
getServerSnapshot
32+
)
33+
const [closing, setClosing] = useState(false)
34+
35+
if (dismissed) return null
36+
37+
return (
38+
<div
39+
className={cn(
40+
"grid shrink-0 transition-[grid-template-rows] duration-[360ms]",
41+
closing ? "grid-rows-[0fr]" : "grid-rows-[1fr]"
42+
)}
43+
style={{ transitionTimingFunction: "cubic-bezier(0.19, 1, 0.22, 1)" }}
44+
onTransitionEnd={(e) => {
45+
if (e.target === e.currentTarget) dismiss()
46+
}}
47+
>
48+
<div className="overflow-hidden">
49+
<div
50+
className={cn(
51+
"relative flex items-center justify-center bg-tw-card px-10 py-2 transition-opacity duration-200",
52+
closing && "opacity-0"
53+
)}
54+
>
55+
<p className="text-[13px] leading-tight font-medium text-white">
56+
Tripwire is in closed beta. Please raise any issues via DM on X{" "}
57+
<a
58+
href="https://x.com/tripwiredotsh"
59+
target="_blank"
60+
rel="noreferrer"
61+
className="underline underline-offset-2"
62+
>
63+
@tripwiredotsh
64+
</a>
65+
</p>
66+
<Button
67+
variant="ghost"
68+
aria-label="Dismiss beta banner"
69+
className="absolute right-2 h-6 w-6 p-0 text-white hover:bg-transparent hover:opacity-70"
70+
onClick={() => setClosing(true)}
71+
>
72+
<CloseIcon className="size-3.5" />
73+
</Button>
74+
</div>
75+
</div>
76+
</div>
77+
)
78+
}

0 commit comments

Comments
 (0)