naive-ui/demo/SiteHeader.vue

558 lines
14 KiB
Vue
Raw Normal View History

2019-09-17 19:28:28 +08:00
<template>
2021-04-05 17:59:04 +08:00
<n-layout-header bordered class="nav" :style="style">
<n-text tag="div" class="ui-logo" :depth="1" @click="handleLogoClick">
<img src="./assets/images/naivelogo.svg" />
2021-04-06 01:31:09 +08:00
<span v-if="!isXs">Naive UI</span>
2021-04-05 17:59:04 +08:00
</n-text>
2021-04-06 01:31:09 +08:00
<div :style="!isXs ? 'display: flex; align-items: center;' : ''">
<div class="nav-menu" v-if="!isS">
2021-04-05 17:59:04 +08:00
<n-menu
mode="horizontal"
:value="menuValue"
:options="menuOptions"
@update:value="handleMenuUpdateValue"
2020-03-03 19:25:25 +08:00
/>
</div>
2021-04-05 17:59:04 +08:00
<n-auto-complete
v-model:value="searchPattern"
2021-04-06 01:31:09 +08:00
:style="!isXs ? 'width: 216px; margin-left: 24px' : undefined"
2021-04-05 17:59:04 +08:00
:placeholder="t('searchPlaceholder')"
:options="searchOptions"
clear-after-select
blur-after-select
@select="handleSearch"
/>
</div>
2021-04-06 01:31:09 +08:00
<n-popover
v-if="isXs"
style="padding: 0; width: 288px"
placement="bottom-end"
display-directive="show"
trigger="click"
>
<template #trigger>
<n-icon size="20" style="margin-left: 12px"><menu-outline /></n-icon>
</template>
2021-04-06 18:06:04 +08:00
<div style="overflow: auto; max-height: 79vh">
2021-04-06 01:31:09 +08:00
<n-menu
:value="xsMenuValue"
:options="xsMenuOptions"
:indent="18"
@update:value="handleUpdateXsMenu"
/>
</div>
</n-popover>
<n-popover
v-else-if="isS"
style="padding: 0; width: 288px"
placement="bottom-end"
display-directive="show"
trigger="hover"
>
<template #trigger>
<n-icon size="20" style="margin-left: 12px"><menu-outline /></n-icon>
</template>
2021-04-06 18:06:04 +08:00
<div style="overflow: auto; max-height: 75vh">
2021-04-06 01:31:09 +08:00
<n-menu
:value="sMenuValue"
:options="sMenuOptions"
:indent="18"
@update:value="handleUpdateSMenu"
/>
</div>
</n-popover>
<div style="display: flex" v-else-if="isM">
<n-popover
style="padding: 0; width: 180px"
placement="bottom-end"
display-directive="show"
trigger="hover"
>
<template #trigger>
<n-icon size="20" style="margin-left: 12px"><menu-outline /></n-icon>
</template>
<n-menu
:value="mMenuValue"
:options="mMenuOptions"
:indent="18"
@update:value="handleUpdateMMenu"
/>
</n-popover>
</div>
<div style="display: flex" v-else>
2021-04-05 17:59:04 +08:00
<n-button size="small" class="nav-picker" @click="handleThemeUpdate">
{{ themeLabelMap[theme] }}
</n-button>
<n-popselect
:options="localeOptions"
v-model:value="locale"
overlap
placement="top"
trigger="click"
>
<n-button size="small" class="nav-picker">
{{ localeLabelMap[locale] }}
</n-button>
2021-04-05 17:59:04 +08:00
</n-popselect>
<n-popselect
v-if="tusimple || dev"
:options="configProviderOptions"
v-model:value="configProviderName"
overlap
placement="top"
trigger="click"
>
<n-button size="small" class="nav-picker">
{{ cfgProviderLabelMap[configProviderName] }}
2020-11-28 14:33:04 +08:00
</n-button>
2021-04-05 17:59:04 +08:00
</n-popselect>
<n-popselect
v-if="dev"
:options="displayModeOptions"
v-model:value="displayMode"
overlap
placement="top"
trigger="click"
>
<n-button size="small" class="nav-picker">{{
displayModeLabelMap[displayMode]
}}</n-button>
</n-popselect>
<n-button size="small">
{{ version }}
</n-button>
</div>
2020-03-03 19:25:25 +08:00
</n-layout-header>
2019-09-17 19:28:28 +08:00
</template>
<script>
import { computed, ref } from 'vue'
2021-04-05 17:59:04 +08:00
import { useRouter, useRoute } from 'vue-router'
import { useMessage, version } from 'naive-ui'
2021-04-05 17:59:04 +08:00
import { MenuOutline } from '@vicons/ionicons5'
2021-04-06 01:31:09 +08:00
import { i18n, useIsXs, useIsM, useIsS } from './utils/composables'
2021-04-05 17:59:04 +08:00
import { findMenuValue } from './utils/route'
2020-12-12 13:51:22 +08:00
import {
2021-01-13 12:01:02 +08:00
useThemeName,
useLocaleName,
useDisplayMode,
2021-02-17 23:31:56 +08:00
useFlattenedDocOptions,
2021-04-05 17:59:04 +08:00
useConfigProviderName,
useDocOptions,
useComponentOptions
2021-01-13 12:01:02 +08:00
} from './store'
2019-09-17 19:28:28 +08:00
2021-04-05 17:59:04 +08:00
// match substr
2020-02-26 17:21:03 +08:00
function match (pattern, string) {
if (!pattern.length) return true
if (!string.length) return false
if (pattern[0] === string[0]) return match(pattern.slice(1), string.slice(1))
return match(pattern, string.slice(1))
}
2021-04-05 17:59:04 +08:00
const locales = {
'zh-CN': {
dark: '深色',
light: '浅色',
searchPlaceholder: '搜索',
home: '首页',
doc: '文档',
component: '组件',
common: '常规',
debug: '调试',
alreadyHome: '别点了,你已经在首页了',
tusimpleTheme: '图森主题',
defaultTheme: '默认主题'
},
'en-US': {
dark: 'Dark',
light: 'Light',
searchPlaceholder: 'Search',
home: 'Home',
doc: 'Docs',
component: 'Components',
common: 'Common',
debug: 'Debug',
alreadyHome: 'You are already in home page. No clicking anymore.',
tusimpleTheme: 'Tusimple Theme',
defaultTheme: 'Default Theme'
}
}
2019-09-17 19:28:28 +08:00
export default {
2020-09-27 22:27:25 +08:00
name: 'SiteHeader',
2021-04-05 17:59:04 +08:00
components: {
MenuOutline
},
2020-09-27 22:27:25 +08:00
setup () {
2021-03-26 01:09:16 +08:00
const message = useMessage()
2021-04-05 17:59:04 +08:00
const route = useRoute()
const router = useRouter()
// i18n
const { t } = i18n(locales)
// menu
const menuOptionsRef = computed(() => {
2020-10-07 20:45:51 +08:00
return [
{
2021-02-14 14:52:14 +08:00
key: 'home',
2020-10-07 20:45:51 +08:00
title: t('home')
},
{
2021-02-14 14:52:14 +08:00
key: 'doc',
2020-10-07 20:45:51 +08:00
title: t('doc')
2021-02-14 14:52:14 +08:00
},
{
key: 'component',
title: t('component')
2020-10-07 20:45:51 +08:00
}
]
})
2021-04-05 17:59:04 +08:00
const themeAndLocaleReg = /^(\/[^/]+){2}/
function handleMenuUpdateValue (value) {
if (value === 'home') {
router.push(themeAndLocaleReg.exec(route.path)[0])
}
if (value === 'doc') {
if (!/^(\/[^/]+){2}\/docs/.test(route.path)) {
router.push(
2021-04-19 21:47:29 +08:00
themeAndLocaleReg.exec(route.path)[0] + '/docs/introduction'
2021-04-05 17:59:04 +08:00
)
}
}
if (value === 'component') {
if (!/^(\/[^/]+){2}\/components/.test(route.path)) {
router.push(
themeAndLocaleReg.exec(route.path)[0] + '/components/button'
2021-04-05 17:59:04 +08:00
)
}
2020-10-07 20:45:51 +08:00
}
2021-04-05 17:59:04 +08:00
}
const menuValueRef = computed(() => {
if (/\/docs\//.test(route.path)) return 'doc'
if (/\/components\//.test(route.path)) return 'component'
else if (route.name === 'home') return 'home'
return null
})
2021-04-06 01:31:09 +08:00
// m options
const mMenuOptionsRef = computed(() => [
{
key: 'theme',
title: themeLabelMapRef.value[themeNameRef.value]
},
{
key: 'locale',
title: localeNameRef.value === 'zh-CN' ? 'English' : '中文'
}
])
function handleUpdateMMenu (value, { path }) {
if (value === 'theme') {
handleThemeUpdate()
} else if (value === 'locale') {
if (localeNameRef.value === 'zh-CN') {
localeNameRef.value = 'en-US'
} else {
localeNameRef.value = 'zh-CN'
}
}
}
// s opitions
const sMenuOptionsRef = computed(() => {
return [
{
key: 'theme',
title: themeLabelMapRef.value[themeNameRef.value]
},
{
key: 'locale',
title: localeNameRef.value === 'zh-CN' ? 'English' : '中文'
},
{
key: 'home',
title: t('home')
},
{
key: 'doc',
title: t('doc')
},
{
key: 'component',
title: t('component')
}
]
})
function handleUpdateSMenu (value) {
if (value === 'theme') {
handleThemeUpdate()
} else if (value === 'locale') {
if (localeNameRef.value === 'zh-CN') {
localeNameRef.value = 'en-US'
} else {
localeNameRef.value = 'zh-CN'
}
} else {
handleMenuUpdateValue(value)
}
}
// xs options
2021-04-05 17:59:04 +08:00
const docOptionsRef = useDocOptions()
const componentOptionsRef = useComponentOptions()
2021-04-06 01:31:09 +08:00
const xsMenuOptionsRef = computed(() => {
2021-04-05 17:59:04 +08:00
return [
{
key: 'theme',
title: themeLabelMapRef.value[themeNameRef.value]
},
{
key: 'locale',
title: localeNameRef.value === 'zh-CN' ? 'English' : '中文'
},
{
key: 'home',
title: t('home')
},
{
key: 'doc',
title: t('doc'),
children: docOptionsRef.value
},
{
key: 'component',
title: t('component'),
children: componentOptionsRef.value
}
]
})
2021-04-06 01:31:09 +08:00
const xsMenuValueRef = computed(() => {
2021-04-05 20:06:50 +08:00
if (route.name === 'home') return 'home'
2021-04-06 01:31:09 +08:00
return findMenuValue(xsMenuOptionsRef.value, route.path)
2021-04-05 17:59:04 +08:00
})
2021-04-06 01:31:09 +08:00
function handleUpdateXsMenu (value, { path }) {
2021-04-05 17:59:04 +08:00
if (value === 'theme') {
handleThemeUpdate()
} else if (value === 'locale') {
if (localeNameRef.value === 'zh-CN') {
localeNameRef.value = 'en-US'
} else {
localeNameRef.value = 'zh-CN'
}
} else if (path) {
router.push(path)
} else {
handleMenuUpdateValue(value)
}
}
// theme
const themeNameRef = useThemeName()
const themeLabelMapRef = computed(() => ({
dark: t('light'),
light: t('dark')
2020-10-07 20:45:51 +08:00
}))
2021-04-05 17:59:04 +08:00
function handleThemeUpdate () {
if (themeNameRef.value === 'dark') {
themeNameRef.value = 'light'
} else {
themeNameRef.value = 'dark'
}
}
// locale
const localeNameRef = useLocaleName()
const localeLabelMap = {
'zh-CN': 'English',
'en-US': '中文'
2021-04-05 17:59:04 +08:00
}
const localeOptions = [
{
label: 'English',
value: 'en-US'
},
{
label: '中文',
value: 'zh-CN'
}
]
// display mode
const displayModeRef = useDisplayMode()
const displayModeLabelMap = {
common: 'Prod',
debug: 'Debug'
}
const displayModeOptions = [
{
label: 'Prod',
value: 'common'
},
{
label: 'Debug',
value: 'debug'
}
]
// config provider
const configProviderNameRef = useConfigProviderName()
const cfgProviderLabelMapRef = computed(() => ({
2021-03-03 17:26:54 +08:00
tusimple: t('tusimpleTheme'),
default: t('defaultTheme')
}))
const configProviderOptionsRef = computed(() => [
{
label: t('defaultTheme'),
value: 'default'
},
{
label: t('tusimpleTheme'),
value: 'tusimple'
}
])
2021-04-05 17:59:04 +08:00
// search
const searchableOptionsRef = useFlattenedDocOptions()
const searchPatternRef = ref('')
const searchOptionsRef = computed(() => {
2020-02-11 18:10:49 +08:00
function getLabel (item) {
2021-02-14 15:19:32 +08:00
if (item.label) {
return item.label + (item.extra ? ' ' + item.extra : '')
2020-12-12 15:33:41 +08:00
}
2021-02-14 15:19:32 +08:00
return item.key
2020-02-11 18:10:49 +08:00
}
2021-04-05 17:59:04 +08:00
if (!searchPatternRef.value) return []
2020-02-11 18:10:49 +08:00
const replaceRegex = / |-/g
2021-04-05 17:59:04 +08:00
return searchableOptionsRef.value
2020-12-12 13:51:22 +08:00
.filter((item) => {
2021-04-05 17:59:04 +08:00
const pattern = searchPatternRef.value
2020-12-12 13:51:22 +08:00
.toLowerCase()
.replace(replaceRegex, '')
.slice(0, 20)
const label = getLabel(item).toLowerCase().replace(replaceRegex, '')
return match(pattern, label)
})
.map((item) => ({
label: getLabel(item),
value: item.path
}))
2021-04-05 17:59:04 +08:00
})
function handleSearch (value) {
router.push(value)
2019-09-23 11:32:50 +08:00
}
2021-04-05 17:59:04 +08:00
// common
2021-04-06 01:31:09 +08:00
const isXsRef = useIsXs()
2021-04-05 17:59:04 +08:00
function handleLogoClick () {
if (/^(\/[^/]+){2}$/.test(route.path)) {
message.info(t('alreadyHome'))
2020-09-27 22:27:25 +08:00
return
}
2021-04-05 17:59:04 +08:00
router.push(/^(\/[^/]+){2}/.exec(route.path)[0])
}
return {
2021-04-06 01:31:09 +08:00
// xsMenuOptions,
2021-04-05 17:59:04 +08:00
tusimple: process.env.TUSIMPLE,
dev: __DEV__,
message,
t,
version,
2021-04-06 01:31:09 +08:00
isXs: isXsRef,
isM: useIsM(),
isS: useIsS(),
2021-04-05 17:59:04 +08:00
// theme
theme: themeNameRef,
handleThemeUpdate,
themeLabelMap: themeLabelMapRef,
// displayMode
displayMode: displayModeRef,
displayModeLabelMap,
displayModeOptions,
// locale
locale: localeNameRef,
localeLabelMap,
localeOptions,
// configProvider
configProviderName: configProviderNameRef,
configProviderOptions: configProviderOptionsRef,
cfgProviderLabelMap: cfgProviderLabelMapRef,
2021-04-05 17:59:04 +08:00
// search
searchPattern: searchPatternRef,
searchOptions: searchOptionsRef,
handleSearch,
// menu
menuOptions: menuOptionsRef,
menuValue: menuValueRef,
handleMenuUpdateValue,
2021-04-06 01:31:09 +08:00
// m menu
mMenuOptions: mMenuOptionsRef,
handleUpdateMMenu,
mMenuValue: null,
// s menu
sMenuOptions: sMenuOptionsRef,
handleUpdateSMenu,
sMenuValue: menuValueRef,
// xs menu
xsMenuOptions: xsMenuOptionsRef,
handleUpdateXsMenu,
xsMenuValue: xsMenuValueRef,
2021-04-05 17:59:04 +08:00
// common
handleLogoClick,
style: computed(() => {
2021-04-06 01:31:09 +08:00
return isXsRef.value
2021-04-05 17:59:04 +08:00
? {
'--side-padding': '16px',
'grid-template-columns': 'auto 1fr auto'
}
: {
'--side-padding': '32px',
'grid-template-columns':
'calc(272px - var(--side-padding)) 1fr auto'
}
})
2019-09-17 19:28:28 +08:00
}
}
}
</script>
2020-11-01 19:35:00 +08:00
<style scoped>
2019-09-17 19:28:28 +08:00
.nav {
display: grid;
2020-02-27 18:09:23 +08:00
grid-template-rows: 63px;
2019-09-17 19:28:28 +08:00
align-items: center;
2021-04-05 17:59:04 +08:00
padding: 0 var(--side-padding);
2019-09-17 19:28:28 +08:00
}
2019-09-17 19:28:28 +08:00
.ui-logo {
2020-02-27 23:03:15 +08:00
cursor: pointer;
2019-10-20 00:18:55 +08:00
display: flex;
align-items: center;
font-size: 18px;
}
2019-10-20 00:18:55 +08:00
.ui-logo > img {
margin-right: 12px;
height: 32px;
width: 32px;
2019-09-17 19:28:28 +08:00
}
2020-02-27 18:09:23 +08:00
.nav-menu {
2020-11-28 13:34:45 +08:00
padding-left: 36px;
2020-02-27 18:09:23 +08:00
}
2020-09-17 10:43:29 +08:00
2020-03-04 14:34:14 +08:00
.nav-picker {
margin-right: 12px;
2020-11-01 19:35:00 +08:00
}
.nav-picker:last-child {
margin-right: 0;
2019-09-17 19:28:28 +08:00
}
</style>
2020-11-14 20:38:30 +08:00
<style>
.nav-menu .n-menu-item {
height: 63px !important;
}
</style>