feat: 拆分App.vue

This commit is contained in:
539943419 committed 2024-12-25 21:26:22 +08:00
1 parent 8605bd19ea
commit 8ef243f790
5 files changed
+433 -327

No files matched your search

+16 -313
View File
@@ -7,16 +7,7 @@ import {
shallowRef,
useTemplateRef
} from 'vue'
import { NIcon, NScrollbar, NDropdown } from 'naive-ui'
import {
EyeOffOutline,
EyeOutline,
CloseOutline,
CopyOutline,
EllipsisVertical,
QrCodeOutline,
ExtensionPuzzleOutline
} from '@vicons/ionicons5'
import { QrCodeOutline, ExtensionPuzzleOutline } from '@vicons/ionicons5'
import type VirtualDirectory from './class/VirtualDirectory'
import type { VirtualFile } from './class/VirtualDirectory'
import MiaoMask from './components/miaoMask.vue'
@@ -29,23 +20,20 @@ import PluginCenter, { PluginGroup } from './class/PluginCenter'
import { renderIcon } from './utils/miaoTools'
import { DropdownMixedOption } from 'naive-ui/es/dropdown/src/interface'
import useRootVDirectory from './hooks/useRootVDirectory'
import ViewController from '@/components/APP/ViewController.vue'
import ViewContainer from '@/components/APP/ViewContainer.vue'
const { baseUrl } = config
const showModal = ref<boolean>(false)
const viewRef = ref<HTMLDivElement>()
const modalData = shallowRef<{
component: any
props: any
}>()
const messageProviderRef = useTemplateRef('messageProviderRef')
const views = useVirtualPages()
let pluginCenter = ref<PluginCenter>()
const rootDirectory = useRootVDirectory()
// component就是一个vue组件,类似于miaoDirectory
@@ -139,94 +127,17 @@ provide('rootDirectory', rootDirectory)
<template>
<div class="view" ref="viewRef">
<miao-message-provider ref="messageProviderRef">
<div class="view-controller">
<n-scrollbar x-scrollable>
<div class="tabs-container">
<transition-group name="tab">
<div
class="tab"
v-for="(view, index) of views._views"
:key="view.id">
<span
class="tab-title"
:title="view.title"
@click="handleClickTitle(index)">
{{
view.title.length > 5 && 0
? `${view.title.substring(0, 5)}...`
: view.title
}}
</span>
<div class="tab-control">
<div
class="tab-point"
:style="{ backgroundColor: view.color }"></div>
<n-icon
class="tag-control-icon icon"
@click="view.switchShow()">
<EyeOutline
v-show="view.visible"
class="icon-inner" />
<EyeOffOutline
v-show="!view.visible"
class="icon-inner" />
</n-icon>
<n-icon
class="tag-control-icon icon"
@click="
createView(
view.component,
view.name,
view.currentDirectories,
view.currentFiles,
index + 1
)
"
v-if="view.allowCopy">
<CopyOutline />
</n-icon>
<n-icon
class="tag-control-icon icon"
@click="deleteView(index)">
<CloseOutline class="icon-inner" />
</n-icon>
</div>
</div>
</transition-group>
</div>
</n-scrollbar>
<div class="view-controller-menu">
<div class="view-controller-menu-item">
<n-dropdown
trigger="click"
:options="openMenuOption"
@select="handleMenuSelect">
<n-icon class="icon">
<EllipsisVertical class="icon-inner" />
</n-icon>
</n-dropdown>
</div>
</div>
</div>
<div class="view-container">
<!-- <transition-group name="page"> -->
<div
class="view-container-item"
v-for="(view, index) of views._views"
:class="!view.visible ? 'view-container-item-hidden' : ''"
:key="view.id">
<component
:is="view.component"
v-model:current-directories="view.currentDirectories"
v-model:current-files="view.currentFiles"
:id="view.id"
:color="view.color"
:view="view"
:views="views"
@exit="deleteView(index)"></component>
</div>
<!-- </transition-group> -->
</div>
<ViewController
:views="views"
:handleClickTitle="handleClickTitle"
:createView="createView"
:deleteView="deleteView"
:openMenuOption="openMenuOption"
:handleMenuSelect="handleMenuSelect" />
<ViewContainer
:views="views"
:deleteView="deleteView"
:handleClickTitle="handleClickTitle" />
</miao-message-provider>
</div>
<!-- 模态框展示,用来显示分享二维码,设置菜单之类的东西 -->
@@ -239,6 +150,8 @@ provide('rootDirectory', rootDirectory)
</template>
<style lang="scss" scoped>
@use "styles/default.scss";
$controller-height: 25px;
$tag-width: 170px;
@@ -247,215 +160,5 @@ $tag-width: 170px;
position: relative;
height: 100%;
width: 100%;
.view-controller {
display: flex;
height: $controller-height;
width: 100%;
background-color: #dadada;
// overflow: hidden;
.tabs-container {
display: flex;
margin-left: 5px;
flex: 1;
// overflow-x: scroll;
.tab {
position: relative;
width: $tag-width;
height: $controller-height;
margin: 0 5px;
// flex: 1;
display: flex;
border-radius: 5px 5px 0 0;
align-items: center;
.tab-title {
// font-family: monospace;
// font-weight: bolder;
margin-left: 4px;
width: 90px;
user-select: none;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
span {
user-select: none;
cursor: pointer;
}
}
.tab-point {
height: 5px;
aspect-ratio: 1;
border-radius: 66px;
margin-right: 5px;
}
.tab-control {
position: absolute;
right: 10px;
display: flex;
align-items: center;
.tab-control-icon:not(:last-child) {
margin-right: 5px;
}
}
&:not(:last-child)::after {
content: '';
height: calc($controller-height * 0.6);
width: 1px;
border-right: 1px solid black;
position: absolute;
right: 0px;
}
}
}
.view-controller-menu {
position: relative;
display: flex;
align-items: center;
padding: 0 5px;
.view-controller-menu-item {
height: 100%;
aspect-ratio: 1;
display: flex;
justify-content: center;
align-items: center;
}
&::before {
content: '';
height: calc($controller-height * 0.6);
width: 1px;
border-right: 1px solid black;
position: absolute;
left: 2px;
}
}
.icon {
height: calc($controller-height * 0.7);
width: calc($controller-height * 0.7);
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background-color: rgba(128, 128, 128, 0);
transition: background-color 0.3s;
&:hover {
background-color: rgba(128, 128, 128, 0.4);
}
}
}
.view-container {
position: relative;
display: flex;
// flex-direction: column;
height: calc(100% - $controller-height);
overflow-y: hidden;
overflow-x: overlay;
.view-container-item {
flex: 1;
height: 100%;
min-width: 180px;
opacity: 1;
transition:
flex 0.25s ease,
opacity 0.25s ease;
}
.view-container-item-hidden {
flex: 0;
min-width: 0px;
opacity: 0;
// transition-delay: opacity .25s;
// transition: opacity 5.25s ease;
}
&::-webkit-scrollbar {
position: absolute;
width: 4px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
// background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: #e0e0e0;
// border-radius: 5px;
}
&::-webkit-scrollbar-thumb:hover {
background: #999999;
}
}
}
// transition动画相关
.view {
.view-controller {
.tabs-container {
.tab-move,
.tab-enter-active {
transition: all 0.2s ease;
}
.tab-leave-active {
opacity: 0;
transition: none;
}
.tab-enter-from {
opacity: 0;
transform: translateY(-30px);
}
// .tab-leave-to {
// opacity: 0;
// transform: translateY(-80px) translateX(calc($tag-width + 10px));
// }
.tab-leave-active {
position: absolute;
}
}
}
// .view-container {
// .page-move {
// // transition: all 0.55s ease;
// }
// .page-enter-active {}
// .page-leave-active {
// transition: none !important;
// }
// .page-enter-from {
// // opacity: 0;
// }
// .page-leave-active {
// display: none;
// position: absolute;
// }
// }
}
</style>
+79
View File
@@ -0,0 +1,79 @@
<script setup lang="ts">
const props = defineProps({
views: {
type: Object,
required: true
},
deleteView: {
type: Function,
required: true
}
})
</script>
<template>
<div class="view-container">
<div
class="view-container-item"
v-for="(view, index) of props.views._views"
:class="!view.visible ? 'view-container-item-hidden' : ''"
:key="view.id">
<component
:is="view.component"
v-model:current-directories="view.currentDirectories"
v-model:current-files="view.currentFiles"
:id="view.id"
:color="view.color"
:view="view"
:views="props.views"
@exit="props.deleteView(index)"></component>
</div>
</div>
</template>
<style lang="scss" scoped>
$controller-height: 25px;
.view-container {
position: relative;
display: flex;
height: calc(100% - $controller-height);
overflow-y: hidden;
overflow-x: overlay;
.view-container-item {
flex: 1;
height: 100%;
min-width: 180px;
opacity: 1;
transition:
flex 0.25s ease,
opacity 0.25s ease;
}
.view-container-item-hidden {
flex: 0;
min-width: 0px;
opacity: 0;
}
&::-webkit-scrollbar {
position: absolute;
width: 4px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: #e0e0e0;
}
&::-webkit-scrollbar-thumb:hover {
background: #999999;
}
}
</style>
+233
View File
@@ -0,0 +1,233 @@
<script setup lang="ts">
import { NIcon, NScrollbar, NDropdown } from 'naive-ui'
import {
EyeOffOutline,
EyeOutline,
CloseOutline,
CopyOutline,
EllipsisVertical
} from '@vicons/ionicons5'
import type { DropdownMixedOption } from 'naive-ui/es/dropdown/src/interface'
import type { VirtualPages } from '@/class/VirtualPage'
import type VirtualDirectory from '@/class/VirtualDirectory'
import type { VirtualFile } from '@/class/VirtualDirectory'
const props = defineProps<{
views: VirtualPages
handleClickTitle: (index: number) => void
createView: (
component: any,
name: string,
currentDirectories?: VirtualDirectory[],
currentFiles?: VirtualFile[],
index?: number
) => void
deleteView: (index: number) => void
openMenuOption: DropdownMixedOption[]
handleMenuSelect: (key: string) => any
}>()
</script>
<template>
<div class="view-controller">
<n-scrollbar x-scrollable>
<div class="tabs-container">
<transition-group name="tab">
<div
class="tab"
v-for="(view, index) of props.views._views"
:key="view.id">
<span
class="tab-title"
:title="view.title"
@click="props.handleClickTitle(index)">
{{
view.title.length > 5 && 0
? `${view.title.substring(0, 5)}...`
: view.title
}}
</span>
<div class="tab-control">
<div
class="tab-point"
:style="{ backgroundColor: view.color }"></div>
<n-icon
class="tag-control-icon icon"
@click="view.switchShow()">
<EyeOutline v-show="view.visible" class="icon-inner" />
<EyeOffOutline
v-show="!view.visible"
class="icon-inner" />
</n-icon>
<n-icon
class="tag-control-icon icon"
@click="
props.createView(
view.component,
view.name,
view.currentDirectories,
view.currentFiles,
index + 1
)
"
v-if="view.allowCopy">
<CopyOutline />
</n-icon>
<n-icon
class="tag-control-icon icon"
@click="props.deleteView(index)">
<CloseOutline class="icon-inner" />
</n-icon>
</div>
</div>
</transition-group>
</div>
</n-scrollbar>
<div class="view-controller-menu">
<div class="view-controller-menu-item">
<n-dropdown
trigger="click"
:options="props.openMenuOption"
@select="props.handleMenuSelect">
<n-icon class="icon">
<EllipsisVertical class="icon-inner" />
</n-icon>
</n-dropdown>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
$controller-height: 25px;
$tag-width: 170px;
.view-controller {
display: flex;
height: $controller-height;
width: 100%;
background-color: #dadada;
.tabs-container {
display: flex;
margin-left: 5px;
flex: 1;
.tab {
position: relative;
width: $tag-width;
height: $controller-height;
margin: 0 5px;
display: flex;
border-radius: 5px 5px 0 0;
align-items: center;
.tab-title {
margin-left: 4px;
width: 90px;
user-select: none;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
span {
user-select: none;
cursor: pointer;
}
}
.tab-point {
height: 5px;
aspect-ratio: 1;
border-radius: 66px;
margin-right: 5px;
}
.tab-control {
position: absolute;
right: 10px;
display: flex;
align-items: center;
.tab-control-icon:not(:last-child) {
margin-right: 5px;
}
}
&:not(:last-child)::after {
content: '';
height: calc($controller-height * 0.6);
width: 1px;
border-right: 1px solid black;
position: absolute;
right: 0px;
}
}
}
.view-controller-menu {
position: relative;
display: flex;
align-items: center;
padding: 0 5px;
.view-controller-menu-item {
height: 100%;
aspect-ratio: 1;
display: flex;
justify-content: center;
align-items: center;
}
&::before {
content: '';
height: calc($controller-height * 0.6);
width: 1px;
border-right: 1px solid black;
position: absolute;
left: 2px;
}
}
.icon {
height: calc($controller-height * 0.7);
width: calc($controller-height * 0.7);
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background-color: rgba(128, 128, 128, 0);
transition: background-color 0.3s;
&:hover {
background-color: rgba(128, 128, 128, 0.4);
}
}
}
// transition动画相关
.view-controller {
.tabs-container {
.tab-move,
.tab-enter-active {
transition: all 0.2s ease;
}
.tab-leave-active {
opacity: 0;
transition: none;
}
.tab-enter-from {
opacity: 0;
transform: translateY(-30px);
}
.tab-leave-active {
position: absolute;
}
}
}
</style>
@@ -9,19 +9,21 @@
:style="{ backgroundColor: props.color }"></div>
<div class="container-top-breadcrumb">
<div class="container-top-breadcrumb-container">
<n-breadcrumb separator=">" style="margin-left: 5px">
<n-breadcrumb-item :clickable="false">
<n-icon size="18">
<CloudOutline />
</n-icon>
</n-breadcrumb-item>
<n-breadcrumb-item
v-for="dir in currentDirectory?.getParents"
@click="handleClickBreadcrumbItem(dir)"
:clickable="true">
<div>{{ dir.name }}</div>
</n-breadcrumb-item>
</n-breadcrumb>
<!-- <n-scrollbar x-scrollable> -->
<n-breadcrumb separator=">" style="margin-left: 5px">
<n-breadcrumb-item :clickable="false">
<n-icon size="18">
<CloudOutline />
</n-icon>
</n-breadcrumb-item>
<n-breadcrumb-item
v-for="dir in currentDirectory?.getParents"
@click="handleClickBreadcrumbItem(dir)"
:clickable="true">
<div>{{ dir.name }}</div>
</n-breadcrumb-item>
</n-breadcrumb>
<!-- </n-scrollbar> -->
</div>
</div>
<div class="container-top-tools">
@@ -50,7 +52,7 @@
</template>
<script setup lang="ts">
import { NBreadcrumbItem, NBreadcrumb, NIcon, NDropdown } from 'naive-ui'
import { NBreadcrumbItem, NBreadcrumb, NIcon, NDropdown, NScrollbar } from 'naive-ui'
import {
CloudOutline,
ChevronBackOutline,
+89
View File
@@ -1,3 +1,92 @@
:root body {
background-color: aliceblue;
}
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
vertical-align: baseline;
box-sizing: border-box;
}