diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 858976d7c..942538da0 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,5 +1,5 @@ import { defineConfig } from 'vitepress' -import { nav, sidebar } from './data' +import { markdownConfig, nav, sidebar } from './configs' export default defineConfig({ lang: 'en-US', @@ -37,10 +37,7 @@ gtag('config', 'G-29NKGSL23C');`, description: 'Explore and extend more macros and syntax sugar to Vue.', lastUpdated: true, cleanUrls: 'with-subfolders', - markdown: { - theme: 'material-palenight', - lineNumbers: true, - }, + markdown: markdownConfig, vue: { reactivityTransform: true, diff --git a/docs/.vitepress/configs/index.ts b/docs/.vitepress/configs/index.ts new file mode 100644 index 000000000..7806229f2 --- /dev/null +++ b/docs/.vitepress/configs/index.ts @@ -0,0 +1,2 @@ +export * from './navs' +export * from './markdown' diff --git a/docs/.vitepress/configs/markdown.ts b/docs/.vitepress/configs/markdown.ts new file mode 100644 index 000000000..4893942e1 --- /dev/null +++ b/docs/.vitepress/configs/markdown.ts @@ -0,0 +1,19 @@ +import { useCodeGroup, useCodeGroupItem } from '../theme/components/markdown' +import type { MarkdownOptions } from 'vitepress' + +/** + * vitepress markdown config + * @see https://vitepress.vuejs.org/config/app-configs.html#markdown + */ +export const markdownConfig: MarkdownOptions = { + lineNumbers: true, + theme: 'material-palenight', + config: (md) => { + md.use(useCodeGroup.container, useCodeGroup.type, { + render: useCodeGroup.render, + }) + md.use(useCodeGroupItem.container, useCodeGroupItem.type, { + render: useCodeGroupItem.render, + }) + }, +} diff --git a/docs/.vitepress/data.ts b/docs/.vitepress/configs/navs.ts similarity index 100% rename from docs/.vitepress/data.ts rename to docs/.vitepress/configs/navs.ts diff --git a/docs/.vitepress/theme/components/CodeGroup.ts b/docs/.vitepress/theme/components/CodeGroup.ts new file mode 100644 index 000000000..3d61ce7e5 --- /dev/null +++ b/docs/.vitepress/theme/components/CodeGroup.ts @@ -0,0 +1,79 @@ +import { defineComponent, h, ref } from 'vue' +import type { Component, ComponentOptions, VNode } from 'vue' + +export const CodeGroup: ComponentOptions = defineComponent({ + name: 'CodeGroup', + + setup(_, { slots }) { + // index of current active item + const activeIndex = ref(-1) + + return () => { + // NOTICE: here we put the `slots.default()` inside the render function to make + // the slots reactive, otherwise the slot content won't be changed once the + // `setup()` function of current component is called + + // get children code-group-item + const items = (slots.default?.() || []) + .filter((vnode) => (vnode.type as Component).name === 'CodeGroupItem') + .map((vnode) => { + if (vnode.props === null) vnode.props = {} + + return vnode as VNode & { props: Exclude } + }) + + // do not render anything if there is no code-group-item + if (items.length === 0) return null + + if (activeIndex.value < 0 || activeIndex.value > items.length - 1) { + // if `activeIndex` is invalid + + // find the index of the code-group-item with `active` props + activeIndex.value = items.findIndex( + (vnode) => vnode.props.active === '' || vnode.props.active === true + ) + + // if there is no `active` props on code-group-item, set the first item active + if (activeIndex.value === -1) activeIndex.value = 0 + } else { + // set the active item + items.forEach((vnode, i) => { + vnode.props.active = i === activeIndex.value + }) + } + + return h('div', { class: 'code-group' }, [ + h( + 'div', + { class: 'code-group__nav' }, + h( + 'ul', + { class: 'code-group__ul' }, + items.map((vnode, i) => { + const isActive = i === activeIndex.value + + return h( + 'li', + { class: 'code-group__li' }, + h( + 'button', + { + class: { + 'code-group__nav-tab': true, + 'code-group__nav-tab-active': isActive, + }, + ariaPressed: isActive, + ariaExpanded: isActive, + onClick: () => (activeIndex.value = i), + }, + vnode.props.title + ) + ) + }) + ) + ), + items, + ]) + } + }, +}) diff --git a/docs/.vitepress/theme/components/CodeGroup.vue b/docs/.vitepress/theme/components/CodeGroup.vue new file mode 100644 index 000000000..3714fa181 --- /dev/null +++ b/docs/.vitepress/theme/components/CodeGroup.vue @@ -0,0 +1,72 @@ + + + diff --git a/docs/.vitepress/theme/components/CodeGroupItem.vue b/docs/.vitepress/theme/components/CodeGroupItem.vue new file mode 100644 index 000000000..46c4f64ad --- /dev/null +++ b/docs/.vitepress/theme/components/CodeGroupItem.vue @@ -0,0 +1,21 @@ + + + diff --git a/docs/.vitepress/theme/components/markdown/index.ts b/docs/.vitepress/theme/components/markdown/index.ts new file mode 100644 index 000000000..5d03abd86 --- /dev/null +++ b/docs/.vitepress/theme/components/markdown/index.ts @@ -0,0 +1,13 @@ +import { useMarkdownContainer } from './plugins/container' + +export const useCodeGroup = useMarkdownContainer({ + type: 'code-group', + before: () => '\n', + after: () => '\n', +}) + +export const useCodeGroupItem = useMarkdownContainer({ + type: 'code-group-item', + before: (info: string) => `\n`, + after: () => '\n', +}) diff --git a/docs/.vitepress/theme/components/markdown/plugins/container.ts b/docs/.vitepress/theme/components/markdown/plugins/container.ts new file mode 100644 index 000000000..8dccce4a5 --- /dev/null +++ b/docs/.vitepress/theme/components/markdown/plugins/container.ts @@ -0,0 +1,59 @@ +import container from 'markdown-it-container' + +type RenderPlaceFunction = (info: string) => string + +interface ContainerPluginOptions { + /** + * The type of the container + * + * It would be used as the `name` of the container + * + * @see https://github.com/markdown-it/markdown-it-container#api + */ + type: string + + /** + * A function to render the starting tag of the container. + * + * This option will not take effect if you don't specify the `after` option. + */ + before: RenderPlaceFunction + + /** + * A function to render the ending tag of the container. + * + * This option will not take effect if you don't specify the `before` option. + */ + after: RenderPlaceFunction +} + +/** Powered by vuepress-next */ +export const useMarkdownContainer = ({ + type, + after, + before, +}: ContainerPluginOptions) => { + const infoStack: string[] = [] + const render = (tokens: any, index: number): string => { + const token = tokens[index] + if (token.nesting === 1) { + // resolve info (title) + const info = token.info.trim().slice(type.length).trim() + infoStack.push(info) + return before(info) + } else { + // `after` tag + + // pop the info from stack + const info = infoStack.pop() || '' + + // render + return after(info) + } + } + return { + container, + type, + render, + } +} diff --git a/docs/.vitepress/theme/components/markdown/plugins/markdown-it-container.d.ts b/docs/.vitepress/theme/components/markdown/plugins/markdown-it-container.d.ts new file mode 100644 index 000000000..84e449f76 --- /dev/null +++ b/docs/.vitepress/theme/components/markdown/plugins/markdown-it-container.d.ts @@ -0,0 +1,5 @@ +declare module 'markdown-it-container' { + import type { PluginWithParams } from 'markdown-it' + const container: PluginWithParams + export = container +} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 31ce2c409..f42060754 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,7 +1,10 @@ import { h } from 'vue' import Theme from 'vitepress/theme' -import 'uno.css' import HomePage from '../components/HomePage.vue' +import CodeGroup from './components/CodeGroup.vue' +import CodeGroupItemVue from './components/CodeGroupItem.vue' +import type { EnhanceAppContext } from 'vitepress' +import 'uno.css' import './style.css' export default { @@ -11,4 +14,8 @@ export default { 'home-features-after': () => h(HomePage), }) }, + enhanceApp({ app }: EnhanceAppContext) { + app.component('CodeGroup', CodeGroup) + app.component('CodeGroupItem', CodeGroupItemVue) + }, } diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 1b3a0b79e..22b13c7f0 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -4,16 +4,34 @@ ### Installation +:::: code-group + +::: code-group-item npm + ```bash npm i -D unplugin-vue-macros +``` -# or yarn +::: + +::: code-group-item yarn + +```bash yarn add -D unplugin-vue-macros +``` + +::: + +::: code-group-item pnpm -# or pnpm +```bash pnpm add -D unplugin-vue-macros ``` +::: + +:::: + #### Vite (first-class support) ```ts diff --git a/docs/package.json b/docs/package.json index be1399388..2aa0c8c9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -8,8 +8,11 @@ "serve": "vitepress serve" }, "devDependencies": { + "@vitejs/plugin-vue-jsx": "^2.0.1", + "markdown-it-container": "^3.0.0", "unocss": "^0.45.29", - "vitepress": "1.0.0-alpha.20", + "unplugin-vue-define-options": "npm:unplugin-vue-define-options", + "vitepress": "^1.0.0-alpha.20", "vue": "^3.2.40" } } diff --git a/docs/tsconfig.json b/docs/tsconfig.json index d5624d4a8..af0e921ea 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -13,7 +13,11 @@ "noUnusedLocals": true, "strictNullChecks": true, "forceConsistentCasingInFileNames": true, - "types": ["vite/client", "vitepress"], + "types": [ + "vite/client", + "vitepress", + "unplugin-vue-define-options/macros-global" + ], "paths": { "~/*": ["src/*"] } diff --git a/docs/unocss.config.ts b/docs/unocss.config.ts index aeb9a12c8..13520673e 100644 --- a/docs/unocss.config.ts +++ b/docs/unocss.config.ts @@ -1,5 +1,6 @@ -import { presetAttributify, presetUno } from 'unocss' +import { presetAttributify, presetUno, transformerDirectives } from 'unocss' export default { presets: [presetAttributify(), presetUno()], + transformers: [transformerDirectives()], } diff --git a/docs/vite.config.ts b/docs/vite.config.ts index f9ecb4010..6124ee847 100644 --- a/docs/vite.config.ts +++ b/docs/vite.config.ts @@ -1,6 +1,8 @@ import { defineConfig } from 'vite' import Unocss from 'unocss/vite' +import DefineOptions from 'unplugin-vue-define-options/vite' +import Jsx from '@vitejs/plugin-vue-jsx' export default defineConfig({ - plugins: [Unocss()], + plugins: [Unocss(), DefineOptions(), Jsx()], }) diff --git a/package.json b/package.json index 9a366b6f5..15a4ae125 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,8 @@ "pnpm": { "peerDependencyRules": { "ignoreMissing": [ + "vite", + "@algolia/client-search", "@yarnpkg/core" ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 637f5fd60..d4abeb2fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,11 +46,17 @@ importers: docs: specifiers: + '@vitejs/plugin-vue-jsx': ^2.0.1 + markdown-it-container: ^3.0.0 unocss: ^0.45.29 - vitepress: 1.0.0-alpha.20 + unplugin-vue-define-options: npm:unplugin-vue-define-options + vitepress: ^1.0.0-alpha.20 vue: ^3.2.40 devDependencies: + '@vitejs/plugin-vue-jsx': 2.0.1_vue@3.2.40 + markdown-it-container: 3.0.0 unocss: 0.45.29 + unplugin-vue-define-options: link:../packages/define-options vitepress: 1.0.0-alpha.20 vue: 3.2.40 @@ -521,7 +527,7 @@ packages: '@babel/helper-compilation-targets': 7.19.1_@babel+core@7.19.1 '@babel/helper-module-transforms': 7.19.0 '@babel/helpers': 7.19.0 - '@babel/parser': 7.19.1 + '@babel/parser': 7.19.3 '@babel/template': 7.18.10 '@babel/traverse': 7.19.1 '@babel/types': 7.19.3 @@ -690,6 +696,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.19.3 + dev: false /@babel/parser/7.19.3: resolution: {integrity: sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==} @@ -749,7 +756,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.19.1 + '@babel/parser': 7.19.3 '@babel/types': 7.19.3 /@babel/traverse/7.19.1: @@ -762,7 +769,7 @@ packages: '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.19.1 + '@babel/parser': 7.19.3 '@babel/types': 7.19.3 debug: 4.3.4 globals: 11.12.0 @@ -2746,6 +2753,22 @@ packages: transitivePeerDependencies: - supports-color + /@vitejs/plugin-vue-jsx/2.0.1_vue@3.2.40: + resolution: {integrity: sha512-lmiR1k9+lrF7LMczO0pxtQ8mOn6XeppJDHxnpxkJQpT5SiKz4SKhKdeNstXaTNuR8qZhUo5X0pJlcocn72Y4Jg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^3.0.0 + vue: ^3.0.0 + dependencies: + '@babel/core': 7.19.1 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.19.1 + '@babel/plugin-transform-typescript': 7.19.1_@babel+core@7.19.1 + '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.19.1 + vue: 3.2.40 + transitivePeerDependencies: + - supports-color + dev: true + /@vitejs/plugin-vue/3.1.2_vite@3.1.4+vue@3.2.40: resolution: {integrity: sha512-3zxKNlvA3oNaKDYX0NBclgxTQ1xaFdL7PzwF6zj9tGFziKwmBa3Q/6XcJQxudlT81WxDjEhHmevvIC4Orc1LhQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5947,6 +5970,10 @@ packages: engines: {node: '>=8'} dev: true + /markdown-it-container/3.0.0: + resolution: {integrity: sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==} + dev: true + /mdast-util-from-markdown/0.8.5: resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} dependencies: