Merge branch 'release/2.0.0-alpha3'

This commit is contained in:
purocean
2019-08-02 20:43:16 +08:00
9 changed files with 116 additions and 49 deletions
+8 -4
View File
@@ -136,13 +136,17 @@
## 更新日志
[最新发布](https://github.com/purocean/yn/releases)
### [v2.0.0-alpha3](https://github.com/purocean/yn/releases/tag/v2.0.0-alpha3) 2019-08-02
1. 优化界面样式,提升交互体验
1. 修复若干 v2.0.0-alpha2 的问题
### [v2.0.0-alpha2](https://github.com/purocean/yn/releases/tag/v2.0.0-alpha2) 2019-08-02
1. 默认仓库数据和配置改为在 `<home>/yank-note` 下保存
2. 调整在 Windows 端的仓库配置,不论是否在 WSL 环境下都使用 windows 风格的路径
1. 调整在 Windows 端的仓库配置,不论是否在 WSL 环境下都使用 windows 风格的路径
1. 前端重构文件接口
2. 尝试引入 Electron
3. 后端重构改用 TypeScript
4. 修复若干 v2.0.0-alpha1 的问题
1. 尝试引入 Electron
1. 后端重构改用 TypeScript
1. 修复若干 v2.0.0-alpha1 的问题
### [v2.0.0-alpha1](https://github.com/purocean/yn/releases/tag/v2.0.0-alpha1) 2019-08-01
1. 目录树和集成终端增加拖动调整尺寸功能
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>YN</title>
<title>Yank-Note</title>
</head>
<body>
<div id="app"></div>
+9 -10
View File
@@ -157,17 +157,16 @@ export default {
console.error(error)
}
},
pasteImg (file) {
File.upload(this.currentFile.repo, this.currentFile.path, file, ({ relativePath }) => {
this.$bus.emit('file-uploaded', relativePath)
this.$refs.editor.insert(`![图片](${encodeURI(relativePath)})\n`)
})
async pasteImg (file) {
const { relativePath } = await File.upload(this.currentFile.repo, this.currentFile.path, file)
this.$bus.emit('file-uploaded', relativePath)
this.$refs.editor.insert(`![图片](${encodeURI(relativePath)})\n`)
},
uploadFile (file) {
File.upload(this.currentFile.repo, this.currentFile.path, file, ({ relativePath }) => {
this.$bus.emit('file-uploaded', relativePath)
this.$refs.editor.insert(`附件 [${dayjs().format('YYYY-MM-DD HH:mm')}]:[${file.name} (${(file.size / 1024).toFixed(2)}KiB)](${encodeURI(relativePath).replace('(', '%28').replace(')', '%29')}){class=open target=_blank}\n`)
}, `${dayjs().format('YYYYMMDDHHmmss')}.${file.name}`)
async uploadFile (file) {
const filename = `${dayjs().format('YYYYMMDDHHmmss')}.${file.name}`
const { relativePath } = await File.upload(this.currentFile.repo, this.currentFile.path, file, filename)
this.$bus.emit('file-uploaded', relativePath)
this.$refs.editor.insert(`附件 [${dayjs().format('YYYY-MM-DD HH:mm')}]:[${file.name} (${(file.size / 1024).toFixed(2)}KiB)](${encodeURI(relativePath).replace('(', '%28').replace(')', '%29')}){class=open target=_blank}\n`)
},
async changeFile (current, previous) {
this.clearTimer()
+23 -10
View File
@@ -3,7 +3,7 @@
<div class="wrapper" @click.stop>
<h4>{{title}}</h4>
<p v-if="content">{{content}}</p>
<input v-if="type === 'input'" ref="input" @keydown.enter.stop="ok" :type="type" :placeholder="inputHint" v-model="inputValue">
<input v-if="type === 'input'" ref="input" :type="inputType" :placeholder="inputHint" v-model="inputValue">
<div class="action">
<button @click="cancel">取消</button>
<button class="primary" @click="ok">确定</button>
@@ -30,38 +30,51 @@ export default {
}
},
methods: {
cancel () {
this.resolve && this.resolve(this.type === 'input' ? null : false)
handle (val) {
this.show = false
this.inputValue = ''
try {
this.resolve && this.resolve(val)
} catch (error) {
throw error
} finally {
this.resolve = null
}
},
cancel () {
this.handle(this.type === 'input' ? null : false)
},
ok () {
this.resolve && this.resolve(this.type === 'input' ? this.inputValue : true)
this.show = false
this.inputValue = ''
this.handle(this.type === 'input' ? this.inputValue : true)
},
confirm ({ title, content }) {
this.type = 'confirm'
this.show = true
this.title = title || '提示'
this.content = content || ''
this.show = true
return new Promise(resolve => {
this.resolve = resolve
})
},
input ({ type, title, hint, value, content }) {
input ({ type, title, hint, value, content, select = true }) {
this.type = 'input'
this.show = true
this.title = title || '请输入'
this.content = content || ''
this.inputType = type || 'text'
this.inputValue = value || ''
this.inputHint = hint || ''
this.show = true
this.$nextTick(() => {
this.$refs.input.focus()
this.$refs.input.select()
if (select) {
this.$refs.input.select()
if (Array.isArray(select)) {
this.$refs.input.setSelectionRange(...select)
}
}
})
return new Promise(resolve => {
+8 -10
View File
@@ -205,12 +205,11 @@ export default {
canvas.width = ximg.naturalWidth
canvas.height = ximg.naturalHeight
canvas.getContext('2d').drawImage(ximg, 0, 0)
canvas.toBlob(blob => {
canvas.toBlob(async blob => {
const imgFile = new File([blob], 'file.png')
file.upload(this.fileRepo, this.filePath, imgFile, result => {
this.$bus.emit('tree-refresh')
this.$bus.emit('editor-replace-value', img.src, result.relativePath)
})
const { relativePath } = await file.upload(this.fileRepo, this.filePath, imgFile)
this.$bus.emit('tree-refresh')
this.$bus.emit('editor-replace-value', img.src, relativePath)
})
}
@@ -221,12 +220,11 @@ export default {
img.src.startsWith('https://')
) {
window.fetch(`api/proxy?url=${encodeURI(img.src)}`).then(r => {
r.blob().then(blob => {
r.blob().then(async blob => {
const imgFile = new File([blob], 'file.' + mime.extension(r.headers.get('content-type')))
file.upload(this.fileRepo, this.filePath, imgFile, result => {
this.$bus.emit('tree-refresh')
this.$bus.emit('editor-replace-value', img.src, encodeURI(result.relativePath))
})
const { relativePath } = await file.upload(this.fileRepo, this.filePath, imgFile)
this.$bus.emit('tree-refresh')
this.$bus.emit('editor-replace-value', img.src, encodeURI(relativePath))
})
})
}
+33 -8
View File
@@ -1,6 +1,6 @@
<template>
<div class="tree-node">
<details v-if="item.type === 'dir'" class="name" :title="item.name + '\n\n' + dirTitle" ref="dir" :open="item.path === '/'">
<details @keydown.enter.prevent v-if="item.type === 'dir'" class="name" :title="item.name + '\n\n' + dirTitle" ref="dir" :open="item.path === '/'">
<summary
class="dir-label"
:style="{background: selected ? '#313131' : 'none'}"
@@ -13,13 +13,12 @@
</details>
<div
v-else
class="name"
:class="{name: true, 'file-name': true, selected}"
:title="item.name + '\n\n' + fileTitle"
@click="select(item)"
@dblclick.ctrl.exact="revealInExplorer()"
@contextmenu.ctrl.prevent="renameFile"
@contextmenu.shift.prevent="deleteFile"
:style="{background: selected ? '#313131' : 'none'}"> {{ item.name }} </div>
@contextmenu.shift.prevent="deleteFile"> {{ item.name }} </div>
</div>
</template>
@@ -99,7 +98,8 @@ export default {
title: '移动文件',
hint: '新的路径',
content: '当前路径:' + this.item.path,
value: this.item.path
value: this.item.path,
select: [this.item.path.lastIndexOf('/') + 1, this.item.path.length, 'forward']
})
if (!newPath) {
@@ -153,10 +153,18 @@ export default {
computed: {
...mapState('app', ['currentFile', 'currentRepo']),
selected () {
return this.currentFile && this.currentFile.path === this.item.path && this.currentFile.repo === this.item.repo
if (!this.currentFile) {
return false
}
if (this.item.type === 'dir') {
return this.currentFile.repo === this.item.repo && this.currentFile.path.startsWith(this.item.path + '/')
}
return this.currentFile.repo === this.item.repo && this.currentFile.path === this.item.path
},
shouldOpen () {
return this.currentFile && this.item.type === 'dir' && this.currentFile.path.startsWith(this.item.path + '/')
return this.item.type === 'dir' && this.currentFile && this.currentFile.path.startsWith(this.item.path + '/') && this.currentFile.repo === this.item.repo
}
},
watch: {
@@ -178,7 +186,7 @@ export default {
.tree-node {
border-left: 1px rgb(87, 87, 87) solid;
font-size: 16px;
line-height: 1.3em;
line-height: 1.4em;
padding-left: 1em;
}
@@ -192,6 +200,23 @@ export default {
overflow: hidden;
}
.file-name {
padding-left: 0.2em;
transition: 50ms ease;
}
.file-name.selected {
background: #5d5d5d;
}
.file-name:hover {
background: #5d5d5d;
}
.file-name:active {
padding-left: 0.3em;
}
.dir-label .count {
color: #989898;
font-size: 12px;
+1 -1
View File
@@ -98,7 +98,7 @@ const search = async (repo, text) => {
}
const upload = async (repo, belongPath, uploadFile, name = null) => {
return Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
belongPath = belongPath.replace(/\\/g, '/')
const fr = new FileReader()
+30 -2
View File
@@ -1,6 +1,34 @@
import Storage from '@/lib/Storage'
import file from '@/lib/file'
const getLastOpenFile = repo => {
const currentFile = Storage.get('currentFile')
const recentOpenTime = Storage.get('recentOpenTime', {})
if (!repo) {
return null
}
if (currentFile && currentFile.repo === repo.name) {
return currentFile
}
const item = Object.entries(recentOpenTime)
.filter(x => x[0].startsWith(repo.name + '|'))
.sort((a, b) => b[1] - a[1])[0]
if (!item) {
return null
}
const path = item[0].split('|', 2)[1]
if (!path) {
return null
}
return { repo: repo.name, name: file.basename(path), path }
}
export default {
namespaced: true,
state: {
@@ -13,7 +41,7 @@ export default {
previousContent: '',
previousHash: '',
currentRepo: Storage.get('currentRepo'),
currentFile: Storage.get('currentFile'),
currentFile: getLastOpenFile(Storage.get('currentRepo')),
recentOpenTime: Storage.get('recentOpenTime', {}),
passwordHash: {},
documentInfo: {
@@ -59,7 +87,7 @@ export default {
},
setCurrentRepo (state, data) {
state.currentRepo = data
state.currentFile = null
state.currentFile = getLastOpenFile(data)
state.tree = null
Storage.set('currentRepo', data)
},
+3 -3
View File
@@ -3,13 +3,13 @@ module.exports = {
port: 8066,
proxy: {
'/static': {
target: 'http://localhost:3044'
target: 'http://localhost:3000'
},
'/api': {
target: 'http://localhost:3044'
target: 'http://localhost:3000'
},
'/ws': {
target: 'http://localhost:3044',
target: 'http://localhost:3000',
ws: true
}
}