mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Joplin desktop Dark Mode (#921)
* Added support for the dark mode on desktop * Add dark highlighting to the code tags * Update app/theme.js to be more clear and more easily support additional themes Update more files to conform to theming
This commit is contained in:
parent
19f5a144e5
commit
ee106105d8
@ -45,15 +45,21 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
const style = this.props.style;
|
||||
const theme = themeStyle(this.props.theme);
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
overflowY: 'scroll',
|
||||
height:style.height,
|
||||
});
|
||||
|
||||
const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 });
|
||||
|
||||
const stepBoxStyle = {
|
||||
border: "1px solid #ccc",
|
||||
padding: 15,
|
||||
paddingTop: 0,
|
||||
marginBottom: 15,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
};
|
||||
|
||||
let webClipperStatusComps = [];
|
||||
@ -68,7 +74,7 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
webClipperStatusComps.push(<button key="disable_button" onClick={this.disableClipperServer_click}>{_('Disable Web Clipper Service')}</button>)
|
||||
} else {
|
||||
webClipperStatusComps.push(<p key="text_4" style={theme.textStyle}>{_('The web clipper service is not enabled.')}</p>)
|
||||
webClipperStatusComps.push(<button key="enable_button" onClick={this.enableClipperServer_click}>{_('Enable Web Clipper Service')}</button>)
|
||||
webClipperStatusComps.push(<button key="enable_button" style={buttonStyle} onClick={this.enableClipperServer_click}>{_('Enable Web Clipper Service')}</button>)
|
||||
}
|
||||
|
||||
const apiTokenStyle = Object.assign({}, theme.textStyle, {
|
||||
@ -81,7 +87,7 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<Header style={headerStyle} />
|
||||
<div style={{overflowY:'scroll', height:style.height}}>
|
||||
<div style={containerStyle}>
|
||||
<div style={{padding: theme.margin}}>
|
||||
<p style={theme.textStyle}>{_('Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.')}</p>
|
||||
<p style={theme.textStyle}>{_('In order to use the web clipper, you need to do the following:')}</p>
|
||||
@ -106,7 +112,7 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
<div style={stepBoxStyle}>
|
||||
<p style={theme.h1Style}>{_('Advanced options')}</p>
|
||||
<p style={theme.textStyle}>{_('Authorisation token:')}</p>
|
||||
<p style={apiTokenStyle}>{this.props.apiToken} <a href="#" onClick={this.copyToken_click}>{_('Copy token')}</a></p>
|
||||
<p style={apiTokenStyle}>{this.props.apiToken} <a style={theme.urlStyle} href="#" onClick={this.copyToken_click}>{_('Copy token')}</a></p>
|
||||
<p style={theme.textStyle}>{_('This authorisation token is only needed to allow third-party applications to access Joplin.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -128,4 +134,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const ClipperConfigScreen = connect(mapStateToProps)(ClipperConfigScreenComponent);
|
||||
|
||||
module.exports = { ClipperConfigScreen };
|
||||
module.exports = { ClipperConfigScreen };
|
||||
|
@ -53,10 +53,13 @@ class ConfigScreenComponent extends React.Component {
|
||||
const labelStyle = Object.assign({}, theme.textStyle, {
|
||||
display: 'inline-block',
|
||||
marginRight: 10,
|
||||
color: theme.color,
|
||||
});
|
||||
|
||||
const controlStyle = {
|
||||
display: 'inline-block',
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
};
|
||||
|
||||
const descriptionStyle = Object.assign({}, theme.textStyle, {
|
||||
@ -120,7 +123,10 @@ class ConfigScreenComponent extends React.Component {
|
||||
updateSettingValue(key, event.target.value);
|
||||
}
|
||||
|
||||
const inputStyle = Object.assign({}, controlStyle, { width: '50%', minWidth: '20em' });
|
||||
const inputStyle = Object.assign({}, controlStyle, {
|
||||
width: '50%',
|
||||
minWidth: '20em',
|
||||
border: '1px solid' });
|
||||
const inputType = md.secure === true ? 'password' : 'text';
|
||||
|
||||
return (
|
||||
@ -164,21 +170,19 @@ class ConfigScreenComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
const theme = themeStyle(this.props.theme);
|
||||
const style = Object.assign({}, this.props.style, { overflow: 'auto' });
|
||||
const style = Object.assign({
|
||||
backgroundColor: theme.backgroundColor
|
||||
}, this.props.style, { overflow: 'auto' });
|
||||
const settings = this.state.settings;
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
|
||||
const containerStyle = {
|
||||
padding: 10,
|
||||
};
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, { padding: 10 });
|
||||
|
||||
const buttonStyle = {
|
||||
const buttonStyle = Object.assign({}, theme.buttonStyle, {
|
||||
display: this.state.changedSettingKeys.length ? 'inline-block' : 'none',
|
||||
marginRight: 10,
|
||||
}
|
||||
});
|
||||
|
||||
const settingComps = shared.settingsToComponents(this, 'desktop', settings);
|
||||
|
||||
@ -195,7 +199,7 @@ class ConfigScreenComponent extends React.Component {
|
||||
|
||||
settingComps.push(
|
||||
<div key="check_sync_config_button" style={this.rowStyle_}>
|
||||
<button disabled={this.state.checkSyncConfigResult === 'checking'} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
|
||||
<button style={buttonStyle} disabled={this.state.checkSyncConfigResult === 'checking'} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
|
||||
{ statusComp }
|
||||
</div>);
|
||||
}
|
||||
@ -228,4 +232,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const ConfigScreen = connect(mapStateToProps)(ConfigScreenComponent);
|
||||
|
||||
module.exports = { ConfigScreen };
|
||||
module.exports = { ConfigScreen };
|
||||
|
@ -28,16 +28,18 @@ class DropboxLoginScreenComponent extends React.Component {
|
||||
const style = this.props.style;
|
||||
const theme = themeStyle(this.props.theme);
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
padding: theme.margin,
|
||||
height: style.height - theme.headerHeight - theme.margin * 2,
|
||||
});
|
||||
|
||||
const inputStyle = Object.assign({}, theme.inputStyle, { width: 500 });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Header style={headerStyle} />
|
||||
<div style={{padding: theme.margin}}>
|
||||
<div style={containerStyle}>
|
||||
<p style={theme.textStyle}>{_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')}</p>
|
||||
<p style={theme.textStyle}>{_('Step 1: Open this URL in your browser to authorise the application:')}</p>
|
||||
<a style={theme.textStyle} href="#" onClick={this.shared_.loginUrl_click}>{this.state.loginUrl}</a>
|
||||
@ -59,4 +61,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const DropboxLoginScreen = connect(mapStateToProps)(DropboxLoginScreenComponent);
|
||||
|
||||
module.exports = { DropboxLoginScreen };
|
||||
module.exports = { DropboxLoginScreen };
|
||||
|
@ -50,6 +50,13 @@ class EncryptionConfigScreenComponent extends React.Component {
|
||||
renderMasterKey(mk) {
|
||||
const theme = themeStyle(this.props.theme);
|
||||
|
||||
const passwordStyle = {
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
border: '1px solid',
|
||||
borderColor: theme.dividerColor,
|
||||
}
|
||||
|
||||
const onSaveClick = () => {
|
||||
return shared.onSavePasswordClick(this, mk);
|
||||
}
|
||||
@ -69,7 +76,7 @@ class EncryptionConfigScreenComponent extends React.Component {
|
||||
<td style={theme.textStyle}>{mk.source_application}</td>
|
||||
<td style={theme.textStyle}>{time.formatMsToLocal(mk.created_time)}</td>
|
||||
<td style={theme.textStyle}>{time.formatMsToLocal(mk.updated_time)}</td>
|
||||
<td style={theme.textStyle}><input type="password" value={password} onChange={(event) => onPasswordChange(event)}/> <button onClick={() => onSaveClick()}>{_('Save')}</button></td>
|
||||
<td style={theme.textStyle}><input type="password" style={passwordStyle} value={password} onChange={(event) => onPasswordChange(event)}/> <button style={theme.buttonStyle} onClick={() => onSaveClick()}>{_('Save')}</button></td>
|
||||
<td style={theme.textStyle}>{passwordOk}</td>
|
||||
</tr>
|
||||
);
|
||||
@ -81,15 +88,13 @@ class EncryptionConfigScreenComponent extends React.Component {
|
||||
const masterKeys = this.state.masterKeys;
|
||||
const containerPadding = 10;
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
|
||||
const containerStyle = {
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
padding: containerPadding,
|
||||
overflow: 'auto',
|
||||
height: style.height - theme.headerHeight - containerPadding * 2,
|
||||
};
|
||||
});
|
||||
|
||||
const mkComps = [];
|
||||
let nonExistingMasterKeyIds = this.props.notLoadedMasterKeys.slice();
|
||||
@ -126,7 +131,7 @@ class EncryptionConfigScreenComponent extends React.Component {
|
||||
}
|
||||
|
||||
const decryptedItemsInfo = <p style={theme.textStyle}>{shared.decryptedStatText(this)}</p>;
|
||||
const toggleButton = <button onClick={() => { onToggleButtonClick() }}>{this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')}</button>
|
||||
const toggleButton = <button style={theme.buttonStyle} onClick={() => { onToggleButtonClick() }}>{this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')}</button>
|
||||
|
||||
let masterKeySection = null;
|
||||
|
||||
@ -213,4 +218,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const EncryptionConfigScreen = connect(mapStateToProps)(EncryptionConfigScreenComponent);
|
||||
|
||||
module.exports = { EncryptionConfigScreen };
|
||||
module.exports = { EncryptionConfigScreen };
|
||||
|
@ -108,6 +108,9 @@ class HeaderComponent extends React.Component {
|
||||
color: style.color,
|
||||
fontSize: style.fontSize,
|
||||
fontFamily: style.fontFamily,
|
||||
backgroundColor: style.searchColor,
|
||||
border: '1px solid',
|
||||
borderColor: style.dividerColor,
|
||||
};
|
||||
|
||||
const searchButton = {
|
||||
@ -171,6 +174,8 @@ class HeaderComponent extends React.Component {
|
||||
paddingLeft: theme.headerButtonHPadding,
|
||||
paddingRight: theme.headerButtonHPadding,
|
||||
color: theme.color,
|
||||
searchColor: theme.backgroundColor,
|
||||
dividerColor: theme.dividerColor,
|
||||
textDecoration: 'none',
|
||||
fontFamily: theme.fontFamily,
|
||||
fontSize: theme.fontSize,
|
||||
@ -212,4 +217,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const Header = connect(mapStateToProps)(HeaderComponent);
|
||||
|
||||
module.exports = { Header };
|
||||
module.exports = { Header };
|
||||
|
@ -35,4 +35,4 @@ class IconButton extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
module.exports = { IconButton };
|
||||
module.exports = { IconButton };
|
||||
|
@ -336,14 +336,17 @@ class MainScreenComponent extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const style = this.props.style;
|
||||
const theme = themeStyle(this.props.theme);
|
||||
const style = Object.assign({
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
}, this.props.style);
|
||||
const promptOptions = this.state.promptOptions;
|
||||
const folders = this.props.folders;
|
||||
const notes = this.props.notes;
|
||||
const messageBoxVisible = this.props.hasDisabledSyncItems || this.props.showMissingMasterKeyMessage;
|
||||
const sidebarVisibility = this.props.sidebarVisibility;
|
||||
const styles = this.styles(this.props.theme, style.width, style.height, messageBoxVisible, sidebarVisibility);
|
||||
const theme = themeStyle(this.props.theme);
|
||||
const selectedFolderId = this.props.selectedFolderId;
|
||||
const onConflictFolder = this.props.selectedFolderId === Folder.conflictFolderId();
|
||||
|
||||
|
@ -37,6 +37,7 @@ require('brace/mode/markdown');
|
||||
// https://ace.c9.io/build/kitchen-sink.html
|
||||
// https://highlightjs.org/static/demo/
|
||||
require('brace/theme/chrome');
|
||||
require('brace/theme/twilight');
|
||||
|
||||
class NoteTextComponent extends React.Component {
|
||||
|
||||
@ -1401,6 +1402,10 @@ class NoteTextComponent extends React.Component {
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
marginRight: rootStyle.paddingLeft,
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
border: '1px solid',
|
||||
borderColor: theme.dividerColor,
|
||||
};
|
||||
|
||||
const toolbarStyle = {
|
||||
@ -1432,6 +1437,9 @@ class NoteTextComponent extends React.Component {
|
||||
paddingTop: paddingTop + 'px',
|
||||
lineHeight: theme.textAreaLineHeight + 'px',
|
||||
fontSize: theme.fontSize + 'px',
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
editorTheme: theme.editorTheme,
|
||||
};
|
||||
|
||||
if (visiblePanes.indexOf('viewer') < 0) {
|
||||
@ -1462,7 +1470,8 @@ class NoteTextComponent extends React.Component {
|
||||
|
||||
const htmlHasChanged = this.lastSetHtml_ !== html;
|
||||
if (htmlHasChanged) {
|
||||
this.webview_.send('setHtml', html);
|
||||
let options = {codeTheme: theme.codeThemeCss};
|
||||
this.webview_.send('setHtml', html, options);
|
||||
this.lastSetHtml_ = html;
|
||||
}
|
||||
|
||||
@ -1535,7 +1544,7 @@ class NoteTextComponent extends React.Component {
|
||||
const editor = <AceEditor
|
||||
value={body}
|
||||
mode="markdown"
|
||||
theme="chrome"
|
||||
theme={editorRootStyle.editorTheme}
|
||||
style={editorRootStyle}
|
||||
width={editorStyle.width + 'px'}
|
||||
height={editorStyle.height + 'px'}
|
||||
@ -1597,4 +1606,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const NoteText = connect(mapStateToProps)(NoteTextComponent);
|
||||
|
||||
module.exports = { NoteText };
|
||||
module.exports = { NoteText };
|
||||
|
@ -73,14 +73,14 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
const style = this.props.style;
|
||||
const theme = themeStyle(this.props.theme);
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
|
||||
const webviewStyle = {
|
||||
width: this.props.style.width,
|
||||
height: this.props.style.height - theme.headerHeight,
|
||||
overflow: 'hidden',
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
};
|
||||
|
||||
const headerButtons = [
|
||||
@ -109,4 +109,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const OneDriveLoginScreen = connect(mapStateToProps)(OneDriveLoginScreenComponent);
|
||||
|
||||
module.exports = { OneDriveLoginScreen };
|
||||
module.exports = { OneDriveLoginScreen };
|
||||
|
@ -59,7 +59,7 @@ class PromptDialog extends React.Component {
|
||||
};
|
||||
|
||||
this.styles_.promptDialog = {
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: theme.backgroundColor,
|
||||
padding: 16,
|
||||
display: 'inline-block',
|
||||
boxShadow: '6px 6px 20px rgba(0,0,0,0.5)',
|
||||
@ -69,6 +69,10 @@ class PromptDialog extends React.Component {
|
||||
minWidth: theme.buttonMinWidth,
|
||||
minHeight: theme.buttonMinHeight,
|
||||
marginLeft: 5,
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
border: '1px solid',
|
||||
borderColor: theme.dividerColor,
|
||||
};
|
||||
|
||||
this.styles_.label = {
|
||||
@ -82,6 +86,10 @@ class PromptDialog extends React.Component {
|
||||
this.styles_.input = {
|
||||
width: 0.5 * width,
|
||||
maxWidth: 400,
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
border: '1px solid',
|
||||
borderColor: theme.dividerColor,
|
||||
};
|
||||
|
||||
this.styles_.desc = Object.assign({}, theme.textStyle, {
|
||||
@ -142,6 +150,7 @@ class PromptDialog extends React.Component {
|
||||
if (this.props.inputType === 'datetime') {
|
||||
inputComp = <Datetime
|
||||
value={this.state.answer}
|
||||
inputProps={{style: styles.input}}
|
||||
dateFormat={time.dateFormat()}
|
||||
timeFormat={time.timeFormat()}
|
||||
onChange={(momentObject) => onDateTimeChange(momentObject)}
|
||||
@ -166,7 +175,7 @@ class PromptDialog extends React.Component {
|
||||
<div style={styles.modalLayer}>
|
||||
<div style={styles.promptDialog}>
|
||||
<label style={styles.label}>{this.props.label ? this.props.label : ''}</label>
|
||||
<div style={{display: 'inline-block'}}>
|
||||
<div style={{display: 'inline-block', color: 'black', backgroundColor: theme.backgroundColor}}>
|
||||
{inputComp}
|
||||
{descComp}
|
||||
</div>
|
||||
@ -180,4 +189,4 @@ class PromptDialog extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
module.exports = { PromptDialog };
|
||||
module.exports = { PromptDialog };
|
||||
|
@ -47,17 +47,14 @@ class StatusScreenComponent extends React.Component {
|
||||
const theme = themeStyle(this.props.theme);
|
||||
const style = this.props.style;
|
||||
|
||||
const headerStyle = {
|
||||
width: style.width,
|
||||
};
|
||||
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
|
||||
|
||||
const containerPadding = 10;
|
||||
|
||||
const containerStyle = {
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
padding: containerPadding,
|
||||
overflowY: 'auto',
|
||||
height: style.height - theme.headerHeight - containerPadding * 2,
|
||||
};
|
||||
});
|
||||
|
||||
function renderSectionTitleHtml(key, title) {
|
||||
return <h2 key={'section_' + key} style={theme.h2Style}>{title}</h2>
|
||||
@ -134,4 +131,4 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const StatusScreen = connect(mapStateToProps)(StatusScreenComponent);
|
||||
|
||||
module.exports = { StatusScreen };
|
||||
module.exports = { StatusScreen };
|
||||
|
@ -30,4 +30,4 @@ class Dialogs {
|
||||
|
||||
const dialogs = new Dialogs();
|
||||
|
||||
module.exports = dialogs;
|
||||
module.exports = dialogs;
|
||||
|
@ -59,7 +59,7 @@
|
||||
let hljsScriptAdded = false;
|
||||
let hljsLoaded = false;
|
||||
|
||||
function loadHljs(callback) {
|
||||
function loadHljs(options) {
|
||||
hljsScriptAdded = true;
|
||||
|
||||
const script = document.createElement('script');
|
||||
@ -74,16 +74,16 @@
|
||||
link.rel = 'stylesheet';
|
||||
// https://ace.c9.io/build/kitchen-sink.html
|
||||
// https://highlightjs.org/static/demo/
|
||||
link.href = 'highlight/styles/atom-one-light.css';
|
||||
link.href = 'highlight/styles/' + options.codeTheme;
|
||||
document.getElementById('hlScriptContainer').appendChild(link);
|
||||
}
|
||||
|
||||
function loadAndApplyHljs() {
|
||||
function loadAndApplyHljs(options) {
|
||||
var codeElements = document.getElementsByClassName('code');
|
||||
if (!codeElements.length) return;
|
||||
|
||||
if (!hljsScriptAdded) {
|
||||
this.loadHljs();
|
||||
this.loadHljs(options);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@
|
||||
|
||||
contentElement.innerHTML = html;
|
||||
|
||||
loadAndApplyHljs();
|
||||
loadAndApplyHljs(event.options);
|
||||
|
||||
// Remove the bullet from "ul" for checkbox lists and extra padding
|
||||
// const checkboxes = document.getElementsByClassName('checkbox');
|
||||
@ -319,4 +319,4 @@
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
ipcRenderer.on('setHtml', (event, html) => {
|
||||
window.postMessage({ target: 'webview', name: 'setHtml', data: { html: html } }, '*');
|
||||
ipcRenderer.on('setHtml', (event, html, options) => {
|
||||
window.postMessage({ target: 'webview', name: 'setHtml', data: { html: html, options: options } }, '*');
|
||||
});
|
||||
|
||||
ipcRenderer.on('setPercentScroll', (event, percent) => {
|
||||
@ -33,4 +33,4 @@ window.addEventListener('message', (event) => {
|
||||
} else {
|
||||
throw new Error('Unsupported number of args');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -81,4 +81,4 @@ table td, table th {
|
||||
|
||||
.note-property-box .rdt {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
@ -2,55 +2,30 @@ const Setting = require('lib/models/Setting.js');
|
||||
|
||||
const zoomRatio = Setting.value('style.zoom') / 100;
|
||||
|
||||
// globalStyle should be used for properties that do not change across themes
|
||||
// i.e. should not be used for colors
|
||||
const globalStyle = {
|
||||
fontSize: Math.round(12 * zoomRatio),
|
||||
fontFamily: 'sans-serif',
|
||||
margin: 15, // No text and no interactive component should be within this margin
|
||||
itemMarginTop: 10,
|
||||
itemMarginBottom: 10,
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColorTransparent: 'rgba(255,255,255,0.9)',
|
||||
oddBackgroundColor: "#dddddd",
|
||||
color: "#222222", // For regular text
|
||||
colorError: "red",
|
||||
colorWarn: "#9A5B00",
|
||||
colorFaded: "#777777", // For less important text
|
||||
fontSizeSmaller: 14,
|
||||
dividerColor: "#dddddd",
|
||||
selectedColor: '#e5e5e5',
|
||||
disabledOpacity: 0.3,
|
||||
buttonMinWidth: 50,
|
||||
buttonMinHeight: 30,
|
||||
textAreaLineHeight: 17,
|
||||
|
||||
//backgroundColor2: "#2B2634",
|
||||
backgroundColor2: "#162B3D",
|
||||
color2: "#ffffff",
|
||||
//selectedColor2: "#5A4D70",
|
||||
selectedColor2: "#0269C2",
|
||||
colorError2: "#ff6c6c",
|
||||
|
||||
warningBackgroundColor: "#FFD08D",
|
||||
|
||||
headerHeight: 35,
|
||||
headerButtonHPadding: 6,
|
||||
|
||||
toolbarHeight: 35,
|
||||
|
||||
raisedBackgroundColor: "#0080EF",
|
||||
raisedColor: "#003363",
|
||||
raisedHighlightedColor: "#ffffff",
|
||||
|
||||
tagItemPadding: 3,
|
||||
tagBackgroundColor: '#e5e5e5'
|
||||
tagBackgroundColor: '#e5e5e5',
|
||||
};
|
||||
|
||||
// For WebView - must correspond to the properties above
|
||||
globalStyle.htmlFontSize = globalStyle.fontSize + 'px';
|
||||
globalStyle.htmlColor ='black'; // Note: CSS in WebView component only supports named colors or rgb() notation
|
||||
globalStyle.htmlBackgroundColor ='white';
|
||||
globalStyle.htmlDividerColor = 'rgb(150,150,150)';
|
||||
globalStyle.htmlLinkColor ='blue';
|
||||
globalStyle.htmlLineHeight = Math.round(20 * zoomRatio) + 'px';
|
||||
|
||||
globalStyle.marginRight = globalStyle.margin;
|
||||
@ -60,28 +35,22 @@ globalStyle.marginBottom = globalStyle.margin;
|
||||
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
|
||||
|
||||
globalStyle.icon = {
|
||||
color: globalStyle.color,
|
||||
fontSize: 30,
|
||||
};
|
||||
|
||||
globalStyle.lineInput = {
|
||||
color: globalStyle.color,
|
||||
backgroundColor: globalStyle.backgroundColor,
|
||||
fontFamily: globalStyle.fontFamily,
|
||||
};
|
||||
|
||||
globalStyle.textStyle = {
|
||||
color: globalStyle.color,
|
||||
fontFamily: globalStyle.fontFamily,
|
||||
fontSize: globalStyle.fontSize,
|
||||
lineHeight: '1.6em',
|
||||
};
|
||||
|
||||
globalStyle.textStyle2 = Object.assign({}, globalStyle.textStyle, {
|
||||
color: globalStyle.color2,
|
||||
});
|
||||
globalStyle.textStyle2 = Object.assign({}, globalStyle.textStyle, {});
|
||||
|
||||
globalStyle.urlStyle = Object.assign({}, globalStyle.textStyle, { color: "#155BDA", textDecoration: 'underline' });
|
||||
globalStyle.urlStyle = Object.assign({}, globalStyle.textStyle, { textDecoration: 'underline' });
|
||||
|
||||
globalStyle.h1Style = Object.assign({}, globalStyle.textStyle);
|
||||
globalStyle.h1Style.fontSize *= 1.5;
|
||||
@ -98,7 +67,6 @@ globalStyle.toolbarStyle = {
|
||||
alignItems: 'center',
|
||||
paddingLeft: globalStyle.headerButtonHPadding,
|
||||
paddingRight: globalStyle.headerButtonHPadding,
|
||||
color: globalStyle.color,
|
||||
textDecoration: 'none',
|
||||
fontFamily: globalStyle.fontFamily,
|
||||
fontSize: globalStyle.fontSize,
|
||||
@ -107,6 +75,97 @@ globalStyle.toolbarStyle = {
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
globalStyle.headerStyle = {};
|
||||
|
||||
globalStyle.inputStyle = {
|
||||
border: '1px solid',
|
||||
};
|
||||
|
||||
globalStyle.containerStyle = {
|
||||
overflow: 'auto',
|
||||
overflowY: 'auto',
|
||||
};
|
||||
|
||||
globalStyle.buttonStyle = {
|
||||
marginRight: 10,
|
||||
border: '1px solid',
|
||||
};
|
||||
|
||||
const lightStyle = {
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColorTransparent: 'rgba(255,255,255,0.9)',
|
||||
oddBackgroundColor: "#dddddd",
|
||||
color: "#222222", // For regular text
|
||||
colorError: "red",
|
||||
colorWarn: "#9A5B00",
|
||||
colorFaded: "#777777", // For less important text
|
||||
dividerColor: "#dddddd",
|
||||
selectedColor: '#e5e5e5',
|
||||
urlColor: '#155BDA',
|
||||
|
||||
backgroundColor2: "#162B3D",
|
||||
color2: "#ffffff",
|
||||
selectedColor2: "#0269C2",
|
||||
colorError2: "#ff6c6c",
|
||||
|
||||
raisedBackgroundColor: "#0080EF",
|
||||
raisedColor: "#003363",
|
||||
raisedHighlightedColor: "#ffffff",
|
||||
|
||||
warningBackgroundColor: "#FFD08D",
|
||||
|
||||
codeColor: "#EFF0F1",
|
||||
codeBorderColor: '#CBCBCB',
|
||||
|
||||
htmlColor:'black', // Note: CSS in WebView component only supports named colors or rgb() notation
|
||||
htmlBackgroundColor: 'white',
|
||||
htmlDividerColor: 'rgb(150,150,150)',
|
||||
htmlLinkColor: 'blue',
|
||||
htmlCodeColor: 'rgb(239, 240, 241)',
|
||||
htmlCodeBorderColor: 'rgb(203, 203, 203)',
|
||||
|
||||
editorTheme: "chrome",
|
||||
codeThemeCss: "atom-one-light.css",
|
||||
};
|
||||
|
||||
const darkStyle = {
|
||||
backgroundColor: '#1D2024',
|
||||
backgroundColorTransparent: 'rgba(255,255,255,0.9)',
|
||||
oddBackgroundColor: "#dddddd",
|
||||
color: '#dddddd',
|
||||
colorFaded: '#777777',
|
||||
colorError: "red",
|
||||
colorWarn: "#9A5B00",
|
||||
colorFaded: "#777777", // For less important text
|
||||
dividerColor: '#555555',
|
||||
selectedColor: '#333333',
|
||||
urlColor: '#4E87EE',
|
||||
|
||||
backgroundColor2: "#162B3D",
|
||||
color2: "#ffffff",
|
||||
selectedColor2: "#0269C2",
|
||||
colorError2: "#ff6c6c",
|
||||
|
||||
raisedBackgroundColor: "#0F2051",
|
||||
raisedColor: "#788BC3",
|
||||
raisedHighlightedColor: "#ffffff",
|
||||
|
||||
warningBackgroundColor: "#CC6600",
|
||||
|
||||
codeColor: "#2F3031",
|
||||
codeBorderColor: '#464646',
|
||||
|
||||
htmlColor: 'rgb(220,220,220)', // Note: CSS in WebView component only supports named colors or rgb() notation
|
||||
htmlBackgroundColor: 'rgb(29,32,36)',
|
||||
htmlDividerColor: 'rgb(150,150,150)',
|
||||
htmlLinkColor: 'rgb(166,166,255)',
|
||||
htmlCodeColor: 'rgb(47, 48, 49)',
|
||||
htmlCodeBorderColor: 'rgb(70, 70, 70)',
|
||||
|
||||
editorTheme: 'twilight',
|
||||
codeThemeCss: "atom-one-dark-reasonable.css",
|
||||
};
|
||||
|
||||
globalStyle.tagStyle = {
|
||||
fontSize: globalStyle.fontSize,
|
||||
fontFamily: globalStyle.fontFamily,
|
||||
@ -126,25 +185,93 @@ function themeStyle(theme) {
|
||||
if (!theme) throw new Error('Theme must be specified');
|
||||
if (themeCache_[theme]) return themeCache_[theme];
|
||||
|
||||
let output = Object.assign({}, globalStyle);
|
||||
if (theme == Setting.THEME_LIGHT) return output;
|
||||
let output = {};
|
||||
if (theme == Setting.THEME_LIGHT) {
|
||||
output = Object.assign({}, globalStyle, lightStyle);
|
||||
}
|
||||
else if (theme == Setting.THEME_DARK) {
|
||||
output = Object.assign({}, globalStyle, darkStyle);
|
||||
}
|
||||
|
||||
output.backgroundColor = '#1D2024';
|
||||
output.color = '#dddddd';
|
||||
output.colorFaded = '#777777';
|
||||
output.dividerColor = '#555555';
|
||||
output.selectedColor = '#333333';
|
||||
output.textStyle = Object.assign({},
|
||||
output.textStyle,
|
||||
{ color: output.color }
|
||||
);
|
||||
|
||||
output.raisedBackgroundColor = "#0F2051";
|
||||
output.raisedColor = "#788BC3";
|
||||
output.raisedHighlightedColor = "#ffffff";
|
||||
output.icon = Object.assign({},
|
||||
output.icon,
|
||||
{ color: output.color }
|
||||
);
|
||||
|
||||
output.htmlColor = 'rgb(220,220,220)';
|
||||
output.htmlBackgroundColor = 'rgb(29,32,36)';
|
||||
output.htmlLinkColor = 'rgb(166,166,255)';
|
||||
output.lineInput = Object.assign({},
|
||||
output.lineInput,
|
||||
{
|
||||
color: output.color,
|
||||
backgroundColor: output.backgroundColor,
|
||||
}
|
||||
);
|
||||
|
||||
output.textStyle2 = Object.assign({},
|
||||
output.textStyle2,
|
||||
{ color: output.color2, }
|
||||
);
|
||||
|
||||
output.urlStyle = Object.assign({},
|
||||
output.urlStyle,
|
||||
{ color: output.urlColor }
|
||||
);
|
||||
|
||||
output.h1Style = Object.assign({},
|
||||
output.h1Style,
|
||||
{ color: output.color }
|
||||
);
|
||||
|
||||
output.h2Style = Object.assign({},
|
||||
output.h2Style,
|
||||
{ color: output.color }
|
||||
);
|
||||
|
||||
output.toolbarStyle = Object.assign({},
|
||||
output.toolbarStyle,
|
||||
{ color: output.color }
|
||||
);
|
||||
|
||||
output.headerStyle = Object.assign({},
|
||||
output.headerStyle,
|
||||
{
|
||||
color: output.color,
|
||||
backgroundColor: output.backgroundColor,
|
||||
}
|
||||
);
|
||||
|
||||
output.inputStyle = Object.assign({},
|
||||
output.inputStyle,
|
||||
{
|
||||
color: output.color,
|
||||
backgroundColor: output.backgroundColor,
|
||||
borderColor: output.dividerColor,
|
||||
}
|
||||
);
|
||||
|
||||
output.containerStyle = Object.assign({},
|
||||
output.containerStyle,
|
||||
{
|
||||
color: output.color,
|
||||
backgroundColor: output.backgroundColor,
|
||||
}
|
||||
);
|
||||
|
||||
output.buttonStyle = Object.assign({},
|
||||
output.buttonStyle,
|
||||
{
|
||||
color: output.color,
|
||||
backgroundColor: output.backgroundColor,
|
||||
borderColor: output.dividerColor,
|
||||
}
|
||||
);
|
||||
|
||||
themeCache_[theme] = output;
|
||||
return themeCache_[theme];
|
||||
}
|
||||
|
||||
module.exports = { themeStyle };
|
||||
module.exports = { themeStyle };
|
||||
|
@ -599,8 +599,8 @@ class MdToHtml {
|
||||
max-width: 100%;
|
||||
}
|
||||
.inline-code {
|
||||
border: 1px solid #CBCBCB;
|
||||
background-color: #eff0f1;
|
||||
border: 1px solid ` + style.htmlCodeBorderColor + `;
|
||||
background-color: ` + style.htmlCodeColor + `;
|
||||
padding-right: .2em;
|
||||
padding-left: .2em;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class Setting extends BaseModel {
|
||||
options[Setting.TIME_FORMAT_2] = time.formatMsToLocal(now, Setting.TIME_FORMAT_2);
|
||||
return options;
|
||||
}},
|
||||
'theme': { value: Setting.THEME_LIGHT, type: Setting.TYPE_INT, public: true, appTypes: ['mobile'], isEnum: true, label: () => _('Theme'), options: () => {
|
||||
'theme': { value: Setting.THEME_LIGHT, type: Setting.TYPE_INT, public: true, appTypes: ['mobile', 'desktop'], isEnum: true, label: () => _('Theme'), options: () => {
|
||||
let output = {};
|
||||
output[Setting.THEME_LIGHT] = _('Light');
|
||||
output[Setting.THEME_DARK] = _('Dark');
|
||||
@ -576,4 +576,4 @@ Setting.constants_ = {
|
||||
|
||||
Setting.autoSaveEnabled = true;
|
||||
|
||||
module.exports = Setting;
|
||||
module.exports = Setting;
|
||||
|
Loading…
Reference in New Issue
Block a user