[UI] Added navigation crumbs to the file browser.

This commit is contained in:
Fabio Manganiello 2023-11-12 15:53:46 +01:00
parent 724f625963
commit 6dfe2324c1
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
1 changed files with 100 additions and 18 deletions

View File

@ -2,27 +2,46 @@
<div class="browser-container">
<Loading v-if="loading" />
<div class="row item" @click="path = (path || '') + '/..'" v-if="path?.length && path !== '/'">
<div class="col-10 left side">
<i class="icon fa fa-folder" />
<span class="name">..</span>
</div>
<div class="nav" ref="nav">
<span class="path"
v-for="(token, i) in pathTokens"
:key="i"
@click="path = pathTokens.slice(0, i + 1).join('/').slice(1)">
<span class="token">
{{ token }}
</span>
<span class="separator" v-if="(i > 0 || pathTokens.length > 1) && i < pathTokens.length - 1">
<i class="fa fa-chevron-right" />
</span>
</span>
</div>
<div class="row item" v-for="(file, i) in filteredFiles" :key="i" @click="path = file.path">
<div class="col-10">
<i class="icon fa" :class="{'fa-file': file.type !== 'directory', 'fa-folder': file.type === 'directory'}" />
<span class="name">
{{ file.name }}
</span>
<div class="items" ref="items">
<div class="row item"
@click="onBack"
v-if="(path?.length && path !== '/') || hasBack">
<div class="col-10 left side">
<i class="icon fa fa-folder" />
<span class="name">..</span>
</div>
</div>
<div class="col-2 actions">
<Dropdown>
<DropdownItem icon-class="fa fa-play" text="Play"
@click="$emit('play', {type: 'file', url: `file://${file.path}`})"
v-if="isMedia && mediaExtensions.has(file.name.split('.').pop())" />
</Dropdown>
<div class="row item" v-for="(file, i) in filteredFiles" :key="i" @click="path = file.path">
<div class="col-10">
<i class="icon fa" :class="{'fa-file': file.type !== 'directory', 'fa-folder': file.type === 'directory'}" />
<span class="name">
{{ file.name }}
</span>
</div>
<div class="col-2 actions">
<Dropdown>
<DropdownItem icon-class="fa fa-play" text="Play"
@click="$emit('play', {type: 'file', url: `file://${file.path}`})"
v-if="isMedia && mediaExtensions.has(file.name.split('.').pop()?.toLowerCase())" />
</Dropdown>
</div>
</div>
</div>
</div>
@ -39,9 +58,14 @@ export default {
name: "Browser",
components: {DropdownItem, Dropdown, Loading},
mixins: [Utils, MediaUtils],
emits: ['path-change'],
emits: ['back', 'path-change', 'play'],
props: {
hasBack: {
type: Boolean,
default: false,
},
initialPath: {
type: String,
},
@ -71,11 +95,24 @@ export default {
return this.files.filter((file) => (file?.name || '').toLowerCase().indexOf(this.filter.toLowerCase()) >= 0)
},
pathTokens() {
if (!this.path?.length)
return ['/']
return ['/', ...this.path.split(/(?<!\\)\//).slice(1)]
},
},
methods: {
async refresh() {
this.loading = true
this.$nextTick(() => {
// Scroll to the end of the path navigator
this.$refs.nav.scrollLeft = 99999
// Scroll to the top of the items list
this.$refs.items.scrollTop = 0
})
try {
this.files = await this.request('file.list', {path: this.path})
@ -84,6 +121,13 @@ export default {
this.loading = false
}
},
onBack() {
if (!this.path?.length || this.path === '/')
this.$emit('back')
else
this.path = [...this.pathTokens].slice(0, -1).join('/').slice(1)
},
},
mounted() {
@ -96,12 +140,50 @@ export default {
<style lang="scss" scoped>
@import "src/style/items";
$nav-height: 2.5em;
.browser-container {
height: 100%;
display: flex;
flex-direction: column;
.item {
.actions {
display: inline-flex;
justify-content: right;
}
}
.nav {
width: 100%;
height: $nav-height;
padding: 0.5em 1em;
background: $tab-bg;
box-shadow: $border-shadow-bottom;
white-space: nowrap;
overflow: hidden;
.path {
cursor: pointer;
.token {
&:hover {
color: $default-hover-fg;
text-decoration: underline;
}
}
.separator {
font-size: 1em;
width: 1.2em;
padding: 0 1em;
}
}
}
.items {
height: calc(100% - #{$nav-height});
overflow: auto;
}
}
</style>