Skip to content

Commit

Permalink
feat(explorer): support create directory
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 25, 2023
1 parent 6897219 commit e2f9a6e
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 26 deletions.
99 changes: 82 additions & 17 deletions plugins/explorer/client/file-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<template #prefix><slot name="prefix"></slot></template>
<template #suffix><slot name="suffix"></slot></template>
<template #control>
<el-button @click="showDialog = true">{{ lastname || hint }}</el-button>
<el-button @click="showDialog = true">{{ target ?? hint }}</el-button>
<el-dialog class="file-picker" destroy-on-close v-model="showDialog">
<template #header>
<el-button class="back-button" :disabled="current === '/'" @click="toPrevious()">
Expand All @@ -16,12 +16,25 @@
</template>
<el-scrollbar>
<div class="entry" v-for="entry in entries" :key="entry.name" @click="handleClick(entry)">
<k-icon class="entry-icon" :name="entry.type"></k-icon>{{ entry.name }}
<k-icon class="entry-icon" :name="entry.type"></k-icon>
<input
v-focus
v-if="entry.filename === current"
v-model="entry.name"
@keypress.enter.prevent="confirmRename()"
@keydown.escape.prevent="cancelRename()"
/>
<template v-else>{{ entry.name }}</template>
</div>
</el-scrollbar>
<template #footer>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="showDialog = false">确定</el-button>
<div class="left">
<el-button v-if="options.allowCreate" @click="createFolder()">创建新目录</el-button>
</div>
<div class="right">
<el-button @click="showDialog = false">取消</el-button>
<el-button v-if="allowDirectory" type="primary" @click="confirm()">选定当前目录</el-button>
</div>
</template>
</el-dialog>
</template>
Expand All @@ -31,9 +44,10 @@
<script lang="ts" setup>
import { computed, PropType, ref } from 'vue'
import { Schema, SchemaBase, store } from '@koishijs/client'
import { files } from './store'
import { isNullable, Schema, SchemaBase, send, store, useConfig } from '@koishijs/client'
import { files, vFocus } from './store'
import { Entry } from '@koishijs/plugin-explorer'
import {} from 'koishi'
const props = defineProps({
schema: {} as PropType<Schema>,
Expand All @@ -43,12 +57,20 @@ const props = defineProps({
initial: {} as PropType<{}>,
})
const emit = defineEmits(['update:modelValue'])
const config = useConfig<string>()
defineEmits(['update:modelValue'])
const options = computed<Schemastery.Path.Options>(() => ({
filters: ['file'],
...props.schema.meta.extra,
}))
const allowDirectory = computed(() => options.value.filters.includes('directory'))
const hint = computed(() => {
const { filters = ['file'] } = props.schema.meta.extra
if (filters.includes('directory')) {
return filters.length === 1 ? '选择目录' : '选择目录或文件'
if (allowDirectory.value) {
return options.value.filters.length === 1 ? '选择目录' : '选择目录或文件'
} else {
return '选择文件'
}
Expand All @@ -62,25 +84,69 @@ const entries = computed(() => {
})
function handleClick(entry: Entry) {
if (entry.filename === current.value) return
if (entry.type === 'directory') {
current.value = current.value + entry.name + '/'
} else {
emit('update:modelValue', current.value.slice(1) + entry.name)
config.value = current.value.slice(1) + entry.name
showDialog.value = false
}
}
const lastname = computed(() => {
if (!props.modelValue) return
const index = props.modelValue.lastIndexOf('/')
return index === -1 ? props.modelValue : props.modelValue.slice(index + 1)
function createFolder() {
files[current.value] = {
type: 'directory',
name: '',
filename: current.value,
oldValue: '',
newValue: '',
}
const parent = files[current.value.slice(0, -1)]?.children || store?.explorer || []
parent.push(files[current.value])
}
function confirmRename() {
const entry = files[current.value]
if (!entry) return
const filename = current.value + entry.name
if (filename in files || !entry.name) {
cancelRename()
} else {
files[filename] = entry
delete files[current.value]
send('explorer/mkdir', filename)
entry.filename = filename
}
}
function cancelRename() {
const entry = files[current.value]
if (!entry) return
delete files[current.value]
const parent = files[current.value.slice(0, -1)]?.children || store?.explorer || []
parent.splice(parent.indexOf(entry), 1)
}
const target = computed(() => {
if (isNullable(config.value)) return
if (!config.value) return '根目录'
const entry = files['/' + config.value]
if (!entry) return config.value
return (entry.type === 'file' ? '文件:' : '目录:') + entry.name
})
function toPrevious() {
const index = current.value.slice(0, -1).lastIndexOf('/')
current.value = current.value.slice(0, index + 1)
}
function confirm() {
showDialog.value = false
if (allowDirectory.value) {
config.value = current.value.slice(1, -1)
}
}
</script>

<style lang="scss">
Expand Down Expand Up @@ -128,8 +194,7 @@ function toPrevious() {
.el-dialog__footer {
display: flex;
gap: 1rem;
justify-content: flex-end;
justify-content: space-between;
}
}
Expand Down
12 changes: 4 additions & 8 deletions plugins/explorer/client/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,15 @@

<script lang="ts" setup>
import { Directive, ref, computed, watch, onActivated, nextTick } from 'vue'
import { ref, computed, watch, onActivated, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useDark, useElementSize, useEventListener } from '@vueuse/core'
import { send, store, base64ToArrayBuffer, arrayBufferToBase64 } from '@koishijs/client'
import { Entry } from '../src'
import { files } from './store'
import { Entry } from '@koishijs/plugin-explorer'
import { files, vFocus } from './store'
import { model } from './editor'
import * as monaco from 'monaco-editor'
const vFocus: Directive = {
mounted: (el) => el.focus()
}
interface TreeEntry extends Entry {
expanded?: boolean
}
Expand Down Expand Up @@ -373,7 +369,7 @@ async function downloadFile(filename: string) {
const blob = new Blob([base64ToArrayBuffer(base64)])
const url = URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url;
a.href = url
a.download = filename
a.click()
URL.revokeObjectURL(url)
Expand Down
6 changes: 5 additions & 1 deletion plugins/explorer/client/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dict, store } from '@koishijs/client'
import { reactive, watch } from 'vue'
import { Directive, reactive, watch } from 'vue'
import { Entry } from '@koishijs/plugin-explorer'

export const files = reactive<Dict<Entry>>({})
Expand All @@ -20,3 +20,7 @@ watch(() => store.explorer, () => {
delete files[filename]
}
}, { immediate: true })

export const vFocus: Directive = {
mounted: (el) => el.focus(),
}

0 comments on commit e2f9a6e

Please sign in to comment.