修复搜索结果卡片视图筛选可视性,优化季集显示位置,重构nodatafound情形ui,重构文件管理器ui并增加文件树功能,优化侧边栏高度规避竖向滑动条

This commit is contained in:
madrays
2025-03-30 17:25:34 +08:00
parent 59b5e4a330
commit c4f54dcddc
14 changed files with 1627 additions and 343 deletions
+267 -74
View File
@@ -112,86 +112,279 @@ const sortIcon = computed(() => {
if (sort.value === 'time') return 'mdi-sort-clock-ascending-outline'
else return 'mdi-sort-alphabetical-ascending'
})
// 保存路径片段引用
const pathSegmentRef = ref<HTMLElement | null>(null)
// 检查文本是否被截断
function checkTextTruncated(event: MouseEvent) {
const target = event.target as HTMLElement
if (!target) return
// 动态设置tooltip是否禁用
const isTextOverflowing = target.offsetWidth < target.scrollWidth
// 找到最近的tooltip组件并设置disabled属性
const tooltipEl = target.closest('.v-tooltip')
if (tooltipEl) {
const tooltipComponent = (tooltipEl as any).__vue__
if (tooltipComponent && tooltipComponent.isActive !== undefined) {
tooltipComponent.isActive = isTextOverflowing
}
}
}
</script>
<template>
<VToolbar flat dense>
<VToolbarItems class="overflow-hidden">
<VMenu v-if="inProps.storages?.length || 0 > 1" offset-y>
<template #activator="{ props }">
<VBtn v-bind="props">
<VIcon icon="mdi-arrow-down-drop-circle-outline" />
<VToolbar flat dense class="file-toolbar">
<VToolbarItems class="overflow-hidden w-100">
<VBtn
variant="text"
:input-value="inProps.item?.path === '/'"
color="primary"
class="px-1 path-button home-button"
@click="changePath(inProps.itemstack[0])"
>
<VIcon icon="mdi-home" class="me-2" />
<span class="text-truncate">根目录</span>
</VBtn>
<div class="breadcrumb">
<template v-for="(segment, index) in pathSegments" :key="index">
<VBtn
v-if="display.mdAndUp.value"
variant="text"
color="primary"
density="comfortable"
:input-value="index === pathSegments.length - 1"
:class="['px-1', 'path-button', {'current-path': index === pathSegments.length - 1}]"
@click="changePath(inProps.itemstack[index + 1])"
>
<VIcon icon="mdi-chevron-right" size="small" />
<VTooltip>
<template #activator="{ props }">
<span
class="path-segment"
v-bind="props"
ref="pathSegmentRef"
@mouseover="checkTextTruncated"
>
{{ segment.name }}
</span>
</template>
{{ segment.name }}
</VTooltip>
</VBtn>
</template>
<VList>
<VListItem
v-for="(item, index) in storages"
:key="index"
:disabled="item.value === storageObject?.value"
@click="changeStorage(item.value)"
>
<template #prepend>
<Icon :icon="item.icon" />
</div>
<VSpacer />
<div class="file-actions">
<VTooltip text="调整排序">
<template #activator="{ props }">
<VBtn
v-bind="props"
@click="changeSort"
icon
variant="text"
color="primary"
class="action-button"
>
<VIcon :icon="sortIcon" />
</VBtn>
</template>
</VTooltip>
<VTooltip text="返回上一级" v-if="pathSegments.length > 0">
<template #activator="{ props }">
<VBtn
v-bind="props"
@click="goUp"
icon
variant="text"
color="primary"
class="action-button"
>
<VIcon icon="mdi-arrow-up" />
</VBtn>
</template>
</VTooltip>
<VDialog v-model="newFolderPopper" max-width="40rem" class="mkdir-dialog">
<template #activator="{ props }">
<VBtn
v-bind="props"
icon
variant="text"
color="primary"
class="action-button"
>
<VTooltip text="新建文件夹">
<template #activator="{ props: _props }">
<VIcon v-bind="_props" icon="mdi-folder-plus" />
</template>
</VTooltip>
</VBtn>
</template>
<VCard title="新建文件夹" class="pa-2">
<template #title>
<div class="d-flex align-center px-4 pt-4">
<VIcon icon="mdi-folder-plus" color="primary" class="me-2" />
<span class="text-h6">新建文件夹</span>
</div>
</template>
<VListItemTitle>{{ item.title }}</VListItemTitle>
</VListItem>
</VList>
</VMenu>
<VBtn variant="text" :input-value="item.path === '/'" class="px-1" @click="changePath(inProps.itemstack[0])">
<VIcon :icon="storageObject?.icon" class="mr-2" />
{{ storageObject?.title }}
</VBtn>
<template v-for="(segment, index) in pathSegments" :key="index">
<VBtn
v-if="display.mdAndUp.value"
variant="text"
:input-value="index === pathSegments.length - 1"
class="px-1"
@click="changePath(inProps.itemstack[index + 1])"
>
<VIcon icon=" mdi-chevron-right" />
{{ segment.name }}
</VBtn>
</template>
<DialogCloseBtn @click="newFolderPopper = false" />
<VDivider class="mt-3" />
<VCardText>
<VTextField
v-model="newFolderName"
label="文件夹名称"
placeholder="请输入文件夹名称"
variant="outlined"
hide-details="auto"
autofocus
@keyup.enter="mkdir"
/>
</VCardText>
<VCardActions class="pa-4 pt-0">
<VSpacer />
<VBtn color="grey" variant="text" @click="newFolderPopper = false">取消</VBtn>
<VBtn
:disabled="!newFolderName"
color="primary"
variant="elevated"
@click="mkdir"
class="ms-2"
>
创建
</VBtn>
</VCardActions>
</VCard>
</VDialog>
</div>
</VToolbarItems>
<div class="flex-grow-1" />
<VTooltip text="调整排序">
<template #activator="{ props }">
<IconBtn v-bind="props" @click="changeSort">
<VIcon :icon="sortIcon" />
</IconBtn>
</template>
</VTooltip>
<VTooltip text="返回上一级" v-if="pathSegments.length > 0">
<template #activator="{ props }">
<IconBtn v-bind="props" @click="goUp">
<VIcon icon="mdi-arrow-up-bold-outline" />
</IconBtn>
</template>
</VTooltip>
<VDialog v-model="newFolderPopper" max-width="50rem">
<template #activator="{ props }">
<IconBtn v-bind="props">
<VTooltip text="新建文件夹">
<template #activator="{ props: _props }">
<VIcon v-bind="_props" icon="mdi-folder-plus-outline" />
</template>
</VTooltip>
</IconBtn>
</template>
<VCard title="新建文件夹">
<DialogCloseBtn @click="newFolderPopper = false" />
<VDivider />
<VCardText>
<VTextField v-model="newFolderName" label="名称" />
</VCardText>
<VCardActions>
<div class="flex-grow-1" />
<VBtn :disabled="!newFolderName" variant="elevated" @click="mkdir" prepend-icon="mdi-check" class="px-5 me-3">
新建
</VBtn>
</VCardActions>
</VCard>
</VDialog>
</VToolbar>
</template>
<style lang="scss" scoped>
.file-toolbar {
background-color: var(--v-theme-surface);
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
flex-shrink: 0;
}
.home-button {
min-width: 50px;
flex-shrink: 0;
@media (min-width: 960px) {
max-width: unset;
}
@media (max-width: 959px) {
max-width: 120px;
}
}
.breadcrumb {
display: flex;
align-items: center;
overflow-x: auto;
white-space: nowrap;
scrollbar-width: none;
-ms-overflow-style: none;
flex: 1;
min-width: 0;
&::-webkit-scrollbar {
display: none;
}
// 确保当面包屑宽度超出容器时,最后一个元素可见
&:hover {
scroll-behavior: smooth;
}
// 允许在触摸设备上滚动
touch-action: pan-x;
}
.path-button {
padding: 0 4px;
min-width: auto;
height: 36px;
font-weight: normal;
flex-shrink: 0;
&:not(.current-path) {
@media (max-width: 959px) {
max-width: 120px;
}
}
&.current-path {
flex-shrink: 1;
}
}
.path-segment {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
.path-button:not(.current-path) & {
@media (min-width: 1200px) {
max-width: 200px;
}
@media (min-width: 960px) and (max-width: 1199px) {
max-width: 150px;
}
@media (min-width: 600px) and (max-width: 959px) {
max-width: 100px;
}
@media (max-width: 599px) {
max-width: 80px;
}
}
.current-path & {
@media (min-width: 960px) {
max-width: unset;
}
@media (max-width: 959px) {
max-width: 150px;
}
@media (max-width: 599px) {
max-width: 120px;
}
}
}
.action-button {
margin: 0 2px;
border-radius: 4px;
flex-shrink: 0;
&:hover {
background-color: rgba(var(--v-theme-primary), 0.05);
}
}
.mkdir-dialog {
.v-card {
border-radius: 8px;
}
}
.file-actions {
display: flex;
align-items: center;
}
</style>