From 0f8acc37dcf28cc1aebc7681880ad0afe77d02e7 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Mon, 22 Jan 2024 00:33:47 +0800 Subject: [PATCH] feat: update `demo-wrapper` container --- docs/2.preview/主题效果预览.md | 11 +++- theme/src/client/styles/md-enhance.scss | 79 ++++++++++++++++++++++++- theme/src/node/container.ts | 45 +++++++++++++- 3 files changed, 128 insertions(+), 7 deletions(-) diff --git a/docs/2.preview/主题效果预览.md b/docs/2.preview/主题效果预览.md index bf7cd47e..d505d8c7 100644 --- a/docs/2.preview/主题效果预览.md +++ b/docs/2.preview/主题效果预览.md @@ -106,17 +106,22 @@ H~2~O **demo wrapper** -::: demo-wrapper + +::: demo-wrapper title="示例" no-padding height="200px"
-
main
-
aside
+
main
+
aside
::: diff --git a/theme/src/client/styles/md-enhance.scss b/theme/src/client/styles/md-enhance.scss index 497cc085..6474cf2e 100644 --- a/theme/src/client/styles/md-enhance.scss +++ b/theme/src/client/styles/md-enhance.scss @@ -419,22 +419,53 @@ /* --------------------- demo-wrapper ------------------------ */ .plume-content .demo-wrapper { + display: flex; + flex-direction: column; min-height: 40px; margin: 40px -16px; border: solid 1px var(--vp-c-divider); border-radius: 8px; box-shadow: var(--vp-shadow-2); + &.has-title .demo-head { + border-bottom-color: transparent; + } + + &.only-img { + overflow: hidden; + } + + &.only-img img { + display: block; + } + + &.only-img .demo-container, + &.no-padding .demo-container { + padding: 0; + } + + &.has-height .demo-container { + height: var(--demo-container-height); + overflow-y: auto; + } + .demo-head { + display: flex; + align-items: center; + justify-content: flex-start; + min-height: 0; + border-bottom: solid 1px var(--vp-c-divider); + } + + .demo-ctrl { display: flex; gap: 5px; align-items: center; justify-content: flex-start; padding: 5px 0 5px 8px; - border-bottom: solid 1px var(--vp-c-divider); } - .demo-head i { + .demo-ctrl i { display: inline-block; width: 10px; height: 10px; @@ -454,8 +485,52 @@ } } + .demo-title { + position: relative; + min-width: 0; + padding: 0 16px; + margin: 0 20px -1px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-2); + background-color: var(--vp-c-bg-alt); + border-top-left-radius: 8px; + border-top-right-radius: 8px; + } + + .demo-title p { + max-width: 100%; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + text-wrap: nowrap; + } + + .demo-title::after, + .demo-title::before { + position: absolute; + bottom: 0; + z-index: 1; + width: 8px; + height: 8px; + content: " "; + } + + .demo-title::before { + left: 100%; + background: radial-gradient(16px at right top, transparent 50%, var(--vp-c-bg-alt) 50%); + } + + .demo-title::after { + right: 100%; + background: radial-gradient(16px at left top, transparent 50%, var(--vp-c-bg-alt) 50%); + } + .demo-container { + min-height: 0; padding: 20px; + font-size: 14px; + line-height: 22px; background-color: var(--vp-c-bg-alt); border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; diff --git a/theme/src/node/container.ts b/theme/src/node/container.ts index 5231ce12..109be69d 100644 --- a/theme/src/node/container.ts +++ b/theme/src/node/container.ts @@ -2,13 +2,54 @@ import containerPlugin from '@vuepress/plugin-container' import type { Plugin } from '@vuepress/core' export const customContainers: Plugin[] = [ + /** + * :::demo-wrapper img no-padding title="xxx" height="100px" + * ::: + */ containerPlugin({ type: 'demo-wrapper', - before() { - return `
\n` + before(info) { + const title = resolveAttr(info, 'title') + const wrapperClasses: string[] = ['demo-wrapper'] + let containerStyle = '' + if (title) + wrapperClasses.push('has-title') + + if (info.includes('img')) + wrapperClasses.push('only-img') + + if (info.includes('no-padding')) + wrapperClasses.push('no-padding') + + const height = resolveAttr(info, 'height') + if (height) { + const h = Number.parseFloat(height) === Number(height) ? `${height}px` : height + containerStyle += `--demo-container-height: ${h};` + wrapperClasses.push('has-height') + } + + return `
+
+
+ ${title ? `

${title}

` : ''} +
+
\n` }, after() { return '
\n' }, }), ] + +/** + * Resolve the specified attribute from token info + */ +function resolveAttr(info: string, attr: string): string | null { + // try to match specified attr mark + const pattern = `\\b${attr}\\s*=\\s*(?['"])(?.+?)\\k(\\s|$)` + const regex = new RegExp(pattern, 'i') + const match = info.match(regex) + + // return content if matched, null if not specified + return match?.groups?.content ?? null +}