diff --git a/docs/.vuepress/theme.ts b/docs/.vuepress/theme.ts
index 9aed9138..7ce369de 100644
--- a/docs/.vuepress/theme.ts
+++ b/docs/.vuepress/theme.ts
@@ -73,6 +73,7 @@ export const theme: Theme = themePlume({
youtube: true,
icons: true,
codepen: true,
+ replit: true,
},
comment: {
provider: 'Giscus',
diff --git a/docs/README.md b/docs/README.md
index 47a20544..60737bc4 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -77,8 +77,11 @@ config:
title: 加密
description: 支持全站加密、部分加密(加密目录、加密文章)。
-
- title: 代码复制
- description: 一键复制代码块中的内容
+ title: 代码
+ description: 代码复制,CodePen演示,Replit演示
+ -
+ title: 资源嵌入
+ description: 图表,视频,PDF
-
type: text-image
title: 博客
diff --git a/docs/notes/theme/guide/markdown/进阶.md b/docs/notes/theme/guide/markdown/进阶.md
index 4ff9981d..29c2f016 100644
--- a/docs/notes/theme/guide/markdown/进阶.md
+++ b/docs/notes/theme/guide/markdown/进阶.md
@@ -476,6 +476,63 @@ export default defineUserConfig({
@[codepen editable tab="html,result"](leimapapa/RwOZQOW)
+## Replit
+
+主题支持在 Markdown 文件中嵌入 [Replit](https://replit.com/)。
+
+### 配置
+
+此功能默认不启用,你可以在配置文件中启用它。
+
+::: code-tabs
+@tab .vuepress/config.ts
+
+```ts
+export default defineUserConfig({
+ theme: plumeTheme({
+ plugins: {
+ markdownPower: {
+ replit: true, // [!code highlight]
+ },
+ }
+ })
+})
+```
+
+:::
+
+### 语法
+
+简单的语法
+
+```md
+@[replit](user/repl-name)
+```
+
+更多选项
+
+```md
+@[replit title="" width="100%" height="450px" theme="dark"](user/repl-name#filepath)
+```
+
+- `title`: 标题
+- `width`: 容器宽度
+- `height`: 容器高度
+- `theme`: 主题, 可选值 `dark` 和 `light`
+- `user`: Replit 用户名
+- `repl-name`: Replit repl 名称
+- `filepath`: Replit 默认打开的文件路径
+
+输入:
+
+```md
+@[replit](@TechPandaPro/Cursor-Hangout#package.json)
+````
+
+输出:
+
+@[replit](@TechPandaPro/Cursor-Hangout#package.json)
+
## 导入文件
主题支持在 Markdown 文件中导入文件切片。
diff --git a/docs/notes/theme/guide/介绍.md b/docs/notes/theme/guide/介绍.md
index b9d3f751..d1b89e2f 100644
--- a/docs/notes/theme/guide/介绍.md
+++ b/docs/notes/theme/guide/介绍.md
@@ -42,3 +42,6 @@ VuePress 是一个 [静态站点生成器](https://en.wikipedia.org/wiki/Static_
- 👀 支持 搜索、文章评论
- 👨💻 支持 浅色/深色 主题 (包括代码高亮)
- 📠 markdown 增强,支持 代码块分组、提示容器、任务列表、数学公式、代码演示 等
+- 📚 代码演示,支持 CodePen, Replit
+- 📊 嵌入图标,支持 chart.js,Echarts,Mermaid,flowchart
+- 🎛 资源嵌入,支持 PDF, bilibili视频,youtube视频等
diff --git a/plugins/plugin-md-power/src/client/components/Youtube.vue b/plugins/plugin-md-power/src/client/components/Youtube.vue
index ffb33b4e..04e2e8df 100644
--- a/plugins/plugin-md-power/src/client/components/Youtube.vue
+++ b/plugins/plugin-md-power/src/client/components/Youtube.vue
@@ -15,10 +15,6 @@ const IFRAME_ALLOW = 'accelerometer; autoplay; clipboard-write; encrypted-media;
const options = toRefs(props)
const { el, width, height, resize } = useSize(options)
-
-function onLoad() {
- resize()
-}
@@ -30,7 +26,7 @@ function onLoad() {
:title="title || 'Youtube'"
:style="{ width, height }"
:allow="IFRAME_ALLOW"
- @load="onLoad"
+ @load="resize"
/>
diff --git a/plugins/plugin-md-power/src/client/config.ts b/plugins/plugin-md-power/src/client/config.ts
index a29aeef0..7ab308c6 100644
--- a/plugins/plugin-md-power/src/client/config.ts
+++ b/plugins/plugin-md-power/src/client/config.ts
@@ -5,6 +5,7 @@ import { setupCanIUse } from './composables/setupCanIUse.js'
import PDFViewer from './components/PDFViewer.vue'
import Bilibili from './components/Bilibili.vue'
import Youtube from './components/Youtube.vue'
+import Replit from './components/Replit.vue'
import '@internal/md-power/icons.css'
@@ -21,6 +22,9 @@ export default defineClientConfig({
if (pluginOptions.youtube)
app.component('VideoYoutube', Youtube)
+ if (pluginOptions.replit)
+ app.component('ReplitViewer', Replit)
+
if (__VUEPRESS_SSR__)
return
diff --git a/plugins/plugin-md-power/src/node/plugin.ts b/plugins/plugin-md-power/src/node/plugin.ts
index 517cb23c..3604e7d5 100644
--- a/plugins/plugin-md-power/src/node/plugin.ts
+++ b/plugins/plugin-md-power/src/node/plugin.ts
@@ -7,6 +7,7 @@ import { createIconCSSWriter, iconsPlugin } from './features/icons/index.js'
import { bilibiliPlugin } from './features/video/bilibili.js'
import { youtubePlugin } from './features/video/youtube.js'
import { codepenPlugin } from './features/codepen.js'
+import { replitPlugin } from './features/replit.js'
const __dirname = getDirname(import.meta.url)
@@ -58,6 +59,11 @@ export function markdownPowerPlugin(options: MarkdownPowerPluginOptions = {}): P
// @[codepen](user/slash)
md.use(codepenPlugin)
}
+
+ if (options.replit) {
+ // @[replit](user/repl-name)
+ md.use(replitPlugin)
+ }
},
}
}
diff --git a/plugins/plugin-md-power/src/shared/plugin.ts b/plugins/plugin-md-power/src/shared/plugin.ts
index 17f8565d..31575788 100644
--- a/plugins/plugin-md-power/src/shared/plugin.ts
+++ b/plugins/plugin-md-power/src/shared/plugin.ts
@@ -3,16 +3,18 @@ import type { PDFOptions } from './pdf.js'
import type { IconsOptions } from './icons.js'
export interface MarkdownPowerPluginOptions {
-
pdf?: boolean | PDFOptions
+
+ // new syntax
icons?: boolean | IconsOptions
- // video
+ // video embed
bilibili?: boolean
youtube?: boolean
- // code
+ // code embed
codepen?: boolean
+ replit?: boolean
caniuse?: boolean | CanIUseOptions
}
diff --git a/theme/src/client/composables/darkMode.ts b/theme/src/client/composables/darkMode.ts
index c0a7e153..fd3e37f9 100644
--- a/theme/src/client/composables/darkMode.ts
+++ b/theme/src/client/composables/darkMode.ts
@@ -1,5 +1,5 @@
-import { inject, onMounted, provide, ref } from 'vue'
-import type { InjectionKey, Ref } from 'vue'
+import { inject, onMounted, ref } from 'vue'
+import type { App, InjectionKey, Ref } from 'vue'
export type DarkModeRef = Ref
@@ -22,10 +22,18 @@ export function useDarkMode(): DarkModeRef {
* Create dark mode ref and provide as global computed in setup
*/
export function setupDarkMode(): void {
- const isDark = ref(false)
+ const isDark = useDarkMode()
onMounted(() => {
if (document.documentElement.classList.contains('dark'))
isDark.value = true
})
- provide(darkModeSymbol, isDark)
+}
+
+export function injectDarkMode(app: App): void {
+ const isDark = ref(false)
+ app.provide(darkModeSymbol, isDark)
+
+ Object.defineProperty(app.config.globalProperties, '$isDark', {
+ get: () => isDark,
+ })
}
diff --git a/theme/src/client/config.ts b/theme/src/client/config.ts
index b2cf7e55..a14301ea 100644
--- a/theme/src/client/config.ts
+++ b/theme/src/client/config.ts
@@ -5,13 +5,15 @@ import type { ClientConfig } from 'vuepress/client'
import { h } from 'vue'
import Badge from './components/global/Badge.vue'
import ExternalLinkIcon from './components/global/ExternalLinkIcon.vue'
-import { setupDarkMode, useScrollPromise } from './composables/index.js'
+import { injectDarkMode, setupDarkMode, useScrollPromise } from './composables/index.js'
import Layout from './layouts/Layout.vue'
import NotFound from './layouts/NotFound.vue'
import HomeBox from './components/Home/HomeBox.vue'
export default defineClientConfig({
enhance({ app, router }) {
+ injectDarkMode(app)
+
// global component
app.component('Badge', Badge)