New file properties modal
This commit is contained in:
parent
fb13a52157
commit
ab97d9d9fc
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app" :class="themeClasses">
|
<div class="app" :class="classes">
|
||||||
<splash-screen v-if="!ready"></splash-screen>
|
<splash-screen v-if="!ready"></splash-screen>
|
||||||
<layout v-else></layout>
|
<layout v-else></layout>
|
||||||
<modal v-if="showModal"></modal>
|
<modal v-if="showModal"></modal>
|
||||||
@ -81,7 +81,7 @@ export default {
|
|||||||
ready: false,
|
ready: false,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
themeClasses() {
|
classes() {
|
||||||
const result = themeClasses[this.$store.getters['data/computedSettings'].colorTheme];
|
const result = themeClasses[this.$store.getters['data/computedSettings'].colorTheme];
|
||||||
return Array.isArray(result) ? result : themeClasses.light;
|
return Array.isArray(result) ? result : themeClasses.light;
|
||||||
},
|
},
|
||||||
|
@ -232,6 +232,19 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal__title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal__sub-title {
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.modal__error {
|
.modal__error {
|
||||||
color: #de2c00;
|
color: #de2c00;
|
||||||
}
|
}
|
||||||
@ -241,6 +254,12 @@ export default {
|
|||||||
border-radius: $border-radius-base;
|
border-radius: $border-radius-base;
|
||||||
margin: 1.2em 0;
|
margin: 1.2em 0;
|
||||||
padding: 0.75em 1.25em;
|
padding: 0.75em 1.25em;
|
||||||
|
font-size: 0.95em;
|
||||||
|
line-height: 1.6;
|
||||||
|
|
||||||
|
pre {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal__button-bar {
|
.modal__button-bar {
|
||||||
@ -266,6 +285,10 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-entry__label-info {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.form-entry__field {
|
.form-entry__field {
|
||||||
border: 1px solid #d8d8d8;
|
border: 1px solid #d8d8d8;
|
||||||
border-radius: $border-radius-base;
|
border-radius: $border-radius-base;
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
<div class="navigation-bar__inner navigation-bar__inner--edit-pagedownButtons">
|
<div class="navigation-bar__inner navigation-bar__inner--edit-pagedownButtons">
|
||||||
<button class="navigation-bar__button button" @click="undo" v-title="'Undo'" :disabled="!canUndo"><icon-undo></icon-undo></button>
|
<button class="navigation-bar__button button" @click="undo" v-title="'Undo'" :disabled="!canUndo"><icon-undo></icon-undo></button>
|
||||||
<button class="navigation-bar__button button" @click="redo" v-title="'Redo'" :disabled="!canRedo"><icon-redo></icon-redo></button>
|
<button class="navigation-bar__button button" @click="redo" v-title="'Redo'" :disabled="!canRedo"><icon-redo></icon-redo></button>
|
||||||
<div v-for="button in pagedownButtons" :key="button.action">
|
<div v-for="button in pagedownButtons" :key="button.method">
|
||||||
<button class="navigation-bar__button button" v-if="button.action" @click="pagedownClick(button.action)" v-title="button.title">
|
<button class="navigation-bar__button button" v-if="button.method" @click="pagedownClick(button.method)" v-title="button.titleWithShortcut">
|
||||||
<component :is="button.iconClass"></component>
|
<component :is="button.iconClass"></component>
|
||||||
</button>
|
</button>
|
||||||
<div class="navigation-bar__spacer" v-else></div>
|
<div class="navigation-bar__spacer" v-else></div>
|
||||||
@ -55,6 +55,28 @@ import animationSvc from '../services/animationSvc';
|
|||||||
import tempFileSvc from '../services/tempFileSvc';
|
import tempFileSvc from '../services/tempFileSvc';
|
||||||
import utils from '../services/utils';
|
import utils from '../services/utils';
|
||||||
import pagedownButtons from '../data/pagedownButtons';
|
import pagedownButtons from '../data/pagedownButtons';
|
||||||
|
import store from '../store';
|
||||||
|
|
||||||
|
// According to mousetrap
|
||||||
|
const mod = /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'Meta' : 'Ctrl';
|
||||||
|
|
||||||
|
const getShortcut = (method) => {
|
||||||
|
let result = '';
|
||||||
|
Object.entries(store.getters['data/computedSettings'].shortcuts).some(([keys, shortcut]) => {
|
||||||
|
if (`${shortcut.method || shortcut}` !== method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result = keys.split('+').map(key => key.toLowerCase()).map((key) => {
|
||||||
|
if (key === 'mod') {
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
// Capitalize
|
||||||
|
return key && `${key[0].toUpperCase()}${key.slice(1)}`;
|
||||||
|
}).join('+');
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return result && ` – ${result}`;
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@ -90,14 +112,11 @@ export default {
|
|||||||
publishLocations: 'current',
|
publishLocations: 'current',
|
||||||
}),
|
}),
|
||||||
pagedownButtons() {
|
pagedownButtons() {
|
||||||
return pagedownButtons.map((button) => {
|
return pagedownButtons.map(button => ({
|
||||||
const title = button.title;
|
...button,
|
||||||
return {
|
titleWithShortcut: `${button.title}${getShortcut(button.method)}`,
|
||||||
...button,
|
iconClass: `icon-${button.icon}`,
|
||||||
title,
|
}));
|
||||||
iconClass: `icon-${button.icon}`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
isSyncPossible() {
|
isSyncPossible() {
|
||||||
return this.$store.getters['workspace/syncToken'] ||
|
return this.$store.getters['workspace/syncToken'] ||
|
||||||
|
@ -44,27 +44,29 @@ export default class EditorClassApplier {
|
|||||||
};
|
};
|
||||||
|
|
||||||
editorSvc.clEditor.on('contentChanged', this.restoreClass);
|
editorSvc.clEditor.on('contentChanged', this.restoreClass);
|
||||||
nextTick(() => this.applyClass());
|
nextTick(() => this.restoreClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
applyClass() {
|
applyClass() {
|
||||||
const offset = this.offsetGetter();
|
if (!this.stopped) {
|
||||||
if (offset && offset.start !== offset.end) {
|
const offset = this.offsetGetter();
|
||||||
const range = editorSvc.clEditor.selectionMgr.createRange(
|
if (offset && offset.start !== offset.end) {
|
||||||
Math.min(offset.start, offset.end),
|
const range = editorSvc.clEditor.selectionMgr.createRange(
|
||||||
Math.max(offset.start, offset.end),
|
Math.min(offset.start, offset.end),
|
||||||
);
|
Math.max(offset.start, offset.end),
|
||||||
const properties = {
|
);
|
||||||
...this.properties,
|
const properties = {
|
||||||
className: this.classGetter().join(' '),
|
...this.properties,
|
||||||
};
|
className: this.classGetter().join(' '),
|
||||||
editorSvc.clEditor.watcher.noWatch(() => {
|
};
|
||||||
utils.wrapRange(range, properties);
|
editorSvc.clEditor.watcher.noWatch(() => {
|
||||||
});
|
utils.wrapRange(range, properties);
|
||||||
if (editorSvc.clEditor.selectionMgr.hasFocus()) {
|
});
|
||||||
nextTickRestoreSelection();
|
if (editorSvc.clEditor.selectionMgr.hasFocus()) {
|
||||||
|
nextTickRestoreSelection();
|
||||||
|
}
|
||||||
|
this.lastEltCount = this.eltCollection.length;
|
||||||
}
|
}
|
||||||
this.lastEltCount = this.eltCollection.length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,5 +82,6 @@ export default class EditorClassApplier {
|
|||||||
stop() {
|
stop() {
|
||||||
editorSvc.clEditor.off('contentChanged', this.restoreClass);
|
editorSvc.clEditor.off('contentChanged', this.restoreClass);
|
||||||
nextTick(() => this.removeClass());
|
nextTick(() => this.removeClass());
|
||||||
|
this.stopped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,30 +32,32 @@ export default class PreviewClassApplier {
|
|||||||
};
|
};
|
||||||
|
|
||||||
editorSvc.$on('previewCtxWithDiffs', this.restoreClass);
|
editorSvc.$on('previewCtxWithDiffs', this.restoreClass);
|
||||||
nextTick(() => this.applyClass());
|
nextTick(() => this.restoreClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
applyClass() {
|
applyClass() {
|
||||||
const offset = this.offsetGetter();
|
if (!this.stopped) {
|
||||||
if (offset) {
|
const offset = this.offsetGetter();
|
||||||
const offsetStart = editorSvc.getPreviewOffset(
|
if (offset) {
|
||||||
offset.start, editorSvc.previewCtx.sectionDescList);
|
const offsetStart = editorSvc.getPreviewOffset(
|
||||||
const offsetEnd = editorSvc.getPreviewOffset(
|
offset.start, editorSvc.previewCtx.sectionDescList);
|
||||||
offset.end, editorSvc.previewCtx.sectionDescList);
|
const offsetEnd = editorSvc.getPreviewOffset(
|
||||||
if (offsetStart != null && offsetEnd != null && offsetStart !== offsetEnd) {
|
offset.end, editorSvc.previewCtx.sectionDescList);
|
||||||
const start = cledit.Utils.findContainer(
|
if (offsetStart != null && offsetEnd != null && offsetStart !== offsetEnd) {
|
||||||
editorSvc.previewElt, Math.min(offsetStart, offsetEnd));
|
const start = cledit.Utils.findContainer(
|
||||||
const end = cledit.Utils.findContainer(
|
editorSvc.previewElt, Math.min(offsetStart, offsetEnd));
|
||||||
editorSvc.previewElt, Math.max(offsetStart, offsetEnd));
|
const end = cledit.Utils.findContainer(
|
||||||
const range = document.createRange();
|
editorSvc.previewElt, Math.max(offsetStart, offsetEnd));
|
||||||
range.setStart(start.container, start.offsetInContainer);
|
const range = document.createRange();
|
||||||
range.setEnd(end.container, end.offsetInContainer);
|
range.setStart(start.container, start.offsetInContainer);
|
||||||
const properties = {
|
range.setEnd(end.container, end.offsetInContainer);
|
||||||
...this.properties,
|
const properties = {
|
||||||
className: this.classGetter().join(' '),
|
...this.properties,
|
||||||
};
|
className: this.classGetter().join(' '),
|
||||||
utils.wrapRange(range, properties);
|
};
|
||||||
this.lastEltCount = this.eltCollection.length;
|
utils.wrapRange(range, properties);
|
||||||
|
this.lastEltCount = this.eltCollection.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,5 +69,6 @@ export default class PreviewClassApplier {
|
|||||||
stop() {
|
stop() {
|
||||||
editorSvc.$off('previewCtxWithDiffs', this.restoreClass);
|
editorSvc.$off('previewCtxWithDiffs', this.restoreClass);
|
||||||
nextTick(() => this.removeClass());
|
nextTick(() => this.removeClass());
|
||||||
|
this.stopped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ import UserName from '../UserName';
|
|||||||
import EditorClassApplier from '../common/EditorClassApplier';
|
import EditorClassApplier from '../common/EditorClassApplier';
|
||||||
import PreviewClassApplier from '../common/PreviewClassApplier';
|
import PreviewClassApplier from '../common/PreviewClassApplier';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
import editorSvc from '../../services/editorSvc';
|
|
||||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
|
|
||||||
@ -137,22 +136,20 @@ export default {
|
|||||||
previewClassAppliers.forEach(previewClassApplier => previewClassApplier.stop());
|
previewClassAppliers.forEach(previewClassApplier => previewClassApplier.stop());
|
||||||
previewClassAppliers = [];
|
previewClassAppliers = [];
|
||||||
if (revisionContent) {
|
if (revisionContent) {
|
||||||
editorSvc.$once('previewCtxWithDiffs', () => {
|
let offset = 0;
|
||||||
let offset = 0;
|
revisionContent.diffs.forEach(([type, text]) => {
|
||||||
revisionContent.diffs.forEach(([type, text]) => {
|
if (type) {
|
||||||
if (type) {
|
const classes = ['revision-diff', `revision-diff--${type > 0 ? 'insert' : 'delete'}`];
|
||||||
const classes = ['revision-diff', `revision-diff--${type > 0 ? 'insert' : 'delete'}`];
|
const offsets = {
|
||||||
const offsets = {
|
start: offset,
|
||||||
start: offset,
|
end: offset + text.length,
|
||||||
end: offset + text.length,
|
};
|
||||||
};
|
editorClassAppliers.push(new EditorClassApplier(
|
||||||
editorClassAppliers.push(new EditorClassApplier(
|
[`revision-diff--${utils.uid()}`, ...classes], offsets));
|
||||||
[`revision-diff--${utils.uid()}`, ...classes], offsets));
|
previewClassAppliers.push(new PreviewClassApplier(
|
||||||
previewClassAppliers.push(new PreviewClassApplier(
|
[`revision-diff--${utils.uid()}`, ...classes], offsets));
|
||||||
[`revision-diff--${utils.uid()}`, ...classes], offsets));
|
}
|
||||||
}
|
offset += text.length;
|
||||||
offset += text.length;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2,26 +2,76 @@
|
|||||||
<modal-inner class="modal__inner-1--file-properties" aria-label="File properties">
|
<modal-inner class="modal__inner-1--file-properties" aria-label="File properties">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="tabs flex flex--row">
|
<div class="tabs flex flex--row">
|
||||||
<tab :active="tab === 'custom'" @click="tab = 'custom'">
|
<tab :active="tab === 'simple'" @click="setSimpleTab()">
|
||||||
Current file properties
|
Simple properties
|
||||||
</tab>
|
</tab>
|
||||||
<tab :active="tab === 'default'" @click="tab = 'default'">
|
<tab :active="tab === 'yaml'" @click="setYamlTab()">
|
||||||
Default properties
|
YAML properties
|
||||||
</tab>
|
</tab>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-entry" v-if="tab === 'custom'" role="tabpanel" aria-label="Current file properties">
|
<div v-if="tab === 'simple'">
|
||||||
<label class="form-entry__label">YAML</label>
|
<div class="modal__title">Extensions</div>
|
||||||
<div class="form-entry__field">
|
<div class="modal__sub-title">Configure the Markdown engine.</div>
|
||||||
<code-editor lang="yaml" :value="customProperties" key="custom-properties" @changed="setCustomProperties"></code-editor>
|
<form-entry label="Preset">
|
||||||
|
<select slot="field" class="textfield" v-model="preset" @keydown.enter="resolve()">
|
||||||
|
<option v-for="(preset, id) in presets" :key="id" :value="preset">
|
||||||
|
{{ preset }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</form-entry>
|
||||||
|
<div class="modal__title">Metadata</div>
|
||||||
|
<div class="modal__sub-title">Add info to your publications (Wordpress, Blogger...).</div>
|
||||||
|
<form-entry label="Title">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="title" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Author">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="author" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Tags" info="comma-separated">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="tags" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Categories" info="comma-separated">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="categories" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Excerpt">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="excerpt" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Featured image">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="featuredImage" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Status">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="status" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Date" info="YYYY-MM-DD">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="date" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
</div>
|
||||||
|
<div v-if="tab === 'yaml'">
|
||||||
|
<div class="form-entry" role="tabpanel" aria-label="YAML properties">
|
||||||
|
<label class="form-entry__label">YAML</label>
|
||||||
|
<div class="form-entry__field">
|
||||||
|
<code-editor lang="yaml" :value="yamlProperties" key="custom-properties" @changed="setYamlProperties"></code-editor>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal__error modal__error--file-properties">{{error}}</div>
|
||||||
|
<div class="modal__info">
|
||||||
|
<p><strong>ProTip:</strong> You can manually toggle extensions:</p>
|
||||||
|
<pre class=" language-yaml"><code class="prism language-yaml"><span class="token key atrule">extensions</span><span class="token punctuation">:</span>
|
||||||
|
<span class="token key atrule">emoji</span><span class="token punctuation">:</span>
|
||||||
|
<span class="token comment"># Enable emoji shortcuts like :) :-(</span>
|
||||||
|
<span class="token key atrule">shortcuts</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
|
||||||
|
</code></pre>
|
||||||
|
<p>Use preset <code>zero</code> to make your own configuration:</p>
|
||||||
|
<pre class=" language-yaml"><code class="prism language-yaml"><span class="token key atrule">extensions</span><span class="token punctuation">:</span>
|
||||||
|
<span class="token key atrule">preset</span><span class="token punctuation">:</span> zero
|
||||||
|
<span class="token key atrule">markdown</span><span class="token punctuation">:</span>
|
||||||
|
<span class="token key atrule">table</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
|
||||||
|
<span class="token key atrule">katex</span><span class="token punctuation">:</span>
|
||||||
|
<span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
|
||||||
|
</code></pre>
|
||||||
|
<p>For the full list of options, see <a href="https://github.com/benweet/stackedit/blob/master/src/data/presets.js" target="_blank">here</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-entry" v-else-if="tab === 'default'" role="tabpanel" aria-label="Default properties">
|
|
||||||
<label class="form-entry__label">YAML</label>
|
|
||||||
<div class="form-entry__field">
|
|
||||||
<code-editor lang="yaml" :value="defaultProperties" key="default-properties" disabled="true"></code-editor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal__error modal__error--file-properties">{{error}}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button" @click="config.reject()">Cancel</button>
|
<button class="button" @click="config.reject()">Cancel</button>
|
||||||
@ -35,56 +85,135 @@ import yaml from 'js-yaml';
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import ModalInner from './common/ModalInner';
|
import ModalInner from './common/ModalInner';
|
||||||
import Tab from './common/Tab';
|
import Tab from './common/Tab';
|
||||||
|
import FormEntry from './common/FormEntry';
|
||||||
import CodeEditor from '../CodeEditor';
|
import CodeEditor from '../CodeEditor';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
import defaultProperties from '../../data/defaultFileProperties.yml';
|
import presets from '../../data/presets';
|
||||||
|
|
||||||
const emptyProperties = `# Add custom properties for the current file here
|
const simpleProperties = {
|
||||||
# to override the default properties.
|
title: '',
|
||||||
`;
|
author: '',
|
||||||
|
tags: '',
|
||||||
|
categories: '',
|
||||||
|
excerpt: '',
|
||||||
|
featuredImage: '',
|
||||||
|
status: '',
|
||||||
|
date: '',
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ModalInner,
|
ModalInner,
|
||||||
Tab,
|
Tab,
|
||||||
|
FormEntry,
|
||||||
CodeEditor,
|
CodeEditor,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
contentId: null,
|
contentId: null,
|
||||||
tab: 'custom',
|
yamlProperties: null,
|
||||||
defaultProperties,
|
preset: '',
|
||||||
customProperties: null,
|
|
||||||
error: null,
|
error: null,
|
||||||
|
...simpleProperties,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('modal', [
|
...mapGetters('modal', [
|
||||||
'config',
|
'config',
|
||||||
]),
|
]),
|
||||||
strippedCustomProperties() {
|
presets: () => Object.keys(presets).sort(),
|
||||||
return this.customProperties === emptyProperties ? '\n' : this.customProperties.replace(/\t/g, ' ');
|
tab: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters['data/localSettings'].filePropertiesTab;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.dispatch('data/patchLocalSettings', {
|
||||||
|
filePropertiesTab: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
const content = this.$store.getters['content/current'];
|
const content = this.$store.getters['content/current'];
|
||||||
this.contentId = content.id;
|
this.contentId = content.id;
|
||||||
const properties = content.properties;
|
this.setYamlProperties(content.properties);
|
||||||
this.setCustomProperties(properties === '\n' ? emptyProperties : properties);
|
if (this.tab !== 'yaml') {
|
||||||
|
this.setSimpleTab();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setCustomProperties(value) {
|
yamlToSimple() {
|
||||||
this.customProperties = value;
|
const properties = this.properties || {};
|
||||||
|
const extensions = properties.extensions || {};
|
||||||
|
this.preset = extensions.preset;
|
||||||
|
if (this.presets.indexOf(this.preset) === -1) {
|
||||||
|
this.preset = 'default';
|
||||||
|
}
|
||||||
|
Object.keys(simpleProperties).forEach((name) => {
|
||||||
|
this[name] = `${properties[name] || ''}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
simpleToYaml() {
|
||||||
|
let hasChanged = false;
|
||||||
|
const properties = this.properties || {};
|
||||||
|
const extensions = properties.extensions || {};
|
||||||
|
if (this.preset !== extensions.preset) {
|
||||||
|
if (this.preset !== 'default') {
|
||||||
|
extensions.preset = this.preset;
|
||||||
|
hasChanged = true;
|
||||||
|
} else if (extensions.preset) {
|
||||||
|
delete extensions.preset;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.keys(simpleProperties).forEach((name) => {
|
||||||
|
if (this[name] !== properties[name]) {
|
||||||
|
if (this[name]) {
|
||||||
|
properties[name] = this[name];
|
||||||
|
hasChanged = true;
|
||||||
|
} else if (properties[name]) {
|
||||||
|
delete properties[name];
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (hasChanged) {
|
||||||
|
if (Object.keys(extensions).length) {
|
||||||
|
properties.extensions = extensions;
|
||||||
|
} else {
|
||||||
|
delete properties.extensions;
|
||||||
|
}
|
||||||
|
this.setYamlProperties(Object.keys(properties).length
|
||||||
|
? yaml.safeDump(properties)
|
||||||
|
: '\n');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSimpleTab() {
|
||||||
|
this.tab = 'simple';
|
||||||
|
this.yamlToSimple();
|
||||||
|
},
|
||||||
|
setYamlTab() {
|
||||||
|
this.tab = 'yaml';
|
||||||
|
this.simpleToYaml();
|
||||||
|
},
|
||||||
|
setYamlProperties(value) {
|
||||||
|
this.yamlProperties = value;
|
||||||
try {
|
try {
|
||||||
yaml.safeLoad(this.strippedCustomProperties);
|
this.properties = yaml.safeLoad(value);
|
||||||
this.error = null;
|
this.error = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e.message;
|
this.error = e.message;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolve() {
|
resolve() {
|
||||||
if (!this.error) {
|
if (this.tab === 'simple') {
|
||||||
|
// Compute YAML properties
|
||||||
|
this.simpleToYaml();
|
||||||
|
}
|
||||||
|
if (this.error) {
|
||||||
|
this.setYamlTab();
|
||||||
|
} else {
|
||||||
this.$store.commit('content/patchItem', {
|
this.$store.commit('content/patchItem', {
|
||||||
id: this.contentId,
|
id: this.contentId,
|
||||||
properties: utils.sanitizeText(this.strippedCustomProperties),
|
properties: utils.sanitizeText(this.yamlProperties),
|
||||||
});
|
});
|
||||||
this.config.resolve();
|
this.config.resolve();
|
||||||
}
|
}
|
||||||
@ -97,7 +226,7 @@ export default {
|
|||||||
@import '../common/variables.scss';
|
@import '../common/variables.scss';
|
||||||
|
|
||||||
.modal__inner-1--file-properties {
|
.modal__inner-1--file-properties {
|
||||||
max-width: 600px;
|
max-width: 540px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal__error--file-properties {
|
.modal__error--file-properties {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-entry" :error="error">
|
<div class="form-entry" :error="error">
|
||||||
<label class="form-entry__label" :for="uid">{{label}}</label>
|
<label class="form-entry__label" :for="uid">{{label}}<span class="form-entry__label-info" v-if="info"> — {{info}}</span></label>
|
||||||
<div class="form-entry__field">
|
<div class="form-entry__field">
|
||||||
<slot name="field"></slot>
|
<slot name="field"></slot>
|
||||||
</div>
|
</div>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
import utils from '../../../services/utils';
|
import utils from '../../../services/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['label', 'error'],
|
props: ['label', 'info', 'error'],
|
||||||
data: () => ({
|
data: () => ({
|
||||||
uid: utils.uid(),
|
uid: utils.uid(),
|
||||||
}),
|
}),
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<b>Example:</b> http://example.blogger.com/
|
<b>Example:</b> http://example.blogger.com/
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing page ID (optional)">
|
<form-entry label="Existing page ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="pageId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="pageId" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Template">
|
<form-entry label="Template">
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<b>Example:</b> http://example.blogger.com/
|
<b>Example:</b> http://example.blogger.com/
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing post ID (optional)">
|
<form-entry label="Existing post ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Template">
|
<form-entry label="Template">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="Existing Gist ID (optional)">
|
<form-entry label="Existing Gist ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If the file exists in the Gist, it will be replaced.
|
If the file exists in the Gist, it will be replaced.
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="Existing Gist ID (optional)">
|
<form-entry label="Existing Gist ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If the file exists in the Gist, it will be replaced.
|
If the file exists in the Gist, it will be replaced.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<b>Example:</b> https://github.com/benweet/stackedit
|
<b>Example:</b> https://github.com/benweet/stackedit
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Branch (optional)">
|
<form-entry label="Branch" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If not provided, the <code>master</code> branch will be used.
|
If not provided, the <code>master</code> branch will be used.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<b>Example:</b> https://github.com/benweet/stackedit
|
<b>Example:</b> https://github.com/benweet/stackedit
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Branch (optional)">
|
<form-entry label="Branch" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If not provided, the master branch will be used.
|
If not provided, the master branch will be used.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<b>Example:</b> https://github.com/benweet/stackedit
|
<b>Example:</b> https://github.com/benweet/stackedit
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Branch (optional)">
|
<form-entry label="Branch" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If not provided, the <code>master</code> branch will be used.
|
If not provided, the <code>master</code> branch will be used.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>This will publish <b>{{currentFileName}}</b> to your <b>Google Drive</b> account.</p>
|
<p>This will publish <b>{{currentFileName}}</b> to your <b>Google Drive</b> account.</p>
|
||||||
<form-entry label="Folder ID (optional)">
|
<form-entry label="Folder ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If no folder ID is supplied, the file will be created in your root folder.
|
If no folder ID is supplied, the file will be created in your root folder.
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing file ID (optional)">
|
<form-entry label="Existing file ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
This will overwrite the file on the server.
|
This will overwrite the file on the server.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>This will save <b>{{currentFileName}}</b> to your <b>Google Drive</b> account and keep it synchronized.</p>
|
<p>This will save <b>{{currentFileName}}</b> to your <b>Google Drive</b> account and keep it synchronized.</p>
|
||||||
<form-entry label="Folder ID (optional)">
|
<form-entry label="Folder ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If no folder ID is supplied, the file will be created in your root folder.
|
If no folder ID is supplied, the file will be created in your root folder.
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing file ID (optional)">
|
<form-entry label="Existing file ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
This will overwrite the file on the server.
|
This will overwrite the file on the server.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>This will create a workspace synchronized with a <b>Google Drive</b> folder.</p>
|
<p>This will create a workspace synchronized with a <b>Google Drive</b> folder.</p>
|
||||||
<form-entry label="Folder ID (optional)">
|
<form-entry label="Folder ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
If no folder ID is supplied, a new workspace folder will be created in your root folder.
|
If no folder ID is supplied, a new workspace folder will be created in your root folder.
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
<modal-inner class="modal__inner-1--google-photo" aria-label="Import Google Photo">
|
<modal-inner class="modal__inner-1--google-photo" aria-label="Import Google Photo">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="google-photo__tumbnail" :style="{backgroundImage: thumbnailUrl}"></div>
|
<div class="google-photo__tumbnail" :style="{backgroundImage: thumbnailUrl}"></div>
|
||||||
<form-entry label="Title (optional)">
|
<form-entry label="Title" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="title" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="title" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Size limit (optional)">
|
<form-entry label="Size limit" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="size" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="size" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<b>Jetpack plugin</b> is required for self-hosted sites.
|
<b>Jetpack plugin</b> is required for self-hosted sites.
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing post ID (optional)">
|
<form-entry label="Existing post ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Template">
|
<form-entry label="Template">
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
https://example.zendesk.com/hc/en-us/sections/<b>21857469</b>-Section-name
|
https://example.zendesk.com/hc/en-us/sections/<b>21857469</b>-Section-name
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Existing article ID (optional)">
|
<form-entry label="Existing article ID" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="articleId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="articleId" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Locale (optional)">
|
<form-entry label="Locale" info="optional">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="locale" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="locale" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
<b>Default:</b> en-us
|
<b>Default:</b> en-us
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
## File properties can contain metadata used
|
|
||||||
## for your publications (Wordpress, Blogger...).
|
|
||||||
## For example:
|
|
||||||
|
|
||||||
#title: My article
|
|
||||||
#author:
|
|
||||||
#tags: Tag 1, Tag 2
|
|
||||||
#categories: Categorie 1, Categorie 2
|
|
||||||
#excerpt:
|
|
||||||
#featuredImage:
|
|
||||||
#status: draft
|
|
||||||
#date: YYYY-MM-DD HH:MM:SS
|
|
||||||
|
|
||||||
## Extensions configuration
|
|
||||||
## Preset can be `default`, `commonmark`, `gfm` or `zero`.
|
|
||||||
## Use preset `zero` to manually switch on extensions.
|
|
||||||
|
|
||||||
extensions:
|
|
||||||
preset: default
|
|
||||||
|
|
||||||
## Markdown extension
|
|
||||||
|
|
||||||
#markdown:
|
|
||||||
#abbr: true
|
|
||||||
#breaks: true
|
|
||||||
#deflist: true
|
|
||||||
#del: true
|
|
||||||
#fence: true
|
|
||||||
#footnote: true
|
|
||||||
#imgsize: true
|
|
||||||
#linkify: true
|
|
||||||
#mark: true
|
|
||||||
#sub: true
|
|
||||||
#sup: true
|
|
||||||
#table: true
|
|
||||||
#tasklist: true
|
|
||||||
#typographer: true
|
|
||||||
|
|
||||||
## Emoji extension
|
|
||||||
|
|
||||||
#emoji:
|
|
||||||
#enabled: true
|
|
||||||
|
|
||||||
## Enable shortcuts like :) :-(
|
|
||||||
## These are disabled by default.
|
|
||||||
#shortcuts: false
|
|
||||||
|
|
||||||
## Katex extension
|
|
||||||
## Render LaTeX mathematical expressions by using:
|
|
||||||
## $...$ for inline formulas
|
|
||||||
## $$...$$ for displayed formulas.
|
|
||||||
## See https://math.meta.stackexchange.com/questions/5020
|
|
||||||
|
|
||||||
#katex:
|
|
||||||
#enabled: true
|
|
||||||
|
|
||||||
## Mermaid extension
|
|
||||||
## Convert code blocks starting with ```mermaid
|
|
||||||
## into diagrams and flowcharts.
|
|
||||||
## See https://mermaidjs.github.io/
|
|
||||||
|
|
||||||
#mermaid:
|
|
||||||
#enabled: true
|
|
@ -1,5 +1,6 @@
|
|||||||
export default () => ({
|
export default () => ({
|
||||||
welcomeFileHashes: {},
|
welcomeFileHashes: {},
|
||||||
|
filePropertiesTab: '',
|
||||||
htmlExportTemplate: 'styledHtml',
|
htmlExportTemplate: 'styledHtml',
|
||||||
pdfExportTemplate: 'styledHtml',
|
pdfExportTemplate: 'styledHtml',
|
||||||
pandocExportFormat: 'pdf',
|
pandocExportFormat: 'pdf',
|
||||||
|
@ -24,15 +24,18 @@ shortcuts:
|
|||||||
mod+alt+f: replace
|
mod+alt+f: replace
|
||||||
mod+g: replace
|
mod+g: replace
|
||||||
mod+shift+b: bold
|
mod+shift+b: bold
|
||||||
mod+shift+i: italic
|
mod+shift+c: clist
|
||||||
mod+shift+l: link
|
|
||||||
mod+shift+q: quote
|
|
||||||
mod+shift+k: code
|
mod+shift+k: code
|
||||||
mod+shift+g: image
|
|
||||||
mod+shift+o: olist
|
|
||||||
mod+shift+u: ulist
|
|
||||||
mod+shift+h: heading
|
mod+shift+h: heading
|
||||||
mod+shift+r: hr
|
mod+shift+r: hr
|
||||||
|
mod+shift+g: image
|
||||||
|
mod+shift+i: italic
|
||||||
|
mod+shift+l: link
|
||||||
|
mod+shift+o: olist
|
||||||
|
mod+shift+q: quote
|
||||||
|
mod+shift+s: strikethrough
|
||||||
|
mod+shift+t: table
|
||||||
|
mod+shift+u: ulist
|
||||||
'= = > space':
|
'= = > space':
|
||||||
method: expand
|
method: expand
|
||||||
params:
|
params:
|
||||||
@ -84,6 +87,5 @@ newFileContent: |
|
|||||||
# Default properties for new files
|
# Default properties for new files
|
||||||
newFileProperties: |
|
newFileProperties: |
|
||||||
# extensions:
|
# extensions:
|
||||||
# markdown:
|
# preset: gfm
|
||||||
# breaks: false
|
|
||||||
|
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
export default [{}, {
|
export default [{}, {
|
||||||
action: 'bold',
|
method: 'bold',
|
||||||
title: 'Bold',
|
title: 'Bold',
|
||||||
icon: 'format-bold',
|
icon: 'format-bold',
|
||||||
}, {
|
}, {
|
||||||
action: 'italic',
|
method: 'italic',
|
||||||
title: 'Italic',
|
title: 'Italic',
|
||||||
icon: 'format-italic',
|
icon: 'format-italic',
|
||||||
}, {
|
}, {
|
||||||
action: 'heading',
|
method: 'heading',
|
||||||
title: 'Heading',
|
title: 'Heading',
|
||||||
icon: 'format-size',
|
icon: 'format-size',
|
||||||
}, {
|
}, {
|
||||||
action: 'strikethrough',
|
method: 'strikethrough',
|
||||||
title: 'Strikethrough',
|
title: 'Strikethrough',
|
||||||
icon: 'format-strikethrough',
|
icon: 'format-strikethrough',
|
||||||
}, {}, {
|
}, {}, {
|
||||||
action: 'ulist',
|
method: 'ulist',
|
||||||
title: 'Unordered list',
|
title: 'Unordered list',
|
||||||
icon: 'format-list-bulleted',
|
icon: 'format-list-bulleted',
|
||||||
}, {
|
}, {
|
||||||
action: 'olist',
|
method: 'olist',
|
||||||
title: 'Ordered list',
|
title: 'Ordered list',
|
||||||
icon: 'format-list-numbers',
|
icon: 'format-list-numbers',
|
||||||
}, {
|
}, {
|
||||||
action: 'clist',
|
method: 'clist',
|
||||||
title: 'Check list',
|
title: 'Check list',
|
||||||
icon: 'format-list-checks',
|
icon: 'format-list-checks',
|
||||||
}, {}, {
|
}, {}, {
|
||||||
action: 'quote',
|
method: 'quote',
|
||||||
title: 'Blockquote',
|
title: 'Blockquote',
|
||||||
icon: 'format-quote-close',
|
icon: 'format-quote-close',
|
||||||
}, {
|
}, {
|
||||||
action: 'code',
|
method: 'code',
|
||||||
title: 'Code',
|
title: 'Code',
|
||||||
icon: 'code-tags',
|
icon: 'code-tags',
|
||||||
}, {
|
}, {
|
||||||
action: 'table',
|
method: 'table',
|
||||||
title: 'Table',
|
title: 'Table',
|
||||||
icon: 'table',
|
icon: 'table',
|
||||||
}, {
|
}, {
|
||||||
action: 'link',
|
method: 'link',
|
||||||
title: 'Link',
|
title: 'Link',
|
||||||
icon: 'link-variant',
|
icon: 'link-variant',
|
||||||
}, {
|
}, {
|
||||||
action: 'image',
|
method: 'image',
|
||||||
title: 'Image',
|
title: 'Image',
|
||||||
icon: 'file-image',
|
icon: 'file-image',
|
||||||
}];
|
}];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const zero = {
|
const zero = {
|
||||||
|
// Markdown extensions
|
||||||
markdown: {
|
markdown: {
|
||||||
abbr: false,
|
abbr: false,
|
||||||
breaks: false,
|
breaks: false,
|
||||||
@ -15,13 +16,28 @@ const zero = {
|
|||||||
tasklist: false,
|
tasklist: false,
|
||||||
typographer: false,
|
typographer: false,
|
||||||
},
|
},
|
||||||
|
// Emoji extension
|
||||||
emoji: {
|
emoji: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
// Enable shortcuts like :) :-(
|
||||||
shortcuts: false,
|
shortcuts: false,
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
|
Katex extension
|
||||||
|
Render LaTeX mathematical expressions using:
|
||||||
|
$...$ for inline formulas
|
||||||
|
$$...$$ for displayed formulas.
|
||||||
|
See https://math.meta.stackexchange.com/questions/5020
|
||||||
|
*/
|
||||||
katex: {
|
katex: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
|
Mermaid extension
|
||||||
|
Convert code blocks starting with ```mermaid
|
||||||
|
into diagrams and flowcharts.
|
||||||
|
See https://mermaidjs.github.io/
|
||||||
|
*/
|
||||||
mermaid: {
|
mermaid: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
@ -29,6 +29,7 @@ const methods = {
|
|||||||
image: pagedownHandler('image'),
|
image: pagedownHandler('image'),
|
||||||
olist: pagedownHandler('olist'),
|
olist: pagedownHandler('olist'),
|
||||||
ulist: pagedownHandler('ulist'),
|
ulist: pagedownHandler('ulist'),
|
||||||
|
clist: pagedownHandler('clist'),
|
||||||
heading: pagedownHandler('heading'),
|
heading: pagedownHandler('heading'),
|
||||||
hr: pagedownHandler('hr'),
|
hr: pagedownHandler('hr'),
|
||||||
sync() {
|
sync() {
|
||||||
@ -66,8 +67,7 @@ store.watch(
|
|||||||
(computedSettings) => {
|
(computedSettings) => {
|
||||||
Mousetrap.reset();
|
Mousetrap.reset();
|
||||||
|
|
||||||
const shortcuts = computedSettings.shortcuts;
|
Object.entries(computedSettings.shortcuts).forEach(([key, shortcut]) => {
|
||||||
Object.entries(shortcuts).forEach(([key, shortcut]) => {
|
|
||||||
if (shortcut) {
|
if (shortcut) {
|
||||||
const method = `${shortcut.method || shortcut}`;
|
const method = `${shortcut.method || shortcut}`;
|
||||||
let params = shortcut.params || [];
|
let params = shortcut.params || [];
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import '../libs/clunderscore';
|
import '../libs/clunderscore';
|
||||||
import defaultPropertiesYaml from '../data/defaultFileProperties.yml';
|
|
||||||
import presets from '../data/presets';
|
import presets from '../data/presets';
|
||||||
|
|
||||||
const origin = `${location.protocol}//${location.host}`;
|
const origin = `${location.protocol}//${location.host}`;
|
||||||
@ -56,13 +55,14 @@ const deepCopy = (obj) => {
|
|||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build presets
|
// Compute presets
|
||||||
|
const computedPresets = {};
|
||||||
Object.keys(presets).forEach((key) => {
|
Object.keys(presets).forEach((key) => {
|
||||||
let preset = deepCopy(presets[key][0]);
|
let preset = deepCopy(presets[key][0]);
|
||||||
if (presets[key][1]) {
|
if (presets[key][1]) {
|
||||||
preset = deepOverride(preset, presets[key][1]);
|
preset = deepOverride(preset, presets[key][1]);
|
||||||
}
|
}
|
||||||
presets[key] = preset;
|
computedPresets[key] = preset;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -154,13 +154,17 @@ export default {
|
|||||||
c => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`).join(''));
|
c => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`).join(''));
|
||||||
},
|
},
|
||||||
computeProperties(yamlProperties) {
|
computeProperties(yamlProperties) {
|
||||||
const customProperties = yaml.safeLoad(yamlProperties);
|
let properties = {};
|
||||||
const defaultProperties = yaml.safeLoad(defaultPropertiesYaml);
|
try {
|
||||||
const properties = deepOverride(defaultProperties, customProperties);
|
properties = yaml.safeLoad(yamlProperties) || {};
|
||||||
const preset = deepCopy(presets[properties.extensions.preset] || presets.default);
|
} catch (e) {
|
||||||
const extensions = deepOverride(preset, properties.extensions);
|
// Ignore
|
||||||
extensions.preset = properties.extensions.preset;
|
}
|
||||||
properties.extensions = extensions;
|
const extensions = properties.extensions || {};
|
||||||
|
const computedPreset = deepCopy(computedPresets[extensions.preset] || computedPresets.default);
|
||||||
|
const computedExtensions = deepOverride(computedPreset, properties.extensions);
|
||||||
|
computedExtensions.preset = extensions.preset;
|
||||||
|
properties.extensions = computedExtensions;
|
||||||
return properties;
|
return properties;
|
||||||
},
|
},
|
||||||
randomize(value) {
|
randomize(value) {
|
||||||
|
@ -3,7 +3,7 @@ import pagedownButtons from '../data/pagedownButtons';
|
|||||||
let buttonCount = 0;
|
let buttonCount = 0;
|
||||||
let spacerCount = 0;
|
let spacerCount = 0;
|
||||||
pagedownButtons.forEach((button) => {
|
pagedownButtons.forEach((button) => {
|
||||||
if (button.action) {
|
if (button.method) {
|
||||||
buttonCount += 1;
|
buttonCount += 1;
|
||||||
} else {
|
} else {
|
||||||
spacerCount += 1;
|
spacerCount += 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user