mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
Merge branch 'release/2.4.8'
This commit is contained in:
@@ -6,7 +6,19 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
platform: 'win'
|
||||
- os: ubuntu-latest
|
||||
platform: 'linux'
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
npm_config_disturl: https://atom.io/download/electron
|
||||
npm_config_target: 9.3.1
|
||||
npm_config_runtime: "electron"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -19,7 +31,8 @@ jobs:
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
./win-install.bat
|
||||
yarn
|
||||
yarn run download-pandoc
|
||||
cd frontend
|
||||
yarn
|
||||
cd ..
|
||||
@@ -29,7 +42,8 @@ jobs:
|
||||
cd frontend
|
||||
yarn run build
|
||||
cd ..
|
||||
./win-build.bat
|
||||
yarn run build
|
||||
yarn run electron-builder --${{ matrix.platform }} -p never
|
||||
|
||||
- name: GH Release
|
||||
uses: softprops/action-gh-release@v0.1.5
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
+ 嵌入 drawio 图形:文档支持内嵌 drawio 图形,示例见 FEATURE.md
|
||||
+ 嵌入 ECharts 图形:在文档中嵌入 Echarts 图形,示例见 FEATURE.md
|
||||
+ 嵌入 Mermaid 图形:在文档中嵌入 Mermaid 图形,示例见 FEATURE.md
|
||||
+ 嵌套列表转脑图展示:可将嵌套列表用脑图的方式展示,示例见 FEATURE.md
|
||||
+ 元素属性书写:可自定义元素的任意属性,示例见 FEATURE.md
|
||||
+ 表格解析增强:表格支持表格标题多行文本,列表等特性,示例见 FEATURE.md
|
||||
+ 文档交叉链接跳转:支持在文档中引入其他文档,互相跳转
|
||||
@@ -146,12 +147,15 @@ yarn run start
|
||||
## 更新日志
|
||||
[最新发布](https://github.com/purocean/yn/releases)
|
||||
|
||||
### [v2.4.7](https://github.com/purocean/yn/releases/tag/v2.4.7) 2020-12-02
|
||||
1. 修复编辑表格跨列单元格问题
|
||||
### [v2.4.8](https://github.com/purocean/yn/releases/tag/v2.4.8) 2020-12-15
|
||||
1. 增加大纲列表脑图展示功能
|
||||
|
||||
<details>
|
||||
<summary>展开查看更多版本记录</summary>
|
||||
|
||||
### [v2.4.7](https://github.com/purocean/yn/releases/tag/v2.4.7) 2020-12-02
|
||||
1. 修复编辑表格跨列单元格问题
|
||||
|
||||
### [v2.4.6](https://github.com/purocean/yn/releases/tag/v2.4.6) 2020-11-26
|
||||
1. 增加编辑单元格内容功能
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
@@ -23,6 +23,15 @@
|
||||
],
|
||||
"icon": "./build/icon.ico"
|
||||
},
|
||||
"linux": {
|
||||
"executableName": "yank-note",
|
||||
"category": "Markdown",
|
||||
"maintainer": "purocean <purocean@outlook.com>",
|
||||
"icon": "./build/icon.png",
|
||||
"target": [
|
||||
"deb"
|
||||
]
|
||||
},
|
||||
"nsis": {
|
||||
"perMachine": false
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" href="./kityminder.core.css" rel="stylesheet">
|
||||
<title>Yank Note</title>
|
||||
<script>
|
||||
// 强制 monaco-editor 使用 浏览器模式
|
||||
@@ -19,5 +20,7 @@
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script src="./kity.min.js"></script>
|
||||
<script src="./kityminder.core.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Vendored
+12
File diff suppressed because one or more lines are too long
@@ -0,0 +1,93 @@
|
||||
.km-view {
|
||||
font-family: "STHeitiSC-Light", "STHeiti", "Hei", "Heiti SC", "Microsoft Yahei", Arial, sans-serif;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.km-view .km-receiver {
|
||||
position: absolute;
|
||||
left: -99999px;
|
||||
top: -99999px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.km-view image {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.km-image-viewer {
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, .75);
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-container::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
font-size: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-container img {
|
||||
cursor: zoom-out;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-container img.limited {
|
||||
cursor: zoom-in;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-toolbar {
|
||||
z-index: 1;
|
||||
background: rgba(0, 0, 0, .75);
|
||||
text-align: right;
|
||||
transition: all .25s;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-toolbar.hidden {
|
||||
transform: translate(0, -100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-btn {
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjY0IiBoZWlnaHQ9Ijg4IiB2aWV3Qm94PSIwIDAgMjY0IDg4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5kZWZhdWx0LXNraW4gMjwvdGl0bGU+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Zz48cGF0aCBkPSJNNjcuMDAyIDU5LjV2My43NjhjLTYuMzA3Ljg0LTkuMTg0IDUuNzUtMTAuMDAyIDkuNzMyIDIuMjItMi44MyA1LjU2NC01LjA5OCAxMC4wMDItNS4wOThWNzEuNUw3MyA2NS41ODUgNjcuMDAyIDU5LjV6IiBpZD0iU2hhcGUiIGZpbGw9IiNmZmYiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJNMTMgMjl2LTVoMnYzaDN2MmgtNXpNMTMgMTVoNXYyaC0zdjNoLTJ2LTV6TTMxIDE1djVoLTJ2LTNoLTN2LTJoNXpNMzEgMjloLTV2LTJoM3YtM2gydjV6IiBpZD0iU2hhcGUiLz48L2c+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTYyIDI0djVoLTJ2LTNoLTN2LTJoNXpNNjIgMjBoLTV2LTJoM3YtM2gydjV6TTcwIDIwdi01aDJ2M2gzdjJoLTV6TTcwIDI0aDV2MmgtM3YzaC0ydi01eiIvPjwvZz48cGF0aCBkPSJNMjAuNTg2IDY2bC01LjY1Ni01LjY1NiAxLjQxNC0xLjQxNEwyMiA2NC41ODZsNS42NTYtNS42NTYgMS40MTQgMS40MTRMMjMuNDE0IDY2bDUuNjU2IDUuNjU2LTEuNDE0IDEuNDE0TDIyIDY3LjQxNGwtNS42NTYgNS42NTYtMS40MTQtMS40MTRMMjAuNTg2IDY2eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xMTEuNzg1IDY1LjAzTDExMCA2My41bDMtMy41aC0xMHYtMmgxMGwtMy0zLjUgMS43ODUtMS40NjhMMTE3IDU5bC01LjIxNSA2LjAzeiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xNTIuMjE1IDY1LjAzTDE1NCA2My41bC0zLTMuNWgxMHYtMmgtMTBsMy0zLjUtMS43ODUtMS40NjhMMTQ3IDU5bDUuMjE1IDYuMDN6IiBmaWxsPSIjZmZmIi8+PGc+PHBhdGggaWQ9IlJlY3RhbmdsZS0xMSIgZmlsbD0iI2ZmZiIgZD0iTTE2MC45NTcgMjguNTQzbC0zLjI1LTMuMjUtMS40MTMgMS40MTQgMy4yNSAzLjI1eiIvPjxwYXRoIGQ9Ik0xNTIuNSAyN2MzLjAzOCAwIDUuNS0yLjQ2MiA1LjUtNS41cy0yLjQ2Mi01LjUtNS41LTUuNS01LjUgMi40NjItNS41IDUuNSAyLjQ2MiA1LjUgNS41IDUuNXoiIGlkPSJPdmFsLTEiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTUwIDIxaDV2MWgtNXoiLz48L2c+PGc+PHBhdGggZD0iTTExNi45NTcgMjguNTQzbC0xLjQxNCAxLjQxNC0zLjI1LTMuMjUgMS40MTQtMS40MTQgMy4yNSAzLjI1eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xMDguNSAyN2MzLjAzOCAwIDUuNS0yLjQ2MiA1LjUtNS41cy0yLjQ2Mi01LjUtNS41LTUuNS01LjUgMi40NjItNS41IDUuNSAyLjQ2MiA1LjUgNS41IDUuNXoiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTA2IDIxaDV2MWgtNXoiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTA5LjA0MyAxOS4wMDhsLS4wODUgNS0xLS4wMTcuMDg1LTV6Ii8+PC9nPjwvZz48L2c+PC9zdmc+);
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.km-image-viewer .km-image-viewer-close {
|
||||
background-position: 0 -44px;
|
||||
}
|
||||
+10
File diff suppressed because one or more lines are too long
@@ -61,6 +61,7 @@ import DrawioPlugin from '../plugins/DrawioPlugin'
|
||||
import PlantumlPlugin from '../plugins/PlantumlPlugin'
|
||||
import MermaidPlugin from '../plugins/MermaidPlugin'
|
||||
import CodePlugin from '../plugins/CodePlugin'
|
||||
import MindMapPlugin from '../plugins/MindMapPlugin'
|
||||
import file from '../useful/file'
|
||||
import env from '../useful/env'
|
||||
import { encodeMarkdownLink } from '../useful/utils'
|
||||
@@ -101,6 +102,7 @@ const markdown = Markdown({
|
||||
.use(MarkdownItECharts)
|
||||
.use(MermaidPlugin)
|
||||
.use(CodePlugin)
|
||||
.use(MindMapPlugin)
|
||||
|
||||
export default defineComponent({
|
||||
name: 'xview',
|
||||
@@ -148,6 +150,11 @@ export default defineComponent({
|
||||
nodes.forEach(AppletPlugin.runScript)
|
||||
}
|
||||
|
||||
function renderMindMap () {
|
||||
const nodes = refView.value!!.querySelectorAll<HTMLElement>('.mindmap-list[data-mindmap-source]')
|
||||
nodes.forEach(MindMapPlugin.render)
|
||||
}
|
||||
|
||||
const updatePlantumlDebounce = loadsh.debounce(() => {
|
||||
updatePlantuml()
|
||||
}, 3000, { leading: true })
|
||||
@@ -156,6 +163,10 @@ export default defineComponent({
|
||||
runAppletScript()
|
||||
}, 1000, { leading: true })
|
||||
|
||||
const renderMindmapDebounce = loadsh.debounce(() => {
|
||||
renderMindMap()
|
||||
}, 1000, { leading: true })
|
||||
|
||||
function replaceRelativeLink (md: string) {
|
||||
if (!fileRepo.value) {
|
||||
return md
|
||||
@@ -243,8 +254,11 @@ export default defineComponent({
|
||||
const content = (filePath.value || '').endsWith('.md')
|
||||
? currentContent.value
|
||||
: '```' + file.extname(fileName.value || '').replace(/^\./, '') + '\n' + currentContent.value + '```'
|
||||
refView.value!!.innerHTML = markdown.render(replaceRelativeLink(content))
|
||||
|
||||
const source = replaceRelativeLink(content)
|
||||
refView.value!!.innerHTML = markdown.render(source, { source })
|
||||
runAppletScriptDebounce()
|
||||
renderMindmapDebounce()
|
||||
initDrawio()
|
||||
updateOutline()
|
||||
updateTodoCount()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Markdown from 'markdown-it'
|
||||
import file from '@/useful/file'
|
||||
import env from '@/useful/env'
|
||||
import { useBus } from '@/useful/bus'
|
||||
import { openInNewWindow } from '@/useful/utils'
|
||||
|
||||
const Plugin = (md: Markdown) => {
|
||||
const renderHtml = ({ url, content }: any) => {
|
||||
@@ -119,30 +119,6 @@ const buildSrcdoc = async ({ repo, path, content, url }: F) => {
|
||||
`
|
||||
}
|
||||
|
||||
const openInNewWindow = (srcdoc: string) => {
|
||||
const opener = env.openAlwaysOnTopWindow('about:blank')
|
||||
const frame = document.createElement('iframe')
|
||||
frame.width = '100%'
|
||||
frame.height = '100%'
|
||||
frame.frameBorder = '0'
|
||||
frame.srcdoc = srcdoc
|
||||
|
||||
if (env.isElectron) {
|
||||
const json = JSON.stringify(frame.outerHTML)
|
||||
opener.eval(`
|
||||
document.title = '查看图形'
|
||||
document.body.style.height = '100vh'
|
||||
document.body.style.margin = '0'
|
||||
document.body.innerHTML = ${json}
|
||||
`)
|
||||
} else {
|
||||
opener.document.title = '查看图形'
|
||||
opener.document.body.style.height = '100vh'
|
||||
opener.document.body.style.margin = '0'
|
||||
opener.document.body.appendChild(frame)
|
||||
}
|
||||
}
|
||||
|
||||
Plugin.load = async (el: HTMLIFrameElement, url?: string) => {
|
||||
const bus = useBus()
|
||||
const content = el.dataset.content || ''
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import Markdown from 'markdown-it'
|
||||
import Renderer from 'markdown-it/lib/renderer'
|
||||
import crypto from '@/useful/crypto'
|
||||
import { dataURItoBlobLink, openInNewWindow } from '@/useful/utils'
|
||||
|
||||
const renderRule: Renderer.RenderRule = (tokens, idx, options, { source }, slf) => {
|
||||
const token = tokens[idx]
|
||||
const nextToken = tokens[idx + 1]
|
||||
if (token.level === 0 && token.map && nextToken && nextToken.attrGet('class')?.includes('mindmap')) {
|
||||
const content = source
|
||||
.split('\n')
|
||||
.slice(token.map[0], token.map[1])
|
||||
.join('\n')
|
||||
.replace(/\{.mindmap[^}]*\}/gm, '')
|
||||
.replace(/^(\s*)([+-]*|\d+.) /gm, '$1')
|
||||
|
||||
token.attrJoin('class', 'mindmap-list')
|
||||
token.attrSet('data-mindmap-source', content)
|
||||
}
|
||||
|
||||
return slf.renderToken(tokens, idx, options)
|
||||
}
|
||||
|
||||
const Plugin = (md: Markdown) => {
|
||||
md.renderer.rules.bullet_list_open = renderRule
|
||||
}
|
||||
|
||||
const buildSrcdoc = (json: string) => {
|
||||
return `
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="${location.origin}/kityminder.core.css" rel="stylesheet">
|
||||
<script src="${location.origin}/kity.min.js"></script>
|
||||
<script src="${location.origin}/kityminder.core.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#minder-view {
|
||||
position: absolute;
|
||||
border: 1px solid #ccc;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="width: 100%; height: 100vh; padding: 0; margin: 0">
|
||||
<script id="minder-view" type="application/kityminder" minder-data-type="json">${json}</script>
|
||||
<script type="text/javascript">
|
||||
var km = window.km = new kityminder.Minder();
|
||||
km.setup('#minder-view');
|
||||
km.disable();
|
||||
km.execCommand('hand');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
}
|
||||
|
||||
Plugin.render = async (ele: HTMLElement) => {
|
||||
const code = (ele.dataset.mindmapSource || '').trim()
|
||||
|
||||
const div = document.createElement('div')
|
||||
div.setAttribute('minder-data-type', 'text')
|
||||
div.style.position = 'relative'
|
||||
div.style.height = '400px'
|
||||
ele.replaceWith(div)
|
||||
|
||||
const km = new (window as any).kityminder.Minder()
|
||||
km.setup(div)
|
||||
km.disable()
|
||||
try {
|
||||
await km.importData('text', code)
|
||||
km.useTemplate('default')
|
||||
} catch (error) {
|
||||
await km.importData('text', '转换错误\n 1. 请保证大纲只有一个根项目\n 2. 请保证大纲层级正确')
|
||||
km.useTemplate('structure')
|
||||
}
|
||||
|
||||
km.execCommand('hand')
|
||||
km.useTheme('fresh-green-compat')
|
||||
km.execCommand('camera')
|
||||
|
||||
const tplList = ['default', 'right', 'structure', 'filetree', 'tianpan', 'fish-bone']
|
||||
const switchLayout = () => {
|
||||
const tpl = km.getTemplate()
|
||||
const index = tplList.indexOf(tpl)
|
||||
const nextIndex = index > tplList.length - 2 ? 0 : index + 1
|
||||
km.useTemplate(tplList[nextIndex])
|
||||
km.execCommand('camera')
|
||||
}
|
||||
|
||||
const switchCompat = () => {
|
||||
const theme = km.getTheme().split('-')
|
||||
if (theme[theme.length - 1] === 'compat') {
|
||||
theme.pop()
|
||||
} else {
|
||||
theme.push('compat')
|
||||
}
|
||||
|
||||
km.useTheme(theme.join('-'))
|
||||
km.execCommand('camera')
|
||||
}
|
||||
|
||||
const exportData = async (type: 'png' | 'svg' | 'km') => {
|
||||
const download = (url: string, name: string) => {
|
||||
const link = document.createElement('a')
|
||||
link.href = dataURItoBlobLink(url)
|
||||
link.target = '_blank'
|
||||
link.download = name
|
||||
link.click()
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'svg':
|
||||
download('data:image/svg+xml;base64,' + crypto.strToBase64(await km.exportData('svg')), 'mindmap.svg')
|
||||
break
|
||||
case 'km':
|
||||
download('data:application/octet-stream;base64,' + crypto.strToBase64(await km.exportData('json')), 'mindmap.km')
|
||||
break
|
||||
case 'png':
|
||||
download(await km.exportData('png'), 'mindmap.png')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const buildButton = (text: string, fun: () => void) => {
|
||||
const button = document.createElement('button')
|
||||
button.style.cssText = 'margin-left: 5px;font-size: 14px;background: #cacaca; border: 0; padding: 0 6px; color: #2c2b2b; cursor: pointer; border-radius: 2px; transition: all .3s ease-in-out; line-height: 24px;'
|
||||
button.innerText = text
|
||||
button.onclick = fun
|
||||
return button
|
||||
}
|
||||
|
||||
const action = document.createElement('div')
|
||||
action.className = 'no-print'
|
||||
action.style.cssText = 'position: absolute; right: 15px; top: 3px; z-index: 1;'
|
||||
action.appendChild(buildButton('导出 PNG', () => exportData('png')))
|
||||
action.appendChild(buildButton('导出 SVG', () => exportData('svg')))
|
||||
action.appendChild(buildButton('导出 KM', () => exportData('km')))
|
||||
action.appendChild(buildButton('新窗口打开', () => openInNewWindow(buildSrcdoc(JSON.stringify(km.exportJson())))))
|
||||
action.appendChild(buildButton('切换布局', switchLayout))
|
||||
action.appendChild(buildButton('紧凑/宽松', switchCompat))
|
||||
|
||||
div.appendChild(action)
|
||||
}
|
||||
|
||||
export default Plugin
|
||||
@@ -55,9 +55,14 @@ const binMd5 = (data: any) => {
|
||||
return md5(CryptoJS.enc.Latin1.parse(data))
|
||||
}
|
||||
|
||||
export const strToBase64 = (str: string) => {
|
||||
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str))
|
||||
}
|
||||
|
||||
export default {
|
||||
encrypt,
|
||||
decrypt,
|
||||
md5,
|
||||
binMd5
|
||||
binMd5,
|
||||
strToBase64,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
import env from '@/useful/env'
|
||||
|
||||
export const encodeMarkdownLink = (path: string) => {
|
||||
return path
|
||||
.replace(/\(/g, '%28')
|
||||
.replace(/\)/g, '%29')
|
||||
.replace(/ /g, '%20')
|
||||
}
|
||||
|
||||
export const openInNewWindow = (srcdoc: string) => {
|
||||
const opener = env.openAlwaysOnTopWindow('about:blank')
|
||||
const frame = document.createElement('iframe')
|
||||
frame.width = '100%'
|
||||
frame.height = '100%'
|
||||
frame.frameBorder = '0'
|
||||
frame.srcdoc = srcdoc
|
||||
|
||||
if (env.isElectron) {
|
||||
const json = JSON.stringify(frame.outerHTML)
|
||||
opener.eval(`
|
||||
document.title = '查看图形'
|
||||
document.body.style.height = '100vh'
|
||||
document.body.style.margin = '0'
|
||||
document.body.innerHTML = ${json}
|
||||
`)
|
||||
} else {
|
||||
opener.document.title = '查看图形'
|
||||
opener.document.body.style.height = '100vh'
|
||||
opener.document.body.style.margin = '0'
|
||||
opener.document.body.appendChild(frame)
|
||||
}
|
||||
}
|
||||
|
||||
export const dataURItoBlobLink = (dataURI: string) => {
|
||||
const byteString = atob(dataURI.split(',')[1])
|
||||
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
|
||||
const ab = new ArrayBuffer(byteString.length)
|
||||
const ia = new Uint8Array(ab)
|
||||
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
ia[i] = byteString.charCodeAt(i)
|
||||
}
|
||||
|
||||
const blob = new Blob([ab], { type: mimeString })
|
||||
return window.URL.createObjectURL(blob)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,23 @@ Yank-Note 很多功能可以直接使用的快捷键操作
|
||||
## 脚注功能
|
||||
支持使用脚注[^1]语法[^2]
|
||||
|
||||
## 嵌套列表脑图形式展示
|
||||
只需要在列表根节点加上 `{.mindmap}` 即可。
|
||||
|
||||
+ 中心节点{.mindmap}
|
||||
+ 状态可见原则
|
||||
+ 环境贴切原则
|
||||
+ 用户可控原则
|
||||
+ 一致性原则
|
||||
+ 防错原则
|
||||
+ 易取原则
|
||||
+ 灵活高效原则
|
||||
+ 优美且简约原则
|
||||
+ 容错原则
|
||||
+ 人性化帮助原则
|
||||
|
||||
脑图使用 [kityminder-core](https://github.com/fex-team/kityminder-core) 实现。
|
||||
|
||||
## Mermaid 图形解析
|
||||
|
||||
```mermaid
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yank.note.yang",
|
||||
"version": "2.4.7",
|
||||
"version": "2.4.8",
|
||||
"description": "Yank Note 一款面向程序员的 Markdown 笔记应用",
|
||||
"main": "dist/app.js",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
Reference in New Issue
Block a user