mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-01 10:22:30 +02:00
feat(v2): add ThemedImage component (#3730)
* feat(v2): add ThemedImage component * add themed image problematic example * refactor, SSR fix, openness about extending img tag, docs update * refactor themed-image * update themed image doc Co-authored-by: slorber <lorber.sebastien@gmail.com> Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
This commit is contained in:
parent
73f151d04c
commit
9d90e896f0
9 changed files with 229 additions and 4 deletions
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* 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 from 'react';
|
||||
import type {ThemeContextProps} from '@theme/hooks/useThemeContext';
|
||||
|
||||
const ThemeContext = React.createContext<ThemeContextProps | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
export default ThemeContext;
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* 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 from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
import type {Props} from '@theme/ThemedImage';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const ThemedImage = (props: Props): JSX.Element => {
|
||||
const {isClient} = useDocusaurusContext();
|
||||
const {isDarkTheme} = useThemeContext();
|
||||
const {sources, className, alt = '', ...propsRest} = props;
|
||||
|
||||
type SourceName = keyof Props['sources'];
|
||||
|
||||
const renderedSourceNames: SourceName[] = isClient
|
||||
? isDarkTheme
|
||||
? ['dark']
|
||||
: ['light']
|
||||
: // We need to render both images on the server to avoid flash
|
||||
// See https://github.com/facebook/docusaurus/pull/3730
|
||||
['light', 'dark'];
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderedSourceNames.map((sourceName) => {
|
||||
return (
|
||||
<img
|
||||
key={sourceName}
|
||||
src={sources[sourceName]}
|
||||
alt={alt}
|
||||
className={clsx(
|
||||
styles.themedImage,
|
||||
styles[`themedImage--${sourceName}`],
|
||||
className,
|
||||
)}
|
||||
{...propsRest}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemedImage;
|
|
@ -0,0 +1,11 @@
|
|||
.themedImage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .themedImage--light {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .themedImage--dark {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* 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 {useContext} from 'react';
|
||||
|
||||
import ThemeContext from '@theme/ThemeContext';
|
||||
import type {ThemeContextProps} from '@theme/hooks/useThemeContext';
|
||||
|
||||
// TODO: Un-stub the theme context (#3730)
|
||||
function useThemeContext(): ThemeContextProps {
|
||||
const context = useContext<ThemeContextProps | undefined>(ThemeContext);
|
||||
return context == null ? {isDarkTheme: false} : context;
|
||||
}
|
||||
|
||||
export default useThemeContext;
|
|
@ -78,7 +78,7 @@ declare module '@theme/DocSidebar' {
|
|||
}
|
||||
|
||||
declare module '@theme/Tabs' {
|
||||
import type {ReactElement, ReactNode} from 'react';
|
||||
import type {ReactElement} from 'react';
|
||||
|
||||
export type Props = {
|
||||
readonly block?: boolean;
|
||||
|
@ -88,10 +88,24 @@ declare module '@theme/Tabs' {
|
|||
readonly groupId?: string;
|
||||
};
|
||||
|
||||
const Tabs: () => JSX.Element;
|
||||
const Tabs: (props: Props) => JSX.Element;
|
||||
export default Tabs;
|
||||
}
|
||||
|
||||
declare module '@theme/ThemedImage' {
|
||||
import type {ComponentProps} from 'react';
|
||||
|
||||
export type Props = {
|
||||
readonly sources: {
|
||||
readonly light: string;
|
||||
readonly dark: string;
|
||||
};
|
||||
} & Omit<ComponentProps<'img'>, 'src'>;
|
||||
|
||||
const ThemedImage: (props: Props) => JSX.Element;
|
||||
export default ThemedImage;
|
||||
}
|
||||
|
||||
declare module '@theme/Footer' {
|
||||
const Footer: () => JSX.Element | null;
|
||||
export default Footer;
|
||||
|
@ -125,6 +139,14 @@ declare module '@theme/hooks/useLogo' {
|
|||
export default useLogo;
|
||||
}
|
||||
|
||||
declare module '@theme/hooks/useThemeContext' {
|
||||
export type ThemeContextProps = {
|
||||
isDarkTheme: boolean;
|
||||
};
|
||||
|
||||
export default function useThemeContext(): ThemeContextProps;
|
||||
}
|
||||
|
||||
declare module '@theme/Layout' {
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* 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 from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
import type {Props} from '@theme/ThemedImage';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const ThemedImage = (props: Props): JSX.Element => {
|
||||
const {isClient} = useDocusaurusContext();
|
||||
const {isDarkTheme} = useThemeContext();
|
||||
const {sources, className, alt = '', ...propsRest} = props;
|
||||
|
||||
type SourceName = keyof Props['sources'];
|
||||
|
||||
const renderedSourceNames: SourceName[] = isClient
|
||||
? isDarkTheme
|
||||
? ['dark']
|
||||
: ['light']
|
||||
: // We need to render both images on the server to avoid flash
|
||||
// See https://github.com/facebook/docusaurus/pull/3730
|
||||
['light', 'dark'];
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderedSourceNames.map((sourceName) => {
|
||||
return (
|
||||
<img
|
||||
key={sourceName}
|
||||
src={sources[sourceName]}
|
||||
alt={alt}
|
||||
className={clsx(
|
||||
styles.themedImage,
|
||||
styles[`themedImage--${sourceName}`],
|
||||
className,
|
||||
)}
|
||||
{...propsRest}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemedImage;
|
|
@ -0,0 +1,11 @@
|
|||
.themedImage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .themedImage--light {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .themedImage--dark {
|
||||
display: block;
|
||||
}
|
18
packages/docusaurus-theme-classic/src/types.d.ts
vendored
18
packages/docusaurus-theme-classic/src/types.d.ts
vendored
|
@ -381,7 +381,7 @@ declare module '@theme/TabItem' {
|
|||
readonly className: string;
|
||||
};
|
||||
|
||||
const TabItem: () => JSX.Element;
|
||||
const TabItem: (props: Props) => JSX.Element;
|
||||
export default TabItem;
|
||||
}
|
||||
|
||||
|
@ -399,10 +399,24 @@ declare module '@theme/Tabs' {
|
|||
readonly className?: string;
|
||||
};
|
||||
|
||||
const Tabs: () => JSX.Element;
|
||||
const Tabs: (props: Props) => JSX.Element;
|
||||
export default Tabs;
|
||||
}
|
||||
|
||||
declare module '@theme/ThemedImage' {
|
||||
import type {ComponentProps} from 'react';
|
||||
|
||||
export type Props = {
|
||||
readonly sources: {
|
||||
readonly light: string;
|
||||
readonly dark: string;
|
||||
};
|
||||
} & Omit<ComponentProps<'img'>, 'src'>;
|
||||
|
||||
const ThemedImage: (props: Props) => JSX.Element;
|
||||
export default ThemedImage;
|
||||
}
|
||||
|
||||
declare module '@theme/ThemeProvider' {
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
|
|
|
@ -1086,3 +1086,30 @@ html[data-theme='dark'] .themedDocusaurus [fill='#FFFF50'] {
|
|||
```
|
||||
|
||||
<DocusaurusSvg className="themedDocusaurus" />
|
||||
|
||||
### Themed Images
|
||||
|
||||
Docusaurus supports themed images: the `ThemedImage` component (included in the classic/bootstrap themes) allows you to switch the image source based on the current theme.
|
||||
|
||||
```jsx {5-8}
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: useBaseUrl('img/docusaurus_light.svg'),
|
||||
dark: useBaseUrl('img/docusaurus_dark.svg'),
|
||||
}}
|
||||
/>;
|
||||
```
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: useBaseUrl('img/docusaurus_keytar.svg'),
|
||||
dark: useBaseUrl('img/docusaurus_speed.svg'),
|
||||
}}
|
||||
/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue