From c07fc7135eff3b5ee0937f9874f6b576ca445369 Mon Sep 17 00:00:00 2001 From: Benoit Schweblin Date: Fri, 28 Jul 2017 21:04:12 +0100 Subject: [PATCH] Few fixes --- src/components/App.vue | 90 +------------ src/components/ButtonBar.vue | 1 - src/components/Editor.vue | 1 - src/components/Explorer.vue | 18 +++ src/components/ExplorerItem.vue | 13 ++ src/components/Layout.vue | 106 +++++++-------- src/components/NavigationBar.vue | 120 ++++++++++------- src/components/common/app.scss | 118 +++++++++++++++++ src/components/common/base.scss | 1 + src/components/common/flex.scss | 19 --- .../common/markdownHighlighting.scss | 1 + src/icons/Menu.vue | 5 + src/icons/Settings.vue | 5 + src/icons/index.js | 4 + src/services/localDbSvc.js | 47 ++++--- src/services/syncSvc.js | 2 +- src/store/modules/layout.js | 123 +++++++----------- 17 files changed, 376 insertions(+), 298 deletions(-) create mode 100644 src/components/Explorer.vue create mode 100644 src/components/ExplorerItem.vue create mode 100644 src/components/common/app.scss delete mode 100644 src/components/common/flex.scss create mode 100644 src/icons/Menu.vue create mode 100644 src/icons/Settings.vue diff --git a/src/components/App.vue b/src/components/App.vue index 2b01a1db..17bafaf6 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -20,93 +20,5 @@ export default { diff --git a/src/components/ButtonBar.vue b/src/components/ButtonBar.vue index 113e5784..d53bd69a 100644 --- a/src/components/ButtonBar.vue +++ b/src/components/ButtonBar.vue @@ -34,7 +34,6 @@ export default { 'toggleNavigationBar', 'toggleEditor', 'toggleSidePreview', - 'toggleSideBar', 'toggleStatusBar', ]), }; diff --git a/src/components/Editor.vue b/src/components/Editor.vue index f974daef..a9030c90 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -23,7 +23,6 @@ export default { width: 100%; height: 100%; overflow: auto; - background-color: #fff; } .editor__inner { diff --git a/src/components/Explorer.vue b/src/components/Explorer.vue new file mode 100644 index 00000000..a5c8f753 --- /dev/null +++ b/src/components/Explorer.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/components/ExplorerItem.vue b/src/components/ExplorerItem.vue new file mode 100644 index 00000000..9ada47d4 --- /dev/null +++ b/src/components/ExplorerItem.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/src/components/Layout.vue b/src/components/Layout.vue index f0664718..7e24ea09 100644 --- a/src/components/Layout.vue +++ b/src/components/Layout.vue @@ -1,38 +1,42 @@ diff --git a/src/components/NavigationBar.vue b/src/components/NavigationBar.vue index 7ae77b5b..ac9ed0b2 100644 --- a/src/components/NavigationBar.vue +++ b/src/components/NavigationBar.vue @@ -1,13 +1,24 @@ @@ -142,14 +155,26 @@ export default { position: absolute; width: 100%; height: 100%; - padding: 4px 15px 0; + padding-top: 4px; overflow: hidden; } +.navigation-bar__inner--left { + float: left; +} + .navigation-bar__inner--right { float: right; } +.navigation-bar__inner--button { + margin: 0 4px; +} + +.navigation-bar__inner--edit-buttons { + margin-left: 15px; +} + .navigation-bar__button { display: inline-block; width: 34px; @@ -174,26 +199,29 @@ export default { } } +.navigation-bar__title--fake { + position: absolute; + left: -9999px; + width: auto; + white-space: pre-wrap; +} + .navigation-bar__title--text { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + + .navigation-bar--editor & { + display: none; + } } .navigation-bar__title--input, -.navigation-bar__inner--left { +.navigation-bar__inner--edit-buttons, +.navigation-bar__inner--button { display: none; -} -.navigation-bar--editor { - .navigation-bar__title--text { - position: absolute; - left: -9999px; - width: auto; - } - - .navigation-bar__title--input, - .navigation-bar__inner--left { + .navigation-bar--editor & { display: block; } } diff --git a/src/components/common/app.scss b/src/components/common/app.scss new file mode 100644 index 00000000..53f224c6 --- /dev/null +++ b/src/components/common/app.scss @@ -0,0 +1,118 @@ +@import './variables.scss'; +@import './base'; +@import './markdownHighlighting'; + +body { + background-color: #f3f3f3; + top: 0; + right: 0; + bottom: 0; + left: 0; + position: fixed; + tab-size: 4; + text-rendering: auto; +} + +* { + box-sizing: border-box; +} + +:focus { + outline: none; +} + +.icon { + * { + 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; + } + } +} + +.flex { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; +} + +.flex--row { + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + flex-direction: row; +} + +.flex--column { + -webkit-box-orient: vertical; + -webkit-flex-direction: column; + flex-direction: column; +} + +.side-title { + height: 44px; + line-height: 44px; + padding: 0 10px; + background-color: #ccc; +} + +.side-title__text { + text-transform: uppercase; +} diff --git a/src/components/common/base.scss b/src/components/common/base.scss index a8bdc426..f56afb3c 100644 --- a/src/components/common/base.scss +++ b/src/components/common/base.scss @@ -2,6 +2,7 @@ @import '../../node_modules/katex/dist/katex.css'; @import './variables.scss'; @import './fonts.scss'; +@import './prism'; @include normalize(); diff --git a/src/components/common/flex.scss b/src/components/common/flex.scss deleted file mode 100644 index 58ee9d08..00000000 --- a/src/components/common/flex.scss +++ /dev/null @@ -1,19 +0,0 @@ -.flex { - display: -webkit-box; - display: -webkit-flex; - display: -moz-box; - display: -ms-flexbox; - display: flex; -} - -.flex--row { - -webkit-box-orient: horizontal; - -webkit-flex-direction: row; - flex-direction: row; -} - -.flex--column { - -webkit-box-orient: vertical; - -webkit-flex-direction: column; - flex-direction: column; -} diff --git a/src/components/common/markdownHighlighting.scss b/src/components/common/markdownHighlighting.scss index 6e30ca40..bbfe1ca6 100644 --- a/src/components/common/markdownHighlighting.scss +++ b/src/components/common/markdownHighlighting.scss @@ -127,6 +127,7 @@ .h6 { font-weight: $editor-font-weight-bold; + &, * { line-height: $line-height-title; } diff --git a/src/icons/Menu.vue b/src/icons/Menu.vue new file mode 100644 index 00000000..ee2d30c8 --- /dev/null +++ b/src/icons/Menu.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/Settings.vue b/src/icons/Settings.vue new file mode 100644 index 00000000..a65aae44 --- /dev/null +++ b/src/icons/Settings.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/index.js b/src/icons/index.js index f25701f7..b4b3e07e 100644 --- a/src/icons/index.js +++ b/src/icons/index.js @@ -15,6 +15,8 @@ import StatusBar from './StatusBar'; import NavigationBar from './NavigationBar'; import SidePreview from './SidePreview'; import Eye from './Eye'; +import Menu from './Menu'; +import Settings from './Settings'; Vue.component('iconFormatBold', FormatBold); Vue.component('iconFormatItalic', FormatItalic); @@ -32,3 +34,5 @@ Vue.component('iconStatusBar', StatusBar); Vue.component('iconNavigationBar', NavigationBar); Vue.component('iconSidePreview', SidePreview); Vue.component('iconEye', Eye); +Vue.component('iconMenu', Menu); +Vue.component('iconSettings', Settings); diff --git a/src/services/localDbSvc.js b/src/services/localDbSvc.js index 0bc83ef8..97e967e7 100644 --- a/src/services/localDbSvc.js +++ b/src/services/localDbSvc.js @@ -21,7 +21,7 @@ function getStorePrefixFromType(type) { return store.state[prefix] && prefix; } -const deletedMarkerMaxAge = 1000; +const deleteMarkerMaxAge = 1000; class Connection { constructor() { @@ -67,6 +67,9 @@ class Connection { }; } + /** + * Create a connection asynchronously. + */ createTx(cb) { if (!this.db) { this.getTxCbs.push(cb); @@ -78,10 +81,13 @@ class Connection { window.location.reload(); return; } + + // Open transaction in read/write will prevent conflict with other tabs const tx = this.db.transaction(this.db.objectStoreNames, 'readwrite'); tx.onerror = (evt) => { dbg('Rollback transaction', evt); }; + // Read the current txCounter const dbStore = tx.objectStore(dbStoreName); const request = dbStore.get('txCounter'); request.onsuccess = () => { @@ -101,6 +107,11 @@ export default { updatedMap: Object.create(null), connection: new Connection(), + /** + * Return a promise that is resolved once the synchronization between the store and the localDb + * is finished. Effectively, open a transaction, then read and apply all changes from the DB + * since previous transaction, then write all changes from the store. + */ sync() { return new Promise((resolve) => { const storeItemMap = {}; @@ -117,11 +128,14 @@ export default { }); }, + /** + * Read and apply all changes from the DB since previous transaction. + */ readAll(storeItemMap, tx, cb) { let resetMap; - // We may have missed some deleted markers - if (this.lastTx && tx.txCounter - this.lastTx > deletedMarkerMaxAge) { + // We may have missed some delete markers + if (this.lastTx && tx.txCounter - this.lastTx > deleteMarkerMaxAge) { // Delete all dirty store items (user was asleep anyway...) resetMap = true; // And retrieve everything from DB @@ -138,8 +152,8 @@ export default { if (cursor) { const item = cursor.value; items.push(item); - // Remove old deleted markers - if (!item.updated && tx.txCounter - item.tx > deletedMarkerMaxAge) { + // Remove old delete markers + if (!item.updated && tx.txCounter - item.tx > deleteMarkerMaxAge) { itemsToDelete.push(item); } cursor.continue(); @@ -162,30 +176,28 @@ export default { }; }, + /** + * Write all changes from the store since previous transaction. + */ writeAll(storeItemMap, tx) { this.lastTx = tx.txCounter; const dbStore = tx.objectStore(dbStoreName); // Remove deleted store items - const storedIds = Object.keys(this.updatedMap); - const storedIdsLen = storedIds.length; - for (let i = 0; i < storedIdsLen; i += 1) { - const id = storedIds[i]; + Object.keys(this.updatedMap).forEach((id) => { if (!storeItemMap[id]) { - // Put a deleted marker to notify other tabs + // Put a delete marker to notify other tabs dbStore.put({ id, tx: this.lastTx, }); delete this.updatedMap[id]; } - } + }); // Put changes - const storeItemIds = Object.keys(storeItemMap); - const storeItemIdsLen = storeItemIds.length; - for (let i = 0; i < storeItemIdsLen; i += 1) { - const storeItem = storeItemMap[storeItemIds[i]]; + Object.keys(storeItemMap).forEach((id) => { + const storeItem = storeItemMap[id]; // Store object has changed if (this.updatedMap[storeItem.id] !== storeItem.updated) { const item = { @@ -196,9 +208,12 @@ export default { dbStore.put(item); this.updatedMap[item.id] = item.updated; } - } + }); }, + /** + * Read and apply one DB change. + */ readDbItem(dbItem, storeItemMap) { const existingStoreItem = storeItemMap[dbItem.id]; if (!dbItem.updated) { diff --git a/src/services/syncSvc.js b/src/services/syncSvc.js index a8bb3024..b4e6ea0b 100644 --- a/src/services/syncSvc.js +++ b/src/services/syncSvc.js @@ -38,8 +38,8 @@ store.watch( return store.state.files.itemMap[fileId]; })) .then((currentFile) => { - store.commit('files/patchItem', { id: currentFile.id }); store.commit('files/setCurrentId', currentFile.id); + store.dispatch('files/patchCurrent', {}); // Update `updated` field to make it the mostRecent }), { immediate: true, diff --git a/src/store/modules/layout.js b/src/store/modules/layout.js index 359fe1bd..fa933048 100644 --- a/src/store/modules/layout.js +++ b/src/store/modules/layout.js @@ -1,12 +1,7 @@ -const navigationBarHeight = 44; -const sideBarWidth = 280; const editorMinWidth = 280; -const buttonBarWidth = 30; -const statusBarHeight = 20; -const outOfScreenMargin = 50; const minPadding = 20; const navigationBarSpaceWidth = 30; -const navigationBarLeftWidth = 500; +const navigationBarLeftWidth = 570; const maxTitleMaxWidth = 800; const minTitleMaxWidth = 200; @@ -22,24 +17,25 @@ const toggler = (propertyName, setterName) => ({ state, commit, dispatch }, show export default { namespaced: true, state: { + // Constants + explorerWidth: 280, + sideBarWidth: 280, + navigationBarHeight: 44, + buttonBarWidth: 30, + statusBarHeight: 20, // Configuration showNavigationBar: true, showEditor: true, showSidePreview: true, - showSideBar: false, showStatusBar: true, + showSideBar: false, + showExplorer: false, editorWidthFactor: 1, fontSizeFactor: 1, // Style fontSize: 0, - inner1Y: 0, - inner1Height: 0, - inner2Height: 0, - inner3X: 0, - inner3Width: 0, - navigationBarY: 0, - sideBarX: 0, - statusBarY: 0, + innerWidth: 0, + innerHeight: 0, editorWidth: 0, editorPadding: 0, previewWidth: 0, @@ -50,19 +46,14 @@ export default { setShowNavigationBar: setter('showNavigationBar'), setShowEditor: setter('showEditor'), setShowSidePreview: setter('showSidePreview'), - setShowSideBar: setter('showSideBar'), setShowStatusBar: setter('showStatusBar'), + setShowSideBar: setter('showSideBar'), + setShowExplorer: setter('showExplorer'), setEditorWidthFactor: setter('editorWidthFactor'), setFontSizeFactor: setter('fontSizeFactor'), setFontSize: setter('fontSize'), - setInner1Y: setter('inner1Y'), - setInner1Height: setter('inner1Height'), - setInner2Height: setter('inner2Height'), - setInner3X: setter('inner3X'), - setInner3Width: setter('inner3Width'), - setNavigationBarY: setter('navigationBarY'), - setSideBarX: setter('sideBarX'), - setStatusBarY: setter('statusBarY'), + setInnerWidth: setter('innerWidth'), + setInnerHeight: setter('innerHeight'), setEditorWidth: setter('editorWidth'), setEditorPadding: setter('editorPadding'), setPreviewWidth: setter('previewWidth'), @@ -73,35 +64,39 @@ export default { toggleNavigationBar: toggler('showNavigationBar', 'setShowNavigationBar'), toggleEditor: toggler('showEditor', 'setShowEditor'), toggleSidePreview: toggler('showSidePreview', 'setShowSidePreview'), - toggleSideBar: toggler('showSideBar', 'setShowSideBar'), toggleStatusBar: toggler('showStatusBar', 'setShowStatusBar'), + toggleSideBar: toggler('showSideBar', 'setShowSideBar'), + toggleExplorer: toggler('showExplorer', 'setShowExplorer'), updateStyle({ state, commit, dispatch }) { const bodyWidth = document.body.clientWidth; const bodyHeight = document.body.clientHeight; const showNavigationBar = !state.showEditor || state.showNavigationBar; - const inner1Y = showNavigationBar - ? navigationBarHeight - : 0; - const inner1Height = bodyHeight - inner1Y; - const inner2Height = state.showStatusBar - ? inner1Height - statusBarHeight - : inner1Height; - const navigationBarY = showNavigationBar - ? 0 - : -navigationBarHeight - outOfScreenMargin; - const sideBarX = state.showSideBar - ? bodyWidth - sideBarWidth - : bodyWidth + outOfScreenMargin; - const statusBarY = state.showStatusBar - ? inner2Height - : inner2Height + outOfScreenMargin; - - let doublePanelWidth = bodyWidth - buttonBarWidth; - if (state.showSideBar) { - doublePanelWidth -= sideBarWidth; + let innerHeight = bodyHeight; + if (showNavigationBar) { + innerHeight -= state.navigationBarHeight; } + if (state.showStatusBar) { + innerHeight -= state.statusBarHeight; + } + + let innerWidth = bodyWidth; + if (state.showSideBar) { + innerWidth -= state.sideBarWidth; + } + if (state.showExplorer) { + innerWidth -= state.explorerWidth; + } + let doublePanelWidth = innerWidth - state.buttonBarWidth; if (doublePanelWidth < editorMinWidth) { + if (state.showSideBar) { + dispatch('toggleSideBar', false); + return; + } + if (state.showExplorer) { + dispatch('toggleExplorer', false); + return; + } doublePanelWidth = editorMinWidth; } const splitPanel = state.showEditor && state.showSidePreview; @@ -109,10 +104,6 @@ export default { dispatch('toggleSidePreview', false); return; } - if (state.showSideBar && bodyWidth < editorMinWidth + sideBarWidth) { - dispatch('toggleSideBar', false); - return; - } let fontSize = 18; let textWidth = 990; @@ -130,32 +121,22 @@ export default { fontSize *= state.fontSizeFactor; const panelWidth = doublePanelWidth / 2; - let inner3X = panelWidth; - if (!splitPanel) { - inner3X = state.showEditor - ? doublePanelWidth - : -buttonBarWidth; - } - const inner3Width = splitPanel - ? panelWidth + buttonBarWidth - : doublePanelWidth + buttonBarWidth; - - const previewWidth = splitPanel - ? panelWidth - : bodyWidth; + const previewWidth = splitPanel ? + panelWidth : + innerWidth; let previewPadding = (previewWidth - textWidth) / 2; if (previewPadding < minPadding) { previewPadding = minPadding; } - const editorWidth = splitPanel - ? panelWidth - : doublePanelWidth; + const editorWidth = splitPanel ? + panelWidth : + doublePanelWidth; let editorPadding = (editorWidth - textWidth) / 2; if (editorPadding < minPadding) { editorPadding = minPadding; } - let titleMaxWidth = bodyWidth - navigationBarSpaceWidth; + let titleMaxWidth = innerWidth - navigationBarSpaceWidth; if (state.showEditor) { titleMaxWidth -= navigationBarLeftWidth; } @@ -163,14 +144,8 @@ export default { titleMaxWidth = Math.max(titleMaxWidth, minTitleMaxWidth); commit('setFontSize', fontSize); - commit('setInner1Y', inner1Y); - commit('setInner1Height', inner1Height); - commit('setInner2Height', inner2Height); - commit('setInner3X', inner3X); - commit('setInner3Width', inner3Width); - commit('setNavigationBarY', navigationBarY); - commit('setSideBarX', sideBarX); - commit('setStatusBarY', statusBarY); + commit('setInnerWidth', innerWidth); + commit('setInnerHeight', innerHeight); commit('setPreviewWidth', previewWidth); commit('setPreviewPadding', previewPadding); commit('setEditorWidth', editorWidth);