aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package-lock.json27
-rw-r--r--package.json4
-rw-r--r--src/assets/themeInfo.json1
-rw-r--r--src/components/settings/settings/EditSettingsForm.js10
-rw-r--r--src/components/ui/Button.js13
-rw-r--r--src/components/ui/FullscreenLoader/index.js19
-rw-r--r--src/components/ui/FullscreenLoader/styles.js1
-rw-r--r--src/components/ui/Loader.js15
-rw-r--r--src/config.js3
-rw-r--r--src/containers/settings/EditSettingsScreen.js10
-rw-r--r--src/features/accentColor/index.js55
-rw-r--r--src/features/announcements/api.js2
-rw-r--r--src/i18n/locales/defaultMessages.json110
-rw-r--r--src/i18n/locales/en-US.json2
-rw-r--r--src/i18n/messages/src/components/settings/settings/EditSettingsForm.json65
-rw-r--r--src/i18n/messages/src/containers/settings/EditSettingsScreen.json45
-rw-r--r--src/index.js9
-rw-r--r--src/scripts/build-theme-info.js95
-rw-r--r--src/stores/FeaturesStore.js2
-rw-r--r--src/styles/radio.scss4
-rw-r--r--src/styles/settings.scss12
-rw-r--r--src/styles/tabs.scss4
-rw-r--r--src/styles/type.scss4
23 files changed, 397 insertions, 115 deletions
diff --git a/package-lock.json b/package-lock.json
index 12ae35ed5..fb3b675fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4117,8 +4117,7 @@
4117 "atob": { 4117 "atob": {
4118 "version": "2.1.2", 4118 "version": "2.1.2",
4119 "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", 4119 "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
4120 "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 4120 "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
4121 "dev": true
4122 }, 4121 },
4123 "atob-lite": { 4122 "atob-lite": {
4124 "version": "2.0.0", 4123 "version": "2.0.0",
@@ -6334,6 +6333,17 @@
6334 "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", 6333 "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
6335 "dev": true 6334 "dev": true
6336 }, 6335 },
6336 "css": {
6337 "version": "2.2.4",
6338 "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
6339 "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
6340 "requires": {
6341 "inherits": "^2.0.3",
6342 "source-map": "^0.6.1",
6343 "source-map-resolve": "^0.5.2",
6344 "urix": "^0.1.0"
6345 }
6346 },
6337 "css-select": { 6347 "css-select": {
6338 "version": "1.2.0", 6348 "version": "1.2.0",
6339 "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", 6349 "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@@ -6569,8 +6579,7 @@
6569 "decode-uri-component": { 6579 "decode-uri-component": {
6570 "version": "0.2.0", 6580 "version": "0.2.0",
6571 "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 6581 "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
6572 "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", 6582 "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
6573 "dev": true
6574 }, 6583 },
6575 "decompress-response": { 6584 "decompress-response": {
6576 "version": "3.3.0", 6585 "version": "3.3.0",
@@ -19379,8 +19388,7 @@
19379 "resolve-url": { 19388 "resolve-url": {
19380 "version": "0.2.1", 19389 "version": "0.2.1",
19381 "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 19390 "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
19382 "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", 19391 "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
19383 "dev": true
19384 }, 19392 },
19385 "responselike": { 19393 "responselike": {
19386 "version": "1.0.2", 19394 "version": "1.0.2",
@@ -20489,7 +20497,6 @@
20489 "version": "0.5.2", 20497 "version": "0.5.2",
20490 "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", 20498 "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
20491 "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", 20499 "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
20492 "dev": true,
20493 "requires": { 20500 "requires": {
20494 "atob": "^2.1.1", 20501 "atob": "^2.1.1",
20495 "decode-uri-component": "^0.2.0", 20502 "decode-uri-component": "^0.2.0",
@@ -20510,8 +20517,7 @@
20510 "source-map-url": { 20517 "source-map-url": {
20511 "version": "0.4.0", 20518 "version": "0.4.0",
20512 "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", 20519 "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
20513 "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", 20520 "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
20514 "dev": true
20515 }, 20521 },
20516 "sparkles": { 20522 "sparkles": {
20517 "version": "1.0.1", 20523 "version": "1.0.1",
@@ -22285,8 +22291,7 @@
22285 "urix": { 22291 "urix": {
22286 "version": "0.1.0", 22292 "version": "0.1.0",
22287 "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 22293 "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
22288 "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", 22294 "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
22289 "dev": true
22290 }, 22295 },
22291 "url": { 22296 "url": {
22292 "version": "0.11.0", 22297 "version": "0.11.0",
diff --git a/package.json b/package.json
index d574bfeb9..e016f7359 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,8 @@
30 "uidev": "cd uidev && webpack-dev-server", 30 "uidev": "cd uidev && webpack-dev-server",
31 "postinstall": "npx lerna run prepare", 31 "postinstall": "npx lerna run prepare",
32 "apply-branding": "node ./src/i18n/apply-branding.js", 32 "apply-branding": "node ./src/i18n/apply-branding.js",
33 "prepare-code": "npm run lint && npm run reformat-files && npm run manage-translations && npm run apply-branding" 33 "prepare-code": "npm run lint && npm run reformat-files && npm run manage-translations && npm run apply-branding",
34 "build-theme-info": "node src/scripts/build-theme-info.js"
34 }, 35 },
35 "keywords": [], 36 "keywords": [],
36 "author": "Amine Mouafik <amine@mouafik.fr>", 37 "author": "Amine Mouafik <amine@mouafik.fr>",
@@ -47,6 +48,7 @@
47 "auto-launch": "5.0.5", 48 "auto-launch": "5.0.5",
48 "classnames": "2.2.6", 49 "classnames": "2.2.6",
49 "cld3-asm": "1.0.1", 50 "cld3-asm": "1.0.1",
51 "css": "2.2.4",
50 "darkreader": "4.7.15", 52 "darkreader": "4.7.15",
51 "du": "^0.1.0", 53 "du": "^0.1.0",
52 "electron-dl": "1.14.0", 54 "electron-dl": "1.14.0",
diff --git a/src/assets/themeInfo.json b/src/assets/themeInfo.json
new file mode 100644
index 000000000..d6017de23
--- /dev/null
+++ b/src/assets/themeInfo.json
@@ -0,0 +1 @@
{"color":".theme__dark .app .sidebar .sidebar__button.is-muted, .theme__dark .app .sidebar .sidebar__button.is-active, .sidebar .sidebar__button.is-muted, .sidebar .sidebar__button.is-active, .settings .account .invoices .invoices__action button, .settings-navigation .settings-navigation__link.is-active .badge, a.button, a.link, .auth .welcome .button:hover, .auth .welcome .button__inverted, .franz-form .franz-form__radio.is-selected, .theme__dark .franz-form__button.franz-form__button--inverted, .franz-form__button.franz-form__button--inverted","border-left-color":".tab-item.is-active","border-color":".theme__dark .settings .premium-info, a.button, .franz-form .franz-form__radio.is-selected","background":".settings .settings__header, .settings .settings__close, .settings .settings__close:hover, .settings-navigation .settings-navigation__link.is-active, a.button:hover, .info-bar, .info-bar.info-bar--primary, .infobox.infobox--primary, .theme__dark .badge.badge--primary, .theme__dark .badge.badge--premium, .badge.badge--primary, .badge.badge--premium, .content-tabs .content-tabs__tabs .content-tabs__item.is-active, #electron-app-title-bar .toolbar-dropdown:not(.open) > .toolbar-button > button:hover, #electron-app-title-bar .list-item.selected .menu-item, #electron-app-title-bar .list-item.selected:focus .menu-item, .theme__dark .quick-switch .active, .franz-form .franz-form__toggle-wrapper .franz-form__toggle.is-active .franz-form__toggle-button, .theme__dark .franz-form__button, .theme__dark .franz-form__button:hover, .theme__dark .franz-form__button.franz-form__button--inverted:hover, .franz-form__button, .franz-form__button:hover, .franz-form__button.franz-form__button--inverted:hover","border-right-color":".settings .settings__header .separator"} \ No newline at end of file
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index b01368f69..a826479ad 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -79,6 +79,10 @@ const messages = defineMessages({
79 id: 'settings.app.headlineAppearance', 79 id: 'settings.app.headlineAppearance',
80 defaultMessage: '!!!Appearance', 80 defaultMessage: '!!!Appearance',
81 }, 81 },
82 accentColorInfo: {
83 id: 'settings.app.accentColorInfo',
84 defaultMessage: '!!!Write your accent color in a CSS-compatible format. (Default: #7367f0)',
85 },
82 headlineAdvanced: { 86 headlineAdvanced: {
83 id: 'settings.app.headlineAdvanced', 87 id: 'settings.app.headlineAdvanced',
84 defaultMessage: '!!!Advanced', 88 defaultMessage: '!!!Advanced',
@@ -373,6 +377,12 @@ export default @observer class EditSettingsForm extends Component {
373 <Toggle field={form.$('showDisabledServices')} /> 377 <Toggle field={form.$('showDisabledServices')} />
374 <Toggle field={form.$('showMessageBadgeWhenMuted')} /> 378 <Toggle field={form.$('showMessageBadgeWhenMuted')} />
375 <Toggle field={form.$('darkMode')} /> 379 <Toggle field={form.$('darkMode')} />
380 <Input
381 placeholder="Accent Color"
382 onChange={e => this.submit(e)}
383 field={form.$('accentColor')}
384 />
385 <p>{intl.formatMessage(messages.accentColorInfo)}</p>
376 386
377 {/* Language */} 387 {/* Language */}
378 <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2> 388 <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2>
diff --git a/src/components/ui/Button.js b/src/components/ui/Button.js
index e2d7cea83..f46fd34ea 100644
--- a/src/components/ui/Button.js
+++ b/src/components/ui/Button.js
@@ -1,10 +1,10 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer, inject } from 'mobx-react';
4import Loader from 'react-loader'; 4import Loader from 'react-loader';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
7export default @observer class Button extends Component { 7export default @observer @inject('stores') class Button extends Component {
8 static propTypes = { 8 static propTypes = {
9 className: PropTypes.string, 9 className: PropTypes.string,
10 label: PropTypes.string.isRequired, 10 label: PropTypes.string.isRequired,
@@ -14,6 +14,13 @@ export default @observer class Button extends Component {
14 buttonType: PropTypes.string, 14 buttonType: PropTypes.string,
15 loaded: PropTypes.bool, 15 loaded: PropTypes.bool,
16 htmlForm: PropTypes.string, 16 htmlForm: PropTypes.string,
17 stores: PropTypes.shape({
18 settings: PropTypes.shape({
19 app: PropTypes.shape({
20 accentColor: PropTypes.string.isRequired,
21 }).isRequired,
22 }).isRequired,
23 }).isRequired,
17 }; 24 };
18 25
19 static defaultProps = { 26 static defaultProps = {
@@ -69,7 +76,7 @@ export default @observer class Button extends Component {
69 loaded={loaded} 76 loaded={loaded}
70 lines={10} 77 lines={10}
71 scale={0.4} 78 scale={0.4}
72 color={buttonType !== 'secondary' ? '#FFF' : '#7367F0'} 79 color={buttonType !== 'secondary' ? '#FFF' : this.props.stores.settings.app.accentColor}
73 component="span" 80 component="span"
74 /> 81 />
75 {label} 82 {label}
diff --git a/src/components/ui/FullscreenLoader/index.js b/src/components/ui/FullscreenLoader/index.js
index 06dab1eb6..334bb6c4a 100644
--- a/src/components/ui/FullscreenLoader/index.js
+++ b/src/components/ui/FullscreenLoader/index.js
@@ -1,6 +1,6 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer, inject } from 'mobx-react';
4import injectSheet, { withTheme } from 'react-jss'; 4import injectSheet, { withTheme } from 'react-jss';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
@@ -8,7 +8,7 @@ import Loader from '../Loader';
8 8
9import styles from './styles'; 9import styles from './styles';
10 10
11export default @observer @withTheme @injectSheet(styles) class FullscreenLoader extends Component { 11export default @observer @inject('stores') @withTheme @injectSheet(styles) class FullscreenLoader extends Component {
12 static propTypes = { 12 static propTypes = {
13 className: PropTypes.string, 13 className: PropTypes.string,
14 title: PropTypes.string.isRequired, 14 title: PropTypes.string.isRequired,
@@ -16,6 +16,13 @@ export default @observer @withTheme @injectSheet(styles) class FullscreenLoader
16 theme: PropTypes.object.isRequired, 16 theme: PropTypes.object.isRequired,
17 spinnerColor: PropTypes.string, 17 spinnerColor: PropTypes.string,
18 children: PropTypes.node, 18 children: PropTypes.node,
19 stores: PropTypes.shape({
20 settings: PropTypes.shape({
21 app: PropTypes.shape({
22 accentColor: PropTypes.string.isRequired,
23 }).isRequired,
24 }).isRequired,
25 }).isRequired,
19 }; 26 };
20 27
21 static defaultProps = { 28 static defaultProps = {
@@ -32,10 +39,16 @@ export default @observer @withTheme @injectSheet(styles) class FullscreenLoader
32 spinnerColor, 39 spinnerColor,
33 className, 40 className,
34 theme, 41 theme,
42 stores,
35 } = this.props; 43 } = this.props;
36 44
37 return ( 45 return (
38 <div className={classes.wrapper}> 46 <div
47 className={classes.wrapper}
48 style={{
49 background: stores.app.accentColor,
50 }}
51 >
39 <div 52 <div
40 className={classnames({ 53 className={classnames({
41 [`${classes.component}`]: true, 54 [`${classes.component}`]: true,
diff --git a/src/components/ui/FullscreenLoader/styles.js b/src/components/ui/FullscreenLoader/styles.js
index d516781a8..64d24e4ce 100644
--- a/src/components/ui/FullscreenLoader/styles.js
+++ b/src/components/ui/FullscreenLoader/styles.js
@@ -4,7 +4,6 @@ export default {
4 alignItems: 'center', 4 alignItems: 'center',
5 position: 'absolute', 5 position: 'absolute',
6 width: '100%', 6 width: '100%',
7 background: 'linear-gradient( 135deg, #CE9FFC 10%, #7367F0 100%)',
8 }, 7 },
9 component: { 8 component: {
10 width: '100%', 9 width: '100%',
diff --git a/src/components/ui/Loader.js b/src/components/ui/Loader.js
index de8769b6c..627749273 100644
--- a/src/components/ui/Loader.js
+++ b/src/components/ui/Loader.js
@@ -1,22 +1,30 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import { observer, inject } from 'mobx-react';
2import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
3import Loader from 'react-loader'; 4import Loader from 'react-loader';
4 5
5import { oneOrManyChildElements } from '../../prop-types'; 6import { oneOrManyChildElements } from '../../prop-types';
6 7
7export default class LoaderComponent extends Component { 8export default @observer @inject('stores') class LoaderComponent extends Component {
8 static propTypes = { 9 static propTypes = {
9 children: oneOrManyChildElements, 10 children: oneOrManyChildElements,
10 loaded: PropTypes.bool, 11 loaded: PropTypes.bool,
11 className: PropTypes.string, 12 className: PropTypes.string,
12 color: PropTypes.string, 13 color: PropTypes.string,
14 stores: PropTypes.shape({
15 settings: PropTypes.shape({
16 app: PropTypes.shape({
17 accentColor: PropTypes.string.isRequired,
18 }).isRequired,
19 }).isRequired,
20 }).isRequired,
13 }; 21 };
14 22
15 static defaultProps = { 23 static defaultProps = {
16 children: null, 24 children: null,
17 loaded: false, 25 loaded: false,
18 className: '', 26 className: '',
19 color: '#7367F0', 27 color: 'ACCENT',
20 }; 28 };
21 29
22 render() { 30 render() {
@@ -24,9 +32,10 @@ export default class LoaderComponent extends Component {
24 children, 32 children,
25 loaded, 33 loaded,
26 className, 34 className,
27 color,
28 } = this.props; 35 } = this.props;
29 36
37 const color = this.props.color !== 'ACCENT' ? this.props.color : this.props.stores.settings.app.accentColor;
38
30 return ( 39 return (
31 <Loader 40 <Loader
32 loaded={loaded} 41 loaded={loaded}
diff --git a/src/config.js b/src/config.js
index 924d139a2..d9ef67530 100644
--- a/src/config.js
+++ b/src/config.js
@@ -76,6 +76,7 @@ export const DEFAULT_APP_SETTINGS = {
76 hibernationStrategy: 300, 76 hibernationStrategy: 300,
77 noUpdates: false, 77 noUpdates: false,
78 showServiceNavigationBar: false, 78 showServiceNavigationBar: false,
79 accentColor: '#7367f0',
79}; 80};
80 81
81export const DEFAULT_FEATURES_CONFIG = { 82export const DEFAULT_FEATURES_CONFIG = {
@@ -100,7 +101,7 @@ export const DEFAULT_WINDOW_OPTIONS = {
100 y: 0, 101 y: 0,
101}; 102};
102 103
103export const FRANZ_SERVICE_REQUEST = 'https://github.com/getferdi/recipes/issues'; 104export const FRANZ_SERVICE_REQUEST = 'https://github.com/getferdi/recipes/issues/new/choose';
104export const FRANZ_TRANSLATION = 'https://crowdin.com/project/getferdi'; 105export const FRANZ_TRANSLATION = 'https://crowdin.com/project/getferdi';
105export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub'; 106export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub';
106 107
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js
index f0ceeb8e6..7b0633f79 100644
--- a/src/containers/settings/EditSettingsScreen.js
+++ b/src/containers/settings/EditSettingsScreen.js
@@ -98,6 +98,10 @@ const messages = defineMessages({
98 id: 'settings.app.form.darkMode', 98 id: 'settings.app.form.darkMode',
99 defaultMessage: '!!!Dark Mode', 99 defaultMessage: '!!!Dark Mode',
100 }, 100 },
101 accentColor: {
102 id: 'settings.app.form.accentColor',
103 defaultMessage: '!!!Accent color',
104 },
101 showDisabledServices: { 105 showDisabledServices: {
102 id: 'settings.app.form.showDisabledServices', 106 id: 'settings.app.form.showDisabledServices',
103 defaultMessage: '!!!Display disabled services tabs', 107 defaultMessage: '!!!Display disabled services tabs',
@@ -172,6 +176,7 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
172 enableGPUAcceleration: settingsData.enableGPUAcceleration, 176 enableGPUAcceleration: settingsData.enableGPUAcceleration,
173 showDisabledServices: settingsData.showDisabledServices, 177 showDisabledServices: settingsData.showDisabledServices,
174 darkMode: settingsData.darkMode, 178 darkMode: settingsData.darkMode,
179 accentColor: settingsData.accentColor,
175 showMessageBadgeWhenMuted: settingsData.showMessageBadgeWhenMuted, 180 showMessageBadgeWhenMuted: settingsData.showMessageBadgeWhenMuted,
176 enableSpellchecking: settingsData.enableSpellchecking, 181 enableSpellchecking: settingsData.enableSpellchecking,
177 spellcheckerLanguage: settingsData.spellcheckerLanguage, 182 spellcheckerLanguage: settingsData.spellcheckerLanguage,
@@ -340,6 +345,11 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
340 value: settings.all.app.darkMode, 345 value: settings.all.app.darkMode,
341 default: DEFAULT_APP_SETTINGS.darkMode, 346 default: DEFAULT_APP_SETTINGS.darkMode,
342 }, 347 },
348 accentColor: {
349 label: intl.formatMessage(messages.accentColor),
350 value: settings.all.app.accentColor,
351 default: DEFAULT_APP_SETTINGS.accentColor,
352 },
343 enableGPUAcceleration: { 353 enableGPUAcceleration: {
344 label: intl.formatMessage(messages.enableGPUAcceleration), 354 label: intl.formatMessage(messages.enableGPUAcceleration),
345 value: settings.all.app.enableGPUAcceleration, 355 value: settings.all.app.enableGPUAcceleration,
diff --git a/src/features/accentColor/index.js b/src/features/accentColor/index.js
new file mode 100644
index 000000000..a0f57a2fa
--- /dev/null
+++ b/src/features/accentColor/index.js
@@ -0,0 +1,55 @@
1import { reaction } from 'mobx';
2import themeInfo from '../../assets/themeInfo.json';
3import { DEFAULT_APP_SETTINGS } from '../../config';
4
5const STYLE_ELEMENT_ID = 'accent-color';
6
7function createAccentStyleElement() {
8 const styles = document.createElement('style');
9 styles.id = STYLE_ELEMENT_ID;
10
11 document.querySelector('head').appendChild(styles);
12}
13
14function setAccentStyle(style) {
15 const styleElement = document.getElementById(STYLE_ELEMENT_ID);
16 styleElement.innerHTML = style;
17}
18
19function generateAccentStyle(color) {
20 let style = '';
21
22 Object.keys(themeInfo).forEach((property) => {
23 style += `
24 ${themeInfo[property]} {
25 ${property}: ${color};
26 }
27 `;
28 });
29
30 return style;
31}
32
33export default function initAccentColor(stores) {
34 const { settings } = stores;
35 createAccentStyleElement();
36
37 // Update accent color
38 reaction(
39 () => (
40 settings.all.app.accentColor
41 ),
42 (color) => {
43 if (color === DEFAULT_APP_SETTINGS.accentColor) {
44 // Reset accent style to return to default color scheme
45 setAccentStyle('');
46 } else {
47 const style = generateAccentStyle(color);
48 setAccentStyle(style);
49 }
50 },
51 {
52 fireImmediately: true,
53 },
54 );
55}
diff --git a/src/features/announcements/api.js b/src/features/announcements/api.js
index a7995d6db..f33980d0f 100644
--- a/src/features/announcements/api.js
+++ b/src/features/announcements/api.js
@@ -12,7 +12,7 @@ export const announcementsApi = {
12 12
13 async getChangelog(version) { 13 async getChangelog(version) {
14 debug('fetching release changelog from Github'); 14 debug('fetching release changelog from Github');
15 const url = `https://api.github.com/repos/meetfranz/franz/releases/tags/v${version}`; 15 const url = `https://api.github.com/repos/getferdi/ferdi/releases/tags/v${version}`;
16 const request = await window.fetch(url, { method: 'GET' }); 16 const request = await window.fetch(url, { method: 'GET' });
17 if (!request.ok) return null; 17 if (!request.ok) return null;
18 const data = await request.json(); 18 const data = await request.json();
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index 3fc86c266..f9afe6213 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -2657,172 +2657,185 @@
2657 } 2657 }
2658 }, 2658 },
2659 { 2659 {
2660 "defaultMessage": "!!!Advanced", 2660 "defaultMessage": "!!!Write your accent color in a CSS-compatible format. (Default: #7367f0)",
2661 "end": { 2661 "end": {
2662 "column": 3, 2662 "column": 3,
2663 "line": 85 2663 "line": 85
2664 }, 2664 },
2665 "file": "src/components/settings/settings/EditSettingsForm.js", 2665 "file": "src/components/settings/settings/EditSettingsForm.js",
2666 "id": "settings.app.accentColorInfo",
2667 "start": {
2668 "column": 19,
2669 "line": 82
2670 }
2671 },
2672 {
2673 "defaultMessage": "!!!Advanced",
2674 "end": {
2675 "column": 3,
2676 "line": 89
2677 },
2678 "file": "src/components/settings/settings/EditSettingsForm.js",
2666 "id": "settings.app.headlineAdvanced", 2679 "id": "settings.app.headlineAdvanced",
2667 "start": { 2680 "start": {
2668 "column": 20, 2681 "column": 20,
2669 "line": 82 2682 "line": 86
2670 } 2683 }
2671 }, 2684 },
2672 { 2685 {
2673 "defaultMessage": "!!!Help us to translate Ferdi into your language.", 2686 "defaultMessage": "!!!Help us to translate Ferdi into your language.",
2674 "end": { 2687 "end": {
2675 "column": 3, 2688 "column": 3,
2676 "line": 89 2689 "line": 93
2677 }, 2690 },
2678 "file": "src/components/settings/settings/EditSettingsForm.js", 2691 "file": "src/components/settings/settings/EditSettingsForm.js",
2679 "id": "settings.app.translationHelp", 2692 "id": "settings.app.translationHelp",
2680 "start": { 2693 "start": {
2681 "column": 19, 2694 "column": 19,
2682 "line": 86 2695 "line": 90
2683 } 2696 }
2684 }, 2697 },
2685 { 2698 {
2686 "defaultMessage": "!!!Cache", 2699 "defaultMessage": "!!!Cache",
2687 "end": { 2700 "end": {
2688 "column": 3, 2701 "column": 3,
2689 "line": 93 2702 "line": 97
2690 }, 2703 },
2691 "file": "src/components/settings/settings/EditSettingsForm.js", 2704 "file": "src/components/settings/settings/EditSettingsForm.js",
2692 "id": "settings.app.subheadlineCache", 2705 "id": "settings.app.subheadlineCache",
2693 "start": { 2706 "start": {
2694 "column": 20, 2707 "column": 20,
2695 "line": 90 2708 "line": 94
2696 } 2709 }
2697 }, 2710 },
2698 { 2711 {
2699 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.", 2712 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.",
2700 "end": { 2713 "end": {
2701 "column": 3, 2714 "column": 3,
2702 "line": 97 2715 "line": 101
2703 }, 2716 },
2704 "file": "src/components/settings/settings/EditSettingsForm.js", 2717 "file": "src/components/settings/settings/EditSettingsForm.js",
2705 "id": "settings.app.cacheInfo", 2718 "id": "settings.app.cacheInfo",
2706 "start": { 2719 "start": {
2707 "column": 13, 2720 "column": 13,
2708 "line": 94 2721 "line": 98
2709 } 2722 }
2710 }, 2723 },
2711 { 2724 {
2712 "defaultMessage": "!!!Clear cache", 2725 "defaultMessage": "!!!Clear cache",
2713 "end": { 2726 "end": {
2714 "column": 3, 2727 "column": 3,
2715 "line": 101 2728 "line": 105
2716 }, 2729 },
2717 "file": "src/components/settings/settings/EditSettingsForm.js", 2730 "file": "src/components/settings/settings/EditSettingsForm.js",
2718 "id": "settings.app.buttonClearAllCache", 2731 "id": "settings.app.buttonClearAllCache",
2719 "start": { 2732 "start": {
2720 "column": 23, 2733 "column": 23,
2721 "line": 98 2734 "line": 102
2722 } 2735 }
2723 }, 2736 },
2724 { 2737 {
2725 "defaultMessage": "!!!Check for updates", 2738 "defaultMessage": "!!!Check for updates",
2726 "end": { 2739 "end": {
2727 "column": 3, 2740 "column": 3,
2728 "line": 105 2741 "line": 109
2729 }, 2742 },
2730 "file": "src/components/settings/settings/EditSettingsForm.js", 2743 "file": "src/components/settings/settings/EditSettingsForm.js",
2731 "id": "settings.app.buttonSearchForUpdate", 2744 "id": "settings.app.buttonSearchForUpdate",
2732 "start": { 2745 "start": {
2733 "column": 25, 2746 "column": 25,
2734 "line": 102 2747 "line": 106
2735 } 2748 }
2736 }, 2749 },
2737 { 2750 {
2738 "defaultMessage": "!!!Restart & install update", 2751 "defaultMessage": "!!!Restart & install update",
2739 "end": { 2752 "end": {
2740 "column": 3, 2753 "column": 3,
2741 "line": 109 2754 "line": 113
2742 }, 2755 },
2743 "file": "src/components/settings/settings/EditSettingsForm.js", 2756 "file": "src/components/settings/settings/EditSettingsForm.js",
2744 "id": "settings.app.buttonInstallUpdate", 2757 "id": "settings.app.buttonInstallUpdate",
2745 "start": { 2758 "start": {
2746 "column": 23, 2759 "column": 23,
2747 "line": 106 2760 "line": 110
2748 } 2761 }
2749 }, 2762 },
2750 { 2763 {
2751 "defaultMessage": "!!!Is searching for update", 2764 "defaultMessage": "!!!Is searching for update",
2752 "end": { 2765 "end": {
2753 "column": 3, 2766 "column": 3,
2754 "line": 113 2767 "line": 117
2755 }, 2768 },
2756 "file": "src/components/settings/settings/EditSettingsForm.js", 2769 "file": "src/components/settings/settings/EditSettingsForm.js",
2757 "id": "settings.app.updateStatusSearching", 2770 "id": "settings.app.updateStatusSearching",
2758 "start": { 2771 "start": {
2759 "column": 25, 2772 "column": 25,
2760 "line": 110 2773 "line": 114
2761 } 2774 }
2762 }, 2775 },
2763 { 2776 {
2764 "defaultMessage": "!!!Update available, downloading...", 2777 "defaultMessage": "!!!Update available, downloading...",
2765 "end": { 2778 "end": {
2766 "column": 3, 2779 "column": 3,
2767 "line": 117 2780 "line": 121
2768 }, 2781 },
2769 "file": "src/components/settings/settings/EditSettingsForm.js", 2782 "file": "src/components/settings/settings/EditSettingsForm.js",
2770 "id": "settings.app.updateStatusAvailable", 2783 "id": "settings.app.updateStatusAvailable",
2771 "start": { 2784 "start": {
2772 "column": 25, 2785 "column": 25,
2773 "line": 114 2786 "line": 118
2774 } 2787 }
2775 }, 2788 },
2776 { 2789 {
2777 "defaultMessage": "!!!You are using the latest version of Ferdi", 2790 "defaultMessage": "!!!You are using the latest version of Ferdi",
2778 "end": { 2791 "end": {
2779 "column": 3, 2792 "column": 3,
2780 "line": 121 2793 "line": 125
2781 }, 2794 },
2782 "file": "src/components/settings/settings/EditSettingsForm.js", 2795 "file": "src/components/settings/settings/EditSettingsForm.js",
2783 "id": "settings.app.updateStatusUpToDate", 2796 "id": "settings.app.updateStatusUpToDate",
2784 "start": { 2797 "start": {
2785 "column": 24, 2798 "column": 24,
2786 "line": 118 2799 "line": 122
2787 } 2800 }
2788 }, 2801 },
2789 { 2802 {
2790 "defaultMessage": "!!!Current version:", 2803 "defaultMessage": "!!!Current version:",
2791 "end": { 2804 "end": {
2792 "column": 3, 2805 "column": 3,
2793 "line": 125 2806 "line": 129
2794 }, 2807 },
2795 "file": "src/components/settings/settings/EditSettingsForm.js", 2808 "file": "src/components/settings/settings/EditSettingsForm.js",
2796 "id": "settings.app.currentVersion", 2809 "id": "settings.app.currentVersion",
2797 "start": { 2810 "start": {
2798 "column": 18, 2811 "column": 18,
2799 "line": 122 2812 "line": 126
2800 } 2813 }
2801 }, 2814 },
2802 { 2815 {
2803 "defaultMessage": "!!!Changes require restart", 2816 "defaultMessage": "!!!Changes require restart",
2804 "end": { 2817 "end": {
2805 "column": 3, 2818 "column": 3,
2806 "line": 129 2819 "line": 133
2807 }, 2820 },
2808 "file": "src/components/settings/settings/EditSettingsForm.js", 2821 "file": "src/components/settings/settings/EditSettingsForm.js",
2809 "id": "settings.app.restartRequired", 2822 "id": "settings.app.restartRequired",
2810 "start": { 2823 "start": {
2811 "column": 29, 2824 "column": 29,
2812 "line": 126 2825 "line": 130
2813 } 2826 }
2814 }, 2827 },
2815 { 2828 {
2816 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.", 2829 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.",
2817 "end": { 2830 "end": {
2818 "column": 3, 2831 "column": 3,
2819 "line": 133 2832 "line": 137
2820 }, 2833 },
2821 "file": "src/components/settings/settings/EditSettingsForm.js", 2834 "file": "src/components/settings/settings/EditSettingsForm.js",
2822 "id": "settings.app.languageDisclaimer", 2835 "id": "settings.app.languageDisclaimer",
2823 "start": { 2836 "start": {
2824 "column": 22, 2837 "column": 22,
2825 "line": 130 2838 "line": 134
2826 } 2839 }
2827 } 2840 }
2828 ], 2841 ],
@@ -4019,107 +4032,120 @@
4019 } 4032 }
4020 }, 4033 },
4021 { 4034 {
4022 "defaultMessage": "!!!Display disabled services tabs", 4035 "defaultMessage": "!!!Accent color",
4023 "end": { 4036 "end": {
4024 "column": 3, 4037 "column": 3,
4025 "line": 104 4038 "line": 104
4026 }, 4039 },
4027 "file": "src/containers/settings/EditSettingsScreen.js", 4040 "file": "src/containers/settings/EditSettingsScreen.js",
4041 "id": "settings.app.form.accentColor",
4042 "start": {
4043 "column": 15,
4044 "line": 101
4045 }
4046 },
4047 {
4048 "defaultMessage": "!!!Display disabled services tabs",
4049 "end": {
4050 "column": 3,
4051 "line": 108
4052 },
4053 "file": "src/containers/settings/EditSettingsScreen.js",
4028 "id": "settings.app.form.showDisabledServices", 4054 "id": "settings.app.form.showDisabledServices",
4029 "start": { 4055 "start": {
4030 "column": 24, 4056 "column": 24,
4031 "line": 101 4057 "line": 105
4032 } 4058 }
4033 }, 4059 },
4034 { 4060 {
4035 "defaultMessage": "!!!Show unread message badge when notifications are disabled", 4061 "defaultMessage": "!!!Show unread message badge when notifications are disabled",
4036 "end": { 4062 "end": {
4037 "column": 3, 4063 "column": 3,
4038 "line": 108 4064 "line": 112
4039 }, 4065 },
4040 "file": "src/containers/settings/EditSettingsScreen.js", 4066 "file": "src/containers/settings/EditSettingsScreen.js",
4041 "id": "settings.app.form.showMessagesBadgesWhenMuted", 4067 "id": "settings.app.form.showMessagesBadgesWhenMuted",
4042 "start": { 4068 "start": {
4043 "column": 29, 4069 "column": 29,
4044 "line": 105 4070 "line": 109
4045 } 4071 }
4046 }, 4072 },
4047 { 4073 {
4048 "defaultMessage": "!!!Enable spell checking", 4074 "defaultMessage": "!!!Enable spell checking",
4049 "end": { 4075 "end": {
4050 "column": 3, 4076 "column": 3,
4051 "line": 112 4077 "line": 116
4052 }, 4078 },
4053 "file": "src/containers/settings/EditSettingsScreen.js", 4079 "file": "src/containers/settings/EditSettingsScreen.js",
4054 "id": "settings.app.form.enableSpellchecking", 4080 "id": "settings.app.form.enableSpellchecking",
4055 "start": { 4081 "start": {
4056 "column": 23, 4082 "column": 23,
4057 "line": 109 4083 "line": 113
4058 } 4084 }
4059 }, 4085 },
4060 { 4086 {
4061 "defaultMessage": "!!!Enable GPU Acceleration", 4087 "defaultMessage": "!!!Enable GPU Acceleration",
4062 "end": { 4088 "end": {
4063 "column": 3, 4089 "column": 3,
4064 "line": 116 4090 "line": 120
4065 }, 4091 },
4066 "file": "src/containers/settings/EditSettingsScreen.js", 4092 "file": "src/containers/settings/EditSettingsScreen.js",
4067 "id": "settings.app.form.enableGPUAcceleration", 4093 "id": "settings.app.form.enableGPUAcceleration",
4068 "start": { 4094 "start": {
4069 "column": 25, 4095 "column": 25,
4070 "line": 113 4096 "line": 117
4071 } 4097 }
4072 }, 4098 },
4073 { 4099 {
4074 "defaultMessage": "!!!Include beta versions", 4100 "defaultMessage": "!!!Include beta versions",
4075 "end": { 4101 "end": {
4076 "column": 3, 4102 "column": 3,
4077 "line": 120 4103 "line": 124
4078 }, 4104 },
4079 "file": "src/containers/settings/EditSettingsScreen.js", 4105 "file": "src/containers/settings/EditSettingsScreen.js",
4080 "id": "settings.app.form.beta", 4106 "id": "settings.app.form.beta",
4081 "start": { 4107 "start": {
4082 "column": 8, 4108 "column": 8,
4083 "line": 117 4109 "line": 121
4084 } 4110 }
4085 }, 4111 },
4086 { 4112 {
4087 "defaultMessage": "!!!Disable updates", 4113 "defaultMessage": "!!!Disable updates",
4088 "end": { 4114 "end": {
4089 "column": 3, 4115 "column": 3,
4090 "line": 124 4116 "line": 128
4091 }, 4117 },
4092 "file": "src/containers/settings/EditSettingsScreen.js", 4118 "file": "src/containers/settings/EditSettingsScreen.js",
4093 "id": "settings.app.form.noUpdates", 4119 "id": "settings.app.form.noUpdates",
4094 "start": { 4120 "start": {
4095 "column": 13, 4121 "column": 13,
4096 "line": 121 4122 "line": 125
4097 } 4123 }
4098 }, 4124 },
4099 { 4125 {
4100 "defaultMessage": "!!!Enable Franz Todos", 4126 "defaultMessage": "!!!Enable Franz Todos",
4101 "end": { 4127 "end": {
4102 "column": 3, 4128 "column": 3,
4103 "line": 128 4129 "line": 132
4104 }, 4130 },
4105 "file": "src/containers/settings/EditSettingsScreen.js", 4131 "file": "src/containers/settings/EditSettingsScreen.js",
4106 "id": "settings.app.form.enableTodos", 4132 "id": "settings.app.form.enableTodos",
4107 "start": { 4133 "start": {
4108 "column": 15, 4134 "column": 15,
4109 "line": 125 4135 "line": 129
4110 } 4136 }
4111 }, 4137 },
4112 { 4138 {
4113 "defaultMessage": "!!!Keep all workspaces loaded", 4139 "defaultMessage": "!!!Keep all workspaces loaded",
4114 "end": { 4140 "end": {
4115 "column": 3, 4141 "column": 3,
4116 "line": 132 4142 "line": 136
4117 }, 4143 },
4118 "file": "src/containers/settings/EditSettingsScreen.js", 4144 "file": "src/containers/settings/EditSettingsScreen.js",
4119 "id": "settings.app.form.keepAllWorkspacesLoaded", 4145 "id": "settings.app.form.keepAllWorkspacesLoaded",
4120 "start": { 4146 "start": {
4121 "column": 27, 4147 "column": 27,
4122 "line": 129 4148 "line": 133
4123 } 4149 }
4124 } 4150 }
4125 ], 4151 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index b4649c03c..d3dabc364 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -214,11 +214,13 @@
214 "settings.account.upgradeToPro.label": "Upgrade to Ferdi Professional", 214 "settings.account.upgradeToPro.label": "Upgrade to Ferdi Professional",
215 "settings.account.userInfoRequestFailed": "Could not load user information", 215 "settings.account.userInfoRequestFailed": "Could not load user information",
216 "settings.account.yourLicense": "Your Ferdi License", 216 "settings.account.yourLicense": "Your Ferdi License",
217 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: #7367f0)",
217 "settings.app.buttonClearAllCache": "Clear cache", 218 "settings.app.buttonClearAllCache": "Clear cache",
218 "settings.app.buttonInstallUpdate": "Restart & install update", 219 "settings.app.buttonInstallUpdate": "Restart & install update",
219 "settings.app.buttonSearchForUpdate": "Check for updates", 220 "settings.app.buttonSearchForUpdate": "Check for updates",
220 "settings.app.cacheInfo": "Ferdi cache is currently using {size} of disk space.", 221 "settings.app.cacheInfo": "Ferdi cache is currently using {size} of disk space.",
221 "settings.app.currentVersion": "Current version:", 222 "settings.app.currentVersion": "Current version:",
223 "settings.app.form.accentColor": "Accent color",
222 "settings.app.form.autoLaunchInBackground": "Open in background", 224 "settings.app.form.autoLaunchInBackground": "Open in background",
223 "settings.app.form.autoLaunchOnStart": "Launch Ferdi on start", 225 "settings.app.form.autoLaunchOnStart": "Launch Ferdi on start",
224 "settings.app.form.beta": "Include beta versions", 226 "settings.app.form.beta": "Include beta versions",
diff --git a/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json b/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json
index 97ecf4b5d..16d8e7816 100644
--- a/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json
+++ b/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json
@@ -182,15 +182,28 @@
182 } 182 }
183 }, 183 },
184 { 184 {
185 "id": "settings.app.accentColorInfo",
186 "defaultMessage": "!!!Write your accent color in a CSS-compatible format. (Default: #7367f0)",
187 "file": "src/components/settings/settings/EditSettingsForm.js",
188 "start": {
189 "line": 82,
190 "column": 19
191 },
192 "end": {
193 "line": 85,
194 "column": 3
195 }
196 },
197 {
185 "id": "settings.app.headlineAdvanced", 198 "id": "settings.app.headlineAdvanced",
186 "defaultMessage": "!!!Advanced", 199 "defaultMessage": "!!!Advanced",
187 "file": "src/components/settings/settings/EditSettingsForm.js", 200 "file": "src/components/settings/settings/EditSettingsForm.js",
188 "start": { 201 "start": {
189 "line": 82, 202 "line": 86,
190 "column": 20 203 "column": 20
191 }, 204 },
192 "end": { 205 "end": {
193 "line": 85, 206 "line": 89,
194 "column": 3 207 "column": 3
195 } 208 }
196 }, 209 },
@@ -199,11 +212,11 @@
199 "defaultMessage": "!!!Help us to translate Ferdi into your language.", 212 "defaultMessage": "!!!Help us to translate Ferdi into your language.",
200 "file": "src/components/settings/settings/EditSettingsForm.js", 213 "file": "src/components/settings/settings/EditSettingsForm.js",
201 "start": { 214 "start": {
202 "line": 86, 215 "line": 90,
203 "column": 19 216 "column": 19
204 }, 217 },
205 "end": { 218 "end": {
206 "line": 89, 219 "line": 93,
207 "column": 3 220 "column": 3
208 } 221 }
209 }, 222 },
@@ -212,11 +225,11 @@
212 "defaultMessage": "!!!Cache", 225 "defaultMessage": "!!!Cache",
213 "file": "src/components/settings/settings/EditSettingsForm.js", 226 "file": "src/components/settings/settings/EditSettingsForm.js",
214 "start": { 227 "start": {
215 "line": 90, 228 "line": 94,
216 "column": 20 229 "column": 20
217 }, 230 },
218 "end": { 231 "end": {
219 "line": 93, 232 "line": 97,
220 "column": 3 233 "column": 3
221 } 234 }
222 }, 235 },
@@ -225,11 +238,11 @@
225 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.", 238 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.",
226 "file": "src/components/settings/settings/EditSettingsForm.js", 239 "file": "src/components/settings/settings/EditSettingsForm.js",
227 "start": { 240 "start": {
228 "line": 94, 241 "line": 98,
229 "column": 13 242 "column": 13
230 }, 243 },
231 "end": { 244 "end": {
232 "line": 97, 245 "line": 101,
233 "column": 3 246 "column": 3
234 } 247 }
235 }, 248 },
@@ -238,11 +251,11 @@
238 "defaultMessage": "!!!Clear cache", 251 "defaultMessage": "!!!Clear cache",
239 "file": "src/components/settings/settings/EditSettingsForm.js", 252 "file": "src/components/settings/settings/EditSettingsForm.js",
240 "start": { 253 "start": {
241 "line": 98, 254 "line": 102,
242 "column": 23 255 "column": 23
243 }, 256 },
244 "end": { 257 "end": {
245 "line": 101, 258 "line": 105,
246 "column": 3 259 "column": 3
247 } 260 }
248 }, 261 },
@@ -251,11 +264,11 @@
251 "defaultMessage": "!!!Check for updates", 264 "defaultMessage": "!!!Check for updates",
252 "file": "src/components/settings/settings/EditSettingsForm.js", 265 "file": "src/components/settings/settings/EditSettingsForm.js",
253 "start": { 266 "start": {
254 "line": 102, 267 "line": 106,
255 "column": 25 268 "column": 25
256 }, 269 },
257 "end": { 270 "end": {
258 "line": 105, 271 "line": 109,
259 "column": 3 272 "column": 3
260 } 273 }
261 }, 274 },
@@ -264,11 +277,11 @@
264 "defaultMessage": "!!!Restart & install update", 277 "defaultMessage": "!!!Restart & install update",
265 "file": "src/components/settings/settings/EditSettingsForm.js", 278 "file": "src/components/settings/settings/EditSettingsForm.js",
266 "start": { 279 "start": {
267 "line": 106, 280 "line": 110,
268 "column": 23 281 "column": 23
269 }, 282 },
270 "end": { 283 "end": {
271 "line": 109, 284 "line": 113,
272 "column": 3 285 "column": 3
273 } 286 }
274 }, 287 },
@@ -277,11 +290,11 @@
277 "defaultMessage": "!!!Is searching for update", 290 "defaultMessage": "!!!Is searching for update",
278 "file": "src/components/settings/settings/EditSettingsForm.js", 291 "file": "src/components/settings/settings/EditSettingsForm.js",
279 "start": { 292 "start": {
280 "line": 110, 293 "line": 114,
281 "column": 25 294 "column": 25
282 }, 295 },
283 "end": { 296 "end": {
284 "line": 113, 297 "line": 117,
285 "column": 3 298 "column": 3
286 } 299 }
287 }, 300 },
@@ -290,11 +303,11 @@
290 "defaultMessage": "!!!Update available, downloading...", 303 "defaultMessage": "!!!Update available, downloading...",
291 "file": "src/components/settings/settings/EditSettingsForm.js", 304 "file": "src/components/settings/settings/EditSettingsForm.js",
292 "start": { 305 "start": {
293 "line": 114, 306 "line": 118,
294 "column": 25 307 "column": 25
295 }, 308 },
296 "end": { 309 "end": {
297 "line": 117, 310 "line": 121,
298 "column": 3 311 "column": 3
299 } 312 }
300 }, 313 },
@@ -303,11 +316,11 @@
303 "defaultMessage": "!!!You are using the latest version of Ferdi", 316 "defaultMessage": "!!!You are using the latest version of Ferdi",
304 "file": "src/components/settings/settings/EditSettingsForm.js", 317 "file": "src/components/settings/settings/EditSettingsForm.js",
305 "start": { 318 "start": {
306 "line": 118, 319 "line": 122,
307 "column": 24 320 "column": 24
308 }, 321 },
309 "end": { 322 "end": {
310 "line": 121, 323 "line": 125,
311 "column": 3 324 "column": 3
312 } 325 }
313 }, 326 },
@@ -316,11 +329,11 @@
316 "defaultMessage": "!!!Current version:", 329 "defaultMessage": "!!!Current version:",
317 "file": "src/components/settings/settings/EditSettingsForm.js", 330 "file": "src/components/settings/settings/EditSettingsForm.js",
318 "start": { 331 "start": {
319 "line": 122, 332 "line": 126,
320 "column": 18 333 "column": 18
321 }, 334 },
322 "end": { 335 "end": {
323 "line": 125, 336 "line": 129,
324 "column": 3 337 "column": 3
325 } 338 }
326 }, 339 },
@@ -329,11 +342,11 @@
329 "defaultMessage": "!!!Changes require restart", 342 "defaultMessage": "!!!Changes require restart",
330 "file": "src/components/settings/settings/EditSettingsForm.js", 343 "file": "src/components/settings/settings/EditSettingsForm.js",
331 "start": { 344 "start": {
332 "line": 126, 345 "line": 130,
333 "column": 29 346 "column": 29
334 }, 347 },
335 "end": { 348 "end": {
336 "line": 129, 349 "line": 133,
337 "column": 3 350 "column": 3
338 } 351 }
339 }, 352 },
@@ -342,11 +355,11 @@
342 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.", 355 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.",
343 "file": "src/components/settings/settings/EditSettingsForm.js", 356 "file": "src/components/settings/settings/EditSettingsForm.js",
344 "start": { 357 "start": {
345 "line": 130, 358 "line": 134,
346 "column": 22 359 "column": 22
347 }, 360 },
348 "end": { 361 "end": {
349 "line": 133, 362 "line": 137,
350 "column": 3 363 "column": 3
351 } 364 }
352 } 365 }
diff --git a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json b/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
index 54a8868bf..bd5efb82e 100644
--- a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
+++ b/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
@@ -234,15 +234,28 @@
234 } 234 }
235 }, 235 },
236 { 236 {
237 "id": "settings.app.form.accentColor",
238 "defaultMessage": "!!!Accent color",
239 "file": "src/containers/settings/EditSettingsScreen.js",
240 "start": {
241 "line": 101,
242 "column": 15
243 },
244 "end": {
245 "line": 104,
246 "column": 3
247 }
248 },
249 {
237 "id": "settings.app.form.showDisabledServices", 250 "id": "settings.app.form.showDisabledServices",
238 "defaultMessage": "!!!Display disabled services tabs", 251 "defaultMessage": "!!!Display disabled services tabs",
239 "file": "src/containers/settings/EditSettingsScreen.js", 252 "file": "src/containers/settings/EditSettingsScreen.js",
240 "start": { 253 "start": {
241 "line": 101, 254 "line": 105,
242 "column": 24 255 "column": 24
243 }, 256 },
244 "end": { 257 "end": {
245 "line": 104, 258 "line": 108,
246 "column": 3 259 "column": 3
247 } 260 }
248 }, 261 },
@@ -251,11 +264,11 @@
251 "defaultMessage": "!!!Show unread message badge when notifications are disabled", 264 "defaultMessage": "!!!Show unread message badge when notifications are disabled",
252 "file": "src/containers/settings/EditSettingsScreen.js", 265 "file": "src/containers/settings/EditSettingsScreen.js",
253 "start": { 266 "start": {
254 "line": 105, 267 "line": 109,
255 "column": 29 268 "column": 29
256 }, 269 },
257 "end": { 270 "end": {
258 "line": 108, 271 "line": 112,
259 "column": 3 272 "column": 3
260 } 273 }
261 }, 274 },
@@ -264,11 +277,11 @@
264 "defaultMessage": "!!!Enable spell checking", 277 "defaultMessage": "!!!Enable spell checking",
265 "file": "src/containers/settings/EditSettingsScreen.js", 278 "file": "src/containers/settings/EditSettingsScreen.js",
266 "start": { 279 "start": {
267 "line": 109, 280 "line": 113,
268 "column": 23 281 "column": 23
269 }, 282 },
270 "end": { 283 "end": {
271 "line": 112, 284 "line": 116,
272 "column": 3 285 "column": 3
273 } 286 }
274 }, 287 },
@@ -277,11 +290,11 @@
277 "defaultMessage": "!!!Enable GPU Acceleration", 290 "defaultMessage": "!!!Enable GPU Acceleration",
278 "file": "src/containers/settings/EditSettingsScreen.js", 291 "file": "src/containers/settings/EditSettingsScreen.js",
279 "start": { 292 "start": {
280 "line": 113, 293 "line": 117,
281 "column": 25 294 "column": 25
282 }, 295 },
283 "end": { 296 "end": {
284 "line": 116, 297 "line": 120,
285 "column": 3 298 "column": 3
286 } 299 }
287 }, 300 },
@@ -290,11 +303,11 @@
290 "defaultMessage": "!!!Include beta versions", 303 "defaultMessage": "!!!Include beta versions",
291 "file": "src/containers/settings/EditSettingsScreen.js", 304 "file": "src/containers/settings/EditSettingsScreen.js",
292 "start": { 305 "start": {
293 "line": 117, 306 "line": 121,
294 "column": 8 307 "column": 8
295 }, 308 },
296 "end": { 309 "end": {
297 "line": 120, 310 "line": 124,
298 "column": 3 311 "column": 3
299 } 312 }
300 }, 313 },
@@ -303,11 +316,11 @@
303 "defaultMessage": "!!!Disable updates", 316 "defaultMessage": "!!!Disable updates",
304 "file": "src/containers/settings/EditSettingsScreen.js", 317 "file": "src/containers/settings/EditSettingsScreen.js",
305 "start": { 318 "start": {
306 "line": 121, 319 "line": 125,
307 "column": 13 320 "column": 13
308 }, 321 },
309 "end": { 322 "end": {
310 "line": 124, 323 "line": 128,
311 "column": 3 324 "column": 3
312 } 325 }
313 }, 326 },
@@ -316,11 +329,11 @@
316 "defaultMessage": "!!!Enable Franz Todos", 329 "defaultMessage": "!!!Enable Franz Todos",
317 "file": "src/containers/settings/EditSettingsScreen.js", 330 "file": "src/containers/settings/EditSettingsScreen.js",
318 "start": { 331 "start": {
319 "line": 125, 332 "line": 129,
320 "column": 15 333 "column": 15
321 }, 334 },
322 "end": { 335 "end": {
323 "line": 128, 336 "line": 132,
324 "column": 3 337 "column": 3
325 } 338 }
326 }, 339 },
@@ -329,11 +342,11 @@
329 "defaultMessage": "!!!Keep all workspaces loaded", 342 "defaultMessage": "!!!Keep all workspaces loaded",
330 "file": "src/containers/settings/EditSettingsScreen.js", 343 "file": "src/containers/settings/EditSettingsScreen.js",
331 "start": { 344 "start": {
332 "line": 129, 345 "line": 133,
333 "column": 27 346 "column": 27
334 }, 347 },
335 "end": { 348 "end": {
336 "line": 132, 349 "line": 136,
337 "column": 3 350 "column": 3
338 } 351 }
339 } 352 }
diff --git a/src/index.js b/src/index.js
index 2ee404c0b..4dcabb599 100644
--- a/src/index.js
+++ b/src/index.js
@@ -144,6 +144,13 @@ const createWindow = () => {
144 } 144 }
145 145
146 // Create the browser window. 146 // Create the browser window.
147 let backgroundColor = '#7367F0';
148 if (settings.get('accentColor') !== '#7367f0') {
149 backgroundColor = settings.get('accentColor');
150 } else if (settings.get('darkMode')) {
151 backgroundColor = '#1E1E1E';
152 }
153
147 mainWindow = new BrowserWindow({ 154 mainWindow = new BrowserWindow({
148 x: posX, 155 x: posX,
149 y: posY, 156 y: posY,
@@ -153,7 +160,7 @@ const createWindow = () => {
153 minHeight: 500, 160 minHeight: 500,
154 titleBarStyle: isMac ? 'hidden' : '', 161 titleBarStyle: isMac ? 'hidden' : '',
155 frame: isLinux, 162 frame: isLinux,
156 backgroundColor: !settings.get('darkMode') ? '#7367F0' : '#1E1E1E', 163 backgroundColor,
157 webPreferences: { 164 webPreferences: {
158 nodeIntegration: true, 165 nodeIntegration: true,
159 webviewTag: true, 166 webviewTag: true,
diff --git a/src/scripts/build-theme-info.js b/src/scripts/build-theme-info.js
new file mode 100644
index 000000000..4df5a022b
--- /dev/null
+++ b/src/scripts/build-theme-info.js
@@ -0,0 +1,95 @@
1/**
2 * Script to get information on which selectors use the brand color.
3 * This is needed to provide the accent color feature - the feature will create CSS rules
4 * to overwrite the color of these selectors.
5 */
6const css = require('css');
7const fs = require('fs-extra');
8const path = require('path');
9
10// Colors that should be replaced with the accent color
11const accentColors = [
12 '#7367f0',
13 '#5e50ee',
14];
15
16const cssFile = path.join(__dirname, '../../', 'build', 'styles', 'main.css');
17const outputFile = path.join(__dirname, '../', 'assets', 'themeInfo.json');
18
19// Parse and extract the rules from a CSS stylesheet file
20async function getRulesFromCssFile(file) {
21 const cssSrc = (await fs.readFile(file)).toString();
22 const cssTree = css.parse(cssSrc);
23
24 return cssTree.stylesheet.rules;
25}
26
27/**
28 * Get all selectors from a list of parsed CSS rules that set any property to one of the specified
29 * values.
30 *
31 * This function will output an object in this format:
32 * {
33 * 'property-name': [ array of selectors ]
34 * }
35 *
36 * e.g.
37 * {
38 * 'background-color': [
39 * '.background',
40 * '.input-dark'
41 * ]
42 * }
43 *
44 * @param {Array} rules Rules as outputted by the `css` module
45 * @param {Array} values Array of values that should be searched for
46 */
47function getSelectorsDeclaringValues(rules, values) {
48 const output = {};
49
50 rules.forEach((rule) => {
51 if (rule.declarations) {
52 rule.declarations.forEach((declaration) => {
53 if (declaration.type === 'declaration'
54 && values.includes(declaration.value.toLowerCase())) {
55 if (!output[declaration.property]) {
56 output[declaration.property] = [];
57 }
58 output[declaration.property] = output[declaration.property].concat(rule.selectors);
59 }
60 });
61 }
62 });
63
64 return output;
65}
66
67async function generateThemeInfo() {
68 if (!await fs.pathExists(cssFile)) {
69 console.log('Please make sure to build the project first.');
70 return;
71 }
72
73 // Read and parse css bundle
74 const rules = await getRulesFromCssFile(cssFile);
75
76 console.log(`Found ${rules.length} rules`);
77
78 // Get rules specifying the brand colors
79 const brandRules = getSelectorsDeclaringValues(rules, accentColors);
80
81 console.log(`Found ${Object.keys(brandRules).join(', ')} properties that set color to brand color`);
82
83 // Join array of declarations into a single string
84 Object.keys(brandRules).forEach((rule) => {
85 brandRules[rule] = brandRules[rule].join(', ');
86 });
87
88 // Write object with theme info to file
89 fs.writeFile(
90 outputFile,
91 JSON.stringify(brandRules),
92 );
93}
94
95generateThemeInfo();
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index c39b6d7f3..3d9542245 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -20,6 +20,7 @@ import settingsWS from '../features/settingsWS';
20import serviceLimit from '../features/serviceLimit'; 20import serviceLimit from '../features/serviceLimit';
21import communityRecipes from '../features/communityRecipes'; 21import communityRecipes from '../features/communityRecipes';
22import todos from '../features/todos'; 22import todos from '../features/todos';
23import accentColor from '../features/accentColor';
23 24
24import { DEFAULT_FEATURES_CONFIG } from '../config'; 25import { DEFAULT_FEATURES_CONFIG } from '../config';
25 26
@@ -83,5 +84,6 @@ export default class FeaturesStore extends Store {
83 serviceLimit(this.stores, this.actions); 84 serviceLimit(this.stores, this.actions);
84 communityRecipes(this.stores, this.actions); 85 communityRecipes(this.stores, this.actions);
85 todos(this.stores, this.actions); 86 todos(this.stores, this.actions);
87 accentColor(this.stores, this.actions);
86 } 88 }
87} 89}
diff --git a/src/styles/radio.scss b/src/styles/radio.scss
index 87d401215..b1e148ca0 100644
--- a/src/styles/radio.scss
+++ b/src/styles/radio.scss
@@ -30,7 +30,9 @@
30 30
31 &.is-selected { 31 &.is-selected {
32 background: #FFF; 32 background: #FFF;
33 border: 2px solid $theme-brand-primary; 33 border-width: 2px;
34 border-style: solid;
35 border-color: $theme-brand-primary;
34 color: $theme-brand-primary; 36 color: $theme-brand-primary;
35 } 37 }
36 38
diff --git a/src/styles/settings.scss b/src/styles/settings.scss
index 071861f16..753288b8d 100644
--- a/src/styles/settings.scss
+++ b/src/styles/settings.scss
@@ -59,7 +59,9 @@
59 59
60 .premium-info { 60 .premium-info {
61 background: $dark-theme-gray-darker; 61 background: $dark-theme-gray-darker;
62 border: 2px solid $theme-brand-primary; 62 border-width: 2px;
63 border-style: solid;
64 border-color: $theme-brand-primary;
63 } 65 }
64 .legal { color: $theme-gray-light; } 66 .legal { color: $theme-gray-light; }
65 } 67 }
@@ -170,7 +172,9 @@
170 } 172 }
171 173
172 .separator { 174 .separator {
173 border-right: 1px solid darken($theme-brand-primary, 8%); 175 border-right-width: 1px;
176 border-right-style: solid;
177 border-right-color: $theme-brand-primary;
174 height: 100%; 178 height: 100%;
175 margin: 0 15px; 179 margin: 0 15px;
176 transform: skew(15deg) rotate(2deg); 180 transform: skew(15deg) rotate(2deg);
@@ -224,7 +228,7 @@
224 228
225 .settings__close { 229 .settings__close {
226 background: $theme-brand-primary; 230 background: $theme-brand-primary;
227 border-left: 1px solid darken($theme-brand-primary, 8%); 231 // border-left: 1px solid darken($theme-brand-primary, 8%);
228 color: #FFF; 232 color: #FFF;
229 font-size: 20px; 233 font-size: 20px;
230 height: 50px; 234 height: 50px;
@@ -233,7 +237,9 @@
233 right: 0; 237 right: 0;
234 transition: background $theme-transition-time; 238 transition: background $theme-transition-time;
235 border-top-right-radius: $theme-border-radius; 239 border-top-right-radius: $theme-border-radius;
240 cursor: pointer;
236 241
242 &::before { cursor: pointer; }
237 &:hover { background: darken($theme-brand-primary, 5%); } 243 &:hover { background: darken($theme-brand-primary, 5%); }
238 } 244 }
239 245
diff --git a/src/styles/tabs.scss b/src/styles/tabs.scss
index ee0858687..e500830ed 100644
--- a/src/styles/tabs.scss
+++ b/src/styles/tabs.scss
@@ -34,7 +34,9 @@
34 34
35 &.is-active { 35 &.is-active {
36 background: lighten($theme-brand-primary, 35%); 36 background: lighten($theme-brand-primary, 35%);
37 border-left: 4px solid $theme-brand-primary; 37 border-left-width: 4px;
38 border-left-style: solid;
39 border-left-color: $theme-brand-primary;
38 40
39 .tab-item__icon { margin-left: -4px; } 41 .tab-item__icon { margin-left: -4px; }
40 } 42 }
diff --git a/src/styles/type.scss b/src/styles/type.scss
index 135d32da0..e0b27fe34 100644
--- a/src/styles/type.scss
+++ b/src/styles/type.scss
@@ -39,7 +39,9 @@ a {
39 39
40 &.button { 40 &.button {
41 background: none; 41 background: none;
42 border: 2px solid $theme-brand-primary; 42 border-width: 2px;
43 border-style: solid;
44 border-color: $theme-brand-primary;
43 border-radius: 3px; 45 border-radius: 3px;
44 color: $theme-brand-primary; 46 color: $theme-brand-primary;
45 display: inline-block; 47 display: inline-block;