feat(plugin-iconify): add vuepress-plugin-iconify
This commit is contained in:
parent
74c1bff8c5
commit
3331455790
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -27,6 +27,7 @@
|
||||
"frontmatter",
|
||||
"gsap",
|
||||
"iarna",
|
||||
"iconify",
|
||||
"leancloud",
|
||||
"nprogress",
|
||||
"pnpm",
|
||||
|
||||
21
packages/plugin-iconify/LICENSE
Normal file
21
packages/plugin-iconify/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2021 - PRESENT by pengzhanbo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
18
packages/plugin-iconify/README.md
Normal file
18
packages/plugin-iconify/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# `@vuepress-plume/vuepress-plugin-iconify`
|
||||
|
||||
## Install
|
||||
```
|
||||
yarn add @vuepress-plume/vuepress-plugin-iconify
|
||||
```
|
||||
## Usage
|
||||
``` js
|
||||
// .vuepress/config.js
|
||||
const iconifyPlugin = require('@vuepress-plume/vuepress-plugin-iconify')
|
||||
module.exports = {
|
||||
//...
|
||||
plugins: [
|
||||
iconifyPlugin()
|
||||
]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
49
packages/plugin-iconify/package.json
Normal file
49
packages/plugin-iconify/package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@vuepress-plume/vuepress-plugin-iconify",
|
||||
"version": "1.0.0-beta.57",
|
||||
"description": "The Plugin for VuePres 2",
|
||||
"homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "pengzhanbo <volodymyr@foxmail.com>",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./lib/node/index.js",
|
||||
"./client": "./lib/client/index.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"main": "lib/node/index.js",
|
||||
"types": "./lib/node/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "pnpm run clean && pnpm run copy && pnpm run ts",
|
||||
"clean": "rimraf lib *.tsbuildinfo",
|
||||
"copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib",
|
||||
"copy:watch": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib -w",
|
||||
"dev": "concurrently \"pnpm copy:watch\" \"pnpm ts:watch\"",
|
||||
"ts": "tsc -b tsconfig.build.json",
|
||||
"ts:watch": "tsc -b tsconfig.build.json --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/vue": "^4.1.0",
|
||||
"@vuepress/client": "2.0.0-beta.60",
|
||||
"@vuepress/core": "2.0.0-beta.60",
|
||||
"@vuepress/shared": "2.0.0-beta.60",
|
||||
"@vuepress/utils": "2.0.0-beta.60",
|
||||
"vue": "^3.2.47"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keyword": [
|
||||
"VuePress",
|
||||
"vuepress plugin",
|
||||
"iconify",
|
||||
"vuepress-plugin-plugin-iconify"
|
||||
]
|
||||
}
|
||||
10
packages/plugin-iconify/src/client/clientConfig.ts
Normal file
10
packages/plugin-iconify/src/client/clientConfig.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineClientConfig } from '@vuepress/client'
|
||||
import Iconify from './components/Iconify.vue'
|
||||
|
||||
declare const __VUEPRESS_PLUGIN_ICONIFY_COMPONENT_NAME__: string
|
||||
export default defineClientConfig({
|
||||
enhance({ app }) {
|
||||
const name = __VUEPRESS_PLUGIN_ICONIFY_COMPONENT_NAME__ || 'Iconify'
|
||||
app.component(name, Iconify)
|
||||
},
|
||||
})
|
||||
66
packages/plugin-iconify/src/client/components/Iconify.vue
Normal file
66
packages/plugin-iconify/src/client/components/Iconify.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<script lang="ts" setup>
|
||||
import { Icon as OfflineIcon } from '@iconify/vue/dist/offline.js'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, toRefs } from 'vue'
|
||||
import { useIconify } from '../composables/iconify.js'
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
require: true,
|
||||
default: '',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const { name } = toRefs(props)
|
||||
|
||||
const { icon, loaded } = useIconify(name)
|
||||
|
||||
const size = computed(() => {
|
||||
const size = props.size || __VUEPRESS_PLUGIN_ICONIFY_DEFAULT_SIZE__
|
||||
if (String(Number(size)) === size) {
|
||||
return `${size}px`
|
||||
}
|
||||
return size
|
||||
})
|
||||
const iconStyle = computed(() => {
|
||||
const style: CSSProperties = {
|
||||
color: props.color || __VUEPRESS_PLUGIN_ICONIFY_DEFAULT_COLOR__,
|
||||
width: size.value,
|
||||
height: size.value,
|
||||
}
|
||||
return style
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
declare const __VUEPRESS_PLUGIN_ICONIFY_DEFAULT_SIZE__: string
|
||||
declare const __VUEPRESS_PLUGIN_ICONIFY_DEFAULT_COLOR__: string
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span v-if="!loaded" class="vp-iconify" :style="iconStyle"></span>
|
||||
<OfflineIcon
|
||||
v-else-if="icon"
|
||||
:icon="icon"
|
||||
class="vp-iconify"
|
||||
:style="iconStyle"
|
||||
/>
|
||||
<span v-else class="vp-iconify" :style="{ ...iconStyle, fontSize: size }">
|
||||
{{ props.name }}
|
||||
</span>
|
||||
</template>
|
||||
<style scoped>
|
||||
.vp-iconify {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
27
packages/plugin-iconify/src/client/composables/iconify.ts
Normal file
27
packages/plugin-iconify/src/client/composables/iconify.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import type { IconifyIcon } from '@iconify/vue'
|
||||
import { loadIcon } from '@iconify/vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
|
||||
const iconCache: Ref<Record<string, IconifyIcon>> = ref({})
|
||||
|
||||
export const useIconify = (name: ComputedRef<string> | Ref<string>) => {
|
||||
const icon = computed(() => iconCache.value[name.value])
|
||||
const loaded = ref(false)
|
||||
|
||||
async function loadIconComponent() {
|
||||
if (icon.value) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
loaded.value = false
|
||||
iconCache.value[name.value] = await loadIcon(name.value)
|
||||
} finally {
|
||||
loaded.value = true
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => name.value, loadIconComponent, { immediate: true })
|
||||
|
||||
return { icon, loaded }
|
||||
}
|
||||
2
packages/plugin-iconify/src/client/index.ts
Normal file
2
packages/plugin-iconify/src/client/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './composables/iconify.js'
|
||||
export * from '../shared/index.js'
|
||||
6
packages/plugin-iconify/src/node/index.ts
Normal file
6
packages/plugin-iconify/src/node/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { iconifyPlugin } from './plugin.js'
|
||||
|
||||
export * from './plugin.js'
|
||||
export * from '../shared/index.js'
|
||||
|
||||
export default iconifyPlugin
|
||||
25
packages/plugin-iconify/src/node/plugin.ts
Normal file
25
packages/plugin-iconify/src/node/plugin.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import type { App, Plugin } from '@vuepress/core'
|
||||
import { getDirname, path } from '@vuepress/utils'
|
||||
import type { IconifyOptions } from '../shared/index.js'
|
||||
|
||||
export const iconifyPlugin = ({
|
||||
componentName = 'Iconify',
|
||||
size = '1em',
|
||||
color = 'currentColor',
|
||||
}: IconifyOptions): Plugin => {
|
||||
return (app: App) => {
|
||||
return {
|
||||
name: '@vuepress-plume/vuepress-plugin-iconify',
|
||||
define: {
|
||||
__VUEPRESS_PLUGIN_ICONIFY_COMPONENT_NAME__:
|
||||
JSON.stringify(componentName),
|
||||
__VUEPRESS_PLUGIN_ICONIFY_DEFAULT_SIZE__: JSON.stringify(size),
|
||||
__VUEPRESS_PLUGIN_ICONIFY_DEFAULT_COLOR__: JSON.stringify(color),
|
||||
},
|
||||
clientConfigFile: path.resolve(
|
||||
getDirname(import.meta.url),
|
||||
'../client/clientConfig.js'
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
5
packages/plugin-iconify/src/shared/index.ts
Normal file
5
packages/plugin-iconify/src/shared/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IconifyOptions {
|
||||
componentName?: string
|
||||
color?: string
|
||||
size?: string | number
|
||||
}
|
||||
4
packages/plugin-iconify/src/shim.d.ts
vendored
Normal file
4
packages/plugin-iconify/src/shim.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module '*.vue' {
|
||||
const comp: any
|
||||
export default comp
|
||||
}
|
||||
8
packages/plugin-iconify/tsconfig.build.json
Normal file
8
packages/plugin-iconify/tsconfig.build.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../tsconfig.build.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib"
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
@ -10,6 +10,7 @@
|
||||
{ "path": "./plugin-blog-data/tsconfig.build.json" },
|
||||
{ "path": "./plugin-caniuse/tsconfig.build.json" },
|
||||
{ "path": "./plugin-copy-code/tsconfig.build.json" },
|
||||
{ "path": "./plugin-iconify/tsconfig.build.json" },
|
||||
{ "path": "./plugin-netlify-functions/tsconfig.build.json" },
|
||||
{ "path": "./plugin-notes-data/tsconfig.build.json" },
|
||||
{ "path": "./plugin-page-collection/tsconfig.build.json" },
|
||||
|
||||
29
pnpm-lock.yaml
generated
29
pnpm-lock.yaml
generated
@ -178,6 +178,22 @@ importers:
|
||||
vue: 3.2.47
|
||||
vue-router: 4.1.6_vue@3.2.47
|
||||
|
||||
packages/plugin-iconify:
|
||||
specifiers:
|
||||
'@iconify/vue': ^4.1.0
|
||||
'@vuepress/client': 2.0.0-beta.60
|
||||
'@vuepress/core': 2.0.0-beta.60
|
||||
'@vuepress/shared': 2.0.0-beta.60
|
||||
'@vuepress/utils': 2.0.0-beta.60
|
||||
vue: ^3.2.47
|
||||
dependencies:
|
||||
'@iconify/vue': 4.1.0_vue@3.2.47
|
||||
'@vuepress/client': 2.0.0-beta.60
|
||||
'@vuepress/core': 2.0.0-beta.60
|
||||
'@vuepress/shared': 2.0.0-beta.60
|
||||
'@vuepress/utils': 2.0.0-beta.60
|
||||
vue: 3.2.47
|
||||
|
||||
packages/plugin-netlify-functions:
|
||||
specifiers:
|
||||
'@iarna/toml': ^2.2.5
|
||||
@ -1279,6 +1295,19 @@ packages:
|
||||
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
|
||||
dev: false
|
||||
|
||||
/@iconify/types/2.0.0:
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
dev: false
|
||||
|
||||
/@iconify/vue/4.1.0_vue@3.2.47:
|
||||
resolution: {integrity: sha512-rBQVxNoSDooqgWkQg2MqkIHkH/huNuvXGqui5wijc1zLnU7TKzbBHW9VGmbnV4asNTmIHmqV4Nvt0M2rZ/9nHA==}
|
||||
peerDependencies:
|
||||
vue: '>=3'
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
vue: 3.2.47
|
||||
dev: false
|
||||
|
||||
/@import-maps/resolve/1.0.1:
|
||||
resolution: {integrity: sha512-tWZNBIS1CoekcwlMuyG2mr0a1Wo5lb5lEHwwWvZo+5GLgr3e9LLDTtmgtCWEwBpXMkxn9D+2W9j2FY6eZQq0tA==}
|
||||
dev: false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user