diff --git a/docs/.vuepress/theme.ts b/docs/.vuepress/theme.ts index f6365c864e..2c3e2b8f36 100644 --- a/docs/.vuepress/theme.ts +++ b/docs/.vuepress/theme.ts @@ -59,6 +59,9 @@ export default defaultTheme({ }, themePlugins: { + copyCode: { + inline: true, + }, git: { contributors: { avatar: true, diff --git a/docs/plugins/features/copy-code.md b/docs/plugins/features/copy-code.md index dd2b139102..2257d90938 100644 --- a/docs/plugins/features/copy-code.md +++ b/docs/plugins/features/copy-code.md @@ -56,13 +56,23 @@ export default { ### ignoreSelector -- Type: `string[]` +- Type: `string[] | string` - Details: Elements selector in code blocks, used to ignore related elements when copying. For example, `['.token.comment']` will ignore nodes with the class name `.token.comment` in code blocks (which in `prismjs` refers to ignoring comments). +### inlineSelector + +- Type: `string[] | string | boolean` +- Default: `false` + + Whether to copy inline code content when double click. + + - `boolean`: Whether to copy inline code content when double click. + - `string | string[]`: The selector of inline code. + ### transform - Type: `(preElement: HTMLPreElement) => void` diff --git a/docs/zh/plugins/features/copy-code.md b/docs/zh/plugins/features/copy-code.md index b3ce3d0549..bd7bfe06e0 100644 --- a/docs/zh/plugins/features/copy-code.md +++ b/docs/zh/plugins/features/copy-code.md @@ -56,13 +56,24 @@ export default { ### ignoreSelector -- 类型:`string[]` +- 类型:`string[] | string` - 详情: 代码块中的元素选择器,用于在复制时忽略相关元素。 例如: `['.token.comment']` 将忽略代码块中类名为 `.token.comment` 的节点 (这会在 `prismjs` 中忽略注释)。 +### inlineSelector + +- 类型:`string[] | string | boolean` +- 默认值:`false` +- 详情: + + 是否在双击时复制行内代码内容。 + + - `boolean`: 是否在双击时复制行内代码内容。 + - `string[] | string`: 选择器,表示需要复制的行内代码内容。 + ### transform - 类型:`(preElement: HTMLPreElement) => void` diff --git a/plugins/features/plugin-copy-code/rollup.config.ts b/plugins/features/plugin-copy-code/rollup.config.ts index 4a44353832..c168c8ced6 100644 --- a/plugins/features/plugin-copy-code/rollup.config.ts +++ b/plugins/features/plugin-copy-code/rollup.config.ts @@ -10,7 +10,7 @@ export default [ files: ['config', 'index'], }, { - dtsExternal: ['@vuepress/helper/shared'], + dtsExternal: ['@vuepress/helper/client', '@vuepress/helper/shared'], }, ), ] diff --git a/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts b/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts index 02647eedb3..22e817c58e 100644 --- a/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts +++ b/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts @@ -1,4 +1,4 @@ -import { useLocaleConfig } from '@vuepress/helper/client' +import { Message, useLocaleConfig } from '@vuepress/helper/client' import { useClipboard, useEventListener, @@ -9,19 +9,19 @@ import { computed } from 'vue' import { onContentUpdated } from 'vuepress/client' import type { CopyCodePluginLocaleConfig } from '../types.js' +import '@vuepress/helper/message.css' import '../styles/copy-code.css' import '../styles/vars.css' export interface UseCopyCodeOptions { locales: CopyCodePluginLocaleConfig - selector: string[] + selector: string + ignoreSelector?: string + inlineSelector?: string /** @default 2000 */ duration: number /** @default false */ showInMobile?: boolean - /** @default [] */ - ignoreSelector?: string[] - /** * Transform pre element before copy * @@ -44,14 +44,17 @@ export interface UseCopyCodeOptions { transform?: (preElement: HTMLElement) => void } +const CHECK_ICON = + '' const SHELL_RE = /language-(shellscript|shell|bash|sh|zsh)/ export const useCopyCode = ({ + selector, + ignoreSelector, + inlineSelector, duration = 2000, locales, - selector, showInMobile, - ignoreSelector = [], transform, }: UseCopyCodeOptions): void => { if (__VUEPRESS_SSR__) return @@ -83,9 +86,7 @@ export const useCopyCode = ({ document.body.classList.toggle('no-copy-code', !enabled.value) if (!enabled.value) return - document - .querySelectorAll(selector.join(',')) - .forEach(insertCopyButton) + document.querySelectorAll(selector).forEach(insertCopyButton) } watchImmediate(enabled, appendCopyButton, { @@ -98,6 +99,7 @@ export const useCopyCode = ({ const { copy } = useClipboard({ legacy: true }) const timeoutIdMap = new WeakMap>() + let message: Message | null = null const copyContent = async ( codeContainer: HTMLDivElement, @@ -106,8 +108,8 @@ export const useCopyCode = ({ ): Promise => { const clone = codeContent.cloneNode(true) as HTMLPreElement - if (ignoreSelector.length) { - clone.querySelectorAll(ignoreSelector.join(',')).forEach((node) => { + if (ignoreSelector) { + clone.querySelectorAll(ignoreSelector).forEach((node) => { node.remove() }) } @@ -148,4 +150,28 @@ export const useCopyCode = ({ void copyContent(codeContainer, preBlock, el as HTMLButtonElement) } }) + + if (inlineSelector) { + useEventListener('dblclick', (event) => { + const el = event.target as HTMLElement + + if (enabled.value && el.matches(inlineSelector)) { + const selection = window.getSelection() + + if ( + selection && + (el.contains(selection.anchorNode) || + el.contains(selection.focusNode)) + ) { + selection.removeAllRanges() + } + + void copy(el.textContent || '') + ;(message ??= new Message()).pop( + `${CHECK_ICON}${locale.value.copied} `, + duration, + ) + } + }) + } } diff --git a/plugins/features/plugin-copy-code/src/client/config.ts b/plugins/features/plugin-copy-code/src/client/config.ts index 5283213d78..d62f4fe9c7 100644 --- a/plugins/features/plugin-copy-code/src/client/config.ts +++ b/plugins/features/plugin-copy-code/src/client/config.ts @@ -4,8 +4,9 @@ import type { CopyCodePluginLocaleConfig } from './types.js' declare const __CC_DURATION__: number declare const __CC_LOCALES__: CopyCodePluginLocaleConfig -declare const __CC_SELECTOR__: string[] -declare const __CC_IGNORE_SELECTOR__: string[] +declare const __CC_SELECTOR__: string +declare const __CC_IGNORE_SELECTOR__: string +declare const __CC_INLINE_SELECTOR__: string declare const __CC_SHOW_IN_MOBILE__: boolean export default defineClientConfig({ @@ -13,6 +14,7 @@ export default defineClientConfig({ useCopyCode({ selector: __CC_SELECTOR__, ignoreSelector: __CC_IGNORE_SELECTOR__, + inlineSelector: __CC_INLINE_SELECTOR__, locales: __CC_LOCALES__, duration: __CC_DURATION__, showInMobile: __CC_SHOW_IN_MOBILE__, diff --git a/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts b/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts index 871232d9c7..4cec6a3bcc 100644 --- a/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts +++ b/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts @@ -21,19 +21,26 @@ export const copyCodePlugin = name: PLUGIN_NAME, define: () => ({ - __CC_DURATION__: options.duration ?? 2000, - __CC_IGNORE_SELECTOR__: options.ignoreSelector ?? [], + __CC_SELECTOR__: isArray(options.selector) + ? options.selector.join(',') + : (options.selector ?? '[vp-content] div[class*="language-"] pre'), + __CC_IGNORE_SELECTOR__: Array.isArray(options.ignoreSelector) + ? options.ignoreSelector.join(',') + : (options.ignoreSelector ?? ''), + __CC_INLINE_SELECTOR__: Array.isArray(options.inline) + ? options.inline.join(',') + : isString(options.inline) + ? options.inline + : options.inline + ? '[vp-content] :not(pre) > code' + : '', __CC_LOCALES__: getFullLocaleConfig({ app, name: PLUGIN_NAME, default: copyCodeLocaleInfo, config: options.locales, }), - __CC_SELECTOR__: isArray(options.selector) - ? options.selector - : isString(options.selector) - ? [options.selector] - : ['[vp-content] div[class*="language-"] pre'], + __CC_DURATION__: options.duration ?? 2000, __CC_SHOW_IN_MOBILE__: options.showInMobile ?? false, }), diff --git a/plugins/features/plugin-copy-code/src/node/options.ts b/plugins/features/plugin-copy-code/src/node/options.ts index ac6577d9f8..ea6301b4cd 100644 --- a/plugins/features/plugin-copy-code/src/node/options.ts +++ b/plugins/features/plugin-copy-code/src/node/options.ts @@ -40,7 +40,7 @@ export interface CopyCodePluginOptions { * * @default [] */ - ignoreSelector?: string[] + ignoreSelector?: string[] | string /** * Locale config @@ -48,4 +48,19 @@ export interface CopyCodePluginOptions { * 国际化配置 */ locales?: LocaleConfig + + /** + * Whether to copy inline code content when double click. + * + * - boolean: Whether to copy inline code content when double click. + * - string | string[]: The selector of inline code. + * + * 是否在双击时复制内联代码内容 + * + * - boolean: 是否在双击时复制内联代码内容 + * - string | string[]: 内联代码的选择器 + * + * @default '[vp-content] :not(pre) > code' + */ + inline?: string[] | boolean | string }