Breadcrumbs keep longest path, browsing breadcrumbs with left/right arrows, highlight current.

This commit is contained in:
Leo Vasanko 2023-11-06 18:51:51 +00:00
parent 5386508e28
commit b25d0fc14b
5 changed files with 78 additions and 27 deletions

View File

@ -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>

View File

@ -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) {

View File

@ -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>

View File

@ -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);

View File

@ -142,10 +142,7 @@ const download = async () => {
}
</script>
<style scoped>
.smallgap {
margin-left: 2em;
}
<style>
.select-text {
color: var(--accent-color);
text-wrap: nowrap;