Your Name 3 years ago
parent
commit
09530a9756

+ 65
- 0
src/components/ContextMenu.vue View File

1
+<template>
2
+  <div class="content-menu-box">
3
+    <a-menu @click="handleMenu" v-model:selectedKeys="selectedKeys">
4
+      <a-menu-item key="save">
5
+        新建文件
6
+      </a-menu-item>
7
+      <a-menu-divider />
8
+      <a-menu-item key="newfolder">
9
+        新建文件夹
10
+      </a-menu-item>
11
+    </a-menu>
12
+  </div>
13
+  <a-modal v-model:visible="visible" title="新建" @ok="confirmNew">
14
+    <a-input v-model:value="inputText" placeholder="请输入名称" />
15
+  </a-modal>
16
+</template>
17
+
18
+<script setup>
19
+import { computed, ref } from 'vue'
20
+// import { useModel } from '@zjxpcyc/vue-tiny-store'
21
+import eventBus from '@/utils/eventBus'
22
+
23
+const visible = ref(false)
24
+const inputText = ref()
25
+const menuKey = ref()
26
+const selectedKeys = ref([])
27
+// const { curMenu } = useModel('menu')
28
+// const saveDisabledItem = computed(() => {
29
+//   return !curMenu.value || curMenu.value.type !== 'file'
30
+// })
31
+
32
+const emit = defineEmits(['menuClick'])
33
+
34
+const confirmNew = () => {
35
+  const inputValue = inputText.value
36
+
37
+  switch (menuKey.value) {
38
+    case 'save':
39
+      eventBus.dispatchEvent('menu.newFile', inputValue)
40
+      break;
41
+    case 'newfolder':
42
+      eventBus.dispatchEvent('menu.newFolder', inputValue)
43
+      break;
44
+    default:
45
+      break;
46
+  }
47
+  visible.value = false
48
+  inputText.value = undefined
49
+}
50
+
51
+const handleMenu = (e) => {
52
+  menuKey.value = e.key
53
+  visible.value = true
54
+  // 主要是为了清除样式, 但是暂时不起作用, 不知道为啥
55
+  selectedKeys.value = []
56
+  emit('menuClick')
57
+}
58
+
59
+</script>
60
+
61
+<style lang="less" scoped>
62
+.content-menu-box {
63
+  width: 200px;
64
+}
65
+</style>

+ 42
- 2
src/components/SubMenu.vue View File

3
     <a-sub-menu
3
     <a-sub-menu
4
       v-if="menu.type === 'dir'"
4
       v-if="menu.type === 'dir'"
5
       :key="`/@@dir@@/${menu.path}`"
5
       :key="`/@@dir@@/${menu.path}`"
6
-      :title="menu.name"
7
     >
6
     >
7
+      <template #title>
8
+        <a-tooltip v-model:visible="tipVisible" trigger="contextmenu" placement="bottom" overlayClassName="menu-tooltip">
9
+          <template #title>
10
+            <ContextMenuVue @menuClick="tipVisible = false" />
11
+          </template>
12
+          <div @contextmenu="handleContextMenu(`/@@dir@@/${menu.path}`)">
13
+            {{menu.name}}
14
+          </div>
15
+          </a-tooltip>
16
+      </template>
8
       <template v-if="menu.children">
17
       <template v-if="menu.children">
9
-        <SubMenu :menus="menu.children" :sub-menu="SubMenu" />
18
+        <SubMenu :menus="menu.children" :sub-menu="SubMenu" @contextfolder="handleContextMenu" />
10
       </template>
19
       </template>
11
     </a-sub-menu>
20
     </a-sub-menu>
12
     <a-menu-item v-else :key="`/@@file@@/${menu.path}`">{{ menu.name }}</a-menu-item>
21
     <a-menu-item v-else :key="`/@@file@@/${menu.path}`">{{ menu.name }}</a-menu-item>
14
 </template>
23
 </template>
15
 
24
 
16
 <script setup>
25
 <script setup>
26
+import { ref } from 'vue'
27
+import ContextMenuVue from './ContextMenu.vue';
17
 
28
 
18
 const props = defineProps({
29
 const props = defineProps({
19
   menus: {
30
   menus: {
23
   subMenu: undefined,
34
   subMenu: undefined,
24
 })
35
 })
25
 
36
 
37
+const emit = defineEmits([ 'contextfolder' ])
38
+
26
 const SubMenu = props.subMenu
39
 const SubMenu = props.subMenu
27
 
40
 
41
+const tipVisible = ref(false)
42
+
43
+const handleContextMenu = (key) => {
44
+  if (Array.isArray(key)) {
45
+    emit('contextfolder', key)
46
+  } else {
47
+    emit('contextfolder', [key])
48
+  }
49
+}
50
+
28
 </script>
51
 </script>
52
+
53
+
54
+<style lang="less">
55
+.menu-tooltip {
56
+  .ant-tooltip-arrow-content {
57
+    background-color: transparent;
58
+  }
59
+  
60
+  .ant-tooltip-inner {
61
+    padding: 0;
62
+    background: transparent;
63
+    border: 1px solid rgba(0, 0, 0, 0.1);
64
+    border-radius: 8px;
65
+    overflow: hidden;
66
+  }
67
+}
68
+</style>

+ 2
- 2
src/layouts/NoteLayout.vue View File

1
 <template>
1
 <template>
2
   <a-layout>
2
   <a-layout>
3
-    <a-layout-header>
3
+    <!-- <a-layout-header>
4
       <Header />
4
       <Header />
5
-    </a-layout-header>
5
+    </a-layout-header> -->
6
     <a-layout>
6
     <a-layout>
7
       <a-layout-sider class="layout-sider" :width="siderWidth">
7
       <a-layout-sider class="layout-sider" :width="siderWidth">
8
         <SiderBar :menu-style="menuStyle" />
8
         <SiderBar :menu-style="menuStyle" />

+ 0
- 55
src/layouts/components/Header.vue View File

1
 <template>
1
 <template>
2
   <div></div>
2
   <div></div>
3
-  <div>
4
-    <a-menu theme="dark" mode="horizontal" class="menu-navi" @click="handleMenu">
5
-      <a-menu-item key="save" :disabled="saveDisabledItem">
6
-        <template #icon>
7
-          <save-outlined />
8
-        </template>
9
-        保存
10
-      </a-menu-item>
11
-      <a-menu-item key="newfolder">
12
-        <template #icon>
13
-          <folder-add-outlined />
14
-        </template>
15
-        文件夹
16
-      </a-menu-item>
17
-    </a-menu>
18
-  </div>
19
-  <a-modal v-model:visible="newFolderVisible" title="新建文件夹" @ok="confirmNewFolder">
20
-    <a-input v-model:value="newFolderName" placeholder="请输入文件夹名称" />
21
-  </a-modal>
22
 </template>
3
 </template>
23
 
4
 
24
 <script setup>
5
 <script setup>
25
-import { computed, ref } from 'vue'
26
-import { useModel } from '@zjxpcyc/vue-tiny-store'
27
-import { SaveOutlined, FolderAddOutlined } from '@ant-design/icons-vue';
28
-import eventBus from '@/utils/eventBus'
29
-
30
-const newFolderVisible = ref(false)
31
-const newFolderName = ref()
32
-const { curMenu } = useModel('menu')
33
-const saveDisabledItem = computed(() => {
34
-  return !curMenu.value || curMenu.value.type !== 'file'
35
-})
36
-
37
-const confirmNewFolder = () => {
38
-  newFolderVisible.value = false
39
-  eventBus.dispatchEvent('menu.newFolder', newFolderName.value)
40
-  newFolderName.value = undefined
41
-}
42
-
43
-const handleMenu = (e) => {
44
-  switch (e.key) {
45
-    case 'save':
46
-      eventBus.dispatchEvent('menu.save')
47
-      break;
48
-    case 'newfolder':
49
-      newFolderVisible.value = true
50
-      break;
51
-    default:
52
-      break;
53
-  }
54
-}
55
-
56
 </script>
6
 </script>
57
 
7
 
58
 <style lang="less" scoped>
8
 <style lang="less" scoped>
59
-.menu-navi {
60
-  :deep(.ant-menu-item) {
61
-    color: #fff;
62
-  }
63
-}
64
 </style>
9
 </style>

+ 24
- 2
src/layouts/components/SiderBar.vue View File

8
       mode="inline"
8
       mode="inline"
9
       triggerSubMenuAction="click"
9
       triggerSubMenuAction="click"
10
     >
10
     >
11
-      <SubMenu :menus="menus" :sub-menu="SubMenu"></SubMenu>
11
+      <a-menu-item-group key="g1">
12
+        <template #title>
13
+          <a-tooltip trigger="contextmenu" placement="bottom" overlayClassName="menu-tooltip">
14
+            <template #title>
15
+              <ContextMenuVue />
16
+            </template>
17
+            <div>我的日记</div>
18
+          </a-tooltip>
19
+        </template>
20
+      </a-menu-item-group>
21
+      <SubMenu :menus="menus" :sub-menu="SubMenu" @contextfolder="handleOpenChange"></SubMenu>
12
     </a-menu>
22
     </a-menu>
13
   </div>
23
   </div>
14
 </template>
24
 </template>
15
 
25
 
16
 <script setup>
26
 <script setup>
17
 import { useModel } from '@zjxpcyc/vue-tiny-store'
27
 import { useModel } from '@zjxpcyc/vue-tiny-store'
28
+import ContextMenuVue from '@/components/ContextMenu.vue';
18
 import SubMenu from '@/components/SubMenu.vue';
29
 import SubMenu from '@/components/SubMenu.vue';
19
 import eventBus from '@/utils/eventBus'
30
 import eventBus from '@/utils/eventBus'
20
 
31
 
28
 const { user } = useModel('user')
39
 const { user } = useModel('user')
29
 const { curMenu, menus, getMenus } = useModel('menu')
40
 const { curMenu, menus, getMenus } = useModel('menu')
30
 const { getNote } = useModel('note')
41
 const { getNote } = useModel('note')
42
+const { newFile, newFolder } = useModel('repo')
31
 
43
 
32
 if (!menus || !menus.length) {
44
 if (!menus || !menus.length) {
33
   getMenus(user).then(res => {
45
   getMenus(user).then(res => {
80
 }
92
 }
81
 
93
 
82
 const createNewFolder = (newFolderName) => {
94
 const createNewFolder = (newFolderName) => {
83
-  console.log('----newFolderName---->', newFolderName)
95
+  if (!curMenu.value) return;
96
+
97
+  const path = curMenu.value.path + `/${newFolderName}`
98
+
99
+  newFolder(path, user).then(() => {
100
+    // 获取父级信息, 目的刷新当前目录
101
+    getMenus(user, curMenu.value.path).then(res => {
102
+      curMenu.value.children = res || []
103
+    })
104
+  })
105
+
84
 }
106
 }
85
 
107
 
86
 
108
 

+ 8
- 0
src/store/model/repo.js View File

31
     return request.post(`/api/v5/repos/${user.login}/${repo}`, data).then(res => Object.assign(repo, res))
31
     return request.post(`/api/v5/repos/${user.login}/${repo}`, data).then(res => Object.assign(repo, res))
32
   }
32
   }
33
 
33
 
34
+  // 新增文件
34
   const newFile = (content, path, user, repo = 'my-note') => {
35
   const newFile = (content, path, user, repo = 'my-note') => {
35
     const { access_token } = user.token
36
     const { access_token } = user.token
36
     const data = {
37
     const data = {
40
     }
41
     }
41
     return request.post(`/api/v5/repos/${user.login}/${repo}/contents/${path}`, data)
42
     return request.post(`/api/v5/repos/${user.login}/${repo}/contents/${path}`, data)
42
   }
43
   }
44
+  
45
+  // 新增目录, 其实就是新增一个 内容是 # 的 .gitignore 文件
46
+  const newFolder = (path, user, repo = 'my-note') => {
47
+    const filePath = `${path}/.gitignore`
48
+    return newFile('#', filePath, user, repo)
49
+  }
43
 
50
 
44
   return {
51
   return {
45
     repo,
52
     repo,
47
     newRepo,
54
     newRepo,
48
     newBranch,
55
     newBranch,
49
     newFile,
56
     newFile,
57
+    newFolder,
50
   }
58
   }
51
 }
59
 }