diff --git a/packages/docusaurus-theme-classic/src/__tests__/announcementBarInlineScript.test.ts b/packages/docusaurus-theme-classic/src/__tests__/announcementBarInlineScript.test.ts new file mode 100644 index 000000000000..6b513b3de33f --- /dev/null +++ b/packages/docusaurus-theme-classic/src/__tests__/announcementBarInlineScript.test.ts @@ -0,0 +1,94 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @vitest-environment jsdom + +import {describe, expect, it, beforeEach} from 'vitest'; +import {getAnnouncementBarInlineScript} from '../inlineScripts'; + +describe('announcementBarInlineScript', () => { + beforeEach(() => { + localStorage.clear(); + sessionStorage.clear(); + document.documentElement.removeAttribute( + 'data-announcement-bar-initially-dismissed', + ); + }); + + it('sets initially-dismissed to true when same announcement was dismissed', () => { + localStorage.setItem('docusaurus.announcement.id', 'announcement-1'); + localStorage.setItem('docusaurus.announcement.dismiss', 'true'); + + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-1'}, + }); + + // Execute inline script + eval(script); + + expect( + document.documentElement.getAttribute( + 'data-announcement-bar-initially-dismissed', + ), + ).toBe('true'); + }); + + it('sets initially-dismissed to false when a new announcement id is published', () => { + localStorage.setItem('docusaurus.announcement.id', 'announcement-1'); + localStorage.setItem('docusaurus.announcement.dismiss', 'true'); + + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-2'}, + }); + + // Execute inline script + eval(script); + + expect( + document.documentElement.getAttribute( + 'data-announcement-bar-initially-dismissed', + ), + ).toBe('false'); + }); + + it('sets initially-dismissed to true when sessionStorage holds the dismissed announcement', () => { + sessionStorage.setItem('docusaurus.announcement.id', 'announcement-1'); + sessionStorage.setItem('docusaurus.announcement.dismiss', 'true'); + + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'sessionStorage', namespace: ''}, + announcementBar: {id: 'announcement-1'}, + }); + + // Execute inline script + eval(script); + + expect( + document.documentElement.getAttribute( + 'data-announcement-bar-initially-dismissed', + ), + ).toBe('true'); + }); + + it('sets initially-dismissed to false when no announcement was dismissed', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: {type: 'localStorage', namespace: ''}, + announcementBar: {id: 'announcement-1'}, + }); + + // Execute inline script + eval(script); + + expect( + document.documentElement.getAttribute( + 'data-announcement-bar-initially-dismissed', + ), + ).toBe('false'); + }); +}); diff --git a/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts b/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts index 2690e0b09c89..8cfe6e84bbb9 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/inlineScripts.test.ts @@ -6,7 +6,10 @@ */ import {describe, expect, it} from 'vitest'; -import {getThemeInlineScript} from '../inlineScripts'; +import { + getThemeInlineScript, + getAnnouncementBarInlineScript, +} from '../inlineScripts'; describe('inlineScripts', () => { it('inline javascript for default options', () => { @@ -40,4 +43,36 @@ describe('inlineScripts', () => { }), ).toMatchSnapshot(); }); + + it('announcement bar inline script without id', () => { + expect( + getAnnouncementBarInlineScript({ + siteStorage: { + type: 'localStorage', + namespace: '', + }, + }), + ).toContain( + "storage.getItem('docusaurus.announcement.dismiss') === 'true'", + ); + }); + + it('announcement bar inline script with id', () => { + const script = getAnnouncementBarInlineScript({ + siteStorage: { + type: 'localStorage', + namespace: '', + }, + announcementBar: { + id: 'announcement-2', + }, + }); + expect(script).toContain("var storage = window['localStorage'];"); + expect(script).toContain( + 'storage.getItem(\'docusaurus.announcement.id\') !== "announcement-2"', + ); + expect(script).toContain( + "storage.getItem('docusaurus.announcement.dismiss') === 'true'", + ); + }); }); 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..69d5d0fd3595 100644 --- a/packages/docusaurus-theme-classic/src/inlineScripts.ts +++ b/packages/docusaurus-theme-classic/src/inlineScripts.ts @@ -76,22 +76,36 @@ 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'; + const id = announcementBar?.id; /* language=js */ return `(function() { function isDismissed() { try { - return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true'; + var storage = window['${siteStorage.type}']; + ${ + id + ? `if (storage.getItem('${AnnouncementBarIdStorageKey}') !== ${JSON.stringify( + id, + )}) { + return false; + }` + : '' + } + return storage.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..cbd71d36cc20 100644 --- a/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx @@ -79,6 +79,11 @@ function useContextValue(): ContextValue { if (isNewAnnouncement || !isDismissedInStorage()) { setClosed(false); + if (typeof document !== 'undefined') { + document.documentElement.removeAttribute( + 'data-announcement-bar-initially-dismissed', + ); + } } }, [announcementBar]);