diff options
author | niu tech <jerzyglowacki@gmail.com> | 2021-09-15 10:39:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-15 10:39:27 +0200 |
commit | e2f440ff2dd5179e2d9bc8dea119fc4fe7c562a1 (patch) | |
tree | 2f8a1e012c4c13b2c3e7eb243277bef951b67378 | |
parent | docs: fix link in bug_report template [skip ci] (diff) | |
download | ferdium-app-e2f440ff2dd5179e2d9bc8dea119fc4fe7c562a1.tar.gz ferdium-app-e2f440ff2dd5179e2d9bc8dea119fc4fe7c562a1.tar.zst ferdium-app-e2f440ff2dd5179e2d9bc8dea119fc4fe7c562a1.zip |
Enable Split View Mode (#1926)
-rw-r--r-- | src/components/services/content/ServiceView.js | 2 | ||||
-rw-r--r-- | src/components/settings/settings/EditSettingsForm.js | 4 | ||||
-rw-r--r-- | src/containers/settings/EditSettingsScreen.js | 10 | ||||
-rw-r--r-- | src/environment.js | 1 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 11 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 1 | ||||
-rw-r--r-- | src/i18n/locales/pl.json | 1 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 18 | ||||
-rw-r--r-- | src/stores/UIStore.ts | 21 | ||||
-rw-r--r-- | src/styles/layout.scss | 4 | ||||
-rw-r--r-- | src/styles/services.scss | 20 |
11 files changed, 90 insertions, 3 deletions
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index fa866e153..81401b1d2 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -108,7 +108,7 @@ class ServiceView extends Component { | |||
108 | } | 108 | } |
109 | 109 | ||
110 | return ( | 110 | return ( |
111 | <div className={webviewClasses}> | 111 | <div className={webviewClasses} data-name={service.name}> |
112 | {service.isActive && service.isEnabled && ( | 112 | {service.isActive && service.isEnabled && ( |
113 | <> | 113 | <> |
114 | {service.hasCrashed && ( | 114 | {service.hasCrashed && ( |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index f7e0fdd6f..f5a29ff82 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -537,6 +537,10 @@ class EditSettingsForm extends Component { | |||
537 | 537 | ||
538 | <Hr /> | 538 | <Hr /> |
539 | 539 | ||
540 | <Toggle field={form.$('splitMode')} /> | ||
541 | |||
542 | <Hr /> | ||
543 | |||
540 | <Select field={form.$('serviceRibbonWidth')} /> | 544 | <Select field={form.$('serviceRibbonWidth')} /> |
541 | 545 | ||
542 | <Toggle field={form.$('useVerticalStyle')} /> | 546 | <Toggle field={form.$('useVerticalStyle')} /> |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 92985b68c..36b9e949b 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -164,6 +164,10 @@ const messages = defineMessages({ | |||
164 | id: 'settings.app.form.universalDarkMode', | 164 | id: 'settings.app.form.universalDarkMode', |
165 | defaultMessage: 'Enable universal Dark Mode', | 165 | defaultMessage: 'Enable universal Dark Mode', |
166 | }, | 166 | }, |
167 | splitMode: { | ||
168 | id: 'settings.app.form.splitMode', | ||
169 | defaultMessage: 'Enable Split View Mode', | ||
170 | }, | ||
167 | serviceRibbonWidth: { | 171 | serviceRibbonWidth: { |
168 | id: 'settings.app.form.serviceRibbonWidth', | 172 | id: 'settings.app.form.serviceRibbonWidth', |
169 | defaultMessage: 'Sidebar width', | 173 | defaultMessage: 'Sidebar width', |
@@ -288,6 +292,7 @@ class EditSettingsScreen extends Component { | |||
288 | darkMode: Boolean(settingsData.darkMode), | 292 | darkMode: Boolean(settingsData.darkMode), |
289 | adaptableDarkMode: Boolean(settingsData.adaptableDarkMode), | 293 | adaptableDarkMode: Boolean(settingsData.adaptableDarkMode), |
290 | universalDarkMode: Boolean(settingsData.universalDarkMode), | 294 | universalDarkMode: Boolean(settingsData.universalDarkMode), |
295 | splitMode: Boolean(settingsData.splitMode), | ||
291 | serviceRibbonWidth: Number(settingsData.serviceRibbonWidth), | 296 | serviceRibbonWidth: Number(settingsData.serviceRibbonWidth), |
292 | iconSize: Number(settingsData.iconSize), | 297 | iconSize: Number(settingsData.iconSize), |
293 | useVerticalStyle: Boolean(settingsData.useVerticalStyle), | 298 | useVerticalStyle: Boolean(settingsData.useVerticalStyle), |
@@ -580,6 +585,11 @@ class EditSettingsScreen extends Component { | |||
580 | value: settings.all.app.universalDarkMode, | 585 | value: settings.all.app.universalDarkMode, |
581 | default: DEFAULT_APP_SETTINGS.universalDarkMode, | 586 | default: DEFAULT_APP_SETTINGS.universalDarkMode, |
582 | }, | 587 | }, |
588 | splitMode: { | ||
589 | label: intl.formatMessage(messages.splitMode), | ||
590 | value: settings.all.app.splitMode, | ||
591 | default: DEFAULT_APP_SETTINGS.splitMode, | ||
592 | }, | ||
583 | serviceRibbonWidth: { | 593 | serviceRibbonWidth: { |
584 | label: intl.formatMessage(messages.serviceRibbonWidth), | 594 | label: intl.formatMessage(messages.serviceRibbonWidth), |
585 | value: settings.all.app.serviceRibbonWidth, | 595 | value: settings.all.app.serviceRibbonWidth, |
diff --git a/src/environment.js b/src/environment.js index b30e3778d..b315466fc 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -136,6 +136,7 @@ export const DEFAULT_APP_SETTINGS = { | |||
136 | enableSpellchecking: true, | 136 | enableSpellchecking: true, |
137 | spellcheckerLanguage: 'en-us', | 137 | spellcheckerLanguage: 'en-us', |
138 | darkMode: isMac && electronApi.nativeTheme.shouldUseDarkColors, | 138 | darkMode: isMac && electronApi.nativeTheme.shouldUseDarkColors, |
139 | splitMode: false, | ||
139 | locale: '', | 140 | locale: '', |
140 | fallbackLocale: 'en-US', | 141 | fallbackLocale: 'en-US', |
141 | beta: false, | 142 | beta: false, |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 73e882990..db2b69f99 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -190,6 +190,12 @@ export default class WorkspacesStore extends FeatureStore { | |||
190 | setTimeout(() => { | 190 | setTimeout(() => { |
191 | this.isSwitchingWorkspace = false; | 191 | this.isSwitchingWorkspace = false; |
192 | this.nextWorkspace = null; | 192 | this.nextWorkspace = null; |
193 | if (this.stores.settings.app.splitMode) { | ||
194 | const serviceNames = new Set(this.getWorkspaceServices(workspace).map(service => service.name)); | ||
195 | for (const wrapper of document.querySelectorAll('.services__webview-wrapper')) { | ||
196 | wrapper.style.display = serviceNames.has(wrapper.dataset.name) ? '' : 'none'; | ||
197 | } | ||
198 | } | ||
193 | }, 1000); | 199 | }, 1000); |
194 | }; | 200 | }; |
195 | 201 | ||
@@ -205,6 +211,11 @@ export default class WorkspacesStore extends FeatureStore { | |||
205 | // Indicate that we are done switching to the default workspace | 211 | // Indicate that we are done switching to the default workspace |
206 | setTimeout(() => { | 212 | setTimeout(() => { |
207 | this.isSwitchingWorkspace = false; | 213 | this.isSwitchingWorkspace = false; |
214 | if (this.stores.settings.app.splitMode) { | ||
215 | for (const wrapper of document.querySelectorAll('.services__webview-wrapper')) { | ||
216 | wrapper.style.display = ''; | ||
217 | } | ||
218 | } | ||
208 | }, 1000); | 219 | }, 1000); |
209 | }; | 220 | }; |
210 | 221 | ||
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index e2e0cdc83..25eedb456 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -239,6 +239,7 @@ | |||
239 | "settings.app.form.showDisabledServices": "Display disabled services tabs", | 239 | "settings.app.form.showDisabledServices": "Display disabled services tabs", |
240 | "settings.app.form.showDragArea": "Show draggable area on window", | 240 | "settings.app.form.showDragArea": "Show draggable area on window", |
241 | "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", | 241 | "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", |
242 | "settings.app.form.splitMode": "Enable Split View Mode", | ||
242 | "settings.app.form.startMinimized": "Start minimized", | 243 | "settings.app.form.startMinimized": "Start minimized", |
243 | "settings.app.form.universalDarkMode": "Enable universal Dark Mode", | 244 | "settings.app.form.universalDarkMode": "Enable universal Dark Mode", |
244 | "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", | 245 | "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", |
diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index d0bbe725d..2d79744a6 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json | |||
@@ -239,6 +239,7 @@ | |||
239 | "settings.app.form.showDisabledServices": "Wyświetlaj karty wyłączonych usług", | 239 | "settings.app.form.showDisabledServices": "Wyświetlaj karty wyłączonych usług", |
240 | "settings.app.form.showDragArea": "Show draggable area on window", | 240 | "settings.app.form.showDragArea": "Show draggable area on window", |
241 | "settings.app.form.showMessagesBadgesWhenMuted": "Pokaż licznik nieprzeczytanych wiadomości gdy powiadomienia są wyłączone", | 241 | "settings.app.form.showMessagesBadgesWhenMuted": "Pokaż licznik nieprzeczytanych wiadomości gdy powiadomienia są wyłączone", |
242 | "settings.app.form.splitMode": "Włącz tryb podzielony", | ||
242 | "settings.app.form.startMinimized": "Uruchom zminimalizowany", | 243 | "settings.app.form.startMinimized": "Uruchom zminimalizowany", |
243 | "settings.app.form.universalDarkMode": "Włącz uniwersalny tryb ciemny", | 244 | "settings.app.form.universalDarkMode": "Włącz uniwersalny tryb ciemny", |
244 | "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", | 245 | "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 67fd4103f..16defb327 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -163,6 +163,13 @@ export default class ServicesStore extends Store { | |||
163 | ); | 163 | ); |
164 | 164 | ||
165 | reaction( | 165 | reaction( |
166 | () => this.stores.settings.app.splitMode, | ||
167 | () => { | ||
168 | this._shareSettingsWithServiceProcess(); | ||
169 | }, | ||
170 | ); | ||
171 | |||
172 | reaction( | ||
166 | () => this.stores.settings.app.searchEngine, | 173 | () => this.stores.settings.app.searchEngine, |
167 | () => { | 174 | () => { |
168 | this._shareSettingsWithServiceProcess(); | 175 | this._shareSettingsWithServiceProcess(); |
@@ -667,12 +674,21 @@ export default class ServicesStore extends Store { | |||
667 | } | 674 | } |
668 | } | 675 | } |
669 | 676 | ||
670 | @action _focusActiveService() { | 677 | @action _focusActiveService(focusEvent = null) { |
671 | if (this.stores.user.isLoggedIn) { | 678 | if (this.stores.user.isLoggedIn) { |
672 | // TODO: add checks to not focus service when router path is /settings or /auth | 679 | // TODO: add checks to not focus service when router path is /settings or /auth |
673 | const service = this.active; | 680 | const service = this.active; |
674 | if (service) { | 681 | if (service) { |
675 | this._focusService({ serviceId: service.id }); | 682 | this._focusService({ serviceId: service.id }); |
683 | if (this.stores.settings.app.splitMode && !focusEvent) { | ||
684 | setTimeout(() => { | ||
685 | document.querySelector('.services__webview-wrapper.is-active').scrollIntoView({ | ||
686 | behavior: 'smooth', | ||
687 | block: 'end', | ||
688 | inline: 'nearest', | ||
689 | }); | ||
690 | }, 10); | ||
691 | } | ||
676 | } else { | 692 | } else { |
677 | debug('No service is active'); | 693 | debug('No service is active'); |
678 | } | 694 | } |
diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts index ec48eeb40..6ab63c2ee 100644 --- a/src/stores/UIStore.ts +++ b/src/stores/UIStore.ts | |||
@@ -51,6 +51,13 @@ export default class UIStore extends Store { | |||
51 | }, | 51 | }, |
52 | { fireImmediately: true }, | 52 | { fireImmediately: true }, |
53 | ); | 53 | ); |
54 | reaction( | ||
55 | () => this.isSplitModeActive, | ||
56 | () => { | ||
57 | this._setupModeInDOM(); | ||
58 | }, | ||
59 | { fireImmediately: true }, | ||
60 | ); | ||
54 | } | 61 | } |
55 | 62 | ||
56 | @computed get showMessageBadgesEvenWhenMuted() { | 63 | @computed get showMessageBadgesEvenWhenMuted() { |
@@ -77,6 +84,10 @@ export default class UIStore extends Store { | |||
77 | ); | 84 | ); |
78 | } | 85 | } |
79 | 86 | ||
87 | @computed get isSplitModeActive() { | ||
88 | return this.stores.settings.app.splitMode; | ||
89 | } | ||
90 | |||
80 | @computed get theme() { | 91 | @computed get theme() { |
81 | const themeId = | 92 | const themeId = |
82 | this.isDarkThemeActive || this.stores.settings.app.darkMode | 93 | this.isDarkThemeActive || this.stores.settings.app.darkMode |
@@ -114,4 +125,14 @@ export default class UIStore extends Store { | |||
114 | body?.classList.add('theme__dark'); | 125 | body?.classList.add('theme__dark'); |
115 | } | 126 | } |
116 | } | 127 | } |
128 | |||
129 | _setupModeInDOM() { | ||
130 | const body = document.querySelector('body'); | ||
131 | |||
132 | if (!this.isSplitModeActive) { | ||
133 | body?.classList.remove('mode__split'); | ||
134 | } else { | ||
135 | body?.classList.add('mode__split'); | ||
136 | } | ||
137 | } | ||
117 | } | 138 | } |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index 49e041022..b5d4d86d0 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -82,6 +82,10 @@ body.win32:not(.isFullScreen) .app .app__content { | |||
82 | height: calc(100% - 28px); | 82 | height: calc(100% - 28px); |
83 | } | 83 | } |
84 | 84 | ||
85 | .mode__split .app .app__service { | ||
86 | overflow-x: auto; | ||
87 | } | ||
88 | |||
85 | .app { | 89 | .app { |
86 | .app__content { | 90 | .app__content { |
87 | display: flex; | 91 | display: flex; |
diff --git a/src/styles/services.scss b/src/styles/services.scss index 8b8c27e10..dd053e93d 100644 --- a/src/styles/services.scss +++ b/src/styles/services.scss | |||
@@ -18,6 +18,24 @@ | |||
18 | } | 18 | } |
19 | } | 19 | } |
20 | 20 | ||
21 | .mode__split .services { | ||
22 | display: flex; | ||
23 | overflow: visible; | ||
24 | |||
25 | .services__webview { | ||
26 | position: relative; | ||
27 | flex: 1 0 50%; | ||
28 | |||
29 | @media (min-width: 1280px) { | ||
30 | flex-basis: 33.33%; | ||
31 | } | ||
32 | |||
33 | @media (min-width: 2048px) { | ||
34 | flex-basis: 25%; | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
21 | .services { | 39 | .services { |
22 | background: #FFF; | 40 | background: #FFF; |
23 | flex: 1; | 41 | flex: 1; |
@@ -71,7 +89,7 @@ | |||
71 | } | 89 | } |
72 | 90 | ||
73 | .services__info-layer { | 91 | .services__info-layer { |
74 | position: absolut; | 92 | position: absolute; |
75 | z-index: 110; | 93 | z-index: 110; |
76 | } | 94 | } |
77 | 95 | ||