1
0
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:
Caleb John 2018-11-07 15:37:13 -07:00 committed by Laurent Cozic
parent 19f5a144e5
commit ee106105d8
18 changed files with 286 additions and 119 deletions

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -35,4 +35,4 @@ class IconButton extends React.Component {
}
module.exports = { IconButton };
module.exports = { IconButton };

View File

@ -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();

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -30,4 +30,4 @@ class Dialogs {
const dialogs = new Dialogs();
module.exports = dialogs;
module.exports = dialogs;

View File

@ -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>

View File

@ -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');
}
});
});

View File

@ -81,4 +81,4 @@ table td, table th {
.note-property-box .rdt {
display: inline-block;
}
}

View File

@ -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 };

View File

@ -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;
}

View File

@ -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;