mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
增加文件筛选面板
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
+ 重命名文件/目录:`ctrl + 右键文件/目录`
|
||||
+ 默认快捷键参考 [vscode](https://code.visualstudio.com/)
|
||||
+ 自定义编辑器快捷键
|
||||
+ `Ctrl + p` 打开文件快速跳转面板
|
||||
+ `Ctrl + s` 保存文档
|
||||
+ `Ctrl + Shift + Up` 当前行上移
|
||||
+ `Ctrl + Shift + Down` 当前行下移
|
||||
@@ -80,3 +81,4 @@
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<div @keydown.enter="chooseItem()" @keydown.up="selectItem(-1)" @keydown.down="selectItem(1)" class="filter" @click.stop="nope">
|
||||
<input @keydown.up.prevent="nope" @keydown.down.prevent="nope" ref="input" v-model="searchText" type="text" class="input" autofocus>
|
||||
<ul ref="result" class="result">
|
||||
<li
|
||||
v-for="item in list"
|
||||
:key="item.path"
|
||||
:class="{selected: selected === item}"
|
||||
@click="chooseItem(item)">
|
||||
<span>
|
||||
{{item.name}}
|
||||
</span>
|
||||
<span class="path">
|
||||
{{item.path.substr(0, item.path.lastIndexOf('/'))}}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="list.length < 1">无结果</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'x-filter',
|
||||
components: {},
|
||||
props: {
|
||||
files: Array
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selected: null,
|
||||
searchText: ''
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.input.focus()
|
||||
this.updateSelected()
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
methods: {
|
||||
nope () {
|
||||
// nope
|
||||
},
|
||||
updateSelected (item = null) {
|
||||
if (item) {
|
||||
this.selected = item
|
||||
} else {
|
||||
this.selected = this.list.length > 0 ? this.list[0] : null
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
const li = this.$refs.result.querySelector('li.selected')
|
||||
if (li) {
|
||||
li.scrollIntoViewIfNeeded()
|
||||
}
|
||||
})
|
||||
},
|
||||
selectItem (inc) {
|
||||
if (this.list.length < 1) {
|
||||
this.updateSelected()
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = this.list.findIndex(x => this.selected === x)
|
||||
|
||||
let index = currentIndex + inc
|
||||
if (index > this.list.length - 1) {
|
||||
index = 0
|
||||
} else if (index < 0) {
|
||||
index = this.list.length - 1
|
||||
}
|
||||
|
||||
this.updateSelected(this.list[index])
|
||||
},
|
||||
chooseItem (item = null) {
|
||||
if (item) {
|
||||
this.$emit('choose-item', item)
|
||||
} else if (this.selected) {
|
||||
this.$emit('choose-item', this.selected)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
list () {
|
||||
this.updateSelected()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
list () {
|
||||
return this.files.filter(x => x.path.toLowerCase().indexOf(this.searchText.toLowerCase()) > -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.filter {
|
||||
width: 600px;
|
||||
background: #403e3e;
|
||||
margin: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
font-size: 18px;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
background: #333030;
|
||||
color: #ddd;
|
||||
transition: all .1s ease-in-out;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
background: #242222;
|
||||
}
|
||||
|
||||
.result {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
.result li {
|
||||
color: #999;
|
||||
line-height: 1.5em;
|
||||
font-size: 18px;
|
||||
padding: 2px;
|
||||
transition: all .1s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.result li.selected,
|
||||
.result li:hover {
|
||||
padding: 2px 6px;
|
||||
background: #333030;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.result li span {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
.result li span.path {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
padding-left: .3em;
|
||||
}
|
||||
</style>
|
||||
@@ -8,31 +8,43 @@
|
||||
@move="onMove"
|
||||
@change="change"
|
||||
@select="f => file = f"
|
||||
@delete="onDelete"
|
||||
></TreeNode>
|
||||
@delete="onDelete" />
|
||||
<transition name="fade">
|
||||
<div v-if="showFilter" class="filter-wrapper" @click="showFilter = false">
|
||||
<XFilter @choose-item="f => { file = f; showFilter = false }" :files="files" />
|
||||
</div>
|
||||
</transition>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TreeNode from './TreeNode'
|
||||
import File from '../file'
|
||||
import TreeNode from './TreeNode'
|
||||
import XFilter from './Filter'
|
||||
|
||||
export default {
|
||||
name: 'tree',
|
||||
components: { TreeNode },
|
||||
components: { TreeNode, XFilter },
|
||||
data () {
|
||||
return {
|
||||
files: [],
|
||||
tree: [],
|
||||
file: null
|
||||
file: null,
|
||||
showFilter: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
window.addEventListener('keydown', this.keydownHandler)
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.keydownHandler)
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
File.tree(tree => {
|
||||
this.tree = tree
|
||||
this.files = this.travelFiles(tree)
|
||||
})
|
||||
},
|
||||
onDelete (path) {
|
||||
@@ -53,6 +65,32 @@ export default {
|
||||
},
|
||||
change (path) {
|
||||
this.init()
|
||||
},
|
||||
keydownHandler (e) {
|
||||
if (e.key === 'p' && e.ctrlKey) {
|
||||
this.showFilter = true
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
} else if (e.key === 'Escape' && this.showFilter) {
|
||||
this.showFilter = false
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
},
|
||||
travelFiles (tree) {
|
||||
let tmp = []
|
||||
|
||||
tree.forEach(node => {
|
||||
if (node.type === 'file' && node.path.endsWith('.md')) {
|
||||
tmp.push(node)
|
||||
}
|
||||
|
||||
if (Array.isArray(node.children)) {
|
||||
tmp = tmp.concat(this.travelFiles(node.children))
|
||||
}
|
||||
})
|
||||
|
||||
return tmp
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -67,4 +105,22 @@ export default {
|
||||
.side {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.filter-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, .2);
|
||||
z-index: 99999;
|
||||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user