mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
Merge branch 'release/2.0.0-beta9.0'
This commit is contained in:
@@ -49,13 +49,14 @@
|
||||
+ 样式风格:Markdown 使用 GitHub 风格样式和特性
|
||||
+ 数据仓库:可定义多个数据位置以便文档分类
|
||||
+ 外链转换:将外链或 BASE64 图片转换为本地图片:`Ctrl + Shift + 单击图片` `Ctrl + Alt + L` 转换所有外链图片到本地
|
||||
+ HTML 解析:可以直接在文档里面使用 HTML 代码,也可以使用快捷键 `Ctrl + B + V` 粘贴复制 HTMl 为 Markdown
|
||||
+ HTML 解析:可以直接在文档里面使用 HTML 代码,也可以使用快捷键 `Ctrl + B + V` 粘贴复制 HTML 为 Markdown
|
||||
+ docx 导出:后端使用 pandoc 做转换器
|
||||
+ TOC 支持:生成 TOC 在需要生成目录的地方写入 `[toc]{type: "ol", level: [1,2,3]}` 即可,,示例见 FEATURE.md
|
||||
+ 嵌入小工具:文档支持内嵌 HTML 小工具,示例见 FEATURE.md
|
||||
+ 嵌入 Plantuml 图形:需要安装 Java,graphviz ,示例见 FEATURE.md
|
||||
+ 嵌入 drawio 图形:文档支持内嵌 drawio 图形,示例见 FEATURE.md
|
||||
+ 嵌入 ECharts 图形:在文档中嵌入 Echarts 图形,示例见 FEATURE.md
|
||||
+ 嵌入 Mermaid 图形:在文档中嵌入 Mermaid 图形,示例见 FEATURE.md
|
||||
+ 元素属性书写:可自定义元素的任意属性,示例见 FEATURE.md
|
||||
+ 表格解析增强:表格支持表格标题多行文本,列表等特性,示例见 FEATURE.md
|
||||
|
||||
@@ -147,7 +148,7 @@ yarn run start
|
||||
## 更新日志
|
||||
[最新发布](https://github.com/purocean/yn/releases)
|
||||
|
||||
### [v2.0.0-beta8.4](https://github.com/purocean/yn/releases/tag/v2.0.0-beta8.4) 2019-08-28
|
||||
### [v2.0.0-beta9.0](https://github.com/purocean/yn/releases/tag/v2.0.0-beta9.0) 2019-09-02
|
||||
1. 增加 2.0 计划
|
||||
1. Electron 打包
|
||||
1. 增加 HTML 小工具渲染
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"markdown-it-katex": "^2.0.3",
|
||||
"markdown-it-multimd-table": "^3.1.3",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"mermaid": "^8.2.6",
|
||||
"mime-types": "^2.1.24",
|
||||
"monaco-editor": "^0.17.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<MonacoEditor
|
||||
ref="editor"
|
||||
class="editor"
|
||||
@change="val => $store.commit('app/setCurrentContent', val)"
|
||||
@change="setCurrentValue"
|
||||
@ready="editorReady"
|
||||
@scroll-view="syncScrollView"
|
||||
@paste-img="pasteImg"
|
||||
@@ -52,6 +52,11 @@ export default {
|
||||
this.$bus.off('file-new', this.createFile)
|
||||
},
|
||||
methods: {
|
||||
setCurrentValue ({ uri, value }) {
|
||||
if (this.toUri(this.currentFile) === uri) {
|
||||
this.$store.commit('app/setCurrentContent', value)
|
||||
}
|
||||
},
|
||||
saveFileOpenPosition (top) {
|
||||
if (this.currentFile) {
|
||||
const map = Storage.get(FILE_POSITION_KEY, {})
|
||||
@@ -126,6 +131,13 @@ export default {
|
||||
this.$emit('scroll-line', line)
|
||||
this.saveFileOpenPositionDebounce(top)
|
||||
},
|
||||
toUri (file) {
|
||||
if (file) {
|
||||
return `yank-note://${file.repo}/${file.path.replace(/^\//, '')}`
|
||||
} else {
|
||||
return 'yank-note://system/blank.md'
|
||||
}
|
||||
},
|
||||
async saveFile (f = null) {
|
||||
const file = f || this.currentFile
|
||||
|
||||
@@ -186,7 +198,6 @@ export default {
|
||||
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.$refs.editor.setScrollToTop(0)
|
||||
this.clearTimer()
|
||||
|
||||
if (previous && previous.repo && previous.path) {
|
||||
@@ -195,7 +206,7 @@ export default {
|
||||
|
||||
if (!current) {
|
||||
this.$store.commit('app/setPreviousContent', '\n')
|
||||
this.$refs.editor.setValue('\n')
|
||||
this.$refs.editor.setModel(this.toUri(current), '\n')
|
||||
this.$store.commit('app/setCurrentFile', null)
|
||||
return
|
||||
}
|
||||
@@ -203,7 +214,7 @@ export default {
|
||||
if (current.content) { // 系统文件
|
||||
this.$store.commit('app/setPreviousContent', current.content)
|
||||
this.$store.commit('app/setSavedAt', null)
|
||||
this.$refs.editor.setValue(current.content)
|
||||
this.$refs.editor.setModel(this.toUri(current), current.content)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -222,7 +233,7 @@ export default {
|
||||
this.$store.commit('app/setPreviousContent', content)
|
||||
this.$store.commit('app/setPreviousHash', hash)
|
||||
this.$store.commit('app/setSavedAt', null)
|
||||
this.$refs.editor.setValue(content)
|
||||
this.$refs.editor.setModel(this.toUri(current), content)
|
||||
} catch (error) {
|
||||
this.$store.commit('app/setCurrentFile', null)
|
||||
this.$toast.show('warning', error.message)
|
||||
|
||||
@@ -6,19 +6,14 @@
|
||||
import dayjs from 'dayjs'
|
||||
import TurndownService from 'turndown'
|
||||
|
||||
const models = {}
|
||||
|
||||
const keys = {}
|
||||
|
||||
export default {
|
||||
name: 'monaco-editor',
|
||||
props: {
|
||||
value: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.editor = null
|
||||
if (!window.require) {
|
||||
const loaderScript = document.createElement('script')
|
||||
loaderScript.type = 'text/javascript'
|
||||
@@ -38,6 +33,30 @@ export default {
|
||||
window.removeEventListener('keyup', this.recordKeys)
|
||||
},
|
||||
methods: {
|
||||
getModel (uri, value) {
|
||||
let model = models[uri]
|
||||
|
||||
if (!model) {
|
||||
model = window.monaco.editor.createModel(value, undefined, window.monaco.Uri.parse(uri))
|
||||
model.onDidChangeContent(e => {
|
||||
let value = model.getValue()
|
||||
const eol = model.getEOL()
|
||||
if (!value.endsWith(eol)) {
|
||||
value += eol
|
||||
model.setValue(value)
|
||||
}
|
||||
this.$emit('change', { uri, value })
|
||||
})
|
||||
}
|
||||
|
||||
// TODO 不用 set value 保留编辑状态
|
||||
model.setValue(value)
|
||||
|
||||
// TODO 缓存 model
|
||||
models[uri] = model
|
||||
|
||||
return model
|
||||
},
|
||||
recordKeys (e) {
|
||||
if (e.type === 'keydown') {
|
||||
keys[e.key] = true
|
||||
@@ -56,9 +75,12 @@ export default {
|
||||
})
|
||||
},
|
||||
initMonaco () {
|
||||
window.supportedExtensions = window.monaco.languages.getLanguages().flatMap(x => x.extensions)
|
||||
|
||||
const model = this.getModel('yank-note://system/blank.md', '')
|
||||
|
||||
this.editor = window.monaco.editor.create(window.document.getElementById('editor'), {
|
||||
value: this.value,
|
||||
language: 'markdown',
|
||||
value: '',
|
||||
theme: 'vs-dark',
|
||||
fontSize: 18,
|
||||
wordWrap: false,
|
||||
@@ -73,23 +95,14 @@ export default {
|
||||
scrollbar: {
|
||||
vertical: 'hidden',
|
||||
verticalScrollbarSize: 0
|
||||
}
|
||||
},
|
||||
model,
|
||||
})
|
||||
|
||||
this.editor.onDidChangeCursorSelection(e => {
|
||||
this.$emit('change-document', this.getDucumentInfo())
|
||||
})
|
||||
|
||||
this.editor.onDidChangeModelContent(e => {
|
||||
let val = this.getValue()
|
||||
const eol = this.editor.getModel().getEOL()
|
||||
if (!val.endsWith(eol)) {
|
||||
val += eol
|
||||
this.setValue(val)
|
||||
}
|
||||
this.$emit('change', val)
|
||||
})
|
||||
|
||||
this.editor.onDidScrollChange(e => {
|
||||
const line = this.editor.getVisibleRanges()[0].startLineNumber
|
||||
const top = this.editor.getScrollTop()
|
||||
@@ -248,11 +261,12 @@ export default {
|
||||
getValue () {
|
||||
return this.editor.getModel().getValue(window.monaco.editor.DefaultEndOfLine.LF)
|
||||
},
|
||||
setValue (val) {
|
||||
this.editor.getModel().setValue(val)
|
||||
setModel (uri, value) {
|
||||
const model = this.getModel(uri, value || '')
|
||||
this.editor.setModel(model)
|
||||
},
|
||||
replaceValue (oldValue, newValue) {
|
||||
this.setValue(this.getValue().replace(oldValue, newValue))
|
||||
this.editor.getModel().setValue(this.getValue().replace(oldValue, newValue))
|
||||
},
|
||||
getDucumentInfo () {
|
||||
const selection = this.editor.getSelection()
|
||||
@@ -269,7 +283,7 @@ export default {
|
||||
const isWrapping = this.editor.getConfiguration().wrappingInfo.isViewportWrapping
|
||||
this.editor.updateOptions({ wordWrap: !isWrapping })
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import SourceLinePlugin from '../plugins/SourceLinePlugin'
|
||||
import LinkTargetPlugin from '../plugins/LinkTargetPlugin'
|
||||
import DrawioPlugin from '../plugins/DrawioPlugin'
|
||||
import PlantumlPlugin from '../plugins/PlantumlPlugin'
|
||||
import MermaidPlugin from '../plugins/MermaidPlugin'
|
||||
import file from '@/lib/file'
|
||||
import env from '@/lib/env'
|
||||
|
||||
@@ -91,6 +92,7 @@ const markdown = Markdown({
|
||||
.use(MultimdTable, { enableMultilineRows: true })
|
||||
.use(MarkdownItToc)
|
||||
.use(MarkdownItECharts)
|
||||
.use(MermaidPlugin)
|
||||
|
||||
export default {
|
||||
name: 'xview',
|
||||
@@ -115,13 +117,18 @@ export default {
|
||||
}, 1000, { leading: true })
|
||||
|
||||
this.render = _.debounce(() => {
|
||||
this.$refs.view.innerHTML = markdown.render(this.replaceRelativeLink(this.currentContent))
|
||||
MarkdownItECharts.update()
|
||||
// 编辑非 markdown 文件预览直接显示代码
|
||||
const content = (this.filePath || '').endsWith('.md')
|
||||
? this.currentContent
|
||||
: '```' + file.extname(this.fileName || '').replace(/^\./, '') + '\n' + this.currentContent + '```'
|
||||
this.$refs.view.innerHTML = markdown.render(this.replaceRelativeLink(content))
|
||||
this.runAppletScriptDebounce()
|
||||
this.initDrawio()
|
||||
this.updateOutline()
|
||||
this.updateTodoCount()
|
||||
this.updatePlantumlDebounce()
|
||||
MarkdownItECharts.update()
|
||||
MermaidPlugin.update()
|
||||
|
||||
for (let ele of document.querySelectorAll('code[class^="language-"]')) {
|
||||
HighlightLineNumber.lineNumbersBlock(ele)
|
||||
@@ -282,7 +289,6 @@ export default {
|
||||
env.require && env.require('opn')(link.href)
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,6 +422,7 @@ export default {
|
||||
background: #303133;
|
||||
}
|
||||
|
||||
.markdown-body /deep/ div.mermaid,
|
||||
.markdown-body /deep/ div.drawio-wrapper,
|
||||
.markdown-body /deep/ input,
|
||||
.markdown-body /deep/ img
|
||||
@@ -424,6 +431,7 @@ export default {
|
||||
filter: brightness(70%);
|
||||
}
|
||||
|
||||
.markdown-body /deep/ div.mermaid:hover,
|
||||
.markdown-body /deep/ div.drawio-wrapper:hover,
|
||||
.markdown-body /deep/ img:hover
|
||||
{
|
||||
@@ -683,4 +691,8 @@ button:hover {
|
||||
.view .hljs-ln td.hljs-ln-code {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.view .mermaid {
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import File from '@/lib/file'
|
||||
import Extensions from '@/lib/extensions'
|
||||
import DrawioPlugin from '@/plugins/DrawioPlugin'
|
||||
import 'vue-awesome/icons/folder-plus'
|
||||
|
||||
@@ -110,14 +111,13 @@ export default {
|
||||
},
|
||||
select (item) {
|
||||
if (item.type !== 'dir') {
|
||||
if (item.name.endsWith('.md')) {
|
||||
if (Extensions.supported(item.name)) {
|
||||
this.$store.commit('app/setCurrentFile', item)
|
||||
} else {
|
||||
if (item.path.toLowerCase().endsWith('.drawio')) {
|
||||
DrawioPlugin.open(item)
|
||||
} else {
|
||||
File.openInOS(this.item)
|
||||
// window.open(`api/attachment/${encodeURIComponent(item.name)}?repo=${item.repo}&path=${encodeURIComponent(item.path)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import file from './file'
|
||||
const extensions = [
|
||||
'.txt',
|
||||
'.gitignore',
|
||||
'.json',
|
||||
'.bowerrc',
|
||||
'.jshintrc',
|
||||
'.jscsrc',
|
||||
'.eslintrc',
|
||||
'.babelrc',
|
||||
'.bat',
|
||||
'.cmd',
|
||||
'.coffee',
|
||||
'.c',
|
||||
'.h',
|
||||
'.cpp',
|
||||
'.cc',
|
||||
'.cxx',
|
||||
'.hpp',
|
||||
'.hh',
|
||||
'.hxx',
|
||||
'.cs',
|
||||
'.csx',
|
||||
'.cake',
|
||||
'.css',
|
||||
'.dockerfile',
|
||||
'.fs',
|
||||
'.fsi',
|
||||
'.ml',
|
||||
'.mli',
|
||||
'.fsx',
|
||||
'.fsscript',
|
||||
'.go',
|
||||
'.handlebars',
|
||||
'.hbs',
|
||||
'.html',
|
||||
'.htm',
|
||||
'.shtml',
|
||||
'.xhtml',
|
||||
'.mdoc',
|
||||
'.jsp',
|
||||
'.asp',
|
||||
'.aspx',
|
||||
'.jshtm',
|
||||
'.ini',
|
||||
'.properties',
|
||||
'.gitconfig',
|
||||
'.java',
|
||||
'.jav',
|
||||
'.js',
|
||||
'.es6',
|
||||
'.jsx',
|
||||
'.kt',
|
||||
'.less',
|
||||
'.lua',
|
||||
'.md',
|
||||
'.markdown',
|
||||
'.mdown',
|
||||
'.mkdn',
|
||||
'.mkd',
|
||||
'.mdwn',
|
||||
'.mdtxt',
|
||||
'.mdtext',
|
||||
'.dax',
|
||||
'.msdax',
|
||||
'.m',
|
||||
'.pas',
|
||||
'.p',
|
||||
'.pp',
|
||||
'.php',
|
||||
'.php4',
|
||||
'.php5',
|
||||
'.phtml',
|
||||
'.ctp',
|
||||
'.dats',
|
||||
'.sats',
|
||||
'.hats',
|
||||
'.pq',
|
||||
'.pqm',
|
||||
'.ps1',
|
||||
'.psm1',
|
||||
'.psd1',
|
||||
'.jade',
|
||||
'.pug',
|
||||
'.py',
|
||||
'.rpy',
|
||||
'.pyw',
|
||||
'.cpy',
|
||||
'.gyp',
|
||||
'.gypi',
|
||||
'.r',
|
||||
'.rhistory',
|
||||
'.rprofile',
|
||||
'.rt',
|
||||
'.cshtml',
|
||||
'.redis',
|
||||
'.rb',
|
||||
'.rbx',
|
||||
'.rjs',
|
||||
'.gemspec',
|
||||
'.pp',
|
||||
'.rs',
|
||||
'.rlib',
|
||||
'.sb',
|
||||
'.scss',
|
||||
'.sol',
|
||||
'.sql',
|
||||
'.st',
|
||||
'.iecst',
|
||||
'.iecplc',
|
||||
'.lc3lib',
|
||||
'.swift',
|
||||
'.tcl',
|
||||
'.ts',
|
||||
'.tsx',
|
||||
'.vb',
|
||||
'.xml',
|
||||
'.dtd',
|
||||
'.ascx',
|
||||
'.csproj',
|
||||
'.config',
|
||||
'.wxi',
|
||||
'.wxl',
|
||||
'.wxs',
|
||||
'.xaml',
|
||||
'.svg',
|
||||
'.svgz',
|
||||
'.yaml',
|
||||
'.yml',
|
||||
'.scm',
|
||||
'.ss',
|
||||
'.sch',
|
||||
'.rkt',
|
||||
'.clj',
|
||||
'.cljs',
|
||||
'.cljc',
|
||||
'.edn',
|
||||
'.sh',
|
||||
'.bash',
|
||||
'.pl',
|
||||
'.azcli',
|
||||
'.cls',
|
||||
'.graphql',
|
||||
'.gql'
|
||||
]
|
||||
|
||||
const supported = name => {
|
||||
return extensions.includes(file.extname(name.toLowerCase()))
|
||||
}
|
||||
|
||||
export default {
|
||||
supported
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import mermaid from 'mermaid'
|
||||
|
||||
const mermaidChart = (code) => {
|
||||
try {
|
||||
mermaid.parse(code)
|
||||
return `<div class="mermaid">${code}</div>`
|
||||
} catch ({ str, hash }) {
|
||||
return `<pre>${str}</pre>`
|
||||
}
|
||||
}
|
||||
|
||||
const MermaidPlugin = (md) => {
|
||||
md.mermaid = mermaid
|
||||
mermaid.loadPreferences = (preferenceStore) => {
|
||||
let mermaidTheme = preferenceStore.get('mermaid-theme')
|
||||
if (mermaidTheme === undefined) {
|
||||
mermaidTheme = 'default'
|
||||
}
|
||||
let ganttAxisFormat = preferenceStore.get('gantt-axis-format')
|
||||
if (ganttAxisFormat === undefined) {
|
||||
ganttAxisFormat = '%Y-%m-%d'
|
||||
}
|
||||
mermaid.initialize({
|
||||
theme: mermaidTheme,
|
||||
gantt: { axisFormatter: [
|
||||
[ganttAxisFormat, (d) => {
|
||||
return d.getDay() === 1
|
||||
}]
|
||||
] }
|
||||
})
|
||||
return {
|
||||
'mermaid-theme': mermaidTheme,
|
||||
'gantt-axis-format': ganttAxisFormat
|
||||
}
|
||||
}
|
||||
|
||||
const temp = md.renderer.rules.fence.bind(md.renderer.rules)
|
||||
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
|
||||
const token = tokens[idx]
|
||||
const code = token.content.trim()
|
||||
if (token.info === 'mermaid') {
|
||||
return mermaidChart(code)
|
||||
}
|
||||
const firstLine = code.split(/\n/)[0].trim()
|
||||
if (firstLine === 'gantt' || firstLine === 'sequenceDiagram' || firstLine.match(/^graph (?:TB|BT|RL|LR|TD);?$/)) {
|
||||
return mermaidChart(code)
|
||||
}
|
||||
return temp(tokens, idx, options, env, slf)
|
||||
}
|
||||
}
|
||||
|
||||
MermaidPlugin.update = () => {
|
||||
mermaid.init()
|
||||
}
|
||||
|
||||
export default MermaidPlugin
|
||||
+2466
-44
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,21 @@ Yank-Note 很多功能可以直接使用的快捷键操作
|
||||
2. 加密和解密过程均在前端完成
|
||||
3. 请务必保管好文档密码,密码一旦丢失就只能自己暴力破解了。
|
||||
|
||||
## Mermaid 图形解析
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts <br/>prevail!
|
||||
John-->>Alice: Great!
|
||||
John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
```
|
||||
|
||||
## Plantuml 图形解析
|
||||
系统需要有 Java 环境,并安装有 graphviz
|
||||
示例如下
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yank.note.yang",
|
||||
"version": "2.0.0-beta8.4",
|
||||
"version": "2.0.0-beta9.0",
|
||||
"description": "Yank-Note",
|
||||
"main": "dist/app.js",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
Reference in New Issue
Block a user