Files
miaoDirectory/src/plugins/miaoDirectory/components/miaoDirectoryItem.vue
T

334 lines
7.8 KiB
Vue

<template>
<miao-draggable-div
class="miao-item"
:isDraggable="!draggable"
ref="itemRef"
@on-drag-start="handleDragStart"
>
<miaoContextMenu
:options="dropDownOptions ?? []"
:touch-time-out="500"
@select="handleDropdownSelect"
>
<div
class="item-main"
:class="selected ? 'item-main-selected' : ''"
ref="mainRef"
>
<div
class="item-main-front"
:style="{ backgroundColor: props.color }"
></div>
<Icon
class="item-main-icon"
v-show="clientWidth > 250"
></Icon>
<div class="item-main-info">
<div class="item-main-info-name">
<Icon
class="item-main-info-name-icon"
v-if="clientWidth <= 250"
></Icon>
<n-ellipsis
:style="{ maxWidth: clientWidth > 250 ? '80%' : '75%' }"
>
{{ name }}
</n-ellipsis>
</div>
<div
class="item-main-info-date"
v-if="time"
>
{{ time }}
</div>
</div>
<miao-draggable-div
class="item-main-dragBtn"
:isDraggable="draggable"
>
<ReorderFourOutline></ReorderFourOutline>
</miao-draggable-div>
</div>
</miaoContextMenu>
</miao-draggable-div>
</template>
<script setup lang="ts">
import miaoContextMenu from '@/components/miaoContextMenu.vue'
import {
DocumentText,
FileTray,
Help,
Image,
LogoChrome,
LogoCss3,
LogoJavascript,
LogoVue,
PlayCircle,
Disc,
ReorderFourOutline
} from '@vicons/ionicons5'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import dateFormatter from '@/utils/dateFormatter'
import { NEllipsis } from 'naive-ui'
import { DropdownOption } from 'naive-ui/es/dropdown'
import miaoDraggableDiv from '@/components/miaoDraggableDiv.vue'
// import useMiaoFetchApi from '@/hooks/useMiaoFetchApi'
// const miaoFetchApi = useMiaoFetchApi()
const props = defineProps<{
item: {
name: string
type: 'directory' | 'file'
stats: {
mtimeMs: number
}
}
name?: string
color: string
dropDownOptions?: DropdownOption[]
selected?: boolean
}>()
const emit = defineEmits<{
download: []
delete: []
rename: []
dragStart: [e: DragEvent]
onSelected: []
plugin: [plugin: string]
}>()
const mainRef = ref<HTMLDivElement>()
const draggable = ref(true)
// 使用ResizeObserver实现
// 什么?性能问题?这玩意性能问题多着呢,轮不到它。
const clientWidth = ref<number>(666)
const name = props.name ?? props.item.name
const observer = new ResizeObserver((entries) => {
for (let entry of entries) {
clientWidth.value = entry.contentRect.width
}
})
const time = computed(() => {
return dateFormatter(
new Date(props.item.stats.mtimeMs),
'yyyy-MM-dd hh:mm:ss'
)
})
// 应该将所有事件emit出去才对
const handleDropdownSelect = (key: string) => {
if (key === 'rename') {
emit('rename')
} else if (key === 'download') {
emit('download')
} else if (key === 'delete') {
emit('delete')
} else if (key === 'select') {
emit('onSelected')
} else if (key.startsWith('plugin:')) {
const plugin = key.split(':')[1]
emit('plugin', plugin)
}
}
const Icon = computed(() => {
try {
if (props.item.type === 'directory') {
return FileTray
} else if (props.item.type === 'file') {
const aft = props.item.name.split('.').at(-1)?.toLowerCase()
if (!aft) {
throw 1
} else if (
['txt', 'doc', 'docs', 'docx', 'xls', 'xlsx'].includes(aft)
) {
return DocumentText
} else if (['mp3', 'wav', 'ape', 'acc', 'ogg', 'flac'].includes(aft)) {
return Disc
} else if (
[
'xbm',
'tif',
'pjp',
'svgz',
'jpg',
'jpeg',
'ico',
'tiff',
'gif',
'svg',
'jfif',
'webp',
'png',
'bmp',
'pjpeg',
'avif'
].includes(aft)
) {
return Image
} else if (['mp4', 'm2v', 'mkv'].includes(aft)) {
return PlayCircle
} else if (['js', 'jsx', 'ts', 'tsx'].includes(aft)) {
return LogoJavascript
} else if (['html'].includes(aft)) {
return LogoChrome
} else if (['css', 'scss', 'less'].includes(aft)) {
return LogoCss3
} else if (['vue'].includes(aft)) {
return LogoVue
}
return DocumentText
}
} catch {
return Help
}
})
const itemRef = ref()
const handleDragStart = (e: DragEvent) => {
emit('dragStart', e)
}
onMounted(() => {
if (mainRef.value) {
observer.observe(mainRef.value)
}
})
onBeforeUnmount(() => {
if (mainRef.value) {
observer.unobserve(mainRef.value)
}
})
</script>
<style lang="scss" scoped>
.miao-item {
cursor: pointer;
width: calc(100% - 20px);
// min-width: 170px;
// aspect-ratio: 66/9;
height: 50px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
margin: 10px 10px;
.item-main {
position: relative;
width: 100%;
height: 95%;
background-color: rgb(255, 255, 255);
border-radius: 7px;
display: flex;
align-items: center;
transition: background-color 0.3s ease;
overflow-x: hidden;
.item-main-front {
height: 100%;
min-width: 10px;
border-radius: 7px 0 0 7px;
background-color: rgb(0, 0, 0);
}
.item-main-icon {
min-width: 30px;
margin-left: 10px;
height: 30px;
width: 30px;
color: #00403e;
transition: color 0.15s ease-out;
}
.item-main-info {
margin-left: 10px;
height: 100%;
width: calc(100% - 10px);
display: flex;
flex-direction: column;
&-name {
position: relative;
user-select: none;
display: flex;
align-items: center;
margin-top: 3px;
&-icon {
color: #00403e;
width: 20px;
margin-right: 5px;
transition: color 0.15s ease-out;
}
}
&-date {
user-select: none;
font-size: small;
text-wrap: nowrap;
}
}
.item-main-option {
height: 100%;
width: 20px;
position: absolute;
right: 0;
border-radius: 0 7px 7px 0;
background-color: rgba(0, 0, 0, 0);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: background-color 0.3s;
.item-main-option-icon {
color: #000;
transition: color 0.15s;
}
&:hover,
&:active {
background-color: #8b8b8b;
.item-main-option-icon {
color: #fff;
}
}
}
&:hover,
&:active {
background-color: #d2d2d2;
}
}
.item-main-selected {
background-color: rgba(0, 128, 207, 0.32);
&:hover {
background-color: rgba(0, 128, 207, 0.64);
}
}
}
.item-main-dragBtn {
width: 20px;
height: 20px;
position: absolute;
right: 5px;
}
</style>