mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
feat(theme): add component <NpmBadge />
This commit is contained in:
parent
46b382e0b3
commit
aa96c35bd5
35
theme/src/client/features/components/NpmBadge.vue
Normal file
35
theme/src/client/features/components/NpmBadge.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { toRef } from 'vue'
|
||||
import type { NpmBadgeOptions } from '../composables/npm-badge.js'
|
||||
import { useNpmBadge } from '../composables/npm-badge.js'
|
||||
|
||||
const props = defineProps<NpmBadgeOptions>()
|
||||
|
||||
const info = useNpmBadge(toRef(() => props))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="vp-npm-badge">
|
||||
<img v-if="!info.link" :src="info.badgeUrl" :alt="info.alt">
|
||||
<a v-else :href="info.link" target="_blank" rel="noreferrer">
|
||||
<img :src="info.badgeUrl" :alt="info.alt">
|
||||
</a>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.vp-npm-badge {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
:where(div,p,h2,h3,h4,h5,h6,li):not(.vp-npm-badge-group) > .vp-npm-badge + .vp-npm-badge {
|
||||
margin-inline-start: 8px;
|
||||
}
|
||||
|
||||
.vp-npm-badge a {
|
||||
display: inline-flex;
|
||||
text-decoration: none;
|
||||
text-underline-offset: 0;
|
||||
}
|
||||
</style>
|
||||
37
theme/src/client/features/components/NpmBadgeGroup.vue
Normal file
37
theme/src/client/features/components/NpmBadgeGroup.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, toRef } from 'vue'
|
||||
import type { NpmBadgeGroupOptions, NpmBadgeType } from '../composables/npm-badge.js'
|
||||
import { useNpmBadgeGroup } from '../composables/npm-badge.js'
|
||||
import NpmBadge from './NpmBadge.vue'
|
||||
|
||||
const props = defineProps<NpmBadgeGroupOptions>()
|
||||
|
||||
useNpmBadgeGroup(toRef(() => props))
|
||||
|
||||
const list = computed(() => {
|
||||
if (!props.items)
|
||||
return []
|
||||
|
||||
if (Array.isArray(props.items))
|
||||
return props.items
|
||||
|
||||
return props.items.split(',').map(type => type.trim()) as NpmBadgeType[]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p class="vp-npm-badge-group">
|
||||
<slot>
|
||||
<NpmBadge v-for="(type, index) in list" :key="type + index" :type="type" />
|
||||
</slot>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.vp-npm-badge-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
175
theme/src/client/features/composables/npm-badge.ts
Normal file
175
theme/src/client/features/composables/npm-badge.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import { computed, inject, provide, ref, toValue } from 'vue'
|
||||
import type { ComputedRef, InjectionKey, Ref } from 'vue'
|
||||
|
||||
const DEFAULT_COLOR = '#32A9C3'
|
||||
const DEFAULT_LABEL_COLOR = '#1B3C4A'
|
||||
const BADGE_URL = 'https://img.shields.io'
|
||||
const GITHUB_URL = 'https://github.com'
|
||||
const NPM_URL = 'https://www.npmjs.com/package'
|
||||
|
||||
export type NpmBadgeType =
|
||||
// github
|
||||
| 'source' // github source
|
||||
| 'stars' // github stars
|
||||
| 'forks' // github forks
|
||||
| 'license' // github license
|
||||
// npm
|
||||
| 'version' // npm version
|
||||
| 'dt' // alias d18m
|
||||
| 'd18m' // npm downloads last 18 months
|
||||
| 'dw' // npm downloads weekly
|
||||
| 'dm' // npm downloads monthly
|
||||
| 'dy' // npm downloads yearly
|
||||
|
||||
export type NpmBadgeTheme = 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' | 'social'
|
||||
|
||||
export interface NpmBadgeBaseOptions {
|
||||
// npm package name
|
||||
name?: string
|
||||
// github repo
|
||||
repo?: string
|
||||
// github branch
|
||||
branch?: string
|
||||
// github directory
|
||||
dir?: string
|
||||
// text color
|
||||
color?: string
|
||||
// label color
|
||||
labelColor?: string
|
||||
// badge style
|
||||
theme?: NpmBadgeTheme
|
||||
}
|
||||
|
||||
export interface NpmBadgeOptions extends NpmBadgeBaseOptions {
|
||||
type: NpmBadgeType
|
||||
// label text
|
||||
label?: string
|
||||
}
|
||||
|
||||
export interface NpmBadgeGroupOptions extends Omit<NpmBadgeBaseOptions, 'label'> {
|
||||
items?: string | NpmBadgeType | NpmBadgeType[]
|
||||
}
|
||||
|
||||
export interface NpmBadgeInfo {
|
||||
badgeUrl: string
|
||||
link?: string
|
||||
alt?: string
|
||||
}
|
||||
|
||||
type NpmBadgeBaseOptionsRef = Ref<NpmBadgeBaseOptions>
|
||||
|
||||
const NpmBadgeSymbol: InjectionKey<NpmBadgeBaseOptionsRef> = Symbol(__VUEPRESS_DEV__ ? 'NpmBadge' : '')
|
||||
|
||||
export function useNpmBadge(opt: Ref<NpmBadgeOptions>): ComputedRef<NpmBadgeInfo> {
|
||||
const parentOpt = inject(NpmBadgeSymbol, ref({}) as NpmBadgeBaseOptionsRef)
|
||||
|
||||
return computed(() => {
|
||||
const po = toValue(parentOpt)
|
||||
const o = toValue(opt)
|
||||
const res: NpmBadgeOptions = {
|
||||
name: o.name || po.name,
|
||||
repo: o.repo || po.repo,
|
||||
branch: o.branch || po.branch,
|
||||
dir: o.dir || po.dir,
|
||||
type: o.type,
|
||||
color: o.color || po.color,
|
||||
label: o.label,
|
||||
labelColor: o.labelColor || po.labelColor,
|
||||
theme: o.theme || po.theme,
|
||||
}
|
||||
return resolveNpmBadgeOptions(res)
|
||||
})
|
||||
}
|
||||
|
||||
export function useNpmBadgeGroup(opt: Ref<NpmBadgeGroupOptions>) {
|
||||
const baseOptions = computed<NpmBadgeBaseOptions>(() => {
|
||||
const o = toValue(opt)
|
||||
return {
|
||||
name: o.name,
|
||||
repo: o.repo,
|
||||
branch: o.branch,
|
||||
dir: o.dir,
|
||||
color: o.color,
|
||||
labelColor: o.labelColor,
|
||||
theme: o.theme,
|
||||
}
|
||||
})
|
||||
|
||||
provide(NpmBadgeSymbol, baseOptions)
|
||||
}
|
||||
|
||||
function resolveNpmBadgeOptions(options: NpmBadgeOptions): NpmBadgeInfo {
|
||||
let { name = '', repo = '', branch = 'main', dir = '', type, color, label, labelColor, theme = '' } = options
|
||||
name = name || repo.split('/')?.[1] || ''
|
||||
const normalizeName = encodeURIComponent(name)
|
||||
|
||||
const githubLink = repo ? `${GITHUB_URL}/${repo}${dir ? `/tree/${branch}/${dir}` : ''}` : ''
|
||||
const npmLink = `${NPM_URL}/${name}`
|
||||
|
||||
const params = new URLSearchParams()
|
||||
|
||||
if (type !== 'source' && type !== 'stars' && type !== 'forks') {
|
||||
params.append('style', theme || 'flat')
|
||||
params.append('color', color || DEFAULT_COLOR)
|
||||
params.append('labelColor', labelColor || DEFAULT_LABEL_COLOR)
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'source': {
|
||||
params.append('logo', 'github')
|
||||
params.append('color', labelColor || DEFAULT_LABEL_COLOR)
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/badge/source-a?${params.toString()}`,
|
||||
link: githubLink,
|
||||
alt: 'github source',
|
||||
}
|
||||
}
|
||||
case 'stars':
|
||||
case 'forks': {
|
||||
params.append('style', theme || 'social')
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/github/${type}/${repo}?${params.toString()}`,
|
||||
link: githubLink,
|
||||
alt: `github ${type}`,
|
||||
}
|
||||
}
|
||||
case 'license':
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/github/license/${repo}?${params.toString()}`,
|
||||
link: githubLink,
|
||||
alt: 'license',
|
||||
}
|
||||
case 'version': {
|
||||
params.append('label', label || name || 'npm')
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/npm/v/${normalizeName}?${params.toString()}`,
|
||||
link: npmLink,
|
||||
alt: 'npm version',
|
||||
}
|
||||
}
|
||||
case 'dt':
|
||||
case 'd18m': {
|
||||
params.append('label', label || 'downloads')
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/npm/d18m/${normalizeName}?${params.toString()}`,
|
||||
link: npmLink,
|
||||
alt: 'npm downloads',
|
||||
}
|
||||
}
|
||||
case 'dm':
|
||||
case 'dy':
|
||||
case 'dw': {
|
||||
params.append('label', label || 'downloads')
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/npm/${type}/${normalizeName}?${params.toString()}`,
|
||||
link: npmLink,
|
||||
alt: 'npm downloads',
|
||||
}
|
||||
}
|
||||
default:
|
||||
return {
|
||||
badgeUrl: `${BADGE_URL}/badge/unknown?${params.toString()}`,
|
||||
alt: 'unknown',
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user