-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(v2): add ThemedImage component #3730
Conversation
Deploy preview for docusaurus-2 ready! Built with commit 80309ca |
} | ||
} | ||
|
||
export default ThemedImage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This component will only render one image (the light one) on the other on server-rendered markup.
See useTheme
hook:
const getInitialTheme = () => {
if (!ExecutionEnvironment.canUseDOM) {
return themes.light; // SSR: we don't care
}
return coerceToTheme(document.documentElement.getAttribute('data-theme'));
};
On hydration, the light image will be replaced with the dark one, producing an unwanted flash.
The only viable solution to fix the problem is to always render the 2 images, and display one or the other thanks to CSS (which is loaded before the user actually see anything, so there's no flash)
img.themed-image{
display: none;
}
html[data-theme='light'] img.themed-image.themed-image--light {
display: block;
}
html[data-theme='dark'] img.themed-image.themed-image--dark {
display: block;
}
Note: it's worth considering that light/dark is common nowadays but the CSS spec says this might be expanded to more values in the future. Having an API surface that is more extensible could be more future-proof (ie user can declare its own theme name, we should rather have sources={dark: darkSrc,light:lightSrc,sepia: sepiaSrc}
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would produce an hydration flash.
Can you add an example somewhere so that we can see it in action in deploy previews? (there an example md page if you want)
You can find the example in the added section on the Markdown Features page. |
readonly darkSrc?: string; | ||
} & ComponentProps<'img'>; | ||
|
||
const ThemedImage: () => JSX.Element; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't you use the props here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const ThemedImage: (props: Props) => JSX.Element;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been taken from the Tabs
component types already in that file (https://github.com/facebook/docusaurus/blob/master/packages/docusaurus-theme-classic/src/types.d.ts#L395):
const Tabs: () => JSX.Element;
export default Tabs;
TS should be happy with that construction because this method only serves as the definition for the returned value.
Ah yeah, didn't see, but unfortunately Netlify is failing so can't check the preview
|
@slorber I saw the log, working on this right now. But it is annoying that during the development the app runs correctly and do not fail or warn user in any way, but on build is failing due to some ambiguous errors. Is there any way to improve this processes and make the results of both modes (dev & build/serve) consistent? |
Currently CI fail is related to the issue with V1 build (probably caused by mentioned above PR):
|
const {isDarkTheme} = useThemeContext(); | ||
const {src, darkSrc, lightSrc, alt = '', ...propsRest} = props; | ||
|
||
if (darkSrc && isDarkTheme) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not duplicate essentially the same code, let's use a ternary expression to determine the desired image src?
And why is there a prop just src
? In this case need use native <img>
element, not ThemedImage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not duplicate essentially the same code, let's use a ternary expression to determine the desired image src?
I choose the standard conditional structure for the redability.
And why is there a prop just
src
? In this case need use native<img>
element, notThemedImage
.
Because of TS types inheritance - & ComponentProps<'img'>;
- and props passing. It also serves as fallback, if user provide src
instead of lightSrc
to the themed image.
Most likely the reason for this is Netlify cache, because the tests in the PR with the update deps were successful. |
Hmm, interesting. Can you re-run the pipeline than? |
Maybe @slorber can do it, but I don't have access for that :( |
@lex111 I have pushed the ternary refactor commit but the CI still fails on the same V1 error. Are you sure it is only the Netlify cache issue? |
readonly darkSrc?: string; | ||
} & ComponentProps<'img'>; | ||
|
||
const ThemedImage: () => JSX.Element; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
despite other examples not declaring components props properly, I think we should do this (cf TabItem, Layout).
We'll make sure all comps have props: Props
over time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against this change, but this sound like a feature request or a bug fix request, so I think you should handle this for all theme components in the separate PR.
website/docs/markdown-features.mdx
Outdated
|
||
<ThemedImage | ||
alt="Docusaurus themed image" | ||
lightSrc={useBaseUrl('img/docusaurus_keytar.svg')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we just pass the path as regular string? Accordingly, inside the ThemedImage
component, apply useBaseUrl
to all src paths? Then users would not import useBaseUrl
in their MDX doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lex111 totally agree with that. BTW I imagined we could even have a Docusaurus image component just for this usecase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if processing the base URL inside the component is a good idea. It can blur the functionality and cause a confusion (why img
need useBaseURL when ThemeImage
do not need it)? The goal was to create simple helper not the robust, alternative image component.
And again, I have just looked at the way img
tag is used on the Docusuaurus V2 website - https://github.com/facebook/docusaurus/blob/master/website/src/pages/index.js#L77.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My long-term goal is to simply deprecate useBaseUrl(). But this can probably be done later, so if we don't apply it in the component today, it's fine
agree, you can remove the bootstrap theme from the netlify scripts and the netlify HTML page. We'll add it back when it's more production ready |
b383945
to
82475a3
Compare
It looks like the local rebase and force push of PR branch fixed the V1 CI issue. |
@Simek I added an example so that you understand why your js-based solution will not work in all cases:
Try refreshing this page, with dark mode, and caching enabled: https://deploy-preview-3730--docusaurus-2.netlify.app/classic/docs/markdown-features/ Here, the images added are cached aggressively. The image being served by the server will appear on the user screen before React has time to hydrate. You didn't see this issue because:
I think the server should always render both images, but only display one thanks to CSS. |
@slorber PR has been updated, mostly according to the review suggestions. Feel free to improve or change the docs section (I'm way better at improving the docs rather than creating the initial version). Please remember to remove the SSR example after the successful review, but before the merge. 🙂 |
Motivation
For some websites it is important to be able to switch the image source based on the current theme. This PR introduces the simple theme helper component -
ThemedImage
- which allow users to specify thelightSrc
anddarkSrc
props and switches the image content dynamically on theme change.The docs has also been updated within this PR.
Have you read the Contributing Guidelines on pull requests?
Yes
Test Plan
Changes has been tested locally using Docusuaurus V2 website.
Preview
Related PRs
None.