mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
This commit is contained in:
parent
c42a601467
commit
95d345bf6d
@ -392,31 +392,55 @@ export default defineUserConfig({
|
||||
|
||||
将作为 图标链接 展示在 导航栏最右侧。
|
||||
|
||||
图标可选值:
|
||||
- `'github'`
|
||||
- `'gitlab'`
|
||||
- `'npm'`
|
||||
- `'docker'`
|
||||
- `'discord'`
|
||||
- `'telegram'`
|
||||
- `'facebook'`
|
||||
- `'instagram'`
|
||||
- `'linkedin'`
|
||||
- `'mastodon'`
|
||||
- `'slack'`
|
||||
- `'twitter'`
|
||||
- `'x'`
|
||||
- `'youtube'`
|
||||
- `'juejin'`
|
||||
- `'stackoverflow'`
|
||||
- `'qq'`
|
||||
- `'weibo'`
|
||||
- `'bilibili'`
|
||||
- `'zhihu'`
|
||||
- `'douban'`
|
||||
- `'steam'`
|
||||
- `'xbox'`
|
||||
- `{ svg: string, name?: string }`: 自定义图标,传入 svg 源码字符串,可选 `name` 字段,用于配置 [`navbarSocialInclude`](#navbarsocialinclude)
|
||||
支持 [Iconify](https://icon-sets.iconify.design/) 任意图标,直接使用 iconify name 即可自动加载。
|
||||
|
||||
对于 `simple-icons` 集合下的图标,可以省略 `simple-icons:` 前缀,如 `simple-icons:github` 可以简写为 `github`
|
||||
|
||||
常见的社交图标示例:
|
||||
|
||||
::: flex
|
||||
|
||||
<div style="flex: 1">
|
||||
|
||||
- discord ::simple-icons:discord::
|
||||
- telegram ::simple-icons:telegram::
|
||||
- facebook ::simple-icons:facebook::
|
||||
- github ::simple-icons:github::
|
||||
- instagram ::simple-icons:instagram::
|
||||
- linkedin ::simple-icons:linkedin::
|
||||
- mastodon ::simple-icons:mastodon::
|
||||
- npm ::simple-icons:npm::
|
||||
- slack ::simple-icons:slack::
|
||||
- twitter ::simple-icons:twitter::
|
||||
- x ::simple-icons:x::
|
||||
- youtube ::simple-icons:youtube::
|
||||
- bluesky ::simple-icons:bluesky::
|
||||
- tiktok ::simple-icons:tiktok::
|
||||
|
||||
</div><div style="flex: 1">
|
||||
|
||||
- qq ::simple-icons:qq::
|
||||
- weibo ::simple-icons:sinaweibo::
|
||||
- bilibili ::simple-icons:bilibili::
|
||||
- gitlab ::simple-icons:gitlab::
|
||||
- docker ::simple-icons:docker::
|
||||
- juejin ::simple-icons:juejin::
|
||||
- zhihu ::simple-icons:zhihu::
|
||||
- douban ::simple-icons:douban::
|
||||
- steam ::simple-icons:steam::
|
||||
- stackoverflow ::simple-icons:stackoverflow::
|
||||
- xbox ::simple-icons:xbox::
|
||||
- kuaishou ::simple-icons:kuaishou::
|
||||
- twitch ::simple-icons:twitch::
|
||||
- xiaohongshu ::simple-icons:xiaohongshu::
|
||||
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
[你可以在这里查看 **simple-icons** 所有可用图标](https://icon-sets.iconify.design/simple-icons/){.readmore}
|
||||
|
||||
如果 **Iconify** 无法满足你的需求,可以传入 `{ svg: string, name?: string }`的格式,使用自定义图标,传入 svg 源码字符串,可选 `name` 字段,用于配置 [`navbarSocialInclude`](#navbarsocialinclude)
|
||||
|
||||
示例:
|
||||
|
||||
@ -424,8 +448,10 @@ export default defineUserConfig({
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
social: [
|
||||
// 使用 iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// 使用自定义图标
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
|
||||
@ -397,31 +397,57 @@ export default defineUserConfig({
|
||||
|
||||
Displayed as icon links on the far right of the navbar.
|
||||
|
||||
Available icon options:
|
||||
- `'github'`
|
||||
- `'gitlab'`
|
||||
- `'npm'`
|
||||
- `'docker'`
|
||||
- `'discord'`
|
||||
- `'telegram'`
|
||||
- `'facebook'`
|
||||
- `'instagram'`
|
||||
- `'linkedin'`
|
||||
- `'mastodon'`
|
||||
- `'slack'`
|
||||
- `'twitter'`
|
||||
- `'x'`
|
||||
- `'youtube'`
|
||||
- `'juejin'`
|
||||
- `'stackoverflow'`
|
||||
- `'qq'`
|
||||
- `'weibo'`
|
||||
- `'bilibili'`
|
||||
- `'zhihu'`
|
||||
- `'douban'`
|
||||
- `'steam'`
|
||||
- `'xbox'`
|
||||
- `{ svg: string, name?: string }`: Custom icon, pass the SVG source string. The optional `name` field is used to configure [`navbarSocialInclude`](#navbarsocialinclude).
|
||||
Supports any icon from [Iconify](https://icon-sets.iconify.design/). Simply use the iconify name to load it automatically.
|
||||
|
||||
For icons in the `simple-icons` collection, you can omit the `simple-icons:` prefix.
|
||||
For example, `simple-icons:github` can be abbreviated as `github`.
|
||||
|
||||
Examples of common social icons:
|
||||
|
||||
::: flex
|
||||
|
||||
<div style="flex: 1">
|
||||
|
||||
- discord ::simple-icons:discord::
|
||||
- telegram ::simple-icons:telegram::
|
||||
- facebook ::simple-icons:facebook::
|
||||
- github ::simple-icons:github::
|
||||
- instagram ::simple-icons:instagram::
|
||||
- linkedin ::simple-icons:linkedin::
|
||||
- mastodon ::simple-icons:mastodon::
|
||||
- npm ::simple-icons:npm::
|
||||
- slack ::simple-icons:slack::
|
||||
- twitter ::simple-icons:twitter::
|
||||
- x ::simple-icons:x::
|
||||
- youtube ::simple-icons:youtube::
|
||||
- bluesky ::simple-icons:bluesky::
|
||||
- tiktok ::simple-icons:tiktok::
|
||||
|
||||
</div><div style="flex: 1">
|
||||
|
||||
- qq ::simple-icons:qq::
|
||||
- weibo ::simple-icons:sinaweibo::
|
||||
- bilibili ::simple-icons:bilibili::
|
||||
- gitlab ::simple-icons:gitlab::
|
||||
- docker ::simple-icons:docker::
|
||||
- juejin ::simple-icons:juejin::
|
||||
- zhihu ::simple-icons:zhihu::
|
||||
- douban ::simple-icons:douban::
|
||||
- steam ::simple-icons:steam::
|
||||
- stackoverflow ::simple-icons:stackoverflow::
|
||||
- xbox ::simple-icons:xbox::
|
||||
- kuaishou ::simple-icons:kuaishou::
|
||||
- twitch ::simple-icons:twitch::
|
||||
- xiaohongshu ::simple-icons:xiaohongshu::
|
||||
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
[You can view all available icons for **simple-icons** here](https://icon-sets.iconify.design/simple-icons/){.readmore}
|
||||
|
||||
If **Iconify** does not meet your needs, you can pass in the format `{ svg: string, name?: string }` to use a custom icon.
|
||||
Pass in the SVG source code string, with the optional `name` field for configuring [`navbarSocialInclude`](#navbarsocialinclude).
|
||||
|
||||
Example:
|
||||
|
||||
@ -429,8 +455,10 @@ Example:
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
social: [
|
||||
// use iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// use custom icon
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
|
||||
@ -450,9 +450,15 @@ export default defineUserConfig({
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: 'Blog',
|
||||
// [!code hl:4]
|
||||
// [!code hl:9]
|
||||
social: [
|
||||
{ icon: 'github', link: 'https://github.com/pengzhanbo' },
|
||||
// use iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// use custom icon
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
@ -471,9 +477,15 @@ export default defineThemeConfig({
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: 'Blog',
|
||||
// [!code hl:4]
|
||||
// [!code hl:9]
|
||||
social: [
|
||||
{ icon: 'github', link: 'https://github.com/pengzhanbo' },
|
||||
// use iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// use custom icon
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
@ -482,43 +494,58 @@ export default defineThemeConfig({
|
||||
|
||||
:::
|
||||
|
||||
### Built-in Icon Library
|
||||
Supports any icon from [Iconify](https://icon-sets.iconify.design/). Simply use the iconify name to load it automatically.
|
||||
|
||||
For icons in the `simple-icons` collection, the `simple-icons:` prefix can be omitted.
|
||||
For example, `simple-icons:github` can be abbreviated as `github`.
|
||||
|
||||
Examples of common social icons:
|
||||
|
||||
::: flex
|
||||
|
||||
<div style="flex: 1">
|
||||
|
||||
- discord
|
||||
- telegram
|
||||
- facebook
|
||||
- github
|
||||
- instagram
|
||||
- linkedin
|
||||
- mastodon
|
||||
- npm
|
||||
- slack
|
||||
- twitter
|
||||
- x
|
||||
- youtube
|
||||
- discord ::simple-icons:discord::
|
||||
- telegram ::simple-icons:telegram::
|
||||
- facebook ::simple-icons:facebook::
|
||||
- github ::simple-icons:github::
|
||||
- instagram ::simple-icons:instagram::
|
||||
- linkedin ::simple-icons:linkedin::
|
||||
- mastodon ::simple-icons:mastodon::
|
||||
- npm ::simple-icons:npm::
|
||||
- slack ::simple-icons:slack::
|
||||
- twitter ::simple-icons:twitter::
|
||||
- x ::simple-icons:x::
|
||||
- youtube ::simple-icons:youtube::
|
||||
- bluesky ::simple-icons:bluesky::
|
||||
- tiktok ::simple-icons:tiktok::
|
||||
|
||||
</div><div style="flex: 1">
|
||||
|
||||
- qq
|
||||
- weibo
|
||||
- bilibili
|
||||
- gitlab
|
||||
- docker
|
||||
- juejin
|
||||
- zhihu
|
||||
- douban
|
||||
- steam
|
||||
- stackoverflow
|
||||
- xbox
|
||||
- qq ::simple-icons:qq::
|
||||
- weibo ::simple-icons:sinaweibo::
|
||||
- bilibili ::simple-icons:bilibili::
|
||||
- gitlab ::simple-icons:gitlab::
|
||||
- docker ::simple-icons:docker::
|
||||
- juejin ::simple-icons:juejin::
|
||||
- zhihu ::simple-icons:zhihu::
|
||||
- douban ::simple-icons:douban::
|
||||
- steam ::simple-icons:steam::
|
||||
- stackoverflow ::simple-icons:stackoverflow::
|
||||
- xbox ::simple-icons:xbox::
|
||||
- kuaishou ::simple-icons:kuaishou::
|
||||
- twitch ::simple-icons:twitch::
|
||||
- xiaohongshu ::simple-icons:xiaohongshu::
|
||||
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
[You can view all available icons of **simple-icons** here](https://icon-sets.iconify.design/simple-icons/){.readmore}
|
||||
|
||||
If **Iconify** cannot meet your needs, you can pass in the format `{ svg: string, name?: string }`
|
||||
to use custom icons by providing the SVG source code string.
|
||||
|
||||
## Article Cover Configuration
|
||||
|
||||
The article list page supports cover image display with various layout and size options.
|
||||
|
||||
@ -429,7 +429,7 @@ export default defineThemeConfig({
|
||||
|
||||
## 社交链接
|
||||
|
||||
个人信息区域支持社交链接配置,未配置时继承[主题默认 social 设置](../../config/theme.md#social)。
|
||||
个人信息区域支持社交链接配置,未配置时继承 [主题默认 social 设置](../../config/theme.md#social)。
|
||||
|
||||
::: code-tabs#config
|
||||
|
||||
@ -446,9 +446,15 @@ export default defineUserConfig({
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:4]
|
||||
// [!code hl:9]
|
||||
social: [
|
||||
{ icon: 'github', link: 'https://github.com/pengzhanbo' },
|
||||
// 使用 iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// 使用自定义图标
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
@ -467,9 +473,15 @@ export default defineThemeConfig({
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:4]
|
||||
// [!code hl:9]
|
||||
social: [
|
||||
{ icon: 'github', link: 'https://github.com/pengzhanbo' },
|
||||
// 使用 iconify name
|
||||
{ icon: 'github', link: 'https://github.com/zhangsan' },
|
||||
{
|
||||
// 使用自定义图标
|
||||
icon: { svg: '<svg>xxxxx</svg>', name: 'xxx' },
|
||||
link: 'https://xxx.com'
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
@ -478,43 +490,56 @@ export default defineThemeConfig({
|
||||
|
||||
:::
|
||||
|
||||
### 内置图标库
|
||||
支持 [Iconify](https://icon-sets.iconify.design/) 任意图标,直接使用 iconify name 即可自动加载。
|
||||
|
||||
对于 `simple-icons` 集合下的图标,可以省略 `simple-icons:` 前缀,如 `simple-icons:github` 可以简写为 `github`
|
||||
|
||||
常见的社交图标示例:
|
||||
|
||||
::: flex
|
||||
|
||||
<div style="flex: 1">
|
||||
|
||||
- discord
|
||||
- telegram
|
||||
- facebook
|
||||
- github
|
||||
- instagram
|
||||
- linkedin
|
||||
- mastodon
|
||||
- npm
|
||||
- slack
|
||||
- twitter
|
||||
- x
|
||||
- youtube
|
||||
- discord ::simple-icons:discord::
|
||||
- telegram ::simple-icons:telegram::
|
||||
- facebook ::simple-icons:facebook::
|
||||
- github ::simple-icons:github::
|
||||
- instagram ::simple-icons:instagram::
|
||||
- linkedin ::simple-icons:linkedin::
|
||||
- mastodon ::simple-icons:mastodon::
|
||||
- npm ::simple-icons:npm::
|
||||
- slack ::simple-icons:slack::
|
||||
- twitter ::simple-icons:twitter::
|
||||
- x ::simple-icons:x::
|
||||
- youtube ::simple-icons:youtube::
|
||||
- bluesky ::simple-icons:bluesky::
|
||||
- tiktok ::simple-icons:tiktok::
|
||||
|
||||
</div><div style="flex: 1">
|
||||
|
||||
- qq
|
||||
- weibo
|
||||
- bilibili
|
||||
- gitlab
|
||||
- docker
|
||||
- juejin
|
||||
- zhihu
|
||||
- douban
|
||||
- steam
|
||||
- stackoverflow
|
||||
- xbox
|
||||
- qq ::simple-icons:qq::
|
||||
- weibo ::simple-icons:sinaweibo::
|
||||
- bilibili ::simple-icons:bilibili::
|
||||
- gitlab ::simple-icons:gitlab::
|
||||
- docker ::simple-icons:docker::
|
||||
- juejin ::simple-icons:juejin::
|
||||
- zhihu ::simple-icons:zhihu::
|
||||
- douban ::simple-icons:douban::
|
||||
- steam ::simple-icons:steam::
|
||||
- stackoverflow ::simple-icons:stackoverflow::
|
||||
- xbox ::simple-icons:xbox::
|
||||
- kuaishou ::simple-icons:kuaishou::
|
||||
- twitch ::simple-icons:twitch::
|
||||
- xiaohongshu ::simple-icons:xiaohongshu::
|
||||
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
[你可以在这里查看 **simple-icons** 所有可用图标](https://icon-sets.iconify.design/simple-icons/){.readmore}
|
||||
|
||||
如果 **Iconify** 无法满足你的需求,可以传入 `{ svg: string, name?: string }`的格式,使用自定义图标,传入 svg 源码字符串。
|
||||
|
||||
## 文章封面配置
|
||||
|
||||
文章列表页支持封面图展示,提供多种布局和尺寸选项。
|
||||
|
||||
@ -3,7 +3,7 @@ import type { IconifyIcon } from '@iconify/vue/offline'
|
||||
import { loadIcon } from '@iconify/vue'
|
||||
import { Icon as OfflineIcon } from '@iconify/vue/offline'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useIconsData } from '../composables/index.js'
|
||||
import { normalizeIconClassname } from '../composables/index.js'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
@ -20,15 +20,13 @@ const { name, size, color, prefix, extra } = defineProps<{
|
||||
const icon = ref<IconifyIcon | null>(null)
|
||||
const loaded = ref(false)
|
||||
|
||||
const iconsData = useIconsData()
|
||||
|
||||
const iconName = computed(() => {
|
||||
if (name.includes(':'))
|
||||
return name
|
||||
return prefix ? `${prefix}:${name}` : name
|
||||
})
|
||||
|
||||
const localIconName = computed(() => iconsData.value[iconName.value])
|
||||
const localIconName = computed(() => normalizeIconClassname(iconName.value))
|
||||
|
||||
async function loadRemoteIcon() {
|
||||
if (icon.value)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import type { SocialLinkIcon } from '../../shared/index.js'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import { computed } from 'vue'
|
||||
import { socialFallbacks } from '../composables/index.js'
|
||||
|
||||
const { icon, link, ariaLabel } = defineProps<{
|
||||
icon: SocialLinkIcon
|
||||
@ -8,10 +10,22 @@ const { icon, link, ariaLabel } = defineProps<{
|
||||
ariaLabel?: string
|
||||
}>()
|
||||
|
||||
const svg = computed(() => {
|
||||
if (typeof icon === 'object')
|
||||
return icon.svg
|
||||
return `<span class="vpi-social-${icon}" />`
|
||||
const iconName = computed(() => {
|
||||
if (typeof icon === 'string') {
|
||||
const name = socialFallbacks[icon] || icon
|
||||
if (name.includes(':'))
|
||||
return name
|
||||
return `simple-icons:${name}`
|
||||
}
|
||||
return icon
|
||||
})
|
||||
|
||||
const label = computed(() => {
|
||||
if (ariaLabel)
|
||||
return ariaLabel
|
||||
if (typeof icon === 'string')
|
||||
return icon.includes(':') ? icon.split(':')[1] : icon
|
||||
return icon.name
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -19,9 +33,12 @@ const svg = computed(() => {
|
||||
<a
|
||||
class="vp-social-link no-icon"
|
||||
:href="link"
|
||||
:aria-label="ariaLabel ?? (typeof icon === 'string' ? icon : '')"
|
||||
target="_blank" rel="noopener" v-html="svg"
|
||||
/>
|
||||
:aria-label="label"
|
||||
:title="label"
|
||||
target="_blank" rel="noopener"
|
||||
>
|
||||
<VPIcon :name="iconName" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@ -40,7 +57,7 @@ const svg = computed(() => {
|
||||
}
|
||||
|
||||
.vp-social-link > :deep(svg),
|
||||
.vp-social-link > :deep([class^="vpi-social-"]) {
|
||||
.vp-social-link > :deep([class*="vpi-"]) {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: currentcolor;
|
||||
|
||||
@ -2,15 +2,26 @@ import type { Ref } from 'vue'
|
||||
import { icons } from '@internal/iconify'
|
||||
import { ref } from 'vue'
|
||||
|
||||
type IconsData = Record<string, string>
|
||||
type IconsDataRef = Ref<IconsData>
|
||||
type NeedBackgroundIcons = string[]
|
||||
type IconsDataRef = Ref<NeedBackgroundIcons>
|
||||
|
||||
const iconsData: IconsDataRef = ref(icons)
|
||||
|
||||
export const useIconsData = (): IconsDataRef => iconsData
|
||||
|
||||
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
|
||||
__VUE_HMR_RUNTIME__.updateIcons = (data: IconsData) => {
|
||||
__VUE_HMR_RUNTIME__.updateIcons = (data: NeedBackgroundIcons) => {
|
||||
iconsData.value = data
|
||||
}
|
||||
}
|
||||
|
||||
// 旧版本内置图标别名,映射回 simple-icons 集合中的名称
|
||||
export const socialFallbacks: Record<string, string> = {
|
||||
twitter: 'x',
|
||||
weibo: 'sinaweibo',
|
||||
}
|
||||
|
||||
export function normalizeIconClassname(icon: string): string {
|
||||
const [collect, name] = icon.split(':')
|
||||
return `vpi-${collect}-${name}${iconsData.value.includes(icon) ? ' bg' : ''}`
|
||||
}
|
||||
|
||||
2
theme/src/client/shim.d.ts
vendored
2
theme/src/client/shim.d.ts
vendored
@ -74,7 +74,7 @@ declare module '@internal/encrypt' {
|
||||
}
|
||||
|
||||
declare module '@internal/iconify' {
|
||||
const icons: Record<string, string>
|
||||
const icons: string[]
|
||||
export {
|
||||
icons,
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
@import url("./vars.css");
|
||||
@import url("./normalize.css");
|
||||
@import url("./icons.css");
|
||||
@import url("./social-icons.css");
|
||||
|
||||
/* @import url("./social-icons.css"); */
|
||||
@import url("./compat.css");
|
||||
@import url("./utils.css");
|
||||
@import url("./content.css");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { App, Page } from 'vuepress'
|
||||
import type { IconOptions } from 'vuepress-plugin-md-power'
|
||||
import type { ThemeHomeConfig, ThemeNavItem, ThemeOptions, ThemeSidebar } from '../../shared/index.js'
|
||||
import type { FriendGroup, FriendsItem, SocialLink, ThemeHomeConfig, ThemeNavItem, ThemeOptions, ThemeSidebar } from '../../shared/index.js'
|
||||
import type { FsCache } from '../utils/index.js'
|
||||
import { getIconContentCSS, getIconData } from '@iconify/utils'
|
||||
import { isArray, uniq } from '@pengzhanbo/utils'
|
||||
@ -8,7 +8,7 @@ import { entries, isLinkAbsolute, isLinkHttp, isPlainObject } from '@vuepress/he
|
||||
import { isPackageExists } from 'local-pkg'
|
||||
import { fs } from 'vuepress/utils'
|
||||
import { getThemeConfig } from '../loadConfig/index.js'
|
||||
import { createFsCache, interopDefault, logger, nanoid, perf, resolveContent, writeTemp } from '../utils/index.js'
|
||||
import { createFsCache, interopDefault, logger, perf, resolveContent, writeTemp } from '../utils/index.js'
|
||||
|
||||
interface IconData {
|
||||
className: string
|
||||
@ -34,11 +34,17 @@ let fsCache: FsCache<IconDataMap> | null = null
|
||||
// { iconName: { className, content } }
|
||||
const cache: IconDataMap = {}
|
||||
|
||||
// 旧版本内置图标别名,映射回 simple-icons 集合中的名称
|
||||
const socialFallbacks: Record<string, string> = {
|
||||
twitter: 'x',
|
||||
weibo: 'sinaweibo',
|
||||
}
|
||||
|
||||
export async function prepareIcons(app: App): Promise<void> {
|
||||
perf.mark('prepare:icons:total')
|
||||
const options = getThemeConfig()
|
||||
if (!isInstalled) {
|
||||
await writeTemp(app, JS_FILENAME, resolveContent(app, { name: 'icons', content: '{}' }))
|
||||
await writeTemp(app, JS_FILENAME, resolveContent(app, { name: 'icons', content: '[]' }))
|
||||
return
|
||||
}
|
||||
if (!fsCache && app.env.isDev) {
|
||||
@ -86,9 +92,10 @@ export async function prepareIcons(app: App): Promise<void> {
|
||||
perf.log('prepare:icons:imports')
|
||||
|
||||
let cssCode = ''
|
||||
const map: Record<string, string> = {}
|
||||
const shouldBackground: string[] = []
|
||||
for (const [iconName, { className, content, background }] of entries(cache)) {
|
||||
map[iconName] = `${className}${background ? ' bg' : ''}`
|
||||
if (background)
|
||||
shouldBackground.push(iconName)
|
||||
cssCode += `.${className} {\n --icon: ${content};\n}\n`
|
||||
}
|
||||
|
||||
@ -96,7 +103,7 @@ export async function prepareIcons(app: App): Promise<void> {
|
||||
writeTemp(app, CSS_FILENAME, cssCode),
|
||||
writeTemp(app, JS_FILENAME, resolveContent(app, {
|
||||
name: 'icons',
|
||||
content: map,
|
||||
content: shouldBackground,
|
||||
before: `import './iconify.css'`,
|
||||
})),
|
||||
])
|
||||
@ -106,10 +113,11 @@ export async function prepareIcons(app: App): Promise<void> {
|
||||
perf.log('prepare:icons:total')
|
||||
}
|
||||
|
||||
function isIconify(icon: any): icon is string {
|
||||
function isIconify(icon: unknown): icon is string {
|
||||
if (!icon || typeof icon !== 'string' || isLinkAbsolute(icon) || isLinkHttp(icon))
|
||||
return false
|
||||
return icon[0] !== '{' && ICONIFY_NAME.test(icon)
|
||||
const ic = icon.trim()
|
||||
return ic[0] !== '{' && ICONIFY_NAME.test(ic)
|
||||
}
|
||||
|
||||
function withPrefix(icon: string, prefix?: string): string {
|
||||
@ -130,7 +138,7 @@ function getIconsWithPage(page: Page, { provider = 'iconify', prefix }: IconOpti
|
||||
}
|
||||
|
||||
const addIcon = (icon: unknown): void => {
|
||||
if (isIconify(icon) && (provider === 'iconify' || icon.startsWith('iconify'))) {
|
||||
if (icon && isIconify(icon) && (provider === 'iconify' || icon.startsWith('iconify'))) {
|
||||
list.push(withPrefix(icon.replace(/^iconify /, ''), prefix))
|
||||
}
|
||||
}
|
||||
@ -153,30 +161,58 @@ function getIconsWithPage(page: Page, { provider = 'iconify', prefix }: IconOpti
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fm.pageLayout === 'friends') {
|
||||
const socialList: SocialLink[] = []
|
||||
if ((fm.list as FriendsItem[])?.length) {
|
||||
for (const { socials } of fm.list as FriendsItem[]) {
|
||||
socialList.push(...(socials || []))
|
||||
}
|
||||
}
|
||||
if ((fm.groups as FriendGroup[])?.length) {
|
||||
for (const { list } of fm.groups as FriendGroup[]) {
|
||||
if (!list?.length)
|
||||
continue
|
||||
for (const { socials } of list as FriendsItem[]) {
|
||||
socialList.push(...(socials || []))
|
||||
}
|
||||
}
|
||||
}
|
||||
socialList.forEach(social => addIcon(getIconWithSocial(social)))
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
function getIconWithThemeConfig(options: ThemeOptions, { provider = 'iconify', prefix }: IconOptions): string[] {
|
||||
const list: string[] = []
|
||||
// navbar notes sidebar
|
||||
// navbar / doc collection sidebar / social
|
||||
const locales = options.locales || {}
|
||||
entries(locales).forEach(([, { navbar, sidebar, collections }]) => {
|
||||
entries(locales).forEach(([, { navbar, sidebar, collections, social }]) => {
|
||||
// navbar icon
|
||||
if (navbar) {
|
||||
list.push(...getIconWithNavbar(navbar))
|
||||
}
|
||||
// social
|
||||
const socialList: SocialLink[] = social ? [...social] : []
|
||||
// sidebar icon
|
||||
const sidebarList: ThemeSidebar[] = Object.values(sidebar || {}) as ThemeSidebar[]
|
||||
|
||||
if (collections?.length) {
|
||||
collections.forEach((collection) => {
|
||||
if (collection.type === 'doc' && collection.sidebar)
|
||||
sidebarList.push(collection.sidebar)
|
||||
|
||||
if (collection.type === 'post' && collection.social)
|
||||
socialList.push(...collection.social)
|
||||
})
|
||||
}
|
||||
sidebarList.forEach(sidebar => list.push(...getIconWithSidebar(sidebar)))
|
||||
// social
|
||||
socialList.forEach(social => list.push(getIconWithSocial(social)))
|
||||
})
|
||||
|
||||
const addIcon = (icon: unknown): string | void => {
|
||||
if (isIconify(icon) && (provider === 'iconify' || icon.startsWith('iconify'))) {
|
||||
if (icon && isIconify(icon) && (provider === 'iconify' || icon.startsWith('iconify'))) {
|
||||
return withPrefix(icon.replace(/^iconify /, ''), prefix)
|
||||
}
|
||||
}
|
||||
@ -224,6 +260,15 @@ function getIconWithSidebar(sidebar: ThemeSidebar): string[] {
|
||||
return list
|
||||
}
|
||||
|
||||
function getIconWithSocial({ icon }: SocialLink): string {
|
||||
if (!icon || typeof icon !== 'string')
|
||||
return ''
|
||||
const name = socialFallbacks[icon] || icon
|
||||
if (name.includes(':'))
|
||||
return name
|
||||
return `simple-icons:${name}`
|
||||
}
|
||||
|
||||
async function resolveCollect(collect: string, names: string[]) {
|
||||
const filepath = locate(collect)
|
||||
const config = await readJSON(filepath)
|
||||
@ -251,7 +296,7 @@ async function resolveCollect(collect: string, names: string[]) {
|
||||
*/
|
||||
const background = !data.body.includes('currentColor')
|
||||
cache[icon] = {
|
||||
className: `vpi-${nanoid()}`,
|
||||
className: normalizeClassname(icon),
|
||||
background,
|
||||
content: matched,
|
||||
}
|
||||
@ -260,6 +305,11 @@ async function resolveCollect(collect: string, names: string[]) {
|
||||
return unknownList
|
||||
}
|
||||
|
||||
function normalizeClassname(icon: string): string {
|
||||
const [collect, name] = icon.split(':')
|
||||
return `vpi-${collect}-${name}`
|
||||
}
|
||||
|
||||
async function readJSON(filepath: string) {
|
||||
try {
|
||||
return await fs.readJSON(filepath, 'utf-8')
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { LiteralUnion } from '../utils.js'
|
||||
/**
|
||||
* 社交链接
|
||||
*/
|
||||
@ -10,7 +11,7 @@ export interface SocialLink {
|
||||
/**
|
||||
* 社交链接图标
|
||||
*/
|
||||
export type SocialLinkIcon = SocialLinkIconUnion | { svg: string, name?: string }
|
||||
export type SocialLinkIcon = LiteralUnion<SocialLinkIconUnion> | { svg: string, name?: string }
|
||||
|
||||
export type SocialLinkIconUnion
|
||||
= | 'discord'
|
||||
@ -36,3 +37,9 @@ export type SocialLinkIconUnion
|
||||
| 'steam'
|
||||
| 'stackoverflow'
|
||||
| 'xbox'
|
||||
| 'tiktok'
|
||||
| 'kuaishou'
|
||||
| 'bytedance'
|
||||
| 'xiaohongshu'
|
||||
| 'bluesky'
|
||||
| 'gmail'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user