Skip to content

Commit

Permalink
feat(v2): add ThemedImage component (#3730)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Sébastien Lorber <[email protected]>
  • Loading branch information
3 people authored Nov 13, 2020
1 parent 73f151d commit 9d90e89
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 4 deletions.
15 changes: 15 additions & 0 deletions packages/docusaurus-theme-bootstrap/src/theme/ThemeContext.ts
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.themedImage {
display: none;
}

html[data-theme='light'] .themedImage--light {
display: block;
}

html[data-theme='dark'] .themedImage--dark {
display: block;
}
Original file line number Diff line number Diff line change
@@ -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;
26 changes: 24 additions & 2 deletions packages/docusaurus-theme-bootstrap/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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';

Expand Down
53 changes: 53 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/ThemedImage/index.tsx
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.themedImage {
display: none;
}

html[data-theme='light'] .themedImage--light {
display: block;
}

html[data-theme='dark'] .themedImage--dark {
display: block;
}
18 changes: 16 additions & 2 deletions packages/docusaurus-theme-classic/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ declare module '@theme/TabItem' {
readonly className: string;
};

const TabItem: () => JSX.Element;
const TabItem: (props: Props) => JSX.Element;
export default TabItem;
}

Expand All @@ -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';

Expand Down
27 changes: 27 additions & 0 deletions website/docs/markdown-features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
}}
/>

0 comments on commit 9d90e89

Please sign in to comment.