Second commit

This commit is contained in:
benweet 2017-07-25 09:19:39 +01:00
parent 4622e4842c
commit 274f660850
16 changed files with 930 additions and 91 deletions

20
build/gulpfile.js Normal file
View File

@ -0,0 +1,20 @@
const path = require('path');
const gulp = require('gulp');
const concat = require('gulp-concat');
const prismScripts = [
'prismjs/components/prism-core',
'prismjs/components/prism-markup',
'prismjs/components/prism-clike',
'prismjs/components/prism-c',
'prismjs/components/prism-javascript',
'prismjs/components/prism-css',
'prismjs/components/prism-ruby',
].map(require.resolve);
prismScripts.push(
path.join(path.dirname(require.resolve('prismjs/components/prism-core')), 'prism-!(*.min).js'));
gulp.task('build-prism', () => gulp.src(prismScripts)
.pipe(concat('prism.js'))
.pipe(gulp.dest(path.dirname(require.resolve('prismjs'))))
);

View File

@ -5,7 +5,7 @@
"author": "",
"private": true,
"scripts": {
"dev": "node build/dev-server.js",
"postinstall": "gulp --cwd build build-prism",
"start": "node build/dev-server.js",
"build": "node build/build.js",
"lint": "eslint --ext .js,.vue src"
@ -54,6 +54,8 @@
"extract-text-webpack-plugin": "^2.0.0",
"file-loader": "^0.11.1",
"friendly-errors-webpack-plugin": "^1.1.3",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"html-webpack-plugin": "^2.28.0",
"http-proxy-middleware": "^0.17.3",
"node-sass": "^4.5.3",

View File

@ -45,4 +45,63 @@ body {
fill: currentColor;
}
}
button,
input,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.text-input {
display: block;
width: 100%;
height: 36px;
padding: 3px 12px;
font-size: 22px;
line-height: 1.5;
color: inherit;
background-color: #fff;
background-image: none;
border: 0;
border-radius: $border-radius-base;
}
.button {
color: #333;
background-color: transparent;
display: inline-block;
height: 36px;
padding: 3px 12px;
margin-bottom: 0;
font-size: 22px;
font-weight: 400;
line-height: 1.4;
overflow: hidden;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-image: none;
border: 0;
border-radius: $border-radius-base;
&:focus {
color: #333;
background-color: transparent;
&:active,
& {
outline: 0;
}
}
}
</style>

View File

@ -1,10 +1,5 @@
<template>
<div class="button-bar">
<div class="button-bar__inner button-bar__inner--left" @click="toggleEditor(false)">
<div class="button-bar__button">
<icon-eye></icon-eye>
</div>
</div>
<div class="button-bar__inner button-bar__inner--top">
<div class="button-bar__button" :class="{ 'button-bar__button--on': showNavigationBar }" @click="toggleNavigationBar()">
<icon-navigation-bar></icon-navigation-bar>
@ -12,6 +7,9 @@
<div class="button-bar__button" :class="{ 'button-bar__button--on': showSidePreview }" @click="toggleSidePreview()">
<icon-side-preview></icon-side-preview>
</div>
<div class="button-bar__button" @click="toggleEditor(false)">
<icon-eye></icon-eye>
</div>
</div>
<div class="button-bar__inner button-bar__inner--bottom">
<div class="button-bar__button" :class="{ 'button-bar__button--on': showStatusBar }" @click="toggleStatusBar()">
@ -75,14 +73,4 @@ export default {
.button-bar__button--on {
color: rgba(0, 0, 0, 0.4);
}
.button-bar__inner--left {
left: -52px;
z-index: 1;
.button-bar__button {
width: 30px;
height: 30px;
}
}
</style>

View File

@ -1,52 +1,116 @@
<template>
<div class="navigation-bar">
<div class="navigation-bar__button" v-on:click="pagedownClick('bold')">
<icon-format-bold></icon-format-bold>
<div class="navigation-bar__title-mirror button" v-bind:style="{ maxWidth: titleMaxWidth + 'px' }"></div>
<div class="navigation-bar__inner navigation-bar__inner--right">
<button v-if="!editingTitle" v-on:click="editingTitle = true" v-bind:style="{ width: titleWidth + 'px' }" class="navigation-bar__title button">{{title}}</button>
<input v-if="editingTitle" v-on:blur="editingTitle = false" v-model.lazy.trim="title" v-focus v-autosize @keyup.enter="editingTitle = false" @keyup.esc="resetTitle" type="text" class="navigation-bar__title navigation-bar__title--input text-input">
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('italic')">
<icon-format-italic></icon-format-italic>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('strikethrough')">
<icon-format-strikethrough></icon-format-strikethrough>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('heading')">
<icon-format-size></icon-format-size>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('hr')">
<icon-format-horizontal-rule></icon-format-horizontal-rule>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('ulist')">
<icon-format-list-bulleted></icon-format-list-bulleted>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('olist')">
<icon-format-list-numbers></icon-format-list-numbers>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('table')">
<icon-table></icon-table>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('quote')">
<icon-format-quote-close></icon-format-quote-close>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('code')">
<icon-code-braces></icon-code-braces>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('link')">
<icon-link-variant></icon-link-variant>
</div>
<div class="navigation-bar__button" v-on:click="pagedownClick('image')">
<icon-file-image></icon-file-image>
<div class="navigation-bar__inner navigation-bar__inner--left" v-if="showEditor">
<button class="navigation-bar__button button" v-on:click="pagedownClick('bold')">
<icon-format-bold></icon-format-bold>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('italic')">
<icon-format-italic></icon-format-italic>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('strikethrough')">
<icon-format-strikethrough></icon-format-strikethrough>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('heading')">
<icon-format-size></icon-format-size>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('ulist')">
<icon-format-list-bulleted></icon-format-list-bulleted>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('olist')">
<icon-format-list-numbers></icon-format-list-numbers>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('table')">
<icon-table></icon-table>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('quote')">
<icon-format-quote-close></icon-format-quote-close>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('code')">
<icon-code-braces></icon-code-braces>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('link')">
<icon-link-variant></icon-link-variant>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('image')">
<icon-file-image></icon-file-image>
</button>
<button class="navigation-bar__button button" v-on:click="pagedownClick('hr')">
<icon-format-horizontal-rule></icon-format-horizontal-rule>
</button>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import editorSvc from '../services/editorSvc';
let titleMirrorElt;
export default {
directives: {
focus: {
inserted(elt) {
elt.focus();
elt.select();
},
},
autosize: {
inserted(elt) {
function adjustWidth() {
titleMirrorElt.textContent = elt.value;
const width = titleMirrorElt.getBoundingClientRect().width + 1; // 1px for the caret
elt.style.width = `${width}px`;
}
adjustWidth();
elt.addEventListener('keyup', adjustWidth);
elt.addEventListener('input', adjustWidth);
},
},
},
data: () => ({
editingTitle: null,
isMounted: false,
}),
computed: {
...mapState('layout', {
showEditor: 'showEditor',
titleMaxWidth: 'titleMaxWidth',
}),
title: {
get() {
return this.$store.state.files.currentFile.name;
},
set(value) {
this.$store.commit('files/setCurrentFileName', value);
},
},
titleWidth() {
if (!this.isMounted) {
return 0;
}
titleMirrorElt.textContent = this.$store.state.files.currentFile.name;
return titleMirrorElt.getBoundingClientRect().width + 1; // 1px for the caret
},
},
methods: {
pagedownClick(name) {
editorSvc.pagedownEditor.uiManager.doClick(name);
},
resetTitle(event) {
event.target.value = '';
this.editingTitle = false;
},
},
mounted() {
titleMirrorElt = this.$el.querySelector('.navigation-bar__title-mirror');
this.isMounted = true;
},
};
</script>
@ -57,20 +121,46 @@ export default {
width: 100%;
height: 100%;
background-color: #2c2c2c;
padding: 5px 15px 0;
padding: 4px 15px 0;
overflow: hidden;
}
.navigation-bar__inner--left {
float: left;
}
.navigation-bar__inner--right {
float: right;
}
$navbar-button-color: rgba(255, 255, 255, 0.67);
$navbar-button-hover-background: #484848;
.navigation-bar__button {
display: inline-block;
cursor: pointer;
color: rgba(255, 255, 255, 0.67);
width: 34px;
height: 34px;
padding: 4px;
border-radius: 3px;
padding: 6px 5px;
}
.navigation-bar__title,
.navigation-bar__title-mirror,
.navigation-bar__button {
display: inline-block;
color: $navbar-button-color;
background-color: transparent;
font-weight: 400;
&:active,
&:focus,
&:hover {
color: #fff;
background-color: $navbar-button-hover-background;
}
}
.navigation-bar__title-mirror {
position: absolute;
left: -9999px;
width: auto;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="stat-panel panel no-overflow">
<div class="stat-panel__block stat-panel__block--left">
<div class="stat-panel__block stat-panel__block--left" v-if="showEditor">
<span class="stat-panel__block-name">
Text
<small v-show="textSelection">(selection)</small>
@ -8,6 +8,7 @@
<span v-for="stat in textStats" :key="stat.id">
<span class="stat-panel__value">{{stat.value}}</span> {{stat.name}}
</span>
<span class="stat-panel__value">Ln {{line}}, Col {{column}}</span>
</div>
<div class="stat-panel__block stat-panel__block--right">
<span class="stat-panel__block-name">
@ -22,6 +23,7 @@
</template>
<script>
import { mapState } from 'vuex';
import editorSvc from '../services/editorSvc';
import editorEngineSvc from '../services/editorEngineSvc';
import utils from '../services/utils';
@ -39,6 +41,8 @@ export default {
data: () => ({
textSelection: false,
htmlSelection: false,
line: 0,
column: 0,
textStats: [
new Stat('bytes', '[\\s\\S]'),
new Stat('words', '\\S+'),
@ -50,6 +54,9 @@ export default {
new Stat('paragraphs', '\\S.*'),
],
}),
computed: mapState('layout', {
showEditor: 'showEditor',
}),
created() {
editorSvc.$on('sectionList', () => this.computeText());
editorSvc.$on('selectionRange', () => this.computeText());
@ -61,6 +68,11 @@ export default {
computeText() {
this.textSelection = false;
let text = editorEngineSvc.clEditor.getContent();
const beforeText = text.slice(0, editorEngineSvc.clEditor.selectionMgr.selectionEnd);
const beforeLines = beforeText.split('\n');
this.line = beforeLines.length;
this.column = beforeLines.pop().length;
const selectedText = editorEngineSvc.clEditor.selectionMgr.getSelectedText();
if (selectedText) {
this.textSelection = true;
@ -80,8 +92,8 @@ export default {
this.htmlSelection = false;
text = editorSvc.previewText;
}
if (text !== undefined) {
this.htmlStats.cl_each((stat) => {
if (text != null) {
this.htmlStats.forEach((stat) => {
stat.value = (text.match(stat.regex) || []).length;
});
}
@ -95,12 +107,12 @@ export default {
position: absolute;
width: 100%;
height: 100%;
color: rgba(0, 0, 0, 0.75);
font-size: 12.5px;
color: #fff;
font-size: 13px;
}
.stat-panel__block {
margin: 2px;
margin: 0 10px;
}
.stat-panel__block--left {
@ -112,11 +124,11 @@ export default {
}
.stat-panel__block-name {
font-weight: 500;
margin: 0 10px;
font-weight: 600;
}
.stat-panel__value {
font-weight: 500;
font-weight: 600;
margin-left: 5px;
}
</style>

View File

@ -51,7 +51,7 @@ samp {
}
blockquote {
color: rgba(0, 0, 0, 0.4);
color: rgba(0, 0, 0, 0.5);
margin-left: 1em;
margin-right: 1em;
}

View File

@ -99,6 +99,7 @@
.img {
display: inline-block;
padding: 0;
background-color: transparent;
}
img {

View File

@ -2,9 +2,9 @@ $font-family-editor: "Helvetica Neue", Helvetica, sans-serif;
$font-family-monospace: "Lucida Sans Typewriter", "Lucida Console", monaco, Courrier, monospace;
$font-size-monospace: 0.9em;
$code-bg: rgba(0, 0, 0, 0.05);
$code-border-radius: 3px;
$link-color: #0366d6;
$border-radius-base: 3px;
$code-border-radius: 2px;
$link-color: #007acc;
$border-radius-base: 2px;
$editor-color: rgba(0, 0, 0, 0.8);
$editor-color-light: rgba(0, 0, 0, 0.28);

View File

@ -132,7 +132,7 @@ extensionSvc.onInitConverter(0, (markdown, options) => {
}
}
// If nothing is left after this, use the identifier `section`
// If nothing left after this, use `section`
slug = slug.slice(i) || 'section';
let anchor = slug;

View File

@ -414,6 +414,7 @@ const editorSvc = Object.assign(new Vue(), { // Use a vue instance as an event b
}
}
editorSvc.previewSelectionRange = range;
editorSvc.$emit('previewSelectionRange', editorSvc.previewSelectionRange);
}
}, 50),

View File

@ -16,6 +16,7 @@ const languageAliases = ({
xml: 'markup',
py: 'python',
rb: 'ruby',
yml: 'yaml',
ps1: 'powershell',
psm1: 'powershell',
});
@ -24,7 +25,7 @@ Object.keys(languageAliases).forEach((alias) => {
Prism.languages[alias] = Prism.languages[language];
});
// Add language parsing capability to markdown fences
// Add programming language parsing capability to markdown fences
const insideFences = {};
Object.keys(Prism.languages).forEach((name) => {
const language = Prism.languages[name];
@ -136,13 +137,13 @@ const markdownConversionSvc = {
converter.inline.ruler.enable([], true);
extensionSvc.initConverter(converter, options, isCurrentFile);
Object.keys(startSectionBlockTypeMap).forEach((type) => {
const rule = converter.renderer.rules[type] === true || converter.renderer.renderToken;
converter.renderer.rules[type] = (tokens, idx, opts) => {
const rule = converter.renderer.rules[type] || converter.renderer.renderToken;
converter.renderer.rules[type] = (tokens, idx, opts, env, self) => {
if (tokens[idx].sectionDelimiter) {
// Add section delimiter
return htmlSectionMarker + rule.call(converter.renderer, tokens, idx, opts);
return htmlSectionMarker + rule.call(converter.renderer, tokens, idx, opts, env, self);
}
return rule.call(converter.renderer, tokens, idx, opts);
return rule.call(converter.renderer, tokens, idx, opts, env, self);
};
});
return converter;

View File

@ -78,7 +78,7 @@ const doScrollSync = () => {
}, () => {
isPreviewMoving = true;
});
}, localSkipAnimation ? 500 : 10);
}, localSkipAnimation ? 500 : 50);
} else if (!store.state.layout.showEditor || isScrollPreview) {
// Scroll the editor
isScrollPreview = false;
@ -110,7 +110,7 @@ const doScrollSync = () => {
}, () => {
isEditorMoving = true;
});
}, localSkipAnimation ? 500 : 10);
}, localSkipAnimation ? 500 : 50);
}
};

View File

@ -5,7 +5,7 @@ export default {
state: {
files: [],
currentFile: {
name: null,
name: 'Test',
folderId: null,
isLoaded: true,
content: {
@ -21,6 +21,11 @@ export default {
setCurrentFile: (state, value) => {
state.currentFile = value;
},
setCurrentFileName: (state, value) => {
if (value) {
state.currentFile.name = value;
}
},
setCurrentFileContentText: (state, value) => {
state.currentFile.content.text = value;
},

View File

@ -5,6 +5,9 @@ const buttonBarWidth = 30;
const statusBarHeight = 20;
const outOfScreenMargin = 50;
const minPadding = 20;
const navigationBarLeftWidth = 500;
const titleMaxMaxWidth = 500;
const titleMinMaxWidth = 200;
const setter = propertyName => (state, value) => {
state[propertyName] = value;
@ -23,7 +26,7 @@ export default {
showEditor: true,
showSidePreview: true,
showSideBar: false,
showStatusBar: false,
showStatusBar: true,
editorWidthFactor: 1,
fontSizeFactor: 1,
// Style
@ -40,6 +43,7 @@ export default {
editorPadding: 0,
previewWidth: 0,
previewPadding: 0,
titleMaxWidth: 0,
},
mutations: {
setShowNavigationBar: setter('showNavigationBar'),
@ -62,6 +66,7 @@ export default {
setEditorPadding: setter('editorPadding'),
setPreviewWidth: setter('previewWidth'),
setPreviewPadding: setter('previewPadding'),
setTitleMaxWidth: setter('titleMaxWidth'),
},
actions: {
toggleNavigationBar: toggler('showNavigationBar', 'setShowNavigationBar'),
@ -73,7 +78,7 @@ export default {
const bodyWidth = document.body.clientWidth;
const bodyHeight = document.body.clientHeight;
const showNavigationBar = state.showEditor && state.showNavigationBar;
const showNavigationBar = !state.showEditor || state.showNavigationBar;
const inner1Y = showNavigationBar
? navigationBarHeight
: 0;
@ -149,6 +154,13 @@ export default {
editorPadding = minPadding;
}
let titleMaxWidth = bodyWidth;
if (state.showEditor) {
titleMaxWidth -= navigationBarLeftWidth;
}
titleMaxWidth = Math.min(titleMaxWidth, titleMaxMaxWidth);
titleMaxWidth = Math.max(titleMaxWidth, titleMinMaxWidth);
commit('setFontSize', fontSize);
commit('setInner1Y', inner1Y);
commit('setInner1Height', inner1Height);
@ -162,6 +174,7 @@ export default {
commit('setPreviewPadding', previewPadding);
commit('setEditorWidth', editorWidth);
commit('setEditorPadding', editorPadding);
commit('setTitleMaxWidth', titleMaxWidth);
},
},
};

669
yarn.lock

File diff suppressed because it is too large Load Diff