You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

239 lines
5.0 KiB

<template>
<div
class="item-group"
v-for="(item, index) in fileList"
:key="item.path + item.isOpen"
>
<div
class="file-item"
:class="{
chosen: chosenPath === item.path,
// 'no-chosen': !chosenIndexs.includes(index),
'mode-icon': mode === 'icon',
'mode-list': mode === 'list',
}"
:style="{
'padding-left': level * 12 + 'px',
}"
@click="handleClick(item, index)"
@mousedown.stop
>
<div
class="iconfont"
:class="{
'open-arrow': item.isOpen,
'hide-arrow': item.isOpen && !item.subFileList?.length,
}"
@click.stop="onOpenArrow(item)"
>
<div class="icon-arrow-down"></div>
</div>
<div class="file-item_img">
<FileIcon :file="item" />
</div>
<span class="file-item_title">{{ getName(item) }}</span>
</div>
<div class="sub-tree">
<FileTree
v-if="item.isOpen"
:level="level + 1"
mode="list"
:chosen-path="chosenPath"
:on-refresh="() => onSubRefresh(item)"
:on-open="onSubOpen"
:file-list="item.subFileList"
>
</FileTree>
</div>
</div>
</template>
<script lang="ts" setup>
import { useSystem,OsFileWithoutContent,basename } from '@/system/index.ts';
import { onMounted, ref } from 'vue';
import { dealSystemName } from '@/i18n';
const sys = useSystem();
type FileWithOpen = OsFileWithoutContent & {
isOpen?: boolean;
subFileList?: FileWithOpen[];
};
const props = defineProps({
level: {
type: Number,
default: 0,
},
onOpen: {
type: Function,
default: () => {
//
},
},
onRefresh: {
type: Function,
default: () => {
//
},
},
chosenPath: {
type: String,
default: '',
},
fileList: {
type: Array<FileWithOpen>,
default: () => [],
},
mode: {
type: String,
default: 'icon',
},
});
const chosenIndexs = ref<Array<number>>([]);
function handleClick(item: FileWithOpen, index: number) {
chosenIndexs.value = [index];
props.onOpen(item.path);
}
function getName(item:any){
const name = dealSystemName(basename(item.path))
return name
}
onMounted(() => {
chosenIndexs.value = [];
props.fileList.forEach((item) => {
item.isOpen = false;
});
});
function onSubOpen(path: string) {
props.onOpen(path);
}
async function onSubRefresh(item: FileWithOpen) {
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
}
async function onOpenArrow(item: FileWithOpen) {
if (item.isOpen && !item.subFileList?.length) {
return;
}
item.isOpen = !item.isOpen;
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
}
</script>
<style lang="scss" scoped>
.icon-arrow-down {
display: block;
width: 4px;
height: 4px;
margin: 7px;
transform: translateY(0px) rotate(-45deg);
border: 2px solid rgba(0, 0, 0, 0.465);
border-left: none;
border-top: none;
transition: all 0.1s;
}
.hide-arrow {
border-color: transparent;
}
.open-arrow {
transform: translateY(-2px) translateX(2px) rotate(90deg);
}
.file-item {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
color: var(--icon-title-color);
font-size: var(--ui-font-size);
border: 1px solid transparent;
margin: 2px;
user-select: none;
}
.file-item:hover {
background-color: #b1f1ff4c;
}
.chosen {
border: 1px dashed #3bdbff3d;
background-color: #9595956b;
.file-item_title {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
// background-color: var(--theme-color);
}
.chosen:hover {
background-color: #9595956b;
}
.no-chosen {
.file-item_title {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
.mode-icon {
.file-item_img {
width: 60%;
height: calc(0.6 * var(--desk-item-size));
margin: 0px auto;
user-select: none;
flex-shrink: 0;
}
.file-item_title {
// color: var(--color-ui-desk-item-title);
height: calc(0.4 * var(--desk-item-size));
display: block;
text-align: center;
word-break: break-all;
flex-grow: 0;
}
}
.mode-list {
display: flex;
flex-direction: row;
justify-content: flex-start;
height: calc(0.8 * var(--menulist-item-height));
width: 100%;
.file-item_img {
width: var(--menulist-item-height);
height: calc(0.6 * var(--menulist-item-height));
// margin: 0px auto;
user-select: none;
flex-shrink: 0;
svg {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.file-item_title {
height: min-content;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
</style>