Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.announcementContent a {
text-decoration: underline;
text-underline-offset: 0.2rem;
transition: color 0.2s ease;
}

.announcementContent a:hover {
color: #581c87;
}
106 changes: 106 additions & 0 deletions src/components/AnnouncementBanner/AnnouncementBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from "react"

import AnnouncementContent from "@site/src/content/announcement-banner.mdx"
import * as announcementModule from "@site/src/content/announcement-banner.mdx"
import styles from "./AnnouncementBanner.module.css"

type AnnouncementLevel = "info" | "warning" | "error" | "success"

function getLevelClasses(level: AnnouncementLevel) {
switch (level) {
case "warning":
return "border-amber-200 bg-amber-50 text-amber-950"
case "error":
return "border-red-200 bg-red-50 text-red-950"
case "success":
return "border-emerald-200 bg-emerald-50 text-emerald-950"
case "info":
default:
return "border-purple-200 bg-purple-50 text-purple-950"
}
}

function getDismissStorageKey(id: string) {
return `ory_docs_announcement_dismissed:${id}`
}

export default function AnnouncementBanner() {
const announcement = (announcementModule as any).announcement as
| {
enabled?: boolean
id?: string
level?: string
}
| undefined

const enabled = Boolean(announcement?.enabled)
const id = announcement?.id
const level = (announcement?.level ?? "info") as AnnouncementLevel

const [ready, setReady] = React.useState(false)
const [dismissed, setDismissed] = React.useState(false)

React.useEffect(() => {
if (!enabled || !id) {
setReady(true)
return
}
try {
const isDismissed = window.localStorage.getItem(getDismissStorageKey(id))
setDismissed(Boolean(isDismissed))
} catch {
// ignore (private browsing / blocked storage)
} finally {
setReady(true)
}
}, [enabled, id])

if (!enabled || !id) return null
if (!ready) return null
if (dismissed) return null

return (
<div
role="region"
aria-label="Announcement"
className={[
"border-b",
getLevelClasses(level),
// keep it readable across layouts
"text-base",
].join(" ")}
>
<div className="mx-auto flex max-w-screen-xl items-start gap-3 px-4 py-3">
<div
className={`min-w-0 flex-1 leading-5 pt-3 text-center ${styles.announcementContent}`}
>
<AnnouncementContent />
</div>
<button
type="button"
className={[
"shrink-0 rounded-md p-1.5 mt-3",
"border-none bg-transparent cursor-pointer",
"text-current opacity-60 hover:opacity-100 hover:bg-black/5",
"transition-all duration-200",
"focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white",
"focus-visible:ring-purple-600",
].join(" ")}
aria-label="Dismiss announcement"
onClick={() => {
setDismissed(true)
try {
window.localStorage.setItem(getDismissStorageKey(id), "1")
} catch {
// ignore
}
}}
>
<span aria-hidden="true" className="text-lg font-light leading-none">
</span>
</button>
</div>
</div>
)
}
8 changes: 8 additions & 0 deletions src/content/announcement-banner.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const announcement = {
enabled: true, // Toggle the banner on/off.
id: "example-2026-05-08", // Change this for every new announcement.
level: "info", // Visual emphasis: "info" | "warning" | "error" | "success"
}

We're happy to announce the release of our new product: name - description, read
more about it [here](/docs/getting-started/overview).
2 changes: 2 additions & 0 deletions src/theme/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import React from "react"
import KapaWidget from "./KapaWidget"
import AnnouncementBanner from "@site/src/components/AnnouncementBanner/AnnouncementBanner"
import { Buffer } from "buffer"

// Inject Buffer globally (works for browser + weird runtimes)
Expand All @@ -13,6 +14,7 @@ if (typeof globalThis !== "undefined" && !globalThis.Buffer) {
function Root({ children }) {
return (
<>
<AnnouncementBanner />
{children}
<KapaWidget />
</>
Expand Down
Loading