diff --git a/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts b/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts index 2690e0b09c89..6b49810ad781 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts @@ -5,8 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import {describe, expect, it} from 'vitest'; -import {getThemeInlineScript} from '../inlineScripts'; +import {describe, expect, it, vi} from 'vitest'; +import { + getThemeInlineScript, + getAnnouncementBarInlineScript, +} from '../inlineScripts'; describe('inlineScripts', () => { it('inline javascript for default options', () => { @@ -40,4 +43,114 @@ describe('inlineScripts', () => { }), ).toMatchSnapshot(); }); + + describe('getAnnouncementBarInlineScript', () => { + it('generates announcement bar script with announcement id', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-2'}, + }); + expect(script).toContain( + 'localStorage.getItem(\'docusaurus.announcement.id\') !== "announcement-2"', + ); + expect(script).toContain( + "localStorage.getItem('docusaurus.announcement.dismiss') === 'true'", + ); + }); + + it('generates announcement bar script with custom namespace', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: '.custom'}, + announcementBar: {id: 'announcement-special'}, + }); + expect(script).toContain( + 'localStorage.getItem(\'docusaurus.announcement.id.custom\') !== "announcement-special"', + ); + expect(script).toContain( + "localStorage.getItem('docusaurus.announcement.dismiss.custom') === 'true'", + ); + }); + + it('sets data-announcement-bar-initially-dismissed to false when stored id differs from current id', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-2'}, + }); + + const store: Record = { + 'docusaurus.announcement.id': 'announcement-1', + 'docusaurus.announcement.dismiss': 'true', + }; + const setAttribute = vi.fn(); + + const runScript = new Function('localStorage', 'document', script); + + runScript( + { + getItem: (key: string) => store[key] ?? null, + }, + { + documentElement: {setAttribute}, + }, + ); + + expect(setAttribute).toHaveBeenCalledWith( + 'data-announcement-bar-initially-dismissed', + false, + ); + }); + + it('sets data-announcement-bar-initially-dismissed to true when stored id matches and is dismissed', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-2'}, + }); + + const store: Record = { + 'docusaurus.announcement.id': 'announcement-2', + 'docusaurus.announcement.dismiss': 'true', + }; + const setAttribute = vi.fn(); + + const runScript = new Function('localStorage', 'document', script); + + runScript( + { + getItem: (key: string) => store[key] ?? null, + }, + { + documentElement: {setAttribute}, + }, + ); + + expect(setAttribute).toHaveBeenCalledWith( + 'data-announcement-bar-initially-dismissed', + true, + ); + }); + + it('sets data-announcement-bar-initially-dismissed to false on fresh visit (no stored id)', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-1'}, + }); + + const setAttribute = vi.fn(); + const runScript = new Function('localStorage', 'document', script); + + runScript( + { + getItem: () => null, + }, + { + documentElement: {setAttribute}, + }, + ); + + expect(setAttribute).toHaveBeenCalledWith( + 'data-announcement-bar-initially-dismissed', + false, + ); + }); + }); }); diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index 8c5a236835a3..b57e3bf69eb1 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -134,7 +134,7 @@ export default function themeClassic( innerHTML: ` ${getThemeInlineScript({colorMode, siteStorage})} ${DataAttributeQueryStringInlineJavaScript} -${announcementBar ? getAnnouncementBarInlineScript({siteStorage}) : ''} +${announcementBar ? getAnnouncementBarInlineScript({siteStorage, announcementBar}) : ''} `, }, ], diff --git a/packages/docusaurus-theme-classic/src/inlineScripts.ts b/packages/docusaurus-theme-classic/src/inlineScripts.ts index fe49094a52c4..4512299ad0ec 100644 --- a/packages/docusaurus-theme-classic/src/inlineScripts.ts +++ b/packages/docusaurus-theme-classic/src/inlineScripts.ts @@ -76,14 +76,17 @@ export const DataAttributeQueryStringInlineJavaScript = ` // the announcement bar asap (before React hydration) export function getAnnouncementBarInlineScript({ siteStorage, + announcementBar, }: { siteStorage: SiteStorage; + announcementBar?: {id: string}; }): string { // Duplicated constant. Unfortunately we can't import it from theme-common, as // we need to support older nodejs versions without ESM support // TODO: import from theme-common once we support Node.js with ESM support // + move all those announcementBar stuff there too const AnnouncementBarDismissStorageKey = `docusaurus.announcement.dismiss${siteStorage.namespace}`; + const AnnouncementBarIdStorageKey = `docusaurus.announcement.id${siteStorage.namespace}`; const AnnouncementBarDismissDataAttribute = 'data-announcement-bar-initially-dismissed'; @@ -91,6 +94,15 @@ export function getAnnouncementBarInlineScript({ return `(function() { function isDismissed() { try { + ${ + announcementBar?.id + ? `if (localStorage.getItem('${AnnouncementBarIdStorageKey}') !== ${JSON.stringify( + announcementBar.id, + )}) { + return false; + }` + : '' + } return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true'; } catch (err) {} return false; diff --git a/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx index 71546d20d2b4..133eac9490b8 100644 --- a/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx @@ -79,6 +79,9 @@ function useContextValue(): ContextValue { if (isNewAnnouncement || !isDismissedInStorage()) { setClosed(false); + document.documentElement.removeAttribute( + 'data-announcement-bar-initially-dismissed', + ); } }, [announcementBar]);