Added backup menu. Added print menu. Fixed splash screen.

This commit is contained in:
benweet 2017-10-09 08:11:18 +01:00
parent 3e9b75d3e8
commit e15b9fae16
26 changed files with 317 additions and 93 deletions

View File

@ -48,7 +48,7 @@ export default {
newItem(isFolder) {
let parentId = this.$store.getters['explorer/selectedNodeFolder'].item.id;
if (parentId === 'trash') {
parentId = undefined;
parentId = null;
}
this.$store.dispatch('explorer/openNode', parentId);
this.$store.commit('explorer/setNewItem', {
@ -92,6 +92,7 @@ export default {
id: selectedNode.item.id,
parentId: 'trash',
});
this.$store.commit('file/setCurrentId', this.$store.getters['data/lastOpenedIds'][1]);
}
}
});

View File

@ -58,7 +58,7 @@ export default {
return this.$store.state.explorer.newChildNode.item.name;
},
set(value) {
this.$store.commit('explorer/setNewItemName', value && value.slice(0, 250));
this.$store.commit('explorer/setNewItemName', value);
},
},
editingNodeName: {
@ -91,28 +91,18 @@ export default {
submitNewChild(cancel) {
const newChildNode = this.$store.state.explorer.newChildNode;
if (!cancel && !newChildNode.isNil && newChildNode.item.name) {
const id = utils.uid();
if (newChildNode.isFolder) {
const id = utils.uid();
this.$store.commit('folder/setItem', {
...newChildNode.item,
id,
name: utils.sanitizeName(newChildNode.item.name),
});
this.select(id);
} else {
// Add empty line at the end if needed
const ensureFinalNewLine = text => `${text}\n`.replace(/\n\n$/, '\n');
const text = ensureFinalNewLine(this.$store.getters['data/computedSettings'].newFileContent);
const properties = ensureFinalNewLine(this.$store.getters['data/computedSettings'].newFileProperties);
this.$store.commit('content/setItem', {
id: `${id}/content`,
text,
properties,
});
this.$store.commit('file/setItem', {
...newChildNode.item,
id,
});
this.$store.dispatch('createFile', newChildNode.item)
.then(file => this.select(file.id));
}
this.select(id);
}
this.$store.commit('explorer/setNewItem', null);
},
@ -123,7 +113,7 @@ export default {
if (!cancel && id && value) {
this.$store.commit(editingNode.isFolder ? 'folder/patchItem' : 'file/patchItem', {
id,
name: value.slice(0, 250),
name: utils.sanitizeName(value),
});
}
this.$store.commit('explorer/setEditingId', null);

View File

@ -80,6 +80,7 @@ import editorSvc from '../services/editorSvc';
import syncSvc from '../services/syncSvc';
import publishSvc from '../services/publishSvc';
import animationSvc from '../services/animationSvc';
import utils from '../services/utils';
export default {
data: () => ({
@ -171,7 +172,7 @@ export default {
} else {
const title = this.title.trim();
if (title) {
this.$store.dispatch('file/patchCurrent', { name: title.slice(0, 250) });
this.$store.dispatch('file/patchCurrent', { name: utils.sanitizeName(title) });
} else {
this.title = this.$store.getters['file/current'].name;
}
@ -342,9 +343,7 @@ export default {
}
.navigation-bar__title--input,
.navigation-bar__inner--edit-buttons,
.navigation-bar__inner--button,
.navigation-bar__spinner {
.navigation-bar__inner--edit-buttons {
display: none;
.navigation-bar--editor & {
@ -355,6 +354,7 @@ export default {
.navigation-bar__button {
display: none;
.navigation-bar__inner--button &,
.navigation-bar--editor & {
display: inline-block;
}
@ -374,13 +374,13 @@ $b: $d/10;
$t: 3000ms;
.navigation-bar__spinner {
width: 22px;
width: 24px;
margin: 7px 0 0 8px;
color: #b2b2b2;
.icon {
width: 22px;
height: 22px;
width: 24px;
height: 24px;
color: transparentize($error-color, 0.5);
}
}

View File

@ -1,6 +1,6 @@
<template>
<div class="splash-screen">
<div class="splash-screen__inner background-logo"></div>
<div class="splash-screen__inner logo-background"></div>
</div>
</template>

View File

@ -81,7 +81,8 @@ textarea {
&:active,
&:focus,
&:hover {
&:hover,
.hidden-file:focus + & {
color: #333;
background-color: rgba(0, 0, 0, 0.067);
outline: 0;
@ -193,3 +194,41 @@ textarea {
background: no-repeat center url('../assets/logo.svg');
background-size: contain;
}
@media print {
body {
background-color: transparent !important;
color: #000 !important; // Black prints faster
overflow: visible !important;
position: absolute !important;
div {
display: none !important;
}
a {
text-decoration: underline;
}
}
body > .app,
body > .app > .layout,
body > .app > .layout > .layout__panel,
body > .app > .layout > .layout__panel > .layout__panel,
body > .app > .layout > .layout__panel > .layout__panel > .layout__panel,
body > .app > .layout > .layout__panel > .layout__panel > .layout__panel > .layout__panel--preview,
body > .app > .layout > .layout__panel > .layout__panel > .layout__panel > .layout__panel--preview div {
background-color: transparent !important;
display: block !important;
height: auto !important;
overflow: visible !important;
position: static !important;
width: auto !important;
font-size: 16px;
}
.preview__inner-2 {
padding: 0 50px !important;
}
// scss-lint:enable ImportantRule
}

View File

@ -37,10 +37,19 @@
Markdown cheat sheet
</menu-entry>
<hr>
<menu-entry @click.native="importFile">
<icon-hard-disk slot="icon"></icon-hard-disk>
Import from disk
<menu-entry @click.native="print">
<icon-printer slot="icon"></icon-printer>
Print
</menu-entry>
<input class="hidden-file" id="import-disk-file-input" type="file" @change="onImportFile">
<label class="menu-entry button flex flex--row flex--align-center" for="import-disk-file-input">
<div class="menu-entry__icon flex flex--column flex--center">
<icon-hard-disk></icon-hard-disk>
</div>
<div class="flex flex--column">
Import from disk
</div>
</label>
<menu-entry @click.native="setPanel('export')">
<icon-hard-disk slot="icon"></icon-hard-disk>
Export to disk
@ -58,6 +67,7 @@ import MenuEntry from './MenuEntry';
import UserImage from '../UserImage';
import googleHelper from '../../services/providers/helpers/googleHelper';
import syncSvc from '../../services/syncSvc';
import providerUtils from '../../services/providers/providerUtils';
export default {
components: {
@ -80,13 +90,32 @@ export default {
() => {}, // Cancel
);
},
importFile() {
return this.$store.dispatch('modal/notImplemented');
onImportFile(evt) {
const file = evt.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target.result;
if (content.match(/\uFFFD/)) {
this.$store.dispatch('notification/error', 'File is not readable.');
} else {
this.$store.dispatch('createFile', {
...providerUtils.parseContent(content),
name: file.name,
})
.then(item => this.$store.commit('file/setCurrentId', item.id));
}
};
reader.readAsText(file);
}
},
fileProperties() {
return this.$store.dispatch('modal/open', 'fileProperties')
.catch(() => {}); // Cancel
},
print() {
print();
},
},
};
</script>

View File

@ -37,4 +37,9 @@
border-radius: $border-radius-base;
overflow: hidden;
}
.hidden-file {
position: fixed;
top: -999px;
}
</style>

View File

@ -16,6 +16,20 @@
<span>Sign out and clean local data.</span>
</menu-entry>
<hr>
<input class="hidden-file" id="import-backup-file-input" type="file" @change="onImportBackup">
<label class="menu-entry button flex flex--row flex--align-center" for="import-backup-file-input">
<div class="menu-entry__icon flex flex--column flex--center">
<icon-hard-disk></icon-hard-disk>
</div>
<div class="flex flex--column">
Import backup
</div>
</label>
<menu-entry href="#exportBackup=true" target="_blank">
<icon-hard-disk slot="icon"></icon-hard-disk>
Export backup
</menu-entry>
<hr>
<menu-entry @click.native="about">
<icon-help-circle slot="icon"></icon-help-circle>
<span>About StackEdit</span>
@ -34,12 +48,29 @@
<script>
import MenuEntry from './MenuEntry';
import localDbSvc from '../../services/localDbSvc';
import backupSvc from '../../services/backupSvc';
export default {
components: {
MenuEntry,
},
methods: {
onImportBackup(evt) {
const file = evt.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result;
if (text.match(/\uFFFD/)) {
this.$store.dispatch('notification/error', 'File is not readable.');
} else {
backupSvc.importBackup(text);
}
};
const blob = file.slice(0, 10000000);
reader.readAsText(blob);
}
},
settings() {
return this.$store.dispatch('modal/open', 'settings')
.then(

View File

@ -35,6 +35,7 @@ import yaml from 'js-yaml';
import { mapGetters } from 'vuex';
import Tab from './Tab';
import CodeEditor from '../CodeEditor';
import utils from '../../services/utils';
import defaultProperties from '../../data/defaultFileProperties.yml';
const emptyProperties = '# Add custom properties for the current file here to override the default properties.\n';
@ -79,7 +80,7 @@ export default {
if (!this.error) {
this.$store.commit('content/patchItem', {
id: this.contentId,
properties: this.strippedCustomProperties,
properties: utils.sanitizeText(this.strippedCustomProperties),
});
this.config.resolve();
}

View File

@ -140,7 +140,7 @@ export default {
submitEdit(cancel) {
const template = this.templates[this.selectedId];
if (!cancel && this.editingName) {
template.name = this.editingName.slice(0, 250);
template.name = utils.sanitizeName(this.editingName);
} else {
this.editingName = template.name;
}

5
src/icons/Printer.vue Normal file
View File

@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
<path d="M18,3H6V7H18M19,12C18.45,12 18,11.55 18,11C18,10.45 18.45,10 19,10C19.55,10 20,10.45 20,11C20,11.55 19.55,12 19,12M16,19H8V14H16M19,8H5C3.34,8 2,9.34 2,11V17H6V21H18V17H22V11C22,9.34 20.66,8 19,8Z" />
</svg>
</template>

View File

@ -1,5 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
<path d="M4.037,6l3.5,-3.5l3.5,3.5l-2.5,0l0,12l2.5,0l-3.5,3.5l-3.5,-3.5l2.5,0l0,-12l-2.5,0Zm8.926,0l3.5,-3.5l3.5,3.5l-2.5,0l0,12l2.5,0l-3.5,3.5l-3.5,-3.5l2.5,0l0,-12l-2.5,0Z"/>
<path d="M9,18l3,0l-4,4l-4,-4l3,0l0,-3l2,0l0,3Zm8,0l3,0l-4,4l-4,-4l3,0l0,-3l2,0l0,3Zm0.055,-5l-10.11,0l0,-2l10.11,0l0,2Zm-8.055,-4l-2,0l0,-3l-3,0l4,-4l4,4l4,-4l4,4l-3,0l0,3l-2,0l0,-3l-6,0l0,3Z"/>
</svg>
</template>

View File

@ -42,6 +42,7 @@ import Alert from './Alert';
import SignalOff from './SignalOff';
import Folder from './Folder';
import ScrollSync from './ScrollSync';
import Printer from './Printer';
Vue.component('iconProvider', Provider);
Vue.component('iconFormatBold', FormatBold);
@ -86,3 +87,4 @@ Vue.component('iconAlert', Alert);
Vue.component('iconSignalOff', SignalOff);
Vue.component('iconFolder', Folder);
Vue.component('iconScrollSync', ScrollSync);
Vue.component('iconPrinter', Printer);

68
src/services/backupSvc.js Normal file
View File

@ -0,0 +1,68 @@
import store from '../store';
import utils from './utils';
export default {
importBackup(jsonValue) {
const nameMap = {};
const parentIdMap = {};
const textMap = {};
const propertiesMap = {};
const discussionsMap = {};
const commentsMap = {};
const folderIdMap = {
trash: 'trash',
};
// Parse JSON value
const parsedValue = JSON.parse(jsonValue);
Object.keys(parsedValue).forEach((id) => {
const value = parsedValue[id];
if (value) {
const v4Match = id.match(/^file\.([^.]+)\.([^.]+)$/);
if (v4Match) {
// StackEdit v4 format
const [, v4Id, type] = v4Match;
if (type === 'title') {
nameMap[v4Id] = value;
} else if (type === 'content') {
textMap[v4Id] = value;
}
} else if (value.type === 'folder') {
// StackEdit v5 folder
const folderId = utils.uid();
const name = utils.sanitizeName(value.name);
const parentId = `${value.parentId || ''}` || null;
store.commit('folder/setItem', {
id: folderId,
name,
parentId,
});
folderIdMap[id] = folderId;
} else if (value.type === 'file') {
// StackEdit v5 file
nameMap[id] = utils.sanitizeName(value.name);
parentIdMap[id] = `${value.parentId || ''}`;
} else if (value.type === 'content') {
// StackEdit v5 content
const [fileId] = id.split('/');
if (fileId) {
textMap[fileId] = value.text;
propertiesMap[fileId] = value.properties;
discussionsMap[fileId] = value.discussions;
commentsMap[fileId] = value.comments;
}
}
}
});
// Go through the maps
Object.keys(nameMap).forEach(externalId => store.dispatch('createFile', {
name: nameMap[externalId],
parentId: folderIdMap[parentIdMap[externalId]],
text: textMap[externalId],
properties: propertiesMap[externalId],
discussions: discussionsMap[externalId],
comments: commentsMap[externalId],
}));
},
};

View File

@ -110,9 +110,8 @@ export default {
clEditor.on('contentChanged', (text) => {
const oldContent = store.getters['content/current'];
const newContent = {
...oldContent,
discussions: utils.deepCopy(oldContent.discussions),
text,
...utils.deepCopy(oldContent),
text: utils.sanitizeText(text),
};
syncDiscussionMarkers(newContent, true);
if (!isChangePatch) {

View File

@ -1,5 +1,6 @@
import 'babel-polyfill';
import 'indexeddbshim/dist/indexeddbshim';
import FileSaver from 'file-saver';
import utils from './utils';
import store from '../store';
import welcomeFile from '../data/welcomeFile.md';
@ -8,6 +9,7 @@ const indexedDB = window.indexedDB;
const dbVersion = 1;
const dbVersionKey = `${utils.workspaceId}/localDbVersion`;
const dbStoreName = 'objects';
const exportBackup = utils.queryParams.exportBackup;
if (!indexedDB) {
throw new Error('Your browser is not supported. Please upgrade to the latest version.');
@ -219,7 +221,7 @@ const localDbSvc = {
// DB item is different from the corresponding store item
this.hashMap[dbItem.type][dbItem.id] = dbItem.hash;
// Update content only if it exists in the store
if (existingStoreItem || !contentTypes[dbItem.type]) {
if (existingStoreItem || !contentTypes[dbItem.type] || exportBackup) {
// Put item in the store
dbItem.tx = undefined;
store.commit(`${dbItem.type}/setItem`, dbItem);
@ -314,6 +316,16 @@ const ifNoId = cb => (obj) => {
// Load the DB on boot
localDbSvc.sync()
.then(() => {
if (exportBackup) {
const backup = JSON.stringify(store.getters.allItemMap);
const blob = new Blob([backup], {
type: 'text/plain;charset=utf-8',
});
FileSaver.saveAs(blob, 'StackEdit workspace.json');
return;
}
// Set the ready flag
store.commit('setReady');
// If app was last opened 7 days ago and synchronization is off
@ -333,18 +345,10 @@ localDbSvc.sync()
// If current file has no ID, get the most recent file
.then(ifNoId(() => store.getters['file/lastOpened']))
// If still no ID, create a new file
.then(ifNoId(() => {
const id = utils.uid();
store.commit('content/setItem', {
id: `${id}/content`,
text: welcomeFile,
});
store.commit('file/setItem', {
id,
name: 'Welcome file',
});
return store.state.file.itemMap[id];
}))
.then(ifNoId(() => store.dispatch('createFile', {
name: 'Welcome file',
text: welcomeFile,
})))
.then((currentFile) => {
// Fix current file ID
if (store.getters['file/current'].id !== currentFile.id) {

View File

@ -86,11 +86,7 @@ export default {
msgHandler = event => event.source === wnd && event.origin === utils.origin && clean()
.then(() => {
const data = {};
`${event.data}`.slice(1).split('&').forEach((param) => {
const [key, value] = param.split('=').map(decodeURIComponent);
data[key] = value;
});
const data = utils.parseQueryParams(`${event.data}`.slice(1));
if (data.error || data.state !== state) {
reject('Could not get required authorization.');
} else {

View File

@ -114,7 +114,7 @@ export default providerRegistry.register({
}
store.commit('file/setItem', {
id,
name: name.slice(0, 250),
name: utils.sanitizeName(name),
parentId: store.getters['file/current'].parentId,
});
store.commit('syncLocation/setItem', {

View File

@ -2,8 +2,7 @@ import store from '../../store';
import githubHelper from './helpers/githubHelper';
import providerUtils from './providerUtils';
import providerRegistry from './providerRegistry';
const defaultDescription = 'Untitled';
import utils from '../utils';
export default providerRegistry.register({
id: 'gist',
@ -23,7 +22,7 @@ export default providerRegistry.register({
},
uploadContent(token, content, syncLocation) {
const file = store.state.file.itemMap[syncLocation.fileId];
const description = (file && file.name) || defaultDescription;
const description = utils.sanitizeName(file && file.name);
return githubHelper.uploadGist(
token,
description,

View File

@ -4,8 +4,6 @@ import providerUtils from './providerUtils';
import providerRegistry from './providerRegistry';
import utils from '../utils';
const defaultFilename = 'Untitled';
export default providerRegistry.register({
id: 'googleDrive',
getToken(location) {
@ -25,7 +23,7 @@ export default providerRegistry.register({
},
uploadContent(token, content, syncLocation, ifNotTooLate) {
const file = store.state.file.itemMap[syncLocation.fileId];
const name = (file && file.name) || defaultFilename;
const name = utils.sanitizeName(file && file.name);
const parents = [];
if (syncLocation.driveParentId) {
parents.push(syncLocation.driveParentId);
@ -95,7 +93,7 @@ export default providerRegistry.register({
});
store.commit('file/setItem', {
id,
name: (file.name || defaultFilename).slice(0, 250),
name: utils.sanitizeName(file.name),
parentId: store.getters['file/current'].parentId,
});
store.commit('syncLocation/setItem', {

View File

@ -27,15 +27,26 @@ export default {
return result;
},
parseContent(serializedContent, syncLocation) {
const result = utils.deepCopy(store.state.content.itemMap[`${syncLocation.fileId}/content`]) || emptyContent();
result.text = serializedContent;
const result = utils.deepCopy(store.state.content.itemMap[`${syncLocation.fileId}/content`])
|| emptyContent();
result.text = utils.sanitizeText(serializedContent);
result.history = [];
const extractedData = dataExtractor.exec(serializedContent);
if (extractedData) {
try {
const serializedData = extractedData[1].replace(/\s/g, '');
Object.assign(result, JSON.parse(utils.decodeBase64(serializedData)));
result.text = serializedContent.slice(0, extractedData.index);
const parsedData = JSON.parse(utils.decodeBase64(serializedData));
result.text = utils.sanitizeText(serializedContent.slice(0, extractedData.index));
if (parsedData.properties) {
result.properties = utils.sanitizeText(parsedData.properties);
}
if (parsedData.discussions) {
result.discussions = parsedData.discussions;
}
if (parsedData.comments) {
result.comments = parsedData.comments;
}
result.history = parsedData.history || [];
} catch (e) {
// Ignore
}

View File

@ -197,10 +197,12 @@ function syncFile(fileId, needSyncRestartParam = false) {
}
// Update or set content in store
delete mergedContent.history;
store.commit('content/setItem', {
id: `${fileId}/content`,
...mergedContent,
text: utils.sanitizeText(mergedContent.text),
properties: utils.sanitizeText(mergedContent.properties),
discussions: mergedContent.discussions,
comments: mergedContent.comments,
hash: 0,
});

View File

@ -33,12 +33,23 @@ const setLastFocus = () => {
setLastFocus();
window.addEventListener('focus', setLastFocus);
// For parseQueryParams()
const parseQueryParams = (params) => {
const result = {};
params.split('&').forEach((param) => {
const [key, value] = param.split('=').map(decodeURIComponent);
result[key] = value;
});
return result;
};
// For addQueryParams()
const urlParser = window.document.createElement('a');
export default {
workspaceId,
origin,
queryParams: parseQueryParams(location.hash.slice(1)),
oauth2RedirectUri: `${origin}/oauth2/callback`,
lastOpened,
cleanTrashAfter: 7 * 24 * 60 * 60 * 1000, // 7 days
@ -52,6 +63,15 @@ export default {
'publishLocation',
'data',
],
textMaxLength: 150000,
sanitizeText(text) {
const result = `${text || ''}`.slice(0, this.textMaxLength);
// last char must be a `\n`.
return `${result}\n`.replace(/\n\n$/, '\n');
},
sanitizeName(name) {
return `${name || ''}`.slice(0, 250) || 'Untitled';
},
deepCopy(obj) {
return obj == null ? obj : JSON.parse(JSON.stringify(obj));
},
@ -122,6 +142,7 @@ export default {
isUserActive() {
return lastActivity > Date.now() - inactiveAfter && this.isWindowFocused();
},
parseQueryParams,
addQueryParams(url = '', params = {}) {
const keys = Object.keys(params).filter(key => params[key] != null);
if (!keys.length) {

View File

@ -46,16 +46,33 @@ const store = new Vuex.Store({
},
},
actions: {
setOffline: ({ state, commit }, value) => {
setOffline: ({ state, commit, dispatch }, value) => {
if (state.offline !== value) {
commit('setOffline', value);
if (state.offline) {
return Promise.reject('You are offline.');
}
store.dispatch('notification/info', 'You are back online!');
dispatch('notification/info', 'You are back online!');
}
return Promise.resolve();
},
createFile({ state, getters, commit }, desc) {
const id = utils.uid();
commit('content/setItem', {
id: `${id}/content`,
text: utils.sanitizeText(desc.text || getters['data/computedSettings'].newFileContent),
properties: utils.sanitizeText(
desc.properties || getters['data/computedSettings'].newFileProperties),
discussions: desc.discussions || {},
comments: desc.comments || {},
});
commit('file/setItem', {
id,
name: utils.sanitizeName(desc.name),
parentId: desc.parentId || null,
});
return Promise.resolve(state.file.itemMap[id]);
},
deleteFile({ getters, commit }, fileId) {
commit('file/deleteItem', fileId);
commit('content/deleteItem', `${fileId}/content`);

View File

@ -131,20 +131,27 @@ module.actions.setTemplates = ({ commit }, data) => {
// Last opened
module.getters.lastOpened = getter('lastOpened');
const getLastOpenedIds = (lastOpened, rootState) => Object.keys(lastOpened)
.filter(id => rootState.file.itemMap[id])
.sort((id1, id2) => lastOpened[id2] - lastOpened[id1])
.slice(0, 20);
module.getters.lastOpenedIds = (state, getters, rootState) =>
getLastOpenedIds(getters.lastOpened, rootState);
module.actions.setLastOpenedId = ({ getters, commit, rootState }, fileId) => {
module.getters.lastOpenedIds = (state, getters, rootState) => {
const lastOpened = getters.lastOpened;
return Object.keys(lastOpened)
.filter(id => rootState.file.itemMap[id])
.sort((id1, id2) => lastOpened[id2] - lastOpened[id1])
.slice(0, 20);
};
module.actions.setLastOpenedId = ({ getters, commit, dispatch, rootState }, fileId) => {
const lastOpened = { ...getters.lastOpened };
lastOpened[fileId] = Date.now();
const filteredLastOpened = {};
getLastOpenedIds(lastOpened, rootState)
.forEach((id) => {
filteredLastOpened[id] = lastOpened[id];
});
commit('setItem', itemTemplate('lastOpened', lastOpened));
dispatch('cleanLastOpenedId');
};
module.actions.cleanLastOpenedId = ({ getters, commit, rootState }) => {
const lastOpened = {};
const oldLastOpened = getters.lastOpened;
Object.keys(oldLastOpened).forEach((fileId) => {
if (rootState.file.itemMap[fileId]) {
lastOpened[fileId] = oldLastOpened[fileId];
}
});
commit('setItem', itemTemplate('lastOpened', lastOpened));
};

View File

@ -5,7 +5,7 @@ const editorTopPadding = 10;
const navigationBarEditButtonsWidth = 36 * 12; // 12 buttons
const navigationBarLeftButtonWidth = 38 + 4 + 15;
const navigationBarRightButtonWidth = 38 + 8;
const navigationBarSpinnerWidth = 22 + 8 + 5; // 5 for left margin
const navigationBarSpinnerWidth = 24 + 8 + 5; // 5 for left margin
const navigationBarLocationWidth = 20;
const navigationBarSyncPublishButtonsWidth = 36 + 10;
const navigationBarTitleMargin = 8;
@ -95,17 +95,16 @@ function computeStyles(state, localSettings, getters, styles = {
Math.floor((styles.editorWidth - styles.textWidth) / 2), minPadding);
styles.editorPadding = `${editorTopPadding}px ${editorSidePadding}px ${bottomPadding}px`;
styles.titleMaxWidth = styles.innerWidth;
styles.titleMaxWidth = styles.innerWidth -
navigationBarLeftButtonWidth -
navigationBarRightButtonWidth -
navigationBarSpinnerWidth;
if (styles.showEditor) {
const syncLocations = getters['syncLocation/current'];
const publishLocations = getters['publishLocation/current'];
styles.titleMaxWidth = styles.innerWidth -
navigationBarEditButtonsWidth -
navigationBarLeftButtonWidth -
navigationBarRightButtonWidth -
navigationBarSpinnerWidth -
(navigationBarLocationWidth * (syncLocations.length + publishLocations.length)) -
(navigationBarSyncPublishButtonsWidth * 2) -
styles.titleMaxWidth -= navigationBarEditButtonsWidth +
(navigationBarLocationWidth * (syncLocations.length + publishLocations.length)) +
(navigationBarSyncPublishButtonsWidth * 2) +
navigationBarTitleMargin;
if (styles.titleMaxWidth + navigationBarEditButtonsWidth < minTitleMaxWidth) {
styles.hideLocations = true;