mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-03 11:22:30 +02:00
fix(v2): Fix announcementBar layout shifts (#5040)
* Fix announcementBar layout shift * useAnnouncementBar should return correct state after hydration * refactor announcementBar => move utils to theme-common * restore previous announcementBar * typo
This commit is contained in:
parent
814455f88e
commit
9916a0b4a4
11 changed files with 179 additions and 110 deletions
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {DocusaurusContext, Plugin} from '@docusaurus/types';
|
import {DocusaurusContext, Plugin} from '@docusaurus/types';
|
||||||
import {ThemeConfig} from '@docusaurus/theme-common';
|
import type {ThemeConfig} from '@docusaurus/theme-common';
|
||||||
import {getTranslationFiles, translateThemeConfig} from './translations';
|
import {getTranslationFiles, translateThemeConfig} from './translations';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import Module from 'module';
|
import Module from 'module';
|
||||||
|
@ -24,7 +24,7 @@ const ContextReplacementPlugin = requireFromDocusaurusCore(
|
||||||
|
|
||||||
// Need to be inlined to prevent dark mode FOUC
|
// Need to be inlined to prevent dark mode FOUC
|
||||||
// Make sure that the 'storageKey' is the same as the one in `/theme/hooks/useTheme.js`
|
// Make sure that the 'storageKey' is the same as the one in `/theme/hooks/useTheme.js`
|
||||||
const storageKey = 'theme';
|
const ThemeStorageKey = 'theme';
|
||||||
const noFlashColorMode = ({defaultMode, respectPrefersColorScheme}) => {
|
const noFlashColorMode = ({defaultMode, respectPrefersColorScheme}) => {
|
||||||
return `(function() {
|
return `(function() {
|
||||||
var defaultMode = '${defaultMode}';
|
var defaultMode = '${defaultMode}';
|
||||||
|
@ -37,7 +37,7 @@ const noFlashColorMode = ({defaultMode, respectPrefersColorScheme}) => {
|
||||||
function getStoredTheme() {
|
function getStoredTheme() {
|
||||||
var theme = null;
|
var theme = null;
|
||||||
try {
|
try {
|
||||||
theme = localStorage.getItem('${storageKey}');
|
theme = localStorage.getItem('${ThemeStorageKey}');
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,26 @@ const noFlashColorMode = ({defaultMode, respectPrefersColorScheme}) => {
|
||||||
})();`;
|
})();`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 only support Node.js with ESM support
|
||||||
|
// + move all those announcementBar stuff there too
|
||||||
|
export const AnnouncementBarDismissStorageKey =
|
||||||
|
'docusaurus.announcement.dismiss';
|
||||||
|
const AnnouncementBarDismissDataAttribute =
|
||||||
|
'data-announcement-bar-initially-dismissed';
|
||||||
|
// We always render the announcement bar html on the server, to prevent layout shifts on React hydration
|
||||||
|
// The theme can use CSS + the data attribute to hide the announcement bar asap (before React hydration)
|
||||||
|
const AnnouncementBarInlineJavaScript = `
|
||||||
|
(function() {
|
||||||
|
function isDismissed() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true';
|
||||||
|
} catch (err) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
|
||||||
|
})();`;
|
||||||
|
|
||||||
function getInfimaCSSFile(direction) {
|
function getInfimaCSSFile(direction) {
|
||||||
return `infima/dist/css/default/default${
|
return `infima/dist/css/default/default${
|
||||||
direction === 'rtl' ? '-rtl' : ''
|
direction === 'rtl' ? '-rtl' : ''
|
||||||
|
@ -82,7 +102,11 @@ export default function docusaurusThemeClassic(
|
||||||
i18n: {currentLocale, localeConfigs},
|
i18n: {currentLocale, localeConfigs},
|
||||||
} = context;
|
} = context;
|
||||||
const themeConfig = (roughlyTypedThemeConfig || {}) as ThemeConfig;
|
const themeConfig = (roughlyTypedThemeConfig || {}) as ThemeConfig;
|
||||||
const {colorMode, prism: {additionalLanguages = []} = {}} = themeConfig;
|
const {
|
||||||
|
announcementBar,
|
||||||
|
colorMode,
|
||||||
|
prism: {additionalLanguages = []} = {},
|
||||||
|
} = themeConfig;
|
||||||
const {customCss} = options || {};
|
const {customCss} = options || {};
|
||||||
const {direction} = localeConfigs[currentLocale];
|
const {direction} = localeConfigs[currentLocale];
|
||||||
|
|
||||||
|
@ -178,7 +202,10 @@ export default function docusaurusThemeClassic(
|
||||||
preBodyTags: [
|
preBodyTags: [
|
||||||
{
|
{
|
||||||
tagName: 'script',
|
tagName: 'script',
|
||||||
innerHTML: noFlashColorMode(colorMode),
|
innerHTML: `
|
||||||
|
${noFlashColorMode(colorMode)}
|
||||||
|
${announcementBar ? AnnouncementBarInlineJavaScript : ''}
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,17 +7,13 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
import {useThemeConfig, useAnnouncementBar} from '@docusaurus/theme-common';
|
||||||
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
|
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function AnnouncementBar(): JSX.Element | null {
|
function AnnouncementBar(): JSX.Element | null {
|
||||||
const {
|
const {isClosed, close} = useAnnouncementBar();
|
||||||
isAnnouncementBarClosed,
|
|
||||||
closeAnnouncementBar,
|
|
||||||
} = useUserPreferencesContext();
|
|
||||||
const {announcementBar} = useThemeConfig();
|
const {announcementBar} = useThemeConfig();
|
||||||
|
|
||||||
if (!announcementBar) {
|
if (!announcementBar) {
|
||||||
|
@ -25,7 +21,8 @@ function AnnouncementBar(): JSX.Element | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {content, backgroundColor, textColor, isCloseable} = announcementBar;
|
const {content, backgroundColor, textColor, isCloseable} = announcementBar;
|
||||||
if (!content || (isCloseable && isAnnouncementBarClosed)) {
|
|
||||||
|
if (!content || (isCloseable && isClosed)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +43,7 @@ function AnnouncementBar(): JSX.Element | null {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={clsx(styles.announcementBarClose, 'clean-btn')}
|
className={clsx(styles.announcementBarClose, 'clean-btn')}
|
||||||
onClick={closeAnnouncementBar}
|
onClick={close}
|
||||||
aria-label={translate({
|
aria-label={translate({
|
||||||
id: 'theme.AnnouncementBar.closeButtonAriaLabel',
|
id: 'theme.AnnouncementBar.closeButtonAriaLabel',
|
||||||
message: 'Close',
|
message: 'Close',
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
border-bottom: 1px solid var(--ifm-color-emphasis-100);
|
border-bottom: 1px solid var(--ifm-color-emphasis-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.announcementBar {
|
.announcementBar {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -11,8 +11,8 @@ import {
|
||||||
useThemeConfig,
|
useThemeConfig,
|
||||||
isSamePath,
|
isSamePath,
|
||||||
usePrevious,
|
usePrevious,
|
||||||
|
useAnnouncementBar,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
|
|
||||||
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
|
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
|
||||||
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
|
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
|
||||||
import useScrollPosition from '@theme/hooks/useScrollPosition';
|
import useScrollPosition from '@theme/hooks/useScrollPosition';
|
||||||
|
@ -198,12 +198,10 @@ function DocSidebarItemLink({
|
||||||
}
|
}
|
||||||
|
|
||||||
function useShowAnnouncementBar() {
|
function useShowAnnouncementBar() {
|
||||||
const {isAnnouncementBarClosed} = useUserPreferencesContext();
|
const {isClosed} = useAnnouncementBar();
|
||||||
const [showAnnouncementBar, setShowAnnouncementBar] = useState(
|
const [showAnnouncementBar, setShowAnnouncementBar] = useState(!isClosed);
|
||||||
!isAnnouncementBarClosed,
|
|
||||||
);
|
|
||||||
useScrollPosition(({scrollY}) => {
|
useScrollPosition(({scrollY}) => {
|
||||||
if (!isAnnouncementBarClosed) {
|
if (!isClosed) {
|
||||||
setShowAnnouncementBar(scrollY === 0);
|
setShowAnnouncementBar(scrollY === 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -314,7 +312,7 @@ function DocSidebar({
|
||||||
navbar: {hideOnScroll},
|
navbar: {hideOnScroll},
|
||||||
hideableSidebar,
|
hideableSidebar,
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
const {isAnnouncementBarClosed} = useUserPreferencesContext();
|
const {isClosed: isAnnouncementBarClosed} = useAnnouncementBar();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
showResponsiveSidebar,
|
showResponsiveSidebar,
|
||||||
|
|
|
@ -8,17 +8,22 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ThemeProvider from '@theme/ThemeProvider';
|
import ThemeProvider from '@theme/ThemeProvider';
|
||||||
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
|
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
|
||||||
import {DocsPreferredVersionContextProvider} from '@docusaurus/theme-common';
|
import {
|
||||||
|
AnnouncementBarProvider,
|
||||||
|
DocsPreferredVersionContextProvider,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
import type {Props} from '@theme/LayoutProviders';
|
import type {Props} from '@theme/LayoutProviders';
|
||||||
|
|
||||||
export default function LayoutProviders({children}: Props): JSX.Element {
|
export default function LayoutProviders({children}: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<UserPreferencesProvider>
|
<AnnouncementBarProvider>
|
||||||
<DocsPreferredVersionContextProvider>
|
<UserPreferencesProvider>
|
||||||
{children}
|
<DocsPreferredVersionContextProvider>
|
||||||
</DocsPreferredVersionContextProvider>
|
{children}
|
||||||
</UserPreferencesProvider>
|
</DocsPreferredVersionContextProvider>
|
||||||
|
</UserPreferencesProvider>
|
||||||
|
</AnnouncementBarProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import useTabGroupChoice from '@theme/hooks/useTabGroupChoice';
|
import useTabGroupChoice from '@theme/hooks/useTabGroupChoice';
|
||||||
import useAnnouncementBar from '@theme/hooks/useAnnouncementBar';
|
|
||||||
import UserPreferencesContext from '@theme/UserPreferencesContext';
|
import UserPreferencesContext from '@theme/UserPreferencesContext';
|
||||||
import type {Props} from '@theme/UserPreferencesProvider';
|
import type {Props} from '@theme/UserPreferencesProvider';
|
||||||
|
|
||||||
function UserPreferencesProvider(props: Props): JSX.Element {
|
function UserPreferencesProvider(props: Props): JSX.Element {
|
||||||
const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoice();
|
const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoice();
|
||||||
const {isAnnouncementBarClosed, closeAnnouncementBar} = useAnnouncementBar();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserPreferencesContext.Provider
|
<UserPreferencesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
tabGroupChoices,
|
tabGroupChoices,
|
||||||
setTabGroupChoices,
|
setTabGroupChoices,
|
||||||
isAnnouncementBarClosed,
|
|
||||||
closeAnnouncementBar,
|
|
||||||
}}>
|
}}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</UserPreferencesContext.Provider>
|
</UserPreferencesContext.Provider>
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {useState, useEffect, useCallback} from 'react';
|
|
||||||
import {useThemeConfig, createStorageSlot} from '@docusaurus/theme-common';
|
|
||||||
import type {useAnnouncementBarReturns} from '@theme/hooks/useAnnouncementBar';
|
|
||||||
|
|
||||||
const DismissStorage = createStorageSlot('docusaurus.announcement.dismiss');
|
|
||||||
const IdStorage = createStorageSlot('docusaurus.announcement.id');
|
|
||||||
|
|
||||||
const useAnnouncementBar = (): useAnnouncementBarReturns => {
|
|
||||||
const {announcementBar} = useThemeConfig();
|
|
||||||
|
|
||||||
const [isClosed, setClosed] = useState(true);
|
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
|
||||||
DismissStorage.set('true');
|
|
||||||
setClosed(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!announcementBar) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const {id} = announcementBar;
|
|
||||||
|
|
||||||
let viewedId = IdStorage.get();
|
|
||||||
|
|
||||||
// retrocompatibility due to spelling mistake of default id
|
|
||||||
// see https://github.com/facebook/docusaurus/issues/3338
|
|
||||||
if (viewedId === 'annoucement-bar') {
|
|
||||||
viewedId = 'announcement-bar';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isNewAnnouncement = id !== viewedId;
|
|
||||||
|
|
||||||
IdStorage.set(id);
|
|
||||||
|
|
||||||
if (isNewAnnouncement) {
|
|
||||||
DismissStorage.set('false');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNewAnnouncement || DismissStorage.get() === 'false') {
|
|
||||||
setClosed(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
isAnnouncementBarClosed: isClosed,
|
|
||||||
closeAnnouncementBar: handleClose,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useAnnouncementBar;
|
|
12
packages/docusaurus-theme-classic/src/types.d.ts
vendored
12
packages/docusaurus-theme-classic/src/types.d.ts
vendored
|
@ -117,16 +117,6 @@ declare module '@theme/Heading' {
|
||||||
export const MainHeading: (props: Props) => JSX.Element;
|
export const MainHeading: (props: Props) => JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/hooks/useAnnouncementBar' {
|
|
||||||
export type useAnnouncementBarReturns = {
|
|
||||||
readonly isAnnouncementBarClosed: boolean;
|
|
||||||
readonly closeAnnouncementBar: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useAnnouncementBar: () => useAnnouncementBarReturns;
|
|
||||||
export default useAnnouncementBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useHideableNavbar' {
|
declare module '@theme/hooks/useHideableNavbar' {
|
||||||
export type useHideableNavbarReturns = {
|
export type useHideableNavbarReturns = {
|
||||||
readonly navbarRef: (node: HTMLElement | null) => void;
|
readonly navbarRef: (node: HTMLElement | null) => void;
|
||||||
|
@ -214,8 +204,6 @@ declare module '@theme/hooks/useUserPreferencesContext' {
|
||||||
export type UserPreferencesContextProps = {
|
export type UserPreferencesContextProps = {
|
||||||
tabGroupChoices: {readonly [groupId: string]: string};
|
tabGroupChoices: {readonly [groupId: string]: string};
|
||||||
setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
||||||
isAnnouncementBarClosed: boolean;
|
|
||||||
closeAnnouncementBar: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function useUserPreferencesContext(): UserPreferencesContextProps;
|
export default function useUserPreferencesContext(): UserPreferencesContextProps;
|
||||||
|
|
|
@ -45,3 +45,8 @@ export {
|
||||||
export {DocsPreferredVersionContextProvider} from './utils/docsPreferredVersion/DocsPreferredVersionProvider';
|
export {DocsPreferredVersionContextProvider} from './utils/docsPreferredVersion/DocsPreferredVersionProvider';
|
||||||
|
|
||||||
export {ThemeClassNames} from './utils/ThemeClassNames';
|
export {ThemeClassNames} from './utils/ThemeClassNames';
|
||||||
|
|
||||||
|
export {
|
||||||
|
AnnouncementBarProvider,
|
||||||
|
useAnnouncementBar,
|
||||||
|
} from './utils/announcementBarUtils';
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
ReactNode,
|
||||||
|
useContext,
|
||||||
|
createContext,
|
||||||
|
} from 'react';
|
||||||
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
|
import {createStorageSlot} from './storageUtils';
|
||||||
|
import {useThemeConfig} from './useThemeConfig';
|
||||||
|
|
||||||
|
export const AnnouncementBarDismissStorageKey =
|
||||||
|
'docusaurus.announcement.dismiss';
|
||||||
|
const AnnouncementBarIdStorageKey = 'docusaurus.announcement.id';
|
||||||
|
|
||||||
|
const AnnouncementBarDismissStorage = createStorageSlot(
|
||||||
|
AnnouncementBarDismissStorageKey,
|
||||||
|
);
|
||||||
|
const IdStorage = createStorageSlot(AnnouncementBarIdStorageKey);
|
||||||
|
|
||||||
|
const isDismissedInStorage = () =>
|
||||||
|
AnnouncementBarDismissStorage.get() === 'true';
|
||||||
|
const setDismissedInStorage = (bool: boolean) =>
|
||||||
|
AnnouncementBarDismissStorage.set(String(bool));
|
||||||
|
|
||||||
|
type AnnouncementBarAPI = {
|
||||||
|
readonly isClosed: boolean;
|
||||||
|
readonly close: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
|
||||||
|
const {announcementBar} = useThemeConfig();
|
||||||
|
const {isClient} = useDocusaurusContext();
|
||||||
|
|
||||||
|
const [isClosed, setClosed] = useState(() => {
|
||||||
|
return isClient
|
||||||
|
? // On client navigation: init with localstorage value
|
||||||
|
isDismissedInStorage()
|
||||||
|
: // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
|
||||||
|
false;
|
||||||
|
});
|
||||||
|
// Update state after hydration
|
||||||
|
useEffect(() => {
|
||||||
|
setClosed(isDismissedInStorage());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setDismissedInStorage(true);
|
||||||
|
setClosed(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!announcementBar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {id} = announcementBar;
|
||||||
|
|
||||||
|
let viewedId = IdStorage.get();
|
||||||
|
|
||||||
|
// retrocompatibility due to spelling mistake of default id
|
||||||
|
// see https://github.com/facebook/docusaurus/issues/3338
|
||||||
|
if (viewedId === 'annoucement-bar') {
|
||||||
|
viewedId = 'announcement-bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNewAnnouncement = id !== viewedId;
|
||||||
|
|
||||||
|
IdStorage.set(id);
|
||||||
|
|
||||||
|
if (isNewAnnouncement) {
|
||||||
|
setDismissedInStorage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNewAnnouncement || !isDismissedInStorage()) {
|
||||||
|
setClosed(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
isClosed,
|
||||||
|
close: handleClose,
|
||||||
|
};
|
||||||
|
}, [isClosed]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnnouncementBarContext = createContext<AnnouncementBarAPI | null>(null);
|
||||||
|
|
||||||
|
export const AnnouncementBarProvider = ({children}: {children: ReactNode}) => {
|
||||||
|
const value = useAnnouncementBarContextValue();
|
||||||
|
return (
|
||||||
|
<AnnouncementBarContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</AnnouncementBarContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAnnouncementBar = (): AnnouncementBarAPI => {
|
||||||
|
const api = useContext(AnnouncementBarContext);
|
||||||
|
if (!api) {
|
||||||
|
throw new Error(
|
||||||
|
'useAnnouncementBar(): AnnouncementBar not found in React context: make sure to use the AnnouncementBarProvider on top of the tree',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return api;
|
||||||
|
};
|
|
@ -305,17 +305,10 @@ const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
|
||||||
respectPrefersColorScheme: true,
|
respectPrefersColorScheme: true,
|
||||||
},
|
},
|
||||||
announcementBar: {
|
announcementBar: {
|
||||||
id: 'v1-new-domain',
|
id: 'announcementBar-1', // Increment on change
|
||||||
content:
|
content:
|
||||||
'➡️ Docusaurus v1 documentation has moved to <a target="_blank" rel="noopener noreferrer" href="https://v1.docusaurus.io/">v1.docusaurus.io</a>! 🔄',
|
'⭐️ If you like Docusaurus, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebook/docusaurus">GitHub</a>! ⭐',
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
announcementBar: {
|
|
||||||
id: 'supportus',
|
|
||||||
content:
|
|
||||||
'⭐️ If you like Docusaurus, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebook/docusaurus">GitHub</a>! ⭐️',
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
prism: {
|
prism: {
|
||||||
theme: require('prism-react-renderer/themes/github'),
|
theme: require('prism-react-renderer/themes/github'),
|
||||||
darkTheme: require('prism-react-renderer/themes/dracula'),
|
darkTheme: require('prism-react-renderer/themes/dracula'),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue