feat(theme): add badge support for navbar and sidebar (#559)
This commit is contained in:
parent
0bceda590c
commit
73ed8dc9c5
@ -39,11 +39,11 @@
|
||||
"picocolors": "catalog:prod"
|
||||
},
|
||||
"plume-deps": {
|
||||
"vuepress": "2.0.0-rc.20",
|
||||
"vuepress": "2.0.0-rc.21",
|
||||
"vue": "^3.5.13",
|
||||
"sass-embedded": "^1.86.3",
|
||||
"sass-loader": "^16.0.5",
|
||||
"http-server": "^14.1.1",
|
||||
"typescript": "^5.8.2"
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ export const zhNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: `${version}`,
|
||||
icon: 'codicon:versions',
|
||||
badge: '新',
|
||||
items: [
|
||||
{ text: '更新日志', link: '/changelog/' },
|
||||
{ text: '参与贡献', link: '/contributing/' },
|
||||
|
||||
@ -80,7 +80,7 @@ export const themeGuide = defineNoteConfig({
|
||||
'jsFiddle',
|
||||
'codeSandbox',
|
||||
'replit',
|
||||
{ link: 'frontend-deprecated', text: '前端(弃用)' },
|
||||
'frontend-deprecated',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
title: 通用配置
|
||||
createTime: 2024/03/02 20:01:09
|
||||
permalink: /config/frontmatter/basic/
|
||||
badge: 徽章 badge
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -2,9 +2,6 @@
|
||||
title: Markdown 配置
|
||||
createTime: 2025/03/15 14:54:19
|
||||
permalink: /config/markdown/
|
||||
badge:
|
||||
type: tip
|
||||
text: 1.0.0-rc.136 +
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -97,6 +97,19 @@ export default defineUserConfig({
|
||||
类型: `NavItem[]`
|
||||
|
||||
```ts
|
||||
interface ThemeBadge {
|
||||
/* 徽章文本 */
|
||||
text?: string
|
||||
/* 徽章类型,内置: 'info' | 'tip' | 'danger' | 'warning' */
|
||||
type?: string
|
||||
/* 文本颜色 */
|
||||
color?: string
|
||||
/* 背景颜色 */
|
||||
bgColor?: string
|
||||
/* 边框颜色 */
|
||||
borderColor?: string
|
||||
}
|
||||
|
||||
type NavItem = string | {
|
||||
/**
|
||||
* 导航栏文本
|
||||
@ -110,13 +123,18 @@ type NavItem = string | {
|
||||
*/
|
||||
link: string
|
||||
/**
|
||||
* - 支持 iconify 图标,直接使用 iconify name 即可自动加载
|
||||
* 支持 iconify 图标,直接使用 iconify name 即可自动加载
|
||||
* @see https://icon-sets.iconify.design/
|
||||
*
|
||||
* - 如果 iconify 图标不满足您的需求,也可以支持传入 svg 字符串。
|
||||
* - 还支持使用 本地图片 或 远程图片,本地图片的路径需要以 `/` 开头。
|
||||
*/
|
||||
icon?: string | { svg: string }
|
||||
|
||||
/**
|
||||
* 徽章,支持自定义徽章样式
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
/**
|
||||
* 控制元素何时被激活
|
||||
*/
|
||||
@ -156,12 +174,14 @@ export default defineUserConfig({
|
||||
text: 'vuepress-theme-plume',
|
||||
link: '/vuepress-theme-plume/',
|
||||
icon: 'mdi:paper-airplane',
|
||||
badge: '徽章'
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Vuepress Plugin',
|
||||
icon: 'mingcute:plugin-2-fill',
|
||||
badge: { text: '徽章', type: 'warning' },
|
||||
items: [
|
||||
{
|
||||
text: 'caniuse',
|
||||
@ -184,8 +204,8 @@ export default defineUserConfig({
|
||||
icon: 'material-symbols:note-alt-rounded',
|
||||
},
|
||||
{
|
||||
text: 'shikiji',
|
||||
link: '/vuepress-plugin/shikiji/',
|
||||
text: 'shiki',
|
||||
link: '/vuepress-plugin/shiki/',
|
||||
icon: 'material-symbols-light:code-blocks-outline-rounded',
|
||||
},
|
||||
],
|
||||
|
||||
@ -103,7 +103,20 @@ interface NoteItem {
|
||||
sidebar?: 'auto' | (string | SidebarItem)[]
|
||||
}
|
||||
|
||||
export interface SidebarItem {
|
||||
interface ThemeBadge {
|
||||
/* 徽章文本 */
|
||||
text?: string
|
||||
/* 徽章类型,内置: 'info' | 'tip' | 'danger' | 'warning' */
|
||||
type?: string
|
||||
/* 文本颜色 */
|
||||
color?: string
|
||||
/* 背景颜色 */
|
||||
bgColor?: string
|
||||
/* 边框颜色 */
|
||||
borderColor?: string
|
||||
}
|
||||
|
||||
interface SidebarItem {
|
||||
/**
|
||||
* 侧边栏文本
|
||||
*/
|
||||
@ -119,6 +132,11 @@ export interface SidebarItem {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 次级侧边栏分组
|
||||
* 不超过 3 层
|
||||
|
||||
@ -3,8 +3,6 @@ title: 瀑布流容器
|
||||
icon: ri:layout-masonry-line
|
||||
createTime: 2024/12/14 17:17:06
|
||||
permalink: /guide/components/card-masonry/
|
||||
badge:
|
||||
text: v1.0.0-rc.121 +
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -3,7 +3,6 @@ title: 轮播图
|
||||
icon: dashicons:images-alt2
|
||||
createTime: 2024/09/12 22:00:22
|
||||
permalink: /guide/components/swiper/
|
||||
badge: v1.0.0-rc.98 +
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
---
|
||||
title: 公告板
|
||||
icon: mingcute:announcement-line
|
||||
badge:
|
||||
type: tip
|
||||
text: v1.0.0-rc.112 +
|
||||
createTime: 2024/10/19 21:51:22
|
||||
permalink: /guide/features/bulletin/
|
||||
---
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
---
|
||||
title: 文章变更历史
|
||||
icon: radix-icons:activity-log
|
||||
badge:
|
||||
type: tip
|
||||
text: v1.0.0-rc.115 +
|
||||
createTime: 2024/11/07 18:16:25
|
||||
permalink: /guide/features/changelog/
|
||||
---
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
---
|
||||
title: 文章贡献者
|
||||
icon: simple-icons:contributorcovenant
|
||||
badge:
|
||||
type: tip
|
||||
text: v1.0.0-rc.115 +
|
||||
createTime: 2024/11/07 16:26:54
|
||||
permalink: /guide/features/contributors/
|
||||
---
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
---
|
||||
title: 文章版权所有
|
||||
icon: lucide:creative-commons
|
||||
badge:
|
||||
type: tip
|
||||
text: v1.0.0-rc.118 +
|
||||
createTime: 2024/11/20 10:52:49
|
||||
permalink: /guide/features/copyright/
|
||||
---
|
||||
|
||||
@ -3,9 +3,7 @@ title: 资源链接替换
|
||||
icon: lucide:replace
|
||||
createTime: 2025/04/03 11:45:17
|
||||
permalink: /guide/features/replace-assets/
|
||||
badge:
|
||||
type: tip
|
||||
text: 1.0.0-rc.139 +
|
||||
badge: 新
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -3,9 +3,6 @@ title: 对话记录
|
||||
icon: cil:chat-bubble
|
||||
createTime: 2025/03/24 21:40:18
|
||||
permalink: /guide/markdown/chat/
|
||||
badge:
|
||||
type: tip
|
||||
text: 1.0.0-rc.138
|
||||
---
|
||||
|
||||
## 前言
|
||||
|
||||
@ -3,9 +3,6 @@ title: 折叠面板
|
||||
icon: carbon:collapse-categories
|
||||
createTime: 2025/03/22 22:27:22
|
||||
permalink: /guide/markdown/collapse/
|
||||
badge:
|
||||
type: tip
|
||||
text: 1.0.0-rc.137 +
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -3,9 +3,6 @@ title: 时间线
|
||||
icon: mdi:timeline-text-outline
|
||||
createTime: 2025/03/20 18:05:29
|
||||
permalink: /guide/markdown/timeline/
|
||||
badge:
|
||||
text: 1.0.0-rc.137 +
|
||||
type: tip
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
@ -279,6 +279,21 @@ export default defineNoteConfig({
|
||||
以下是 侧边栏的 类型定义:
|
||||
|
||||
```ts
|
||||
interface ThemeBadge {
|
||||
/* 徽章文本 */
|
||||
text?: string
|
||||
/* 徽章类型,内置: 'info' | 'tip' | 'danger' | 'warning' */
|
||||
type?: string
|
||||
/* 文本颜色 */
|
||||
color?: string
|
||||
/* 背景颜色 */
|
||||
bgColor?: string
|
||||
/* 边框颜色 */
|
||||
borderColor?: string
|
||||
}
|
||||
|
||||
type ThemeIcon = string | { svg: string }
|
||||
|
||||
type Sidebar = (string | SidebarItem)[]
|
||||
|
||||
interface SidebarItem {
|
||||
@ -297,6 +312,11 @@ interface SidebarItem {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 侧边栏徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 当前分组的链接前缀,链接前缀会拼接在 `items` 内的 `link` 之前
|
||||
* 当且仅当 `items` 内的 `link` 为 相对路径时,才会拼接
|
||||
@ -461,7 +481,7 @@ const typescript = defineNoteConfig({
|
||||
|
||||
### 侧边栏图标
|
||||
|
||||
为侧边栏添加 图标 有助于 侧边栏更好的呈现。得益于 [iconify](https://iconify.design/) 这个强大的开源图标库,
|
||||
为侧边栏添加 ==图标== 有助于 侧边栏更好的呈现。得益于 [iconify](https://iconify.design/) 这个强大的开源图标库,
|
||||
你可以使用超过 `200k` 的图标,仅需要添加 `icon` 配置即可。
|
||||
|
||||
```ts title=".vuepress/notes.ts" twoslash
|
||||
@ -519,16 +539,56 @@ const typescript = defineNoteConfig({
|
||||
- …
|
||||
:::
|
||||
|
||||
你可能已经注意到,`sidebar: auto` 时,该如何配置 侧边栏图标,事实上很简单,直接在 文件的 `frontmatter` 部分,
|
||||
添加 一个 `icon` 字段即可。
|
||||
当 `sidebar: auto` 时,可在 md 文件的 `frontmatter` 部分,添加 一个 `icon` 字段:
|
||||
|
||||
```md title="typescript/guide/intro.md"
|
||||
```md title="intro.md"
|
||||
---
|
||||
title: 介绍
|
||||
icon: ep:guide
|
||||
---
|
||||
```
|
||||
|
||||
### 侧边栏徽章 <Badge text="v1.0.0-rc.143 +" />
|
||||
|
||||
主题支持为侧边栏添加徽章,徽章可以用于辅助提供更多的信息。
|
||||
|
||||
```ts title=".vuepress/notes.ts" twoslash
|
||||
import { defineNoteConfig } from 'vuepress-theme-plume'
|
||||
|
||||
const typescript = defineNoteConfig({
|
||||
dir: 'typescript',
|
||||
link: '/typescript/',
|
||||
sidebar: [
|
||||
{
|
||||
text: '指南',
|
||||
prefix: '/guide',
|
||||
badge: { text: '徽章', type: 'danger' }, // [!code hl]
|
||||
items: [
|
||||
{ text: '介绍', link: 'intro', badge: '徽章' }, // [!code hl]
|
||||
],
|
||||
},
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
当 `sidebar: auto` 时,可在 md 文件的 `frontmatter` 部分,添加 一个 `badge` 字段:
|
||||
|
||||
```md title="intro.md"
|
||||
---
|
||||
title: 介绍
|
||||
badge:
|
||||
text: 徽章
|
||||
type: danger
|
||||
---
|
||||
```
|
||||
|
||||
```md title="intro.md"
|
||||
---
|
||||
title: 介绍
|
||||
badge: 徽章
|
||||
---
|
||||
```
|
||||
|
||||
### 侧边栏组内分隔
|
||||
|
||||
在组内对 项 进行分隔 是一个相对小众的需求,它在组的项比较多,但又不适合拆分为多个组,或者组内拆分多组的情况下,
|
||||
|
||||
@ -3,8 +3,6 @@ title: 前端演示
|
||||
icon: icon-park-outline:html-five
|
||||
createTime: 2025/01/08 21:34:26
|
||||
permalink: /guide/repl/frontend/
|
||||
badge:
|
||||
text: 1.0.0-rc.127 +
|
||||
---
|
||||
|
||||
::: important [旧的前端代码演示](./frontend-deprecated.md) 已弃用,请迁移至此新的方案。
|
||||
|
||||
@ -94,4 +94,14 @@ watchEffect(() => {
|
||||
position: fixed;
|
||||
}
|
||||
}
|
||||
|
||||
.vp-nav :deep(.vp-menu-badge) {
|
||||
padding: 3px 4px;
|
||||
margin-left: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
letter-spacing: 0.2px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -41,5 +41,6 @@ const childrenActive = computed(() => isChildActive(props.item))
|
||||
:button="item.text"
|
||||
:items="item.items"
|
||||
:prefix-icon="item.icon"
|
||||
:badge="item.badge"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ResolvedNavItemWithLink } from '../../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { resolveRouteFullPath } from 'vuepress/client'
|
||||
@ -30,6 +31,11 @@ const { page } = useData()
|
||||
>
|
||||
<VPIcon v-if="item.icon" :name="item.icon" />
|
||||
<span v-html="item.text" />
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</VPLink>
|
||||
</template>
|
||||
|
||||
@ -52,4 +58,8 @@ const { page } = useData()
|
||||
.navbar-menu-link:hover {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.navbar-menu-link :deep(.vp-menu-badge) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,6 +18,7 @@ const navbar = useNavbarData()
|
||||
:text="item.text || ''"
|
||||
:items="item.items"
|
||||
:icon="item.icon"
|
||||
:badge="item.badge"
|
||||
/>
|
||||
</template>
|
||||
</nav>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ThemeIcon } from '../../../shared/index.js'
|
||||
import type { ThemeBadge, ThemeIcon } from '../../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPNavScreenMenuGroupLink from '@theme/Nav/VPNavScreenMenuGroupLink.vue'
|
||||
import VPNavScreenMenuGroupSection from '@theme/Nav/VPNavScreenMenuGroupSection.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
@ -11,6 +12,7 @@ import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
const props = defineProps<{
|
||||
text: string
|
||||
icon?: ThemeIcon
|
||||
badge?: string | ThemeBadge
|
||||
items: any[]
|
||||
}>()
|
||||
|
||||
@ -36,6 +38,11 @@ function toggle() {
|
||||
<span class="button-text">
|
||||
<VPIcon v-if="icon" :name="icon" />
|
||||
<span v-html="text" />
|
||||
<VPBadge
|
||||
v-if="badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof badge === 'string' ? { text: badge } : badge"
|
||||
/>
|
||||
</span>
|
||||
<span class="vpi-plus button-icon" />
|
||||
</button>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ResolvedNavItemWithLink } from '../../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { inject } from 'vue'
|
||||
@ -22,6 +23,11 @@ const closeScreen = inject('close-screen') as () => void
|
||||
>
|
||||
<VPIcon v-if="item.icon" :name="item.icon" />
|
||||
<span v-html="item.text" />
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</VPLink>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ResolvedNavItemWithLink } from '../../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { inject } from 'vue'
|
||||
@ -22,6 +23,11 @@ const closeScreen = inject('close-screen') as () => void
|
||||
>
|
||||
<VPIcon v-if="item.icon" :name="item.icon" />
|
||||
<span v-html="item.text" />
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</VPLink>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ThemeBadge, ThemeIcon } from '../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPMenu from '@theme/VPMenu.vue'
|
||||
import { ref } from 'vue'
|
||||
import { useFlyout } from '../composables/index.js'
|
||||
|
||||
defineProps<{
|
||||
prefixIcon?: string | { svg: string }
|
||||
prefixIcon?: ThemeIcon
|
||||
icon?: any
|
||||
button?: string
|
||||
label?: string
|
||||
items?: any[]
|
||||
badge?: string | ThemeBadge
|
||||
}>()
|
||||
|
||||
const open = ref(false)
|
||||
@ -43,6 +46,7 @@ function onBlur() {
|
||||
<VPIcon v-if="prefixIcon" :name="prefixIcon" />
|
||||
<span v-if="icon" class="option-icon" :class="[icon]" />
|
||||
<span v-if="button" v-html="button" />
|
||||
<VPBadge v-if="badge" class="vp-menu-badge" v-bind="typeof badge === 'string' ? { text: badge } : badge" />
|
||||
<span class="vpi-chevron-down text-icon" />
|
||||
</span>
|
||||
|
||||
@ -146,4 +150,8 @@ function onBlur() {
|
||||
margin-left: 4px;
|
||||
fill: currentcolor;
|
||||
}
|
||||
|
||||
.vp-flyout :deep(.vp-menu-badge) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { resolveRouteFullPath } from 'vuepress/client'
|
||||
@ -25,6 +26,11 @@ const { page } = useData()
|
||||
>
|
||||
<VPIcon v-if="item.icon" :name="item.icon" />
|
||||
{{ item.text }}
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</VPLink>
|
||||
</div>
|
||||
</template>
|
||||
@ -64,4 +70,8 @@ const { page } = useData()
|
||||
.link :deep(.vp-icon-img) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.vp-menu-link .link :deep(.vp-menu-badge) {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { ResolvedSidebarItem } from '../../shared/index.js'
|
||||
import VPBadge from '@theme/global/VPBadge.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { FadeInExpandTransition } from '@vuepress/helper/client'
|
||||
@ -86,10 +87,24 @@ function onCaretClick() {
|
||||
class="link"
|
||||
:href="item.link"
|
||||
>
|
||||
<Component :is="textTag" class="text" v-html="item.text" />
|
||||
<Component :is="textTag" class="text">
|
||||
<span v-html="item.text" />
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</Component>
|
||||
</VPLink>
|
||||
|
||||
<Component :is="textTag" v-else class="text" :class="{ separator: isSeparator }" v-html="item.text" />
|
||||
<Component :is="textTag" v-else class="text" :class="{ separator: isSeparator }">
|
||||
<span v-html="item.text" />
|
||||
<VPBadge
|
||||
v-if="item.badge"
|
||||
class="vp-menu-badge"
|
||||
v-bind="typeof item.badge === 'string' ? { text: item.badge } : item.badge"
|
||||
/>
|
||||
</Component>
|
||||
|
||||
<div
|
||||
v-if="item.collapsed != null"
|
||||
@ -173,6 +188,7 @@ function onCaretClick() {
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
transition: color var(--vp-t-color);
|
||||
}
|
||||
|
||||
@ -259,10 +275,12 @@ function onCaretClick() {
|
||||
}
|
||||
|
||||
.item :deep(.vp-icon) {
|
||||
align-self: baseline;
|
||||
margin: 0 0.25rem 0 0;
|
||||
font-size: 0.9em;
|
||||
color: var(--vp-c-text-2);
|
||||
transition: color var(--vp-t-color);
|
||||
transform: translateY(9px);
|
||||
}
|
||||
|
||||
.item :deep(.vp-icon-img) {
|
||||
@ -317,4 +335,19 @@ function onCaretClick() {
|
||||
border-left: 1px solid var(--vp-c-divider);
|
||||
transition: border-left var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-sidebar-item .text :deep(.vp-menu-badge) {
|
||||
padding: 3px 4px;
|
||||
margin-top: 0;
|
||||
margin-left: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
letter-spacing: 0.2px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.vp-sidebar-item.collapsible > .item .text :deep(.vp-menu-badge) {
|
||||
transform: translateY(3px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,14 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { ThemeBadge } from '../../../shared/index.js'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
text?: string
|
||||
type?: string
|
||||
color?: string
|
||||
bgColor?: string
|
||||
borderColor?: string
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
const props = withDefaults(defineProps<ThemeBadge>(), {
|
||||
type: 'tip',
|
||||
borderColor: 'transparent',
|
||||
})
|
||||
|
||||
@ -149,6 +149,7 @@ function resolveSidebarItems(
|
||||
navLink.link = link.startsWith('---') ? link : normalizeLink(_prefix, link)
|
||||
const nav = resolveNavLink(navLink.link)
|
||||
navLink.icon = nav.icon || navLink.icon
|
||||
navLink.badge = nav.badge || navLink.badge
|
||||
}
|
||||
const nextPrefix = normalizePrefix(_prefix, prefix || dir)
|
||||
if (items === 'auto') {
|
||||
@ -157,6 +158,7 @@ function resolveSidebarItems(
|
||||
navLink.link = normalizeLink(autoHomeData.value[nextPrefix])
|
||||
const nav = resolveNavLink(navLink.link)
|
||||
navLink.icon = nav.icon || navLink.icon
|
||||
navLink.badge = nav.badge || navLink.badge
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ResolvedNavItemWithLink } from '../../shared/index.js'
|
||||
import type { ResolvedNavItemWithLink, ThemeBadge } from '../../shared/index.js'
|
||||
import {
|
||||
ensureEndingSlash,
|
||||
ensureLeadingSlash,
|
||||
@ -18,6 +18,7 @@ export function resolveNavLink(link: string): ResolvedNavItemWithLink {
|
||||
const { notFound, meta, path } = resolveRoute<{
|
||||
title?: string
|
||||
icon?: string
|
||||
badge?: string | ThemeBadge
|
||||
}>(link)
|
||||
|
||||
return notFound
|
||||
@ -26,6 +27,7 @@ export function resolveNavLink(link: string): ResolvedNavItemWithLink {
|
||||
text: meta.title || path,
|
||||
link: path,
|
||||
icon: meta.icon,
|
||||
badge: meta.badge,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,10 @@ function cleanPageData(page: Page<ThemePageData>) {
|
||||
page.routeMeta.icon = page.frontmatter.icon
|
||||
}
|
||||
|
||||
if (page.frontmatter.badge) {
|
||||
page.routeMeta.badge = page.frontmatter.badge
|
||||
}
|
||||
|
||||
if (page.frontmatter.home) {
|
||||
page.frontmatter.pageLayout = 'home'
|
||||
delete page.frontmatter.home
|
||||
|
||||
@ -20,3 +20,14 @@ export type ThemeColor = string | { light: string, dark: string }
|
||||
* 页内 heading 导航栏
|
||||
*/
|
||||
export type ThemeOutline = false | number | [number, number] | 'deep'
|
||||
|
||||
/**
|
||||
* 徽章
|
||||
*/
|
||||
export interface ThemeBadge {
|
||||
text?: string
|
||||
type?: string
|
||||
color?: string
|
||||
bgColor?: string
|
||||
borderColor?: string
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ThemeIcon } from '../common/index.js'
|
||||
import type { ThemeBadge, ThemeIcon } from '../common/index.js'
|
||||
|
||||
/**
|
||||
* 导航项
|
||||
@ -19,6 +19,11 @@ export interface NavItemWithLink {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 当前分组的页面前缀
|
||||
*/
|
||||
@ -57,6 +62,11 @@ export interface NavItemChildren {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 导航栏下拉菜单
|
||||
*/
|
||||
@ -75,6 +85,11 @@ export interface NavItemWithChildren {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 导航栏下拉菜单
|
||||
*/
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ThemeIcon } from '../common/index.js'
|
||||
import type { ThemeBadge, ThemeIcon } from '../common/index.js'
|
||||
|
||||
export type ThemeSidebar = 'auto' | (string | ThemeSidebarItem)[] | ThemeSidebarMulti
|
||||
|
||||
@ -25,6 +25,11 @@ export interface ThemeSidebarItem {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 侧边栏徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 次级侧边栏分组
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { WatermarkPluginFrontmatter } from '@vuepress/plugin-watermark'
|
||||
import type { ThemeOutline } from '../common/index.js'
|
||||
import type { ThemeBadge, ThemeIcon, ThemeOutline } from '../common/index.js'
|
||||
import type { NavItemWithLink } from '../features/index.js'
|
||||
import type { ThemeNormalFrontmatter } from './normal.js'
|
||||
|
||||
@ -66,13 +66,10 @@ export interface ThemePageFrontmatter extends ThemeNormalFrontmatter {
|
||||
* 支持 本地、远程 svg 图标,直接使用 svg 的 url 即可
|
||||
* 或直接传入 svg 字符串
|
||||
*/
|
||||
icon?: string | { svg: string }
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 标题徽章
|
||||
*/
|
||||
badge?: string | {
|
||||
text: string
|
||||
type?: 'info' | 'tip' | 'warning' | 'danger'
|
||||
}
|
||||
badge?: string | ThemeBadge
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ThemeIcon } from '../common/index.js'
|
||||
import type { ThemeBadge, ThemeIcon } from '../common/index.js'
|
||||
|
||||
/**
|
||||
* 主题内部使用的已解析的导航项
|
||||
@ -16,6 +16,7 @@ export interface ResolvedNavItemWithLink {
|
||||
text: string
|
||||
link: string
|
||||
icon?: ThemeIcon
|
||||
badge?: string | ThemeBadge
|
||||
items?: never
|
||||
activeMatch?: string
|
||||
rel?: string
|
||||
@ -30,6 +31,7 @@ export interface ResolvedNavItemWithLink {
|
||||
export interface ResolvedNavItemChildren {
|
||||
text?: string
|
||||
icon?: ThemeIcon
|
||||
badge?: string | ThemeBadge
|
||||
items: ResolvedNavItemWithLink[]
|
||||
}
|
||||
|
||||
@ -40,6 +42,7 @@ export interface ResolvedNavItemChildren {
|
||||
export interface ResolvedNavItemWithChildren {
|
||||
text?: string
|
||||
icon?: ThemeIcon
|
||||
badge?: string | ThemeBadge
|
||||
items: (ResolvedNavItemChildren | ResolvedNavItemWithLink)[]
|
||||
activeMatch?: string
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ThemeIcon } from '../common/index.js'
|
||||
import type { ThemeBadge, ThemeIcon } from '../common/index.js'
|
||||
|
||||
/**
|
||||
* 已解析的侧边栏
|
||||
@ -35,6 +35,11 @@ export interface ResolvedSidebarItem {
|
||||
*/
|
||||
icon?: ThemeIcon
|
||||
|
||||
/**
|
||||
* 侧边栏徽章
|
||||
*/
|
||||
badge?: string | ThemeBadge
|
||||
|
||||
/**
|
||||
* 次级侧边栏分组
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user