Breadcrumbs keep longest path, browsing breadcrumbs with left/right arrows, highlight current.
This commit is contained in:
parent
5386508e28
commit
b25d0fc14b
|
@ -1,3 +1,16 @@
|
|||
<template>
|
||||
<LoginModal />
|
||||
<header>
|
||||
<HeaderMain ref="headerMain">
|
||||
<HeaderSelected :path="path.pathList" />
|
||||
</HeaderMain>
|
||||
<BreadCrumb :path="path.pathList" />
|
||||
</header>
|
||||
<main>
|
||||
<RouterView :path="path.pathList" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import type { ComputedRef } from 'vue'
|
||||
|
@ -123,14 +136,3 @@ onUnmounted(() => {
|
|||
})
|
||||
export type { Path }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LoginModal />
|
||||
<header>
|
||||
<HeaderMain ref="headerMain"><HeaderSelected :path="path.pathList" /></HeaderMain>
|
||||
<BreadCrumb :path="path.pathList" />
|
||||
</header>
|
||||
<main>
|
||||
<RouterView :path="path.pathList" />
|
||||
</main>
|
||||
</template>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
}
|
||||
.breadcrumb {
|
||||
font-size: 1.7em;
|
||||
flex-shrink: 10;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 800px) and (--webkit-min-device-pixel-ratio: 2) {
|
||||
|
|
|
@ -1,18 +1,68 @@
|
|||
<template>
|
||||
<div class="breadcrumb">
|
||||
<a href="#/"><component :is="home" /></a>
|
||||
<template v-for="(location, index) in props.path" :key="index">
|
||||
<a :href="`/#/${props.path.slice(0, index + 1).join('/')}/`">{{ location }}</a>
|
||||
<nav
|
||||
class="breadcrumb"
|
||||
aria-label="Breadcrumb"
|
||||
tabindex="0"
|
||||
@keyup.left.stop="move(-1)"
|
||||
@keyup.right.stop="move(1)"
|
||||
@focus="move(0)"
|
||||
>
|
||||
<a href="#/"
|
||||
:ref="el => setLinkRef(0, el)"
|
||||
:class="{ current: !!isCurrent(0) }"
|
||||
:aria-current="isCurrent(0)"
|
||||
>
|
||||
<component :is="home" />
|
||||
</a>
|
||||
<template v-for="(location, index) in longest" :key="index">
|
||||
<a :href="`/#/${longest.slice(0, index + 1).join('/')}/`"
|
||||
:class="{ current: !!isCurrent(index + 1) }"
|
||||
:aria-current="isCurrent(index + 1)"
|
||||
@click.prevent="navigate(index + 1)"
|
||||
:ref="el => setLinkRef(index + 1, el)"
|
||||
>{{ location }}</a>
|
||||
</template>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import home from '@/assets/svg/home.svg'
|
||||
import { onBeforeUpdate, ref, watchEffect } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const links = [] as Array<HTMLElement>
|
||||
const setLinkRef = (index: number, el: any) => { if (el) links[index] = el }
|
||||
onBeforeUpdate(() => { links.length = 1 }) // 1 to keep home
|
||||
|
||||
const props = defineProps<{
|
||||
path: Array<string>
|
||||
}>()
|
||||
|
||||
const longest = ref<Array<string>>([])
|
||||
|
||||
watchEffect(() => {
|
||||
const longcut = longest.value.slice(0, props.path.length)
|
||||
const same = longcut.every((value, index) => value === props.path[index])
|
||||
if (!same) longest.value = props.path
|
||||
else if (props.path.length > longcut.length) {
|
||||
longest.value = longcut.concat(props.path.slice(longcut.length))
|
||||
}
|
||||
})
|
||||
|
||||
const isCurrent = (index: number) => index == props.path.length ? 'location' : undefined
|
||||
|
||||
const navigate = (index: number) => {
|
||||
links[index].focus()
|
||||
router.replace(`/${longest.value.slice(0, index).join('/')}`)
|
||||
}
|
||||
|
||||
const move = (dir: number) => {
|
||||
const index = props.path.length + dir
|
||||
if (index < 0 || index > longest.value.length) return
|
||||
navigate(index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -93,10 +143,8 @@ const props = defineProps<{
|
|||
.breadcrumb a:focus:nth-child(even) {
|
||||
background: var(--breadcrumb-hover-background-even);
|
||||
}
|
||||
.breadcrumb a:hover {
|
||||
color: var(--breadcrumb-hover-color);
|
||||
}
|
||||
.breadcrumb a:hover svg {
|
||||
fill: var(--breadcrumb-hover-color);
|
||||
}
|
||||
.breadcrumb a:hover { color: var(--breadcrumb-hover-color) }
|
||||
.breadcrumb a:hover svg { fill: var(--breadcrumb-hover-color) }
|
||||
.breadcrumb a.current { color: var(--accent-color) }
|
||||
.breadcrumb a.current svg { fill: var(--accent-color) }
|
||||
</style>
|
||||
|
|
|
@ -36,7 +36,7 @@ defineExpose({
|
|||
@click="() => documentStore.fileExplorer.newFolder()"
|
||||
/>
|
||||
<slot></slot>
|
||||
<div class="spacer"></div>
|
||||
<div class="spacer smallgap"></div>
|
||||
<template v-if="showSearchInput">
|
||||
<input
|
||||
ref="search"
|
||||
|
@ -66,6 +66,9 @@ defineExpose({
|
|||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.smallgap {
|
||||
margin-left: 2em;
|
||||
}
|
||||
input[type='search'] {
|
||||
background: var(--primary-background);
|
||||
color: var(--primary-color);
|
||||
|
|
|
@ -142,10 +142,7 @@ const download = async () => {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.smallgap {
|
||||
margin-left: 2em;
|
||||
}
|
||||
<style>
|
||||
.select-text {
|
||||
color: var(--accent-color);
|
||||
text-wrap: nowrap;
|
||||
|
|
Loading…
Reference in New Issue
Block a user