mirror of https://github.com/vuejs/vitepress
feat: allow using components in navigation bar (#4000)
--------- Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>pull/4028/head
parent
fa81e89643
commit
fa87d8150d
@ -0,0 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
|
||||
const props = defineProps<{
|
||||
options: string[]
|
||||
defaultOption: string
|
||||
screenMenu?: boolean
|
||||
}>()
|
||||
|
||||
// reactivity isn't needed for props here
|
||||
|
||||
const key = removeSpaces(`api-preference-${props.options.join('-')}`)
|
||||
const name = key + (props.screenMenu ? '-screen-menu' : '')
|
||||
|
||||
const selected = useLocalStorage(key, () => props.defaultOption)
|
||||
|
||||
const optionsWithKeys = props.options.map((option) => ({
|
||||
key: name + '-' + removeSpaces(option),
|
||||
value: option
|
||||
}))
|
||||
|
||||
function removeSpaces(str: string) {
|
||||
return str.replace(/\s/g, '_')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="VPApiPreference" :class="{ 'screen-menu': screenMenu }">
|
||||
<template v-for="option in optionsWithKeys" :key="option">
|
||||
<input
|
||||
type="radio"
|
||||
:id="option.key"
|
||||
:name="name"
|
||||
:value="option.value"
|
||||
v-model="selected"
|
||||
/>
|
||||
<label :for="option.key">{{ option.value }}</label>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPApiPreference {
|
||||
display: flex;
|
||||
margin: 12px 0;
|
||||
border: 1px solid var(--vp-c-border);
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.VPApiPreference:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.VPApiPreference:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.VPApiPreference.screen-menu {
|
||||
margin: 12px 0 0 12px;
|
||||
}
|
||||
|
||||
.VPApiPreference input[type='radio'] {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.VPApiPreference label {
|
||||
flex: 1;
|
||||
margin: 2px;
|
||||
padding: 4px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.VPApiPreference input[type='radio']:checked + label {
|
||||
background-color: var(--vp-c-default-soft);
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
</style>
|
@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vitepress'
|
||||
import VPNavBarMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavBarMenuGroup.vue'
|
||||
import VPNavScreenMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavScreenMenuGroup.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
versions: { text: string; link: string }[]
|
||||
screenMenu?: boolean
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const sortedVersions = computed(() => {
|
||||
return [...props.versions].sort(
|
||||
(a, b) => b.link.split('/').length - a.link.split('/').length
|
||||
)
|
||||
})
|
||||
|
||||
const currentVersion = computed(() => {
|
||||
return (
|
||||
sortedVersions.value.find((version) => route.path.startsWith(version.link))
|
||||
?.text || 'Versions'
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VPNavBarMenuGroup
|
||||
v-if="!screenMenu"
|
||||
:item="{ text: currentVersion, items: versions }"
|
||||
class="VPNavVersion"
|
||||
/>
|
||||
<VPNavScreenMenuGroup
|
||||
v-else
|
||||
:text="currentVersion"
|
||||
:items="versions"
|
||||
class="VPNavVersion"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPNavVersion :deep(button .text) {
|
||||
color: var(--vp-c-text-1) !important;
|
||||
}
|
||||
|
||||
.VPNavVersion:hover :deep(button .text) {
|
||||
color: var(--vp-c-text-2) !important;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,12 @@
|
||||
import type { Theme } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import ApiPreference from './components/ApiPreference.vue'
|
||||
import NavVersion from './components/NavVersion.vue'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
app.component('ApiPreference', ApiPreference)
|
||||
app.component('NavVersion', NavVersion)
|
||||
}
|
||||
} satisfies Theme
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue