mirror of https://github.com/YunYouJun/valaxy
feat(theme-press): add menu toc in mobile, close #236
This commit is contained in:
parent
52f4734fd0
commit
962cb25a3f
|
@ -258,7 +258,7 @@ You can group multiple code blocks like this:
|
|||
|
||||
```js [config.js]
|
||||
/**
|
||||
* @type {import('vitepress').UserConfig}
|
||||
* @type {import('valaxy').UserConfig}
|
||||
*/
|
||||
const config = {
|
||||
// ...
|
||||
|
@ -268,7 +268,7 @@ export default config
|
|||
```
|
||||
|
||||
```ts [config.ts]
|
||||
import type { UserConfig } from 'vitepress'
|
||||
import type { UserConfig } from 'valaxy'
|
||||
|
||||
const config: UserConfig = {
|
||||
// ...
|
||||
|
@ -286,7 +286,7 @@ export default config
|
|||
|
||||
```js [config.js]
|
||||
/**
|
||||
* @type {import('vitepress').UserConfig}
|
||||
* @type {import('valaxy').UserConfig}
|
||||
*/
|
||||
const config = {
|
||||
// ...
|
||||
|
@ -296,7 +296,7 @@ export default config
|
|||
```
|
||||
|
||||
```ts [config.ts]
|
||||
import type { UserConfig } from 'vitepress'
|
||||
import type { UserConfig } from 'valaxy'
|
||||
|
||||
const config: UserConfig = {
|
||||
// ...
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
[0;90m┌[0m [0;36;1mWelcome to VitePress![0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Where should VitePress initialize the config?[0m
|
||||
[0;90m│[0m [0;2m./docs[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Site title:[0m
|
||||
[0;90m│[0m [0;2mMy Awesome Project[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Site description:[0m
|
||||
[0;90m│[0m [0;2mA VitePress Site[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;36m◆[0m Theme:[0m
|
||||
[0;36m│[0m [0;32m●[0m Default Theme [0;2m(Out of the box, good-looking docs)[0m[0m
|
||||
[0;36m│[0m [0;2m○[0m [0;2mDefault Theme + Customization[0m[0m
|
||||
[0;36m│[0m [0;2m○[0m [0;2mCustom Theme[0m[0m
|
||||
[0;36m└[0m
|
|
@ -13,10 +13,3 @@ pnpm run build
|
|||
# start docs server
|
||||
pnpm run docs
|
||||
```
|
||||
|
||||
Migrate to VitePress.
|
||||
|
||||
```bash
|
||||
# start vitepress docs
|
||||
pnpm run docs:dev
|
||||
```
|
||||
|
|
|
@ -264,7 +264,7 @@ You can group multiple code blocks like this:
|
|||
|
||||
```js [config.js]
|
||||
/**
|
||||
* @type {import('vitepress').UserConfig}
|
||||
* @type {import('valaxy').UserConfig}
|
||||
*/
|
||||
const config = {
|
||||
// ...
|
||||
|
@ -274,7 +274,7 @@ export default config
|
|||
```
|
||||
|
||||
```ts [config.ts]
|
||||
import type { UserConfig } from 'vitepress'
|
||||
import type { UserConfig } from 'valaxy'
|
||||
|
||||
const config: UserConfig = {
|
||||
// ...
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
[0;90m┌[0m [0;36;1mWelcome to VitePress![0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Where should VitePress initialize the config?[0m
|
||||
[0;90m│[0m [0;2m./docs[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Site title:[0m
|
||||
[0;90m│[0m [0;2mMy Awesome Project[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;32m◇[0m Site description:[0m
|
||||
[0;90m│[0m [0;2mA VitePress Site[0m[0m
|
||||
[0;90m│[0m[0m
|
||||
[0;36m◆[0m Theme:[0m
|
||||
[0;36m│[0m [0;32m●[0m Default Theme [0;2m(Out of the box, good-looking docs)[0m[0m
|
||||
[0;36m│[0m [0;2m○[0m [0;2mDefault Theme + Customization[0m[0m
|
||||
[0;36m│[0m [0;2m○[0m [0;2mCustom Theme[0m[0m
|
||||
[0;36m└[0m
|
|
@ -47,7 +47,7 @@
|
|||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^1.0.0-beta.19",
|
||||
"@antfu/eslint-config": "^1.0.0-beta.21",
|
||||
"@iconify-json/logos": "^1.1.37",
|
||||
"@iconify-json/vscode-icons": "^1.1.28",
|
||||
"@microsoft/api-extractor": "^7.38.0",
|
||||
|
|
|
@ -8,8 +8,8 @@ const app = useAppStore()
|
|||
|
||||
<template>
|
||||
<button
|
||||
class="toc-btn shadow-lg fixed press-icon-btn z-99 xl:hidden!"
|
||||
right="5" bottom="8"
|
||||
class="toc-btn shadow-lg fixed press-icon-btn z-99 lt-md:hidden! xl:hidden!"
|
||||
right="5" bottom="24"
|
||||
@click="app.toggleRightSidebar()"
|
||||
>
|
||||
<div i-ri-file-list-line />
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { useSidebar } from 'valaxy'
|
||||
import { useOutline, useSidebar } from 'valaxy'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
open: boolean
|
||||
|
@ -13,11 +14,18 @@ defineEmits<{
|
|||
|
||||
const { hasSidebar } = useSidebar()
|
||||
|
||||
function scrollToTop() {
|
||||
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const navHeight = ref(0)
|
||||
onMounted(() => {
|
||||
navHeight.value = Number.parseInt(
|
||||
getComputedStyle(document.documentElement).getPropertyValue(
|
||||
'--pr-nav-height',
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const { headers } = useOutline()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -34,9 +42,7 @@ const { t } = useI18n()
|
|||
</span>
|
||||
</button>
|
||||
|
||||
<a class="top-link" href="#" @click="scrollToTop">
|
||||
{{ t('sidebar.return_top') }}
|
||||
</a>
|
||||
<PressLocalNavOutlineDropdown :headers="headers" :nav-height="navHeight" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<script setup lang="ts">
|
||||
import { nextTick, ref } from 'vue'
|
||||
import type { MenuItem } from 'valaxy'
|
||||
import { onContentUpdated } from 'valaxy'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps<{
|
||||
headers: MenuItem[]
|
||||
navHeight: number
|
||||
}>()
|
||||
|
||||
const open = ref(false)
|
||||
const vh = ref(0)
|
||||
const items = ref<HTMLDivElement>()
|
||||
|
||||
onContentUpdated(() => {
|
||||
open.value = false
|
||||
})
|
||||
|
||||
function toggle() {
|
||||
open.value = !open.value
|
||||
vh.value = window.innerHeight + Math.min(window.scrollY - props.navHeight, 0)
|
||||
}
|
||||
|
||||
function onItemClick(e: Event) {
|
||||
if ((e.target as HTMLElement).classList.contains('outline-link')) {
|
||||
// disable animation on hash navigation when page jumps
|
||||
if (items.value)
|
||||
items.value.style.transition = 'none'
|
||||
|
||||
nextTick(() => {
|
||||
open.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToTop() {
|
||||
open.value = false
|
||||
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="VPLocalNavOutlineDropdown" :style="{ '--vp-vh': `${vh}px` }">
|
||||
<button v-if="headers.length > 0" :class="{ open }" @click="toggle">
|
||||
{{ t('theme.outlineTitle') }}
|
||||
<div i-ri-arrow-right-s-line class="icon" />
|
||||
</button>
|
||||
<button v-else @click="scrollToTop">
|
||||
{{ t('sidebar.return_top') }}
|
||||
</button>
|
||||
<Transition name="flyout">
|
||||
<div
|
||||
v-if="open"
|
||||
ref="items"
|
||||
class="items"
|
||||
@click="onItemClick"
|
||||
>
|
||||
<div class="header">
|
||||
<a class="top-link" href="#" @click="scrollToTop">
|
||||
{{ t('sidebar.return_top') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="py-2 bg-$vp-c-bg-soft">
|
||||
<PressOutlineItem :headers="headers" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPLocalNavOutlineDropdown {
|
||||
padding: 12px 20px 11px;
|
||||
}
|
||||
|
||||
.VPLocalNavOutlineDropdown button {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
color: var(--vp-c-text-2);
|
||||
transition: color 0.5s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.VPLocalNavOutlineDropdown button:hover {
|
||||
color: var(--vp-c-text-1);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.VPLocalNavOutlineDropdown button.open {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
:deep(.outline-link) {
|
||||
font-size: 14px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.open > .icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.items {
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
display: grid;
|
||||
gap: 1px;
|
||||
border: 1px solid var(--vp-c-border);
|
||||
border-radius: 8px;
|
||||
background-color: var(--vp-c-gutter);
|
||||
max-height: calc(var(--vp-vh, 100vh) - 86px);
|
||||
overflow: hidden auto;
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.top-link {
|
||||
display: block;
|
||||
padding: 0 16px;
|
||||
line-height: 48px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.flyout-enter-active {
|
||||
transition: all .2s ease-out;
|
||||
}
|
||||
|
||||
.flyout-leave-active {
|
||||
transition: all .15s ease-in;
|
||||
}
|
||||
|
||||
.flyout-enter-from,
|
||||
.flyout-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-16px);
|
||||
}
|
||||
</style>
|
|
@ -12,7 +12,7 @@ const { locale } = useI18n()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<ul :class="root ? 'root' : 'nested'">
|
||||
<ul :class="root ? 'root' : 'nested'" class="va-toc css-i18n-toc">
|
||||
<li v-for="{ children, link, title, lang } in headers" :key="link" class="va-toc-item" :lang="lang || locale">
|
||||
<a class="outline-link" :href="link" @click="onClick">{{ title }}</a>
|
||||
<template v-if="children?.length">
|
||||
|
@ -23,26 +23,33 @@ const { locale } = useI18n()
|
|||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.va-toc {
|
||||
.va-toc-item {
|
||||
.outline-link {
|
||||
color: var(--va-c-text-light);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color 0.5s;
|
||||
.root {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: var(--va-c-brand);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
.nested {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
}
|
||||
.outline-link {
|
||||
display: block;
|
||||
line-height: 28px;
|
||||
color: var(--va-c-text-light);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color 0.5s;
|
||||
font-weight: 400;
|
||||
|
||||
.nested {
|
||||
padding-left: 0.8rem;
|
||||
}
|
||||
&:hover,
|
||||
&.active {
|
||||
color: var(--va-c-brand);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.nested {
|
||||
padding-left: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,7 +5,6 @@ import type { ThemeConfig } from '../types'
|
|||
*/
|
||||
export const defaultThemeConfig: ThemeConfig = {
|
||||
logo: '',
|
||||
outlineTitle: 'On this page',
|
||||
|
||||
colors: {
|
||||
primary: '#0078E7',
|
||||
|
|
|
@ -33,12 +33,6 @@ export namespace PressTheme {
|
|||
export interface Config {
|
||||
logo: string
|
||||
|
||||
/**
|
||||
* toc title
|
||||
* @default 'On this page'
|
||||
*/
|
||||
outlineTitle: string
|
||||
|
||||
colors: {
|
||||
/**
|
||||
* primary color
|
||||
|
|
|
@ -9,8 +9,8 @@ importers:
|
|||
.:
|
||||
devDependencies:
|
||||
'@antfu/eslint-config':
|
||||
specifier: ^1.0.0-beta.19
|
||||
version: 1.0.0-beta.19(eslint@8.50.0)(typescript@5.2.2)(vitest@0.34.6)
|
||||
specifier: ^1.0.0-beta.21
|
||||
version: 1.0.0-beta.21(eslint@8.50.0)(typescript@5.2.2)(vitest@0.34.6)
|
||||
'@iconify-json/logos':
|
||||
specifier: ^1.1.37
|
||||
version: 1.1.37
|
||||
|
@ -654,8 +654,8 @@ packages:
|
|||
'@jridgewell/gen-mapping': 0.3.3
|
||||
'@jridgewell/trace-mapping': 0.3.19
|
||||
|
||||
/@antfu/eslint-config@1.0.0-beta.19(eslint@8.50.0)(typescript@5.2.2)(vitest@0.34.6):
|
||||
resolution: {integrity: sha512-xG/5+4AaJhWald30lUmvxeg5060mjSodeeGvmxCjjsEoRUKdi5w6C2CXhYR7CTteMrQoWPMao5/rJEsaqNbGbg==}
|
||||
/@antfu/eslint-config@1.0.0-beta.21(eslint@8.50.0)(typescript@5.2.2)(vitest@0.34.6):
|
||||
resolution: {integrity: sha512-bMTD0IZ6pPxLEANuxbBAQV8cQRCGcGKrsVjghcojtzhEqJjt6iirPrptKk+j/HKOqMDXH2ZaXuqSJfXrY4U+Ng==}
|
||||
peerDependencies:
|
||||
eslint: '>=8.0.0'
|
||||
dependencies:
|
||||
|
@ -5349,7 +5349,7 @@ packages:
|
|||
/eslint-import-resolver-node@0.3.9:
|
||||
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
|
||||
dependencies:
|
||||
debug: 3.2.7(supports-color@5.5.0)
|
||||
debug: 3.2.7(supports-color@8.1.1)
|
||||
is-core-module: 2.13.0
|
||||
resolve: 1.22.4
|
||||
transitivePeerDependencies:
|
||||
|
@ -5378,7 +5378,7 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 6.7.4(eslint@8.50.0)(typescript@5.2.2)
|
||||
debug: 3.2.7(supports-color@5.5.0)
|
||||
debug: 3.2.7(supports-color@8.1.1)
|
||||
eslint: 8.50.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
transitivePeerDependencies:
|
||||
|
@ -5432,7 +5432,7 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: ^7.2.0 || ^8
|
||||
dependencies:
|
||||
debug: 3.2.7(supports-color@5.5.0)
|
||||
debug: 3.2.7(supports-color@8.1.1)
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.50.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
|
|
Loading…
Reference in New Issue