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