fix(renderer): apply dark mode properly to mermaid diagrams

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson
2026-07-14 22:57:35 +02:00
parent cad31957c3
commit be67b09a9e
2 changed files with 18 additions and 13 deletions
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer' import type { CodeProps } from '../../../components/markdown-renderer/replace-components/code-block-component-replacer'
import { useDarkModeState } from '../../../hooks/dark-mode/use-dark-mode-state'
import { cypressId } from '../../../utils/cypress-attribute' import { cypressId } from '../../../utils/cypress-attribute'
import { Logger } from '../../../utils/logger' import { Logger } from '../../../utils/logger'
import styles from './mermaid.module.scss' import styles from './mermaid.module.scss'
@@ -14,7 +15,7 @@ import { ApplicationErrorAlert } from '../../../components/common/application-er
const log = new Logger('MermaidChart') const log = new Logger('MermaidChart')
let mermaidInitialized = false let mermaidInitializedDarkMode: boolean | undefined
const loadMermaid = async (): Promise<(typeof import('mermaid'))['default']> => { const loadMermaid = async (): Promise<(typeof import('mermaid'))['default']> => {
try { try {
@@ -34,6 +35,7 @@ const loadMermaid = async (): Promise<(typeof import('mermaid'))['default']> =>
export const MermaidChart: React.FC<CodeProps> = ({ code }) => { export const MermaidChart: React.FC<CodeProps> = ({ code }) => {
const diagramContainer = useRef<HTMLDivElement>(null) const diagramContainer = useRef<HTMLDivElement>(null)
const { t } = useTranslation() const { t } = useTranslation()
const darkModeEnabled = useDarkModeState()
const { error } = useAsync(async () => { const { error } = useAsync(async () => {
if (!diagramContainer.current) { if (!diagramContainer.current) {
return return
@@ -41,9 +43,14 @@ export const MermaidChart: React.FC<CodeProps> = ({ code }) => {
const mermaid = await loadMermaid() const mermaid = await loadMermaid()
if (!mermaidInitialized) { if (mermaidInitializedDarkMode !== darkModeEnabled) {
mermaid.initialize({ startOnLoad: false, securityLevel: 'sandbox' }) mermaid.initialize({
mermaidInitialized = true startOnLoad: false,
securityLevel: 'antiscript',
theme: darkModeEnabled ? 'dark' : 'default',
darkMode: darkModeEnabled
})
mermaidInitializedDarkMode = darkModeEnabled
} }
try { try {
@@ -53,23 +60,21 @@ export const MermaidChart: React.FC<CodeProps> = ({ code }) => {
await mermaid.parse(code) await mermaid.parse(code)
delete diagramContainer.current.dataset.processed delete diagramContainer.current.dataset.processed
diagramContainer.current.textContent = code diagramContainer.current.textContent = code
await mermaid.init(undefined, diagramContainer.current) await mermaid.run({
nodes: [diagramContainer.current]
})
} catch (error) { } catch (error) {
const message = (error as Error).message const message = (error as Error).message
log.error(error) log.error(error)
diagramContainer.current?.querySelectorAll('iframe').forEach((child) => child.remove()) diagramContainer.current?.querySelectorAll('iframe').forEach((child) => child.remove())
throw new Error(message ?? t('renderer.mermaid.unknownError')) throw new Error(message ?? t('renderer.mermaid.unknownError'))
} }
}, [code, t]) }, [code, darkModeEnabled, t])
return ( return (
<Fragment> <Fragment>
{error !== undefined && <ApplicationErrorAlert className={'text-wrap'}>{error?.message}</ApplicationErrorAlert>} {error !== undefined && <ApplicationErrorAlert className={'text-wrap'}>{error?.message}</ApplicationErrorAlert>}
<div <div {...cypressId('mermaid-frame')} className={`text-center ${styles['mermaid']}`} ref={diagramContainer} />
{...cypressId('mermaid-frame')}
className={`text-center ${styles['mermaid']} bg-dark text-black`}
ref={diagramContainer}
/>
</Fragment> </Fragment>
) )
} }
@@ -1,9 +1,9 @@
/*! /*!
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2026 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
.mermaid > svg { .mermaid > svg {
background-color: #f8f9fa; background-color: transparent;
} }