From 8b9a6c0919f1e81518be2573f3ae7fb13a152145 Mon Sep 17 00:00:00 2001 From: Derek Putnam Date: Thu, 15 Oct 2026 11:19:24 -0400 Subject: [PATCH] Add scoped EPP Navigator announcement bar to Endpoint Protector docs Swizzle AnnouncementBar (wrapper) so the bar renders only under /docs/endpointprotector and its subpages. Stays pinned on desktop, with navbar/sidebar/TOC offsets applied only while the bar is showing. Generated with AI Co-Authored-By: Claude Code --- docusaurus.config.js | 8 ++++ src/css/custom.css | 69 ++++++++++++++++++++++++++++++ src/theme/AnnouncementBar/index.js | 31 ++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/theme/AnnouncementBar/index.js diff --git a/docusaurus.config.js b/docusaurus.config.js index d7ac0c581b..2f2c6f7ca2 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -263,6 +263,14 @@ const config = { themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ + // Shown only on scoped paths — see src/theme/AnnouncementBar + announcementBar: { + id: 'endpointprotector-announcement', + content: '⚡ Skip the searching: Chat with EPP Navigator, an AI guide built on this documentation. (Community account required) ', + backgroundColor: '#5851DB', + textColor: '#ffffff', + isCloseable: true, + }, // MermaidJS Config mermaid: { theme: { diff --git a/src/css/custom.css b/src/css/custom.css index 15a7c6923c..499963db7c 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -635,3 +635,72 @@ html { overflow: hidden; } + +/* Announcement bar (shown only in scoped sections — see src/theme/AnnouncementBar) */ +/* Height var is set only while the bar is showing (attribute set in src/theme/AnnouncementBar) */ +html[data-has-announcement-bar] { + --docusaurus-announcement-bar-height: 64px; +} + +.theme-announcement-bar { + min-height: 64px; + font-size: 1.35rem; + font-weight: 400; + padding: 0 1rem; +} + +/* The theme's Content styles underline links; these selectors outrank them */ +html .theme-announcement-bar a { + color: inherit; + text-decoration: none; +} + +html .theme-announcement-bar a:hover { + color: inherit; + text-decoration: underline; +} + +.theme-announcement-bar strong { + font-family: Hubot Sans, HubotSans-fallback, sans-serif; + font-weight: 700; +} + +.theme-announcement-bar button[class*='closeButton'] { + color: #fff; + align-self: center; + display: flex; + align-items: center; + justify-content: center; +} + +.theme-announcement-bar .announcement-external-icon { + margin-left: 0.4rem; + vertical-align: -0.1em; +} + +/* Keep the bar pinned on desktop; push navbar, sidebar, TOC and anchors below it */ +@media (min-width: 997px) { + html[data-has-announcement-bar] .theme-announcement-bar { + position: sticky; + top: 0; + z-index: calc(var(--ifm-z-index-fixed) + 1); + } + + html[data-has-announcement-bar] .navbar--fixed-top { + top: var(--docusaurus-announcement-bar-height); + } + + html[data-has-announcement-bar] [class*='sidebarViewport_'] { + top: var(--docusaurus-announcement-bar-height); + max-height: calc(100vh - var(--docusaurus-announcement-bar-height)); + } + + html[data-has-announcement-bar] [class*='tableOfContents_'] { + top: calc(var(--ifm-navbar-height) + var(--docusaurus-announcement-bar-height) + 1rem); + max-height: calc(100vh - var(--ifm-navbar-height) - var(--docusaurus-announcement-bar-height) - 2rem); + } + + html[data-has-announcement-bar] [class*='anchorWithStickyNavbar_'] { + scroll-margin-top: calc(var(--ifm-navbar-height) + var(--docusaurus-announcement-bar-height) + 0.5rem); + } +} diff --git a/src/theme/AnnouncementBar/index.js b/src/theme/AnnouncementBar/index.js new file mode 100644 index 0000000000..257edf603a --- /dev/null +++ b/src/theme/AnnouncementBar/index.js @@ -0,0 +1,31 @@ +import React, {useEffect} from 'react'; +import {useLocation} from '@docusaurus/router'; +import {useAnnouncementBar} from '@docusaurus/theme-common/internal'; +import AnnouncementBar from '@theme-original/AnnouncementBar'; + +// Path prefixes (and all subpages) where the announcement bar is shown. +const ANNOUNCEMENT_SCOPES = ['/docs/endpointprotector']; + +export default function AnnouncementBarWrapper(props) { + const {pathname} = useLocation(); + const {isActive} = useAnnouncementBar(); + const inScope = ANNOUNCEMENT_SCOPES.some( + (s) => pathname === s || pathname.startsWith(`${s}/`), + ); + const visible = inScope && isActive; + + // Lets custom.css keep the bar pinned and offset the navbar/sidebar/TOC + // below it — only while the bar is actually showing. (A data attribute, not + // a class: Docusaurus rewrites 's class list and would drop ours.) + useEffect(() => { + const root = document.documentElement; + if (visible) { + root.setAttribute('data-has-announcement-bar', 'true'); + } else { + root.removeAttribute('data-has-announcement-bar'); + } + return () => root.removeAttribute('data-has-announcement-bar'); + }, [visible]); + + return inScope ? : null; +}