From 8f29aa0ac2ac6c72ca8e8d646d87abcf12baab88 Mon Sep 17 00:00:00 2001 From: tobinio Date: Fri, 10 May 2024 20:28:02 +0200 Subject: [PATCH 1/6] basic code modals --- docs/guide/markdown.md | 23 ++++++++++ src/client/app/composables/codeModal.ts | 37 ++++++++++++++++ src/client/app/index.ts | 3 ++ .../styles/components/vp-code.css | 43 +++++++++++++++++++ .../styles/components/vp-doc.css | 20 ++++++--- src/node/markdown/markdown.ts | 13 ++++++ src/node/markdown/plugins/codeModal.ts | 36 ++++++++++++++++ src/node/markdown/plugins/highlight.ts | 2 + src/node/markdown/plugins/preWrapper.ts | 1 + 9 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 src/client/app/composables/codeModal.ts create mode 100644 src/node/markdown/plugins/codeModal.ts diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md index d5b68de68c80..618b8e1f629d 100644 --- a/docs/guide/markdown.md +++ b/docs/guide/markdown.md @@ -597,6 +597,29 @@ const line3 = 'This is line 3' const line4 = 'This is line 4' ``` +## Code Modal + +[//]: # (todo - expand on docs ) + +````md:modal +```ts {1} +// line-numbers is disabled by default +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers {1} +// line-numbers is enabled +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers=2 {1} +// line-numbers is enabled and start from 2 +const line3 = 'This is line 3' +const line4 = 'This is line 4' +``` +```` ## Import Code Snippets You can import code snippets from existing files via following syntax: diff --git a/src/client/app/composables/codeModal.ts b/src/client/app/composables/codeModal.ts new file mode 100644 index 000000000000..489a3b590cc4 --- /dev/null +++ b/src/client/app/composables/codeModal.ts @@ -0,0 +1,37 @@ +import { inBrowser } from 'vitepress' + +export function useCodeModal() { + if (inBrowser) { + window.addEventListener('click', (e) => { + const el = e.target as HTMLElement + + if (el.matches('div[class*="language-"] > button.modal')) { + const parent = el.parentElement + const sibling = el.nextElementSibling + if (!parent || !sibling) { + return + } + + sibling.classList.add('open') + } + + if (el.matches('div[class*="language-"] > div.modal-container')) { + el.classList.remove('open') + } + }) + + window.addEventListener('keydown', (ev) => { + if (ev.key == 'Escape') { + let modal = window.document.querySelector( + 'div[class*="language-"] > div.modal-container.open' + ) + + if (!modal) { + return + } + + modal.classList.remove('open') + } + }) + } +} diff --git a/src/client/app/index.ts b/src/client/app/index.ts index 72cc5063802f..b5501b001d98 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -17,6 +17,7 @@ import { usePrefetch } from './composables/preFetch' import { dataSymbol, initData, siteDataRef, useData } from './data' import { RouterSymbol, createRouter, scrollTo, type Router } from './router' import { inBrowser, pathToFile } from './utils' +import { useCodeModal } from './composables/codeModal' function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme { if (theme.extends) { @@ -57,6 +58,8 @@ const VitePressApp = defineComponent({ useCopyCode() // setup global code groups handler useCodeGroups() + // setup global code modal handler + useCodeModal() if (Theme.setup) Theme.setup() return () => h(Theme.Layout!) diff --git a/src/client/theme-default/styles/components/vp-code.css b/src/client/theme-default/styles/components/vp-code.css index 1ff9429b4ac1..381eba511d5a 100644 --- a/src/client/theme-default/styles/components/vp-code.css +++ b/src/client/theme-default/styles/components/vp-code.css @@ -5,3 +5,46 @@ html:not(.dark) .vp-code span { color: var(--shiki-light, inherit); } + +.vp-code ~ .modal-container:not(.open) { + display: none; +} + +.vp-code ~ .modal-container { + position: fixed; + + z-index: 100; + + top: 0; + left: 0; + width: 100vw; + height: 100vh; + + display: flex; + justify-content: center; + align-items: center; + + background-color: rgba(255, 255, 255, 0.02); + backdrop-filter: blur(2px); +} + +html:not(.dark) .vp-code ~ .modal-container { + background-color: rgba(0, 0, 0, 0.1); +} + +.vp-code ~ .modal-container [class*='language-'] { + position: relative; + margin: 20px; + + max-width: 90%; + width: min-content; + + border-radius: 8px; + + background-color: var(--vp-code-block-bg); + box-shadow: var(--vp-shadow-2); +} + +.vp-code ~ .modal-container [class*='language-']:hover span.lang { + opacity: 0; +} diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index 90afe60e590a..6e64d972a23c 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -429,7 +429,8 @@ color 0.5s; } -.vp-doc [class*='language-'] > button.copy { +.vp-doc [class*='language-'] > button.copy, +.vp-doc [class*='language-'] > button.modal { /*rtl:ignore*/ direction: ltr; position: absolute; @@ -454,13 +455,20 @@ opacity 0.25s; } +.vp-doc [class*='language-'] > button.modal { + top: 64px; +} + .vp-doc [class*='language-']:hover > button.copy, -.vp-doc [class*='language-'] > button.copy:focus { +.vp-doc [class*='language-'] > button.copy:focus, +.vp-doc [class*='language-']:hover > button.modal, +.vp-doc [class*='language-'] > button.modal:focus { opacity: 1; } .vp-doc [class*='language-'] > button.copy:hover, -.vp-doc [class*='language-'] > button.copy.copied { +.vp-doc [class*='language-'] > button.copy.copied, +.vp-doc [class*='language-'] > button.modal:hover { border-color: var(--vp-code-copy-code-hover-border-color); background-color: var(--vp-code-copy-code-hover-bg); } @@ -498,7 +506,7 @@ content: var(--vp-code-copy-copied-text-content); } -.vp-doc [class*='language-'] > span.lang { +.vp-doc [class*='language-'] span.lang { position: absolute; top: 2px; /*rtl:ignore*/ @@ -512,8 +520,8 @@ opacity 0.4s; } -.vp-doc [class*='language-']:hover > button.copy + span.lang, -.vp-doc [class*='language-'] > button.copy:focus + span.lang { +.vp-doc [class*='language-']:hover button.copy + span.lang, +.vp-doc [class*='language-'] button.copy:focus + span.lang { opacity: 0; } diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index bc1c38984000..e5c3c81c7760 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -37,6 +37,7 @@ import { linkPlugin } from './plugins/link' import { preWrapperPlugin } from './plugins/preWrapper' import { restoreEntities } from './plugins/restoreEntities' import { snippetPlugin } from './plugins/snippet' +import { codeModalPlugin } from './plugins/codeModal' export type { Header } from '../shared' @@ -116,6 +117,16 @@ export interface MarkdownOptions extends Options { * @default 'Copy Code' */ codeCopyButtonTitle?: string + /** + * Show an additional button to open a fullscreen modal in code blocks + * @default false + */ + codeModal?: boolean + /** + * The tooltip text for the modal button in code blocks + * @default 'Open Modal' + */ + codeModalButtonTitle?: string /* ==================== Markdown It Plugins ==================== */ @@ -201,6 +212,7 @@ export const createMarkdownRenderer = async ( ): Promise => { const theme = options.theme ?? { light: 'github-light', dark: 'github-dark' } const codeCopyButtonTitle = options.codeCopyButtonTitle || 'Copy Code' + const codeModalButtonTitle = options.codeModalButtonTitle || 'Open Modal' const hasSingleTheme = typeof theme === 'string' || 'name' in theme const md = MarkdownIt({ @@ -230,6 +242,7 @@ export const createMarkdownRenderer = async ( base ) .use(lineNumberPlugin, options.lineNumbers) + .use(codeModalPlugin, options.codeModal, { codeModalButtonTitle }) if (options.gfmAlerts !== false) { md.use(gitHubAlertsPlugin) diff --git a/src/node/markdown/plugins/codeModal.ts b/src/node/markdown/plugins/codeModal.ts new file mode 100644 index 000000000000..111351f7a6c2 --- /dev/null +++ b/src/node/markdown/plugins/codeModal.ts @@ -0,0 +1,36 @@ +// markdown-it plugin for generating line numbers. +// It depends on preWrapper plugin. + +import type MarkdownIt from 'markdown-it' +import type { MarkdownOptions } from '../markdown' + +export const codeModalPlugin = ( + md: MarkdownIt, + enable = false, + options: MarkdownOptions = {} +) => { + const fence = md.renderer.rules.fence! + md.renderer.rules.fence = (...args) => { + const rawCode = fence(...args) + + const [tokens, idx] = args + const info = tokens[idx].info + + if ( + (!enable && !/:modal($| |=)/.test(info)) || + (enable && /:no-modal($| )/.test(info)) + ) { + return rawCode + } + + const code = + `` + + '' + + let end = rawCode.lastIndexOf('') + + return rawCode.substring(0, end) + code + '' + } +} diff --git a/src/node/markdown/plugins/highlight.ts b/src/node/markdown/plugins/highlight.ts index 4bfac6333d43..bab767d2b984 100644 --- a/src/node/markdown/plugins/highlight.ts +++ b/src/node/markdown/plugins/highlight.ts @@ -94,6 +94,7 @@ export async function highlight( const vueRE = /-vue$/ const lineNoStartRE = /=(\d*)/ const lineNoRE = /:(no-)?line-numbers(=\d*)?$/ + const modalNoRE = /:(no-)?modal(=\d*)?$/ const mustacheRE = /\{\{.*?\}\}/g return (str: string, lang: string, attrs: string) => { @@ -102,6 +103,7 @@ export async function highlight( lang .replace(lineNoStartRE, '') .replace(lineNoRE, '') + .replace(modalNoRE, '') .replace(vueRE, '') .toLowerCase() || defaultLang diff --git a/src/node/markdown/plugins/preWrapper.ts b/src/node/markdown/plugins/preWrapper.ts index 906cac2afd1e..3d77bcc588d1 100644 --- a/src/node/markdown/plugins/preWrapper.ts +++ b/src/node/markdown/plugins/preWrapper.ts @@ -47,6 +47,7 @@ function extractLang(info: string) { .trim() .replace(/=(\d*)/, '') .replace(/:(no-)?line-numbers({| |$|=\d*).*/, '') + .replace(/:(no-)?modal({| |$|=\d*).*/, '') .replace(/(-vue|{| ).*$/, '') .replace(/^vue-html$/, 'template') .replace(/^ansi$/, '') From 2f982095f85a2222a7ea437a54c5cf209baa0e41 Mon Sep 17 00:00:00 2001 From: tobinio Date: Sat, 11 May 2024 12:52:48 +0200 Subject: [PATCH 2/6] fix weird hover behavior --- src/client/app/composables/codeModal.ts | 3 +++ .../theme-default/styles/components/vp-doc.css | 15 +++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/client/app/composables/codeModal.ts b/src/client/app/composables/codeModal.ts index 489a3b590cc4..8e28b41ff2e6 100644 --- a/src/client/app/composables/codeModal.ts +++ b/src/client/app/composables/codeModal.ts @@ -6,6 +6,9 @@ export function useCodeModal() { const el = e.target as HTMLElement if (el.matches('div[class*="language-"] > button.modal')) { + //remove focus from button + el.blur() + const parent = el.parentElement const sibling = el.nextElementSibling if (!parent || !sibling) { diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index 6e64d972a23c..5a49931bd460 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -459,9 +459,13 @@ top: 64px; } -.vp-doc [class*='language-']:hover > button.copy, +.vp-doc + [class*='language-']:hover:not(:has(.modal-container:hover)) + > button.copy, .vp-doc [class*='language-'] > button.copy:focus, -.vp-doc [class*='language-']:hover > button.modal, +.vp-doc + [class*='language-']:hover:not(:has(.modal-container:hover)) + > button.modal, .vp-doc [class*='language-'] > button.modal:focus { opacity: 1; } @@ -520,8 +524,11 @@ opacity 0.4s; } -.vp-doc [class*='language-']:hover button.copy + span.lang, -.vp-doc [class*='language-'] button.copy:focus + span.lang { +.vp-doc + [class*='language-']:hover:not(:has(.modal-container:hover)) + > button.copy + + span.lang, +.vp-doc [class*='language-'] > button.copy:focus + span.lang { opacity: 0; } From 9626176d7d33f401cbb654ebf3a6b408d68097dd Mon Sep 17 00:00:00 2001 From: tobinio Date: Sat, 11 May 2024 13:26:02 +0200 Subject: [PATCH 3/6] add docs --- docs/guide/markdown.md | 52 ++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md index 618b8e1f629d..818da42cfdb3 100644 --- a/docs/guide/markdown.md +++ b/docs/guide/markdown.md @@ -599,27 +599,49 @@ const line4 = 'This is line 4' ## Code Modal -[//]: # (todo - expand on docs ) +You can enable codeModals for each code blocks via config: -````md:modal -```ts {1} -// line-numbers is disabled by default -const line2 = 'This is line 2' -const line3 = 'This is line 3' +```js +export default { + markdown: { + codeModal: true + } +} ``` -```ts:line-numbers {1} -// line-numbers is enabled -const line2 = 'This is line 2' -const line3 = 'This is line 3' -``` +Please see [`markdown` options](../reference/site-config#markdown) for more details. -```ts:line-numbers=2 {1} -// line-numbers is enabled and start from 2 -const line3 = 'This is line 3' -const line4 = 'This is line 4' +You can add `:modal` / `:no-modal` mark in your fenced code blocks to override the value set in config. + + +**Input** + +````md:modal +```js:modal +export default { + data () { + return { + msg: 'Code with very long lines can often be hard to read in code blocks. Code modals can make seeing the whole content possible.', + lorem: 'ipsum', + } + } +} ``` ```` + +**Output** + +```js:modal +export default { + data () { + return { + msg: 'Code with very long lines can often be hard to read in code blocks. Code modals can make seeing the whole content possible.', + lorem: 'ipsum', + } + } +} +``` + ## Import Code Snippets You can import code snippets from existing files via following syntax: From 15a21f1417c4843f719e59372f842e9b2873f168 Mon Sep 17 00:00:00 2001 From: tobinio Date: Sat, 11 May 2024 13:38:46 +0200 Subject: [PATCH 4/6] add expand icon --- src/client/theme-default/styles/components/vp-doc.css | 1 + src/client/theme-default/styles/icons.css | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index 5a49931bd460..dfa44207bdc6 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -457,6 +457,7 @@ .vp-doc [class*='language-'] > button.modal { top: 64px; + background-image: var(--vp-icon-expand); } .vp-doc diff --git a/src/client/theme-default/styles/icons.css b/src/client/theme-default/styles/icons.css index b5612d1f8192..467be529ab5e 100644 --- a/src/client/theme-default/styles/icons.css +++ b/src/client/theme-default/styles/icons.css @@ -87,6 +87,8 @@ --vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E"); /* clipboard-copy */ --vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E"); + + --vp-icon-expand: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m21 21-6-6m6 6v-4.8m0 4.8h-4.8'/%3E%3Cpath d='M3 16.2V21m0 0h4.8M3 21l6-6'/%3E%3Cpath d='M21 7.8V3m0 0h-4.8M21 3l-6 6'/%3E%3Cpath d='M3 7.8V3m0 0h4.8M3 3l6 6'/%3E%3C/svg%3E"); } /* social icons - used under CC0 1.0 from https://simpleicons.org/ */ From 7b0ff3e847c40542448ad45dbdfa6fba51ee649e Mon Sep 17 00:00:00 2001 From: tobinio Date: Sat, 11 May 2024 13:56:13 +0200 Subject: [PATCH 5/6] add close button to modal --- src/client/app/composables/codeModal.ts | 11 +++++++++++ .../theme-default/styles/components/vp-doc.css | 17 ++++++++++++++--- src/client/theme-default/styles/icons.css | 2 ++ src/node/markdown/plugins/codeModal.ts | 15 ++++++++++----- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/client/app/composables/codeModal.ts b/src/client/app/composables/codeModal.ts index 8e28b41ff2e6..9d6b88f25afb 100644 --- a/src/client/app/composables/codeModal.ts +++ b/src/client/app/composables/codeModal.ts @@ -18,6 +18,17 @@ export function useCodeModal() { sibling.classList.add('open') } + if ( + el.matches('div[class*="language-"] div.modal-container button.close') + ) { + const parent = el.parentElement?.parentElement + if (!parent) { + return + } + + parent.classList.remove('open') + } + if (el.matches('div[class*="language-"] > div.modal-container')) { el.classList.remove('open') } diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index dfa44207bdc6..22d44f1d0c36 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -430,7 +430,8 @@ } .vp-doc [class*='language-'] > button.copy, -.vp-doc [class*='language-'] > button.modal { +.vp-doc [class*='language-'] > button.modal, +.vp-doc [class*='language-'] > button.close { /*rtl:ignore*/ direction: ltr; position: absolute; @@ -460,6 +461,11 @@ background-image: var(--vp-icon-expand); } +.vp-doc [class*='language-'] > button.close { + top: 64px; + background-image: var(--vp-icon-close); +} + .vp-doc [class*='language-']:hover:not(:has(.modal-container:hover)) > button.copy, @@ -467,13 +473,18 @@ .vp-doc [class*='language-']:hover:not(:has(.modal-container:hover)) > button.modal, -.vp-doc [class*='language-'] > button.modal:focus { +.vp-doc [class*='language-'] > button.modal:focus, +.vp-doc + [class*='language-']:hover:not(:has(.modal-container:hover)) + > button.close, +.vp-doc [class*='language-'] > button.close:focus { opacity: 1; } .vp-doc [class*='language-'] > button.copy:hover, .vp-doc [class*='language-'] > button.copy.copied, -.vp-doc [class*='language-'] > button.modal:hover { +.vp-doc [class*='language-'] > button.modal:hover, +.vp-doc [class*='language-'] > button.close:hover { border-color: var(--vp-code-copy-code-hover-border-color); background-color: var(--vp-code-copy-code-hover-bg); } diff --git a/src/client/theme-default/styles/icons.css b/src/client/theme-default/styles/icons.css index 467be529ab5e..a1de8cfef932 100644 --- a/src/client/theme-default/styles/icons.css +++ b/src/client/theme-default/styles/icons.css @@ -89,6 +89,8 @@ --vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E"); --vp-icon-expand: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m21 21-6-6m6 6v-4.8m0 4.8h-4.8'/%3E%3Cpath d='M3 16.2V21m0 0h4.8M3 21l6-6'/%3E%3Cpath d='M21 7.8V3m0 0h-4.8M21 3l-6 6'/%3E%3Cpath d='M3 7.8V3m0 0h4.8M3 3l6 6'/%3E%3C/svg%3E"); + + --vp-icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M8 3v3a2 2 0 0 1-2 2H3'/%3E%3Cpath d='M21 8h-3a2 2 0 0 1-2-2V3'/%3E%3Cpath d='M3 16h3a2 2 0 0 1 2 2v3'/%3E%3Cpath d='M16 21v-3a2 2 0 0 1 2-2h3'/%3E%3C/svg%3E"); } /* social icons - used under CC0 1.0 from https://simpleicons.org/ */ diff --git a/src/node/markdown/plugins/codeModal.ts b/src/node/markdown/plugins/codeModal.ts index 111351f7a6c2..134ad4e0c240 100644 --- a/src/node/markdown/plugins/codeModal.ts +++ b/src/node/markdown/plugins/codeModal.ts @@ -23,14 +23,19 @@ export const codeModalPlugin = ( return rawCode } - const code = + let end = rawCode.lastIndexOf('') + + let innerCode = + rawCode.substring(0, end) + + `` + + '' + + const modal = `` + '' - let end = rawCode.lastIndexOf('') - - return rawCode.substring(0, end) + code + '' + return rawCode.substring(0, end) + modal + '' } } From 6ac6604102479329f918407251ea6dea8a1e8a63 Mon Sep 17 00:00:00 2001 From: tobinio Date: Sat, 11 May 2024 14:03:41 +0200 Subject: [PATCH 6/6] fix interaction with focused-lines --- src/client/theme-default/styles/components/vp-doc.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index 22d44f1d0c36..a10d09ecd661 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -379,7 +379,10 @@ opacity 0.35s; } -.vp-doc [class*='language-']:hover .has-focused-lines .line:not(.has-focus) { +.vp-doc + [class*='language-']:hover:not(:has(.modal-container:hover)) + .has-focused-lines + .line:not(.has-focus) { filter: blur(0); opacity: 1; }