caner 11 months ago
parent
commit
da11eb96f3

+ 0 - 1
package.json

@@ -17,7 +17,6 @@
     "naive-ui": "^2.40.1",
     "pinia": "^2.2.6",
     "vue": "^3.5.13",
-    "vue-router": "^4.4.0",
     "pinia-plugin-persist": "^1.0.0"
   },
   "devDependencies": {

+ 13 - 68
src/App.vue

@@ -2,78 +2,23 @@
   <n-config-provider
     preflight-style-disabled
     inline-theme-disabled
+    :theme="theme"
+    :locale="zhCN"
+    :date-locale="dateZhCN"
+    abstract
   >
-    <div class="box">
-      <Head
-        v-model:show-add="showAdd"
-        v-model:list="tabs"
-        :select-tab="selectKey"
-        @on-change="onChange"
-      />
-      <div class="box-content">
-        <component :is="currentCom.sshCom" />
-      </div>
-    </div>
-    <!-- 弹窗 -->
-    <n-modal v-model:show="showAdd">
-      <Add @call-back="addBack" />
-    </n-modal>
+    <n-notification-provider>
+      <Layout />
+    </n-notification-provider>
   </n-config-provider>
 </template>
 <script setup lang='ts'>
+import { computed } from 'vue'
 import {
-  defineAsyncComponent, onMounted, ref, shallowRef
-} from 'vue'
-import Head from '@/components/head.vue'
-import Add from '@/components/add.vue'
-import { FormData } from '@/components/edit.vue'
-
-// TODO 每个tab都会存储相应组件用户操作过的数据
-const showAdd = ref(false)
-const tabs = shallowRef([
-  {
-    label: 'Home',
-    icon: 'home',
-    size: 14,
-    sshCom: defineAsyncComponent(() => import('@/components/ssh.vue')),
-    sftpCom: undefined
-  }
-] as FormData[])
-const selectKey = ref(0)
-const currentCom = shallowRef(tabs.value[selectKey.value])
-
-function addBack(params: FormData) {
-  tabs.value.push({
-    ...params,
-    icon: 'cmd',
-    size: 13,
-    sshCom: defineAsyncComponent(() => import('@/components/ssh.vue')),
-    sftpCom: undefined
-  })
-  selectKey.value = tabs.value.length - 1
-  currentCom.value = tabs.value[selectKey.value]
-  showAdd.value = false
-}
-
-function onChange(params: { id: number, type: string }) {
-  const { id, type } = params
-  if (type === 'del' && id !== 0) tabs.value.splice(id, 1)
-  selectKey.value = type === 'change' ? id : id - 1
-  currentCom.value = tabs.value[selectKey.value]
-}
+  zhCN, dateZhCN, darkTheme, lightTheme, useOsTheme
+} from 'naive-ui'
+import Layout from '@/components/layout.vue'
 
+const osTheme = useOsTheme()
+const theme = computed(() => (osTheme.value !== 'dark' ? darkTheme : lightTheme))
 </script>
-<style lang="scss" scoped>
-.box {
-  width: 100vw;
-  height: 100vh;
-  border-radius: 8px;
-  overflow: hidden;
-
-  &-content {
-    height: calc(100% - 38px);
-    width: 100%;
-    border-top: solid 3px white;
-  }
-}
-</style>

BIN
src/assets/GLJ.ttf


+ 12 - 19
src/assets/plugin.ts

@@ -1,30 +1,23 @@
 import {
   create,
   NConfigProvider,
-  NModal,
-  NScrollbar,
-  NTooltip,
-  NTabs,
-  NTabPane,
-  NButton,
-  NForm,
-  NFormItem,
-  NInput
+  NLayout,
+  NNotificationProvider,
+  NMenu,
+  NLayoutSider,
+  NLayoutHeader,
+  NLayoutContent
 } from 'naive-ui'
 
 const naive = create({
   components: [
     NConfigProvider,
-    NModal,
-    NScrollbar,
-    NTooltip,
-    NTabs,
-    NTabPane,
-    NButton,
-    NForm,
-    NFormItem,
-    NInput
-
+    NLayout,
+    NNotificationProvider,
+    NMenu,
+    NLayoutSider,
+    NLayoutHeader,
+    NLayoutContent
   ]
 })
 

+ 21 - 10
src/assets/theme.scss

@@ -1,21 +1,33 @@
-* {
-  box-sizing: border-box;
+
+#app,
+html,
+body {
   margin: 0;
   padding: 0;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
+* {
+  box-sizing: border-box;
   user-select: none;
+  outline: none;
 }
 
-@font-face {
-  font-family: 'GLJ';
-  src: url("@/assets/GLJ.ttf");
-  font-style: normal;
+/* 隐藏滚动条 */
+*::-webkit-scrollbar {
+  width: 0 !important;
+  display: none;
 }
 
+.n-layout {
+  height: 100%;
+}
 
 @media (prefers-color-scheme: dark) {
   :root {
-    --background-color: #1d1d1d;
-    --font-color: #ccc;
+
 
   }
 
@@ -24,8 +36,7 @@
 
 @media (prefers-color-scheme: light) {
   :root {
-    --background-color: white;
-    --font-color: #1d1d1d;
+
 
   }
 }

+ 0 - 218
src/components/add.vue

@@ -1,218 +0,0 @@
-<template>
-  <div class="add">
-    <div class="add-top">
-      <div>
-        <Icon
-          name="home"
-          :size="20"
-        />
-        <span>Home</span>
-      </div>
-
-      <n-button
-        size="tiny"
-        text
-        @click="showEdit = true; editData = undefined;"
-      >
-        <Icon name="add" />
-      </n-button>
-    </div>
-    <div class="add-content">
-      <div class="add-content-title">
-        History_
-      </div>
-      <n-scrollbar style="height: calc(100% - 30px);">
-        <div class="add-content-items">
-          <template
-            v-for="(item, index) in history"
-            :key="index"
-          >
-            <div class="add-content-items-item">
-              <Icon
-                name="cmd"
-                :size="30"
-              />
-              <div>
-                <p>{{ item.label }}</p>
-                <p>ssh {{ item.userName }}@{{ item.host }}:{{ item.port }}</p>
-              </div>
-              <div
-                class="add-content-items-item-edit"
-                @click.stop="edit(item)"
-              >
-                <Icon
-                  name="close"
-                  color="white"
-                  :size="15"
-                  @click.stop="history.splice(index, 1)"
-                />
-              </div>
-            </div>
-          </template>
-        </div>
-      </n-scrollbar>
-    </div>
-    <div
-      v-if="showEdit"
-      class="add-edit"
-    >
-      <Edit
-        :data="editData"
-        @call-back="editBack"
-      />
-    </div>
-  </div>
-</template>
-
-<script setup lang='ts'>
-import { reactive, ref } from 'vue'
-import Edit, { FormData } from '@/components/edit.vue'
-
-const emit = defineEmits<{(evt: 'callBack', value: FormData): void}>()
-const history = ref([
-  {
-    label: 'orange', userName: 'root', host: 'caner.top', port: '49657', password: ''
-  }
-] as FormData[])
-const click = reactive({
-  num: 0,
-  delay: 200,
-  timer: null as any
-})
-const showEdit = ref(false)
-const editData = ref(undefined as FormData | undefined)
-
-function edit(item: FormData) {
-  click.num++
-  if (click.num === 1) {
-    click.timer = setTimeout(() => {
-      editData.value = { ...item }
-      showEdit.value = true
-      click.num = 0
-    }, click.delay)
-  } else {
-    clearTimeout(click.timer)
-    emit('callBack', { ...item })
-    click.num = 0
-  }
-}
-
-function editBack(params: null | FormData) {
-  if (params) {
-  // 判断是编辑还是新增
-    const index = history.value.findIndex((el) => el.host === params.host && el.port === params.port && el.userName === params.userName)
-    if (index !== -1) {
-      console.log('修改', params)
-      history.value[index] = { ...params }
-    } else {
-      console.log('新增')
-      history.value.push({ ...params })
-    }
-  }
-  showEdit.value = false
-}
-</script>
-<style lang="scss" scoped>
-.add {
-  width: 90vw;
-  height: 60vh;
-  border-radius: 10px;
-  font-size: 14px;
-  overflow: hidden;
-  background: var(--background-color);
-
-  &-top {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding: 10px 15px;
-    font-size: 15px;
-
-    &>div:first-child {
-      display: flex;
-      align-items: center;
-
-      &>span {
-        margin-left: 5px;
-        font-weight: bold;
-      }
-    }
-  }
-
-  &-content {
-    height: calc(100% - 42px);
-    padding: 0 10px 10px 10px;
-
-    &-title {
-      font-weight: bold;
-      margin-bottom: 10px;
-      text-indent: 10px;
-      font-size: 14px;
-    }
-
-    &-items {
-      padding: 0 20px;
-      display: flex;
-      flex-wrap: wrap;
-      align-items: flex-start;
-
-      &-item {
-        display: flex;
-        align-items: center;
-        border: solid 1px #ccc;
-        border-radius: 10px;
-        padding: 10px;
-        cursor: pointer;
-        position: relative;
-        overflow: hidden;
-        margin-bottom: 10px;
-        width: 240px;
-
-        &>div:nth-child(2) {
-          margin-left: 10px;
-          font-size: 13px;
-
-          &>p:last-child {
-            color: #ccc;
-          }
-        }
-
-        &-edit {
-          position: absolute;
-          width: 100%;
-          height: 100%;
-          background: rgba($color: #000000, $alpha: 0.2);
-          display: none;
-          align-items: flex-start;
-          justify-content: flex-end;
-          left: 0;
-          top: 0;
-          margin: 0;
-          padding: 5px;
-        }
-
-        &:hover &-edit {
-          display: flex;
-        }
-        &:not(:nth-child(3n)){
-          margin-right: 10px;
-        }
-      }
-    }
-  }
-
-  &-edit {
-    position: fixed;
-    width: 100%;
-    height: 100%;
-    background: rgba($color: #000000, $alpha: 0.5);
-    top: 0;
-    left: 0;
-    z-index: 9999;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-
-  }
-}
-</style>

+ 0 - 243
src/components/edit.vue

@@ -1,243 +0,0 @@
-<template>
-  <div class="edit">
-    <div class="edit-top">
-      <span>Host Setting</span>
-      <Icon
-        name="close"
-        :size="20"
-        @click="callBack(false)"
-      />
-    </div>
-    <div class="edit-content">
-      <Icon
-        name="form"
-        :size="240"
-      />
-
-      <div>
-        <n-form
-          ref="formRef"
-          :model="formData"
-          :rules="rules"
-        >
-          <div>
-            <n-form-item
-              label="Address"
-              path="host"
-              inline
-            >
-              <n-input
-                v-model:value="formData.host"
-                placeholder="请输入"
-                clearable
-              />
-            </n-form-item>
-            <n-form-item
-              label="Port"
-              path="port"
-              inline
-            >
-              <n-input
-                v-model:value="formData.port"
-                placeholder="请输入"
-                clearable
-              />
-            </n-form-item>
-          </div>
-
-          <n-form-item
-            label="Label"
-            path="label"
-          >
-            <n-input
-              v-model:value="formData.label"
-              placeholder="请输入"
-              clearable
-            />
-          </n-form-item>
-          <n-form-item
-            label="UserName"
-            path="userName"
-          >
-            <n-input
-              v-model:value="formData.userName"
-              placeholder="请输入"
-              clearable
-            />
-          </n-form-item>
-          <n-form-item
-            label="Passord"
-            path="password"
-          >
-            <n-input
-              v-model:value="formData.password"
-              placeholder="请输入"
-              clearable
-            />
-          </n-form-item>
-        </n-form>
-        <div>
-          <n-button
-            ghost
-            type="tertiary"
-            @click="callBack(false)"
-          >
-            Cancel
-          </n-button>
-          <n-button
-            type="info"
-            ghost
-            @click="callBack(true)"
-          >
-            Save
-          </n-button>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang='ts'>
-import { FormItemRule } from 'naive-ui'
-import { ref } from 'vue'
-
-export interface FormData {
-  host: string,
-  port: string,
-  label: string,
-  userName: string,
-  password: string,
-  icon?: string,
-  size?: number,
-  sshCom?: any,
-  sftpCom?: any
-}
-const props = withDefaults(defineProps<{
-  data?: FormData
-}>(), {
-  data: () => ({
-    host: '',
-    port: '',
-    label: '',
-    userName: '',
-    password: ''
-  })
-})
-const emit = defineEmits<{(evt: 'callBack', value: FormData | null): void }>()
-const formRef = ref()
-class FormOldData {
-  host: string
-
-  port: string
-
-  label: string
-
-  userName: string
-
-  password: string
-
-  constructor() {
-    this.host = ''
-    this.port = ''
-    this.label = ''
-    this.userName = ''
-    this.password = ''
-  }
-}
-const formData = ref(props.data || new FormOldData())
-const rules = ref({
-  host: {
-    required: true, message: '请输入', validator: (_: FormItemRule, value: string) => !!value
-  },
-  port: {
-    required: true, message: '请输入', validator: (_: FormItemRule, value: string) => !!(/^[0-9]*$/.test(value)) && !!value
-  },
-  label: {
-    required: true, message: '请输入', validator: (_: FormItemRule, value: string) => !!value
-  },
-  userName: {
-    required: true, message: '请输入', validator: (_: FormItemRule, value: string) => !!value
-  },
-  password: {
-    required: true, message: '请输入', validator: (_: FormItemRule, value: string) => !!value
-  }
-})
-
-async function callBack(type: boolean) {
-  const data = type ? { ...formData.value } : null
-  if (type) await formRef.value.validate()
-  emit('callBack', data)
-  formData.value = new FormOldData()
-}
-</script>
-
-<style lang="scss" scoped>
-.edit {
-  width: 90vw;
-  height: 60vh;
-  background: var(--background-color);
-  border-radius: 10px;
-  font-size: 14px;
-  overflow: hidden;
-
-  &-top {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    font-weight: bold;
-    padding: 10px 15px;
-
-    &>svg {
-      cursor: pointer;
-    }
-  }
-
-  &-content {
-    padding: 10px 15px 0 0;
-    display: flex;
-    align-items: center;
-
-    &>svg {
-      margin-right: 10px;
-    }
-
-    &>div {
-      width: 100%;
-
-      :deep(.n-form) {
-        .n-input {
-          --n-border-focus: rgba(0, 0, 0, 0);
-          --n-border-hover: rgba(0, 0, 0, 0);
-          --n-box-shadow-focus: 0 0 0 2px rgba(0, 0, 0, .2);
-        }
-
-        &>div:first-child {
-          display: flex;
-
-          &>div:first-child {
-            width: 78%;
-            margin-right: 2%;
-          }
-        }
-      }
-
-      &>div:last-child {
-        display: flex;
-        align-items: center;
-        justify-content: flex-end;
-
-        &>button:last-child {
-          margin-left: 15px;
-        }
-
-        :deep(.n-button) {
-          --n-text-color-hover: none;
-          --n-border-focus: 1px solid #0000;
-          --n-border-hover: 1px solid #0000;
-        }
-      }
-    }
-
-  }
-}
-</style>

+ 0 - 190
src/components/head.vue

@@ -1,190 +0,0 @@
-<template>
-  <div
-    class="head"
-    data-tauri-drag-region
-  >
-    <div
-      ref="scrollItem"
-      class="head-items"
-    >
-      <template
-        v-for="(item, index) in list"
-        :key="index"
-      >
-        <div
-          class="head-items-item"
-          :class="{ active: index === selectTab }"
-          @click.stop="e => onChange(index, 'change')"
-        >
-          <div>
-            <div>
-              <Icon
-                :name="item.icon"
-                :size="item.size"
-              />
-              {{ item.label }}
-            </div>
-            <Icon
-              :style="`opacity:${index === 0 ? 0 : 1} ;`"
-              name="close"
-              :size="12"
-              @click.stop="onChange(index, 'del')"
-            />
-          </div>
-        </div>
-      </template>
-    </div>
-    <div
-      class="head-add"
-      @click="emit('update:showAdd', true)"
-    >
-      <Icon
-        name="add"
-        :size="15"
-      />
-    </div>
-  </div>
-</template>
-<script setup lang='ts'>
-import { ref, watch } from 'vue'
-import { FormData } from '@/components/edit.vue'
-
-const props = withDefaults(defineProps<{
-  showAdd?: boolean,
-  list: FormData[],
-  selectTab: number
-}>(), {
-  showAdd: false,
-  selectTab: 0,
-  list: () => []
-})
-const scrollItem = ref()
-
-const emit = defineEmits<{(evt: 'update:showAdd', value: boolean): void,
-  (evt: 'update:list', value: FormData[]): void,
-  (evt: 'onChange', value: { id: number, type: string }): void,
-}>()
-
-function onChange(id: number, type: string) {
-  if (id === 0 && type === 'del') return
-  emit('onChange', { id, type })
-}
-
-watch(() => props.selectTab, (v) => {
-  setTimeout(() => {
-    // 滚动
-    const dom = scrollItem.value.children[v]
-    const scrollNum = dom.offsetLeft - scrollItem.value.offsetWidth / 2 + dom.offsetWidth / 2
-    scrollItem.value.scrollLeft = scrollNum
-  }, 0)
-})
-
-</script>
-<style lang="scss" scoped>
-.head {
-  width: 100%;
-  height: 38px;
-  user-select: none;
-  text-shadow: 0px -2px -4px var(--shadow-color);
-  display: flex;
-  align-items: flex-end;
-  background: #ccc;
-  overflow: hidden;
-  color: var(--font-color);
-
-  &-items {
-    max-width: 85%;
-    margin-left: 70px;
-    display: flex;
-    align-items: flex-end;
-    overflow-x: auto;
-    scroll-behavior: smooth;
-    padding: 0 12px;
-    cursor: pointer;
-
-    /* 隐藏滚动条 */
-    &::-webkit-scrollbar {
-      width: 0 !important;
-      display: none;
-    }
-
-    &-item {
-      height: 34px;
-      font-size: 13px;
-      color: var(--font-color);
-      padding: 6px 8px 0 8px;
-      position: relative;
-
-      &>div {
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-
-        &>svg {
-          margin-top: 2px;
-          margin-left: 3px;
-          cursor: pointer;
-        }
-
-        &>div {
-          display: flex;
-          align-items: center;
-
-          &>svg {
-            margin-right: 5px;
-          }
-        }
-      }
-
-      &::after {
-        content: '';
-        height: 15px;
-        width: 2px;
-        border-radius: 3px;
-        background: #ddd;
-        position: absolute;
-        right: -2px;
-        top: 50%;
-        transform: translate(0, -50%);
-      }
-    }
-
-    .active {
-      background: white;
-      border-radius: 8px 8px 0 0;
-      position: relative;
-      box-shadow: 8px 8px 0 0 #ffffff, -8px 8px 0 0 #ffffff;
-
-      &::before {
-        content: '';
-        position: absolute;
-        left: -8px;
-        bottom: 0;
-        width: 8px;
-        height: 33px;
-        background: #ccc;
-        border-radius: 0 0 8px 0;
-      }
-
-      &::after {
-        content: '';
-        position: absolute;
-        right: -8px;
-        bottom: 0;
-        width: 8px;
-        height: 33px;
-        background: #ccc;
-        border-radius: 0 0 0 8px;
-      }
-
-    }
-  }
-
-  &-add {
-    height: 70%;
-    margin-left: 5px;
-    -webkit-app-region: no-drag;
-    cursor: pointer;
-  }
-}
-</style>

+ 1 - 1
src/components/icon.vue

@@ -3,7 +3,7 @@ import { computed } from 'vue'
 
 const props = defineProps<{
   name: string,
-  size?: number,
+  size?: number|string,
   color?: string
 }>()
 const symbolId = computed(() => `#icon-${props.name}`)

+ 52 - 0
src/components/layout.vue

@@ -0,0 +1,52 @@
+<template>
+  <n-layout>
+    <n-layout-header data-tauri-drag-region>
+      <div class="head">
+        <Icon
+          name="icon"
+          size="20"
+        />
+      </div>
+    </n-layout-header>
+    <n-layout-content>
+      <n-layout has-sider>
+        <n-layout-sider
+          bordered
+          show-trigger
+          collapse-mode="width"
+          width="216"
+          :native-scrollbar="false"
+        >
+          <n-menu
+            v-model:value="selectedKey"
+            accordion
+            :collapsed-icon-size="24"
+            :options="menuOptions"
+          />
+        </n-layout-sider>
+        <n-layout>
+          <div>13</div>
+        </n-layout>
+      </n-layout>
+    </n-layout-content>
+  </n-layout>
+</template>
+
+<script setup lang='ts'>
+import { h, ref } from 'vue'
+import Icon from './icon.vue'
+
+const selectedKey = ref('')
+const menuOptions = ref([
+  {
+    label: 'test',
+    icon: () => h(Icon, {
+      name: 'add',
+      size: 24
+    }),
+    disabled: true,
+    key: '1'
+  }
+])
+</script>
+<style lang="scss" scoped></style>

+ 0 - 24
src/components/loading.vue

@@ -1,24 +0,0 @@
-<template>
-  <div class="loader" />
-</template>
-<style scoped>
-.loader {
-  border: 5px solid #f3f3f3;
-  border-radius: 50%;
-  border-top: 5px solid #3498db;
-  width: 30px;
-  height: 30px;
-  -webkit-animation: spin 2s linear infinite;
-  animation: spin 2s linear infinite;
-}
-
-@-webkit-keyframes spin {
-  0% { -webkit-transform: rotate(0deg); }
-  100% { -webkit-transform: rotate(360deg); }
-}
-
-@keyframes spin {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(360deg); }
-}
-</style>