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;
+}