pipipi-pikachu 5 anni fa
parent
commit
205c0a04cf
3 ha cambiato i file con 378 aggiunte e 154 eliminazioni
  1. 210 151
      package-lock.json
  2. 1 0
      package.json
  3. 167 3
      src/views/Editor/Thumbnails/index.vue

+ 210 - 151
package-lock.json

@@ -2258,122 +2258,6 @@
         "tslint": "^5.20.1",
         "webpack": "^4.0.0",
         "yorkie": "^2.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792369066&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
-          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz",
-          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz?cache=0&sync_timestamp=1566248870121&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolor-convert%2Fdownload%2Fcolor-convert-2.0.1.tgz",
-          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
-          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
-          "dev": true,
-          "optional": true
-        },
-        "fork-ts-checker-webpack-plugin-v5": {
-          "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
-          "resolved": "https://registry.npm.taobao.org/fork-ts-checker-webpack-plugin/download/fork-ts-checker-webpack-plugin-5.2.1.tgz?cache=0&sync_timestamp=1607912103019&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffork-ts-checker-webpack-plugin%2Fdownload%2Ffork-ts-checker-webpack-plugin-5.2.1.tgz",
-          "integrity": "sha1-eTJthpeXkG+osk4qvPlCH8gFRQ0=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@babel/code-frame": "^7.8.3",
-            "@types/json-schema": "^7.0.5",
-            "chalk": "^4.1.0",
-            "cosmiconfig": "^6.0.0",
-            "deepmerge": "^4.2.2",
-            "fs-extra": "^9.0.0",
-            "memfs": "^3.1.2",
-            "minimatch": "^3.0.4",
-            "schema-utils": "2.7.0",
-            "semver": "^7.3.2",
-            "tapable": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz",
-          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
-          "dev": true,
-          "optional": true
-        },
-        "lru-cache": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427484405&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz",
-          "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "yallist": "^4.0.0"
-          }
-        },
-        "schema-utils": {
-          "version": "2.7.0",
-          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz",
-          "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@types/json-schema": "^7.0.4",
-            "ajv": "^6.12.2",
-            "ajv-keywords": "^3.4.1"
-          }
-        },
-        "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.4.tgz?cache=0&sync_timestamp=1606852064928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.4.tgz",
-          "integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1606205010380&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
-          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "yallist": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
-          "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
-          "dev": true,
-          "optional": true
-        }
       }
     },
     "@vue/cli-plugin-unit-jest": {
@@ -2537,17 +2421,6 @@
             "unique-filename": "^1.1.1"
           }
         },
-        "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz",
-          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
         "cliui": {
           "version": "6.0.0",
           "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz",
@@ -2610,18 +2483,6 @@
             "graceful-fs": "^4.1.6"
           }
         },
-        "loader-utils": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
-          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
@@ -2670,18 +2531,6 @@
           "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=",
           "dev": true
         },
-        "vue-loader-v16": {
-          "version": "npm:vue-loader@16.1.1",
-          "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.1.1.tgz?cache=0&sync_timestamp=1607093677581&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.1.1.tgz",
-          "integrity": "sha1-9bKG1grGiGaExjoXoYQ5HMngGZo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chalk": "^4.1.0",
-            "hash-sum": "^2.0.0",
-            "loader-utils": "^2.0.0"
-          }
-        },
         "wrap-ansi": {
           "version": "6.2.0",
           "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz",
@@ -7468,6 +7317,122 @@
         "worker-rpc": "^0.1.0"
       }
     },
+    "fork-ts-checker-webpack-plugin-v5": {
+      "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
+      "resolved": "https://registry.npm.taobao.org/fork-ts-checker-webpack-plugin/download/fork-ts-checker-webpack-plugin-5.2.1.tgz?cache=0&sync_timestamp=1608028579163&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffork-ts-checker-webpack-plugin%2Fdownload%2Ffork-ts-checker-webpack-plugin-5.2.1.tgz",
+      "integrity": "sha1-eTJthpeXkG+osk4qvPlCH8gFRQ0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@babel/code-frame": "^7.8.3",
+        "@types/json-schema": "^7.0.5",
+        "chalk": "^4.1.0",
+        "cosmiconfig": "^6.0.0",
+        "deepmerge": "^4.2.2",
+        "fs-extra": "^9.0.0",
+        "memfs": "^3.1.2",
+        "minimatch": "^3.0.4",
+        "schema-utils": "2.7.0",
+        "semver": "^7.3.2",
+        "tapable": "^1.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792302448&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz",
+          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+          "dev": true,
+          "optional": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1596294337050&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
+          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+          "dev": true,
+          "optional": true
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz",
+          "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "schema-utils": {
+          "version": "2.7.0",
+          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz",
+          "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "@types/json-schema": "^7.0.4",
+            "ajv": "^6.12.2",
+            "ajv-keywords": "^3.4.1"
+          }
+        },
+        "semver": {
+          "version": "7.3.4",
+          "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.4.tgz?cache=0&sync_timestamp=1606852122426&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.4.tgz",
+          "integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz",
+          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
+          "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
     "form-data": {
       "version": "2.3.3",
       "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz",
@@ -13919,6 +13884,11 @@
         "is-plain-obj": "^1.0.0"
       }
     },
+    "sortablejs": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npm.taobao.org/sortablejs/download/sortablejs-1.10.2.tgz",
+      "integrity": "sha1-bkA2TZE/mLhaFPZnj5K1wSIfUpA="
+    },
     "source-list-map": {
       "version": "2.0.1",
       "resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz",
@@ -15903,6 +15873,87 @@
         }
       }
     },
+    "vue-loader-v16": {
+      "version": "npm:vue-loader@16.1.2",
+      "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.1.2.tgz?cache=0&sync_timestamp=1608187974157&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.1.2.tgz",
+      "integrity": "sha1-XAO2xQ0qX5g8fOuhXFDXjKKymPQ=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "hash-sum": "^2.0.0",
+        "loader-utils": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792302448&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz",
+          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+          "dev": true,
+          "optional": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1596294337050&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
+          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+          "dev": true,
+          "optional": true
+        },
+        "loader-utils": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
+          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz",
+          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "vue-router": {
       "version": "4.0.1",
       "resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-4.0.1.tgz?cache=0&sync_timestamp=1607347245114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-4.0.1.tgz",
@@ -15947,6 +15998,14 @@
         }
       }
     },
+    "vuedraggable": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npm.taobao.org/vuedraggable/download/vuedraggable-4.0.1.tgz?cache=0&sync_timestamp=1606757821496&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuedraggable%2Fdownload%2Fvuedraggable-4.0.1.tgz",
+      "integrity": "sha1-O8qrCAi3lEAwt9min5pj1Z36EsU=",
+      "requires": {
+        "sortablejs": "1.10.2"
+      }
+    },
     "vuex": {
       "version": "4.0.0-rc.2",
       "resolved": "https://registry.npm.taobao.org/vuex/download/vuex-4.0.0-rc.2.tgz?cache=0&sync_timestamp=1606318238493&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuex%2Fdownload%2Fvuex-4.0.0-rc.2.tgz",

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "store2": "^2.12.0",
     "vue": "^3.0.0",
     "vue-router": "^4.0.0-0",
+    "vuedraggable": "^4.0.1",
     "vuex": "^4.0.0-0"
   },
   "devDependencies": {

+ 167 - 3
src/views/Editor/Thumbnails/index.vue

@@ -1,14 +1,147 @@
 <template>
-  <div class="thumbnails">
-    
+  <div 
+    class="thumbnails"
+    @mousedown="() => setThumbnailsFocus(true)"
+    v-click-outside="() => setThumbnailsFocus(false)"
+  >
+    <draggable 
+      class="thumbnail-list"
+      :modelValue="slides"
+      :animation="80"
+      :scroll="true"
+      :scrollSensitivity="50"
+      @end="handleDragEnd"
+      itemKey="id"
+    >
+      <template #item="{ index }">
+        <div
+          class="thumbnail-wrapper"
+          :class="{ 'active': slideIndex === index }"
+          @mousedown="changSlideIndex(index)"
+          v-contextmenu="contextmenus"
+        >
+          <div class="slide-index">{{ fillDigit(index + 1) }}</div>
+          <div class="thumbnail"></div>
+        </div>        
+      </template>
+    </draggable>
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent } from 'vue'
+import { computed, defineComponent } from 'vue'
+import draggable from 'vuedraggable'
+import { useStore } from 'vuex'
+import { State } from '@/store/state'
+import { MutationTypes } from '@/store/constants'
+import { fillDigit } from '@/utils/common'
 
 export default defineComponent({
   name: 'thumbnails',
+  components: {
+    draggable,
+  },
+  setup() {
+    const store = useStore<State>()
+    const slides = computed(() => store.state.slides)
+    const slideIndex = computed(() => store.state.slideIndex)
+
+    const changSlideIndex = (index: number) => {
+      store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
+
+      if(slideIndex.value === index) return
+      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index)
+    }
+
+    const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
+
+    const setThumbnailsFocus = (focus: boolean) => {
+      if(thumbnailsFocus.value === focus) return
+      store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, focus)
+    }
+
+    const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
+      const { newIndex, oldIndex } = eventData
+      if(oldIndex === newIndex) return
+
+      const _slides = JSON.parse(JSON.stringify(slides.value))
+      const _slide = _slides[oldIndex]
+      _slides.splice(oldIndex, 1)
+      _slides.splice(newIndex, 0, _slide)
+      store.commit(MutationTypes.SET_SLIDES, _slides)
+      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, newIndex)
+    }
+
+    const cutSlide = () => {
+      console.log('cutSlide')
+    }
+    const copySlide = () => {
+      console.log('copySlide')
+    }
+    const pasteSlide = () => {
+      console.log('pasteSlide')
+    }
+    const createSlide = () => {
+      console.log('createSlide')
+    }
+    const copyAndPasteSlide = () => {
+      console.log('copyAndPasteSlide')
+    }
+    const deleteSlide = () => {
+      console.log('deleteSlide')
+    }
+
+    const contextmenus = () => {
+      return [
+        {
+          text: '剪切',
+          subText: 'Ctrl + X',
+          icon: 'icon-scissor',
+          action: cutSlide,
+        },
+        {
+          text: '复制',
+          subText: 'Ctrl + C',
+          icon: 'icon-copy',
+          action: copySlide,
+        },
+        {
+          text: '粘贴',
+          subText: 'Ctrl + V',
+          icon: 'icon-paste',
+          action: pasteSlide,
+        },
+        { divider: true },
+        {
+          text: '新建页面',
+          subText: 'Enter',
+          icon: 'icon-add-page',
+          action: createSlide,
+        },
+        {
+          text: '复制页面',
+          icon: 'icon-copy',
+          action: copyAndPasteSlide,
+        },
+        {
+          text: '删除页面',
+          subText: 'Delete',
+          icon: 'icon-delete',
+          action: deleteSlide,
+        },
+      ]
+    }
+
+    return {
+      setThumbnailsFocus,
+      slides,
+      slideIndex,
+      changSlideIndex,
+      contextmenus,
+      fillDigit,
+      handleDragEnd,
+    }
+  },
 })
 </script>
 
@@ -16,7 +149,38 @@ export default defineComponent({
 .thumbnails {
   border-right: solid 1px #eee;
   background-color: #fff;
+  display: flex;
+  flex-direction: column;
   overflow: auto;
   padding: 5px 0;
+  user-select: none;
+}
+.thumbnail-wrapper {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 5px 0;
+
+  .thumbnail {
+    outline: 2px solid rgba($color: $themeColor, $alpha: .1);
+  }
+
+  &.active {
+    .slide-index {
+      color: $themeColor;
+    }
+    .thumbnail {
+      outline-color: $themeColor;
+    }
+  }
+}
+.thumbnail {
+  width: 120px;
+  height: 67.5px;
+}
+.slide-index {
+  font-size: 12px;
+  color: #999;
+  width: 20px;
 }
 </style>