diff --git a/src/main/config.js b/src/main/config.js index e310a51f..a71ecd33 100644 --- a/src/main/config.js +++ b/src/main/config.js @@ -12,7 +12,8 @@ export const editorWinOptions = { useContentSize: true, show: true, frame: false, - titleBarStyle: 'hiddenInset' + titleBarStyle: 'hiddenInset', + zoomFactor: 1.0 } export const defaultPreferenceWinOptions = { @@ -31,7 +32,8 @@ export const defaultPreferenceWinOptions = { show: false, frame: false, thickFrame: !isOsx, - titleBarStyle: 'hiddenInset' + titleBarStyle: 'hiddenInset', + zoomFactor: 1.0 } export const PANDOC_EXTENSIONS = [ diff --git a/src/main/index.js b/src/main/index.js index a23a6c91..5c3aa695 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,6 +1,6 @@ import './globalSetting' import path from 'path' -import { app } from 'electron' +import { app, dialog } from 'electron' import cli from './cli' import setupExceptionHandler, { initExceptionLogger } from './exceptionHandler' import log from 'electron-log' @@ -14,7 +14,7 @@ const initializeLogger = appEnvironment => { log.transports.rendererConsole = null log.transports.file.file = path.join(appEnvironment.paths.logPath, 'main.log') log.transports.file.level = getLogLevel() - log.transports.file.sync = false + log.transports.file.sync = true log.transports.file.init() initExceptionLogger() } @@ -48,7 +48,30 @@ if (!process.mas && process.env.NODE_ENV !== 'development') { // Mark Text environment is configured successfully. You can now access paths, use the logger etc. // Create other instances that need access to the modules from above. -const accessor = new Accessor(appEnvironment) +let accessor = null +try { + accessor = new Accessor(appEnvironment) +} catch (err) { + // Catch errors that may come from invalid configuration files like settings. + const msgHint = err.message.includes('Config schema violation') + ? 'This seems to be an issue with your configuration file(s). ' : '' + + log.error(`Loading Mark Text failed during initialization! ${msgHint}`) + log.error(err) + + const EXIT_ON_ERROR = !!process.env.MARKTEXT_EXIT_ON_ERROR + const SHOW_ERROR_DIALOG = !process.env.MARKTEXT_ERROR_INTERACTION + if (!EXIT_ON_ERROR && SHOW_ERROR_DIALOG) { + dialog.showErrorBox( + 'There was an error during loading', + `${msgHint}${err.message}\n\n${err.stack}` + ) + } + process.exit(1) +} + +// Use synchronous only to report errors in early stage of startup. +log.transports.file.sync = false // ----------------------------------------------- // Be careful when changing code before this line! diff --git a/src/main/menu/actions/window.js b/src/main/menu/actions/window.js index 1dbf6531..4874f605 100644 --- a/src/main/menu/actions/window.js +++ b/src/main/menu/actions/window.js @@ -5,3 +5,17 @@ export const toggleAlwaysOnTop = win => { ipcMain.emit('window-toggle-always-on-top', win) } } + +export const zoomIn = win => { + const { webContents } = win + const zoom = webContents.getZoomFactor() + // WORKAROUND: Electron#16018 + webContents.send('mt::window-zoom', Math.min(2.0, zoom + 0.125)) +} + +export const zoomOut = win => { + const { webContents } = win + const zoom = webContents.getZoomFactor() + // WORKAROUND: Electron#16018 + webContents.send('mt::window-zoom', Math.max(1.0, zoom - 0.125)) +} diff --git a/src/main/menu/templates/window.js b/src/main/menu/templates/window.js index eecf0740..93497b45 100755 --- a/src/main/menu/templates/window.js +++ b/src/main/menu/templates/window.js @@ -1,4 +1,4 @@ -import { toggleAlwaysOnTop } from '../actions/window' +import { toggleAlwaysOnTop, zoomIn, zoomOut } from '../actions/window' import { isOsx } from '../../config' export default function (keybindings) { @@ -18,6 +18,18 @@ export default function (keybindings) { } }, { type: 'separator' + }, { + label: 'Zoom In', + click (menuItem, browserWindow) { + zoomIn(browserWindow) + } + }, { + label: 'Zoom Out', + click (menuItem, browserWindow) { + zoomOut(browserWindow) + } + }, { + type: 'separator' }, { label: 'Toggle Full Screen', accelerator: keybindings.getAccelerator('viewToggleFullScreen'), diff --git a/src/main/preferences/index.js b/src/main/preferences/index.js index 7b08b6a6..df7ab1b9 100644 --- a/src/main/preferences/index.js +++ b/src/main/preferences/index.js @@ -27,6 +27,9 @@ class Preference extends EventEmitter { /** * @param {AppPaths} userDataPath The path instance. + * + * NOTE: This throws an exception when validation fails. + * */ constructor (paths) { super() diff --git a/src/main/preferences/schema.json b/src/main/preferences/schema.json index 7419daf3..31bf5ecf 100644 --- a/src/main/preferences/schema.json +++ b/src/main/preferences/schema.json @@ -4,7 +4,7 @@ "type": "boolean" }, "autoSaveDelay": { - "description": "General--How long do you want to save your document(ms)?", + "description": "General--The time in ms after a change that the file is saved.", "type": "number", "minimum": 1000 }, @@ -23,6 +23,11 @@ "description": "General--Open folder via menu in a new window.", "type": "boolean" }, + "hideScrollbar": { + "description": "General--Whether to hide scrollbars.", + "type": "boolean", + "default": false + }, "aidou": { "description": "General--Enable aidou", "type": "boolean" @@ -76,6 +81,11 @@ "minimum": 1.2, "default": 1.6 }, + "editorLineWidth": { + "description": "Editor--Defines the maximum editor area width. An empty string or suffixes of ch (characters), px (pixels) or % (percentage) are allowed.", + "type": "string", + "pattern": "^(?:$|[0-9]+(?:ch|px|%)$)" + }, "codeFontSize": { "description": "Editor--Font size in code Block, the range is 12 ~ 18", "type": "number", @@ -92,6 +102,7 @@ "monospace" ] }, + "autoPairBracket": { "description": "Editor--Automatically brackets when editing", "type": "boolean" diff --git a/src/main/windows/base.js b/src/main/windows/base.js index 52224d1e..377c36b1 100644 --- a/src/main/windows/base.js +++ b/src/main/windows/base.js @@ -72,7 +72,13 @@ class BaseWindow extends EventEmitter { // NOTE: Only send absolutely necessary values. Full settings are delay loaded. const { type } = this const { debug, paths } = env - const { codeFontFamily, codeFontSize, theme, titleBarStyle } = userPreference.getAll() + const { + codeFontFamily, + codeFontSize, + hideScrollbar, + theme, + titleBarStyle + } = userPreference.getAll() const baseUrl = process.env.NODE_ENV === 'development' ? `http://localhost:9091` @@ -87,6 +93,7 @@ class BaseWindow extends EventEmitter { // Settings url.searchParams.set('cff', codeFontFamily) url.searchParams.set('cfs', codeFontSize) + url.searchParams.set('hsb', hideScrollbar ? '1' : '0') url.searchParams.set('theme', theme) url.searchParams.set('tbs', titleBarStyle) diff --git a/src/main/windows/setting.js b/src/main/windows/setting.js index 2c0763b3..6d6a4b5a 100644 --- a/src/main/windows/setting.js +++ b/src/main/windows/setting.js @@ -1,5 +1,6 @@ import path from 'path' import { BrowserWindow, ipcMain } from 'electron' +import electronLocalshortcut from '@hfelix/electron-localshortcut' import BaseWindow, { WindowLifecycle, WindowType } from './base' import { centerWindowOptions } from './utils' import { TITLE_BAR_HEIGHT, defaultPreferenceWinOptions, isLinux, isOsx } from '../config' @@ -20,7 +21,7 @@ class SettingWindow extends BaseWindow { * @param {*} [options] BrowserWindow options. */ createWindow (options = {}) { - const { menu: appMenu, env, preferences } = this._accessor + const { menu: appMenu, env, keybindings, preferences } = this._accessor const winOptions = Object.assign({}, defaultPreferenceWinOptions, options) centerWindowOptions(winOptions) if (isLinux) { @@ -78,6 +79,13 @@ class SettingWindow extends BaseWindow { win.loadURL(this._buildUrlString(this.id, env, preferences)) win.setSheetOffset(TITLE_BAR_HEIGHT) + electronLocalshortcut.register( + win, + keybindings.getAccelerator('viewDevToggleDeveloperTools'), + () => { + win.webContents.toggleDevTools() + } + ) return win } } diff --git a/src/muya/lib/index.js b/src/muya/lib/index.js index d6e5b141..bba79e73 100644 --- a/src/muya/lib/index.js +++ b/src/muya/lib/index.js @@ -311,6 +311,7 @@ class Muya { if (needRender) { this.contentState.render() } + // Set quick insert hint visibility const hideQuickInsertHint = options['hideQuickInsertHint'] if (typeof hideQuickInsertHint !== 'undefined') { @@ -321,6 +322,7 @@ class Muya { this.container.classList.add('ag-show-quick-insert-hint') } } + if (options.bulletListMarker) { this.contentState.turndownConfig.bulletListMarker = options.bulletListMarker } diff --git a/src/muya/themes/default.css b/src/muya/themes/default.css index 1b7b66b3..5422a102 100644 --- a/src/muya/themes/default.css +++ b/src/muya/themes/default.css @@ -126,6 +126,7 @@ kbd { #ag-editor-id { max-width: var(--editorAreaWidth); + min-width: 400px; min-height: 100%; margin: 0 auto; padding: 20px 50px 100px 50px; diff --git a/src/renderer/bootstrap.js b/src/renderer/bootstrap.js index 85eb099f..6ee5f9f4 100644 --- a/src/renderer/bootstrap.js +++ b/src/renderer/bootstrap.js @@ -21,6 +21,7 @@ const parseUrlArgs = () => { const codeFontFamily = params.get('cff') const codeFontSize = params.get('cfs') const debug = params.get('debug') === '1' + const hideScrollbar = params.get('hsb') === '1' const theme = params.get('theme') const titleBarStyle = params.get('tbs') const userDataPath = params.get('udp') @@ -34,6 +35,7 @@ const parseUrlArgs = () => { initialState: { codeFontFamily, codeFontSize, + hideScrollbar, theme, titleBarStyle } diff --git a/src/renderer/components/editorWithTabs/editor.vue b/src/renderer/components/editorWithTabs/editor.vue index 9dc5a4c7..fc98188c 100644 --- a/src/renderer/components/editorWithTabs/editor.vue +++ b/src/renderer/components/editorWithTabs/editor.vue @@ -9,6 +9,7 @@
state.preferences.fontSize, 'codeFontSize': state => state.preferences.codeFontSize, 'codeFontFamily': state => state.preferences.codeFontFamily, - 'lightColor': state => state.preferences.lightColor, - 'darkColor': state => state.preferences.darkColor, 'editorFontFamily': state => state.preferences.editorFontFamily, 'hideQuickInsertHint': state => state.preferences.hideQuickInsertHint, + 'editorLineWidth': state => state.preferences.editorLineWidth, 'imageInsertAction': state => state.preferences.imageInsertAction, 'imageFolderPath': state => state.preferences.imageFolderPath, 'theme': state => state.preferences.theme, + 'hideScrollbar': state => state.preferences.hideScrollbar, 'currentFile': state => state.editor.currentFile, @@ -147,7 +148,17 @@ 'typewriter': state => state.preferences.typewriter, 'focus': state => state.preferences.focus, 'sourceCode': state => state.preferences.sourceCode - }) + }), + + getEditorLineWidth () { + const { editorLineWidth } = this + if (!editorLineWidth || !/^[0-9]+(?:ch|px|%)$/.test(editorLineWidth)) { + return {} + } + + // Overwrite the theme value and add 100px for padding. + return { '--editorAreaWidth': `calc(100px + ${editorLineWidth})` } + } }, data () { this.defaultFontFamily = DEFAULT_EDITOR_FONT_FAMILY @@ -228,6 +239,11 @@ editor.setOptions({ hideQuickInsertHint: value }) } }, + editorLineWidth: function (value, oldValue) { + if (value !== oldValue) { + // TODO: Ask vue to reload 'getEditorLineWidth' + } + }, autoPairBracket: function (value, oldValue) { const { editor } = this if (value !== oldValue && editor) { @@ -262,7 +278,8 @@ if (value !== oldValue) { addCommonStyle({ codeFontSize: value, - codeFontFamily: this.codeFontFamily + codeFontFamily: this.codeFontFamily, + hideScrollbar: this.hideScrollbar }) } }, @@ -270,7 +287,17 @@ if (value !== oldValue) { addCommonStyle({ codeFontSize: this.codeFontSize, - codeFontFamily: value + codeFontFamily: value, + hideScrollbar: this.hideScrollbar + }) + } + }, + hideScrollbar: function (value, oldValue) { + if (value !== oldValue) { + addCommonStyle({ + codeFontSize: this.codeFontSize, + codeFontFamily: this.codeFontFamily, + hideScrollbar: value }) } }, diff --git a/src/renderer/config.js b/src/renderer/config.js index f310c6e0..df02a7e7 100644 --- a/src/renderer/config.js +++ b/src/renderer/config.js @@ -10,6 +10,7 @@ export const DEFAULT_CODE_FONT_FAMILY = '"DejaVu Sans Mono", "Source Code Pro", export const DEFAULT_STYLE = { codeFontFamily: DEFAULT_CODE_FONT_FAMILY, codeFontSize: '14px', + hideScrollbar: false, theme: 'light' } diff --git a/src/renderer/prefComponents/common/textBox/index.vue b/src/renderer/prefComponents/common/textBox/index.vue new file mode 100644 index 00000000..b19d7ddf --- /dev/null +++ b/src/renderer/prefComponents/common/textBox/index.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/renderer/prefComponents/editor/index.vue b/src/renderer/prefComponents/editor/index.vue index 4d37455e..b9874c37 100644 --- a/src/renderer/prefComponents/editor/index.vue +++ b/src/renderer/prefComponents/editor/index.vue @@ -2,7 +2,7 @@

Editor

@@ -42,20 +42,20 @@ > + +
@@ -84,6 +92,7 @@ import Range from '../common/range' import CurSelect from '../common/select' import Bool from '../common/bool' import Separator from '../common/separator' +import TextBox from '../common/textBox' import { editorFontFamilyOptions, endOfLineOptions, @@ -96,7 +105,8 @@ export default { Range, CurSelect, Bool, - Separator + Separator, + TextBox }, data () { this.editorFontFamilyOptions = editorFontFamilyOptions @@ -117,7 +127,8 @@ export default { textDirection: state => state.preferences.textDirection, codeFontSize: state => state.preferences.codeFontSize, codeFontFamily: state => state.preferences.codeFontFamily, - hideQuickInsertHint: state => state.preferences.hideQuickInsertHint + hideQuickInsertHint: state => state.preferences.hideQuickInsertHint, + editorLineWidth: state => state.preferences.editorLineWidth }) }, methods: { diff --git a/src/renderer/prefComponents/general/index.vue b/src/renderer/prefComponents/general/index.vue index 61739799..9b02798e 100644 --- a/src/renderer/prefComponents/general/index.vue +++ b/src/renderer/prefComponents/general/index.vue @@ -2,12 +2,12 @@

General

+ +
-
The action after Mark Text startup, open the last edited content, open the specified folder or blank page
+
The action after Mark Text startup: open the last edited content, open the specified folder or blank page.
Open the last window state Open a default directory Select Folder Open blank page
state.preferences.autoSaveDelay, titleBarStyle: state => state.preferences.titleBarStyle, openFilesInNewWindow: state => state.preferences.openFilesInNewWindow, + openFolderInNewWindow: state => state.preferences.openFolderInNewWindow, + hideScrollbar: state => state.preferences.hideScrollbar, aidou: state => state.preferences.aidou, fileSortBy: state => state.preferences.fileSortBy, startUpAction: state => state.preferences.startUpAction, diff --git a/src/renderer/prefComponents/image/index.vue b/src/renderer/prefComponents/image/index.vue index 9c8b3904..322dc7a8 100644 --- a/src/renderer/prefComponents/image/index.vue +++ b/src/renderer/prefComponents/image/index.vue @@ -3,7 +3,7 @@

Image

The default behavior after insert image from local folder. - +
diff --git a/src/renderer/prefComponents/markdown/index.vue b/src/renderer/prefComponents/markdown/index.vue index ab070256..101d185a 100644 --- a/src/renderer/prefComponents/markdown/index.vue +++ b/src/renderer/prefComponents/markdown/index.vue @@ -2,20 +2,20 @@

markdown

{ + webFrame.setZoomFactor(zoomFactor) + }) } } diff --git a/src/renderer/store/preferences.js b/src/renderer/store/preferences.js index a2bb4ded..0f60ec55 100644 --- a/src/renderer/store/preferences.js +++ b/src/renderer/store/preferences.js @@ -7,6 +7,7 @@ const state = { titleBarStyle: 'custom', openFilesInNewWindow: false, openFolderInNewWindow: false, + hideScrollbar: false, aidou: true, fileSortBy: 'created', startUpAction: 'lastState', @@ -18,6 +19,8 @@ const state = { lineHeight: 1.6, codeFontSize: 14, codeFontFamily: 'DejaVu Sans Mono', + editorLineWidth: "", + autoPairBracket: true, autoPairMarkdownSyntax: true, autoPairQuote: true, diff --git a/src/renderer/util/theme.js b/src/renderer/util/theme.js index 5a4b372e..5949fbac 100644 --- a/src/renderer/util/theme.js +++ b/src/renderer/util/theme.js @@ -103,8 +103,8 @@ export const addThemeStyle = theme => { } } -export const addCommonStyle = style => { - const { codeFontFamily, codeFontSize } = style +export const addCommonStyle = options => { + const { codeFontFamily, codeFontSize, hideScrollbar } = options let sheet = document.querySelector(`#${COMMON_STYLE_ID}`) if (!sheet) { sheet = document.createElement('style') @@ -112,7 +112,12 @@ export const addCommonStyle = style => { document.head.appendChild(sheet) } - sheet.innerHTML = ` + let scrollbarStyle = '' + if (hideScrollbar) { + scrollbarStyle = '::-webkit-scrollbar {display: none;}' + } + + sheet.innerHTML = `${scrollbarStyle} span code, td code, th code, @@ -146,8 +151,8 @@ export const addElementStyle = () => { } // Append common sheet and theme at the end of head - order is important. -export const addStyles = style => { - const { theme } = style +export const addStyles = options => { + const { theme } = options addThemeStyle(theme) - addCommonStyle(style) + addCommonStyle(options) } diff --git a/static/preference.json b/static/preference.json index 2172b530..fc419576 100644 --- a/static/preference.json +++ b/static/preference.json @@ -4,6 +4,7 @@ "titleBarStyle": "custom", "openFilesInNewWindow": false, "openFolderInNewWindow": false, + "hideScrollbar": false, "aidou": true, "fileSortBy": "created", "startUpAction": "lastState", @@ -15,6 +16,8 @@ "lineHeight": 1.6, "codeFontSize": 14, "codeFontFamily": "DejaVu Sans Mono", + "editorLineWidth": "", + "autoPairBracket": true, "autoPairMarkdownSyntax": true, "autoPairQuote": true,