feat: support dark/light color themes (#682)

Co-authored-by: Kia Ishii <kia.king.08@gmail.com>
pull/686/head
Anthony Fu 3 years ago committed by GitHub
parent 4fd2fad1fa
commit 41247fcfa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -102,7 +102,7 @@ Below shows the the full option you may define within this object.
interface MarkdownOptions extends MarkdownIt.Options { interface MarkdownOptions extends MarkdownIt.Options {
// Syntax highlight theme for Shiki. // Syntax highlight theme for Shiki.
// See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes // See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes
theme?: Shiki.Theme theme?: Shiki.Theme | { light: Shiki.Theme, dark: Shiki.Theme }
// Enable line numbers in code block. // Enable line numbers in code block.
lineNumbers?: boolean lineNumbers?: boolean

@ -26,8 +26,8 @@ Directives also work:
**Input** **Input**
```md ```html
<span v-for="i in 3">{{ i }} </span> <span v-for="i in 3">{{ i }}</span>
``` ```
**Output** **Output**
@ -40,7 +40,7 @@ You can use the [`useData` helper](./api#usedata) in a `<script>` block and expo
**Input** **Input**
```md ```html
<script setup> <script setup>
import { useData } from 'vitepress' import { useData } from 'vitepress'

@ -3,6 +3,7 @@ import './styles/vars.css'
import './styles/base.css' import './styles/base.css'
import './styles/utils.css' import './styles/utils.css'
import './styles/components/custom-block.css' import './styles/components/custom-block.css'
import './styles/components/vp-code.css'
import './styles/components/vp-doc.css' import './styles/components/vp-doc.css'
import './styles/components/vp-sponsor.css' import './styles/components/vp-sponsor.css'

@ -0,0 +1,7 @@
.dark .vp-code-light {
display: none;
}
html:not(.dark) .vp-code-dark {
display: none;
}

@ -376,7 +376,7 @@
background-color: var(--vp-code-block-bg); background-color: var(--vp-code-block-bg);
opacity: 0; opacity: 0;
cursor: pointer; cursor: pointer;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.38)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); background-image: var(--vp-icon-copy);
background-position: 50%; background-position: 50%;
background-size: 20px; background-size: 20px;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -395,7 +395,7 @@
.vp-doc [class*='language-'] > span.copy:hover.copied { .vp-doc [class*='language-'] > span.copy:hover.copied {
border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0;
background-color: var(--vp-code-copy-code-hover-bg); background-color: var(--vp-code-copy-code-hover-bg);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(235,235,235,0.5)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); background-image: var(--vp-icon-copied);
} }
.vp-doc [class*='language-'] > span.copy.copied::before, .vp-doc [class*='language-'] > span.copy.copied::before,
@ -410,7 +410,7 @@
text-align: center; text-align: center;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: var(--vp-c-text-dark-2); color: var(--vp-code-copy-code-active-text);
background-color: var(--vp-code-copy-code-hover-bg); background-color: var(--vp-code-copy-code-hover-bg);
white-space: nowrap; white-space: nowrap;
content: "Copied"; content: "Copied";

@ -175,6 +175,15 @@
--vp-z-index-footer: 50; --vp-z-index-footer: 50;
} }
/**
* Icons
* -------------------------------------------------------------------------- */
:root {
--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E");
--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' class='h-6 w-6' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E");
}
/** /**
* Layouts * Layouts
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
@ -195,16 +204,14 @@
--vp-code-block-bg: #292d3e; --vp-code-block-bg: #292d3e;
--vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5);
--vp-code-line-number-color: var(--vp-c-text-dark-3); --vp-code-line-number-color: var(--vp-c-text-dark-3);
--vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05);
--vp-code-copy-code-active-text: var(--vp-c-text-dark-2);
} }
.dark { .dark {
--vp-code-block-bg: var(--vp-c-bg-alt); --vp-code-block-bg: var(--vp-c-bg-alt);
--vp-code-line-number-color: var(--vp-c-text-dark-3);
} }
/** /**

@ -19,6 +19,8 @@ import attrs from 'markdown-it-attrs'
import emoji from 'markdown-it-emoji' import emoji from 'markdown-it-emoji'
import toc from 'markdown-it-toc-done-right' import toc from 'markdown-it-toc-done-right'
export type ThemeOptions = Theme | { light: Theme; dark: Theme }
export interface MarkdownOptions extends MarkdownIt.Options { export interface MarkdownOptions extends MarkdownIt.Options {
lineNumbers?: boolean lineNumbers?: boolean
config?: (md: MarkdownIt) => void config?: (md: MarkdownIt) => void
@ -31,7 +33,7 @@ export interface MarkdownOptions extends MarkdownIt.Options {
allowedAttributes?: string[] allowedAttributes?: string[]
disable?: boolean disable?: boolean
} }
theme?: Theme theme?: ThemeOptions
// https://github.com/nagaozen/markdown-it-toc-done-right // https://github.com/nagaozen/markdown-it-toc-done-right
toc?: any toc?: any
externalLinks?: Record<string, string> externalLinks?: Record<string, string>

@ -1,14 +1,28 @@
import escapeHtml from 'escape-html'
import { getHighlighter } from 'shiki' import { getHighlighter } from 'shiki'
import type { ThemeOptions } from '../markdown'
export const highlight = async (theme = 'material-palenight') => { export async function highlight(theme: ThemeOptions = 'material-palenight') {
const highlighter = await getHighlighter({ theme }) const themes = typeof theme === 'string' ? [theme] : [theme.dark, theme.light]
const highlighter = await getHighlighter({ themes })
const preRE = /^<pre.*?>/
return (str: string, lang: string) => { return (str: string, lang: string) => {
if (!lang || lang === 'text') { lang = lang || 'text'
return `<pre v-pre><code>${escapeHtml(str)}</code></pre>`
if (typeof theme === 'string') {
return highlighter
.codeToHtml(str, { lang, theme })
.replace(preRE, '<pre v-pre>')
} }
return highlighter.codeToHtml(str, lang).replace(/^<pre.*?>/, '<pre v-pre>') const dark = highlighter
.codeToHtml(str, { lang, theme: theme.dark })
.replace(preRE, '<pre v-pre class="vp-code-dark">')
const light = highlighter
.codeToHtml(str, { lang, theme: theme.light })
.replace(preRE, '<pre v-pre class="vp-code-light">')
return dark + light
} }
} }

Loading…
Cancel
Save