aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-02-27 01:52:55 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-03-06 18:56:47 +0100
commit098d6f9bb1fd26f2d192db497992ab95b258ce55 (patch)
tree22905f87e6ad53032b6ff39bb3af274df2f6287c
parentrefactor: Shared model type factories (diff)
downloadsophie-098d6f9bb1fd26f2d192db497992ab95b258ce55.tar.gz
sophie-098d6f9bb1fd26f2d192db497992ab95b258ce55.tar.zst
sophie-098d6f9bb1fd26f2d192db497992ab95b258ce55.zip
feat: Location bar actions
The buttons and the text field in the location bar shall now affect the BrowserView of the loaded service. Some error handling is still needed, e.g., when loading a web page fails due to a DNS error. Signed-off-by: Kristóf Marussy <kristof@marussy.com>
-rw-r--r--packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts12
-rw-r--r--packages/main/src/infrastructure/electron/types.ts4
-rw-r--r--packages/main/src/stores/MainStore.ts21
-rw-r--r--packages/main/src/stores/Service.ts60
-rw-r--r--packages/renderer/src/components/locationBar/GoAdornment.tsx9
-rw-r--r--packages/renderer/src/components/locationBar/LocationTextField.tsx19
-rw-r--r--packages/renderer/src/components/locationBar/NavigationButtons.tsx16
-rw-r--r--packages/renderer/src/stores/Service.ts46
-rw-r--r--packages/shared/src/contextBridge/SophieRenderer.ts2
-rw-r--r--packages/shared/src/index.ts8
-rw-r--r--packages/shared/src/schemas/Action.ts (renamed from packages/shared/src/schemas.ts)29
-rw-r--r--packages/shared/src/schemas/BrowserViewBounds.ts35
-rw-r--r--packages/shared/src/schemas/ServiceAction.ts51
-rw-r--r--packages/shared/src/schemas/ThemeSource.ts29
-rw-r--r--packages/shared/src/stores/GlobalSettingsBase.ts2
15 files changed, 304 insertions, 39 deletions
diff --git a/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts b/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
index 6ff8e21..e5fdf11 100644
--- a/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
+++ b/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
@@ -105,6 +105,18 @@ export default class ElectronServiceView implements ServiceView {
105 this.browserView.webContents.goForward(); 105 this.browserView.webContents.goForward();
106 } 106 }
107 107
108 reload(ignoreCache: boolean): void {
109 if (ignoreCache) {
110 this.browserView.webContents.reloadIgnoringCache();
111 } else {
112 this.browserView.webContents.reload();
113 }
114 }
115
116 stop(): void {
117 this.browserView.webContents.stop();
118 }
119
108 setBounds(bounds: BrowserViewBounds): void { 120 setBounds(bounds: BrowserViewBounds): void {
109 this.browserView.setBounds(bounds); 121 this.browserView.setBounds(bounds);
110 } 122 }
diff --git a/packages/main/src/infrastructure/electron/types.ts b/packages/main/src/infrastructure/electron/types.ts
index 9f03214..63974ce 100644
--- a/packages/main/src/infrastructure/electron/types.ts
+++ b/packages/main/src/infrastructure/electron/types.ts
@@ -61,6 +61,10 @@ export interface ServiceView {
61 61
62 goForward(): void; 62 goForward(): void;
63 63
64 reload(ignoreCache: boolean): void;
65
66 stop(): void;
67
64 setBounds(bounds: BrowserViewBounds): void; 68 setBounds(bounds: BrowserViewBounds): void;
65 69
66 dispose(): void; 70 dispose(): void;
diff --git a/packages/main/src/stores/MainStore.ts b/packages/main/src/stores/MainStore.ts
index cb4f4c9..bf351d7 100644
--- a/packages/main/src/stores/MainStore.ts
+++ b/packages/main/src/stores/MainStore.ts
@@ -74,9 +74,6 @@ const MainStore = types
74 }, 74 },
75 dispatch(action: Action): void { 75 dispatch(action: Action): void {
76 switch (action.action) { 76 switch (action.action) {
77 case 'reload-all-services':
78 // TODO
79 break;
80 case 'set-browser-view-bounds': 77 case 'set-browser-view-bounds':
81 this.setBrowserViewBounds(action.browserViewBounds); 78 this.setBrowserViewBounds(action.browserViewBounds);
82 break; 79 break;
@@ -89,6 +86,24 @@ const MainStore = types
89 case 'set-show-location-bar': 86 case 'set-show-location-bar':
90 self.settings.setShowLocationBar(action.showLocationBar); 87 self.settings.setShowLocationBar(action.showLocationBar);
91 break; 88 break;
89 case 'reload-all-services':
90 // TODO
91 break;
92 case 'dispatch-service-action': {
93 const { serviceId, serviceAction } = action;
94 const service = self.shared.servicesById.get(serviceId);
95 if (service === undefined) {
96 log.error(
97 'No such service',
98 serviceId,
99 'to dispatch action',
100 serviceAction,
101 );
102 } else {
103 service.dispatch(serviceAction);
104 }
105 break;
106 }
92 default: 107 default:
93 log.error('Unknown action to dispatch', action); 108 log.error('Unknown action to dispatch', action);
94 break; 109 break;
diff --git a/packages/main/src/stores/Service.ts b/packages/main/src/stores/Service.ts
index abef7c2..cbd8662 100644
--- a/packages/main/src/stores/Service.ts
+++ b/packages/main/src/stores/Service.ts
@@ -19,14 +19,17 @@
19 */ 19 */
20 20
21import type { UnreadCount } from '@sophie/service-shared'; 21import type { UnreadCount } from '@sophie/service-shared';
22import { defineServiceModel } from '@sophie/shared'; 22import { defineServiceModel, ServiceAction } from '@sophie/shared';
23import { Instance, getSnapshot } from 'mobx-state-tree'; 23import { Instance, getSnapshot } from 'mobx-state-tree';
24 24
25import type { ServiceView } from '../infrastructure/electron/types'; 25import type { ServiceView } from '../infrastructure/electron/types';
26import { getLogger } from '../utils/log';
26 27
27import ServiceSettings from './ServiceSettings'; 28import ServiceSettings from './ServiceSettings';
28import type ServiceConfig from './config/ServiceConfig'; 29import type ServiceConfig from './config/ServiceConfig';
29 30
31const log = getLogger('Service');
32
30const Service = defineServiceModel(ServiceSettings) 33const Service = defineServiceModel(ServiceSettings)
31 .views((self) => ({ 34 .views((self) => ({
32 get config(): ServiceConfig { 35 get config(): ServiceConfig {
@@ -87,6 +90,61 @@ const Service = defineServiceModel(ServiceSettings)
87 setServiceView(serviceView: ServiceView | undefined): void { 90 setServiceView(serviceView: ServiceView | undefined): void {
88 self.serviceView = serviceView; 91 self.serviceView = serviceView;
89 }, 92 },
93 goBack(): void {
94 self.serviceView?.goBack();
95 },
96 goForward(): void {
97 self.serviceView?.goForward();
98 },
99 reload(ignoreCache = false): void {
100 if (self.serviceView === undefined) {
101 this.startedLoading();
102 } else {
103 self.serviceView?.reload(ignoreCache);
104 }
105 },
106 stop(): void {
107 self.serviceView?.stop();
108 },
109 go(url: string): void {
110 if (self.serviceView === undefined) {
111 self.currentUrl = url;
112 this.startedLoading();
113 } else {
114 self.serviceView?.loadURL(url).catch((error) => {
115 log.warn('Error while loading', url, error);
116 this.crashed();
117 });
118 }
119 },
120 goHome(): void {
121 this.go(self.settings.url);
122 },
123 dispatch(action: ServiceAction): void {
124 switch (action.action) {
125 case 'back':
126 this.goBack();
127 break;
128 case 'forward':
129 this.goForward();
130 break;
131 case 'reload':
132 this.reload(action.ignoreCache);
133 break;
134 case 'stop':
135 this.stop();
136 break;
137 case 'go-home':
138 this.goHome();
139 break;
140 case 'go':
141 this.go(action.url);
142 break;
143 default:
144 log.error('Unknown action to dispatch', action);
145 break;
146 }
147 },
90 })); 148 }));
91 149
92/* 150/*
diff --git a/packages/renderer/src/components/locationBar/GoAdornment.tsx b/packages/renderer/src/components/locationBar/GoAdornment.tsx
index 43c8b7b..f049b8e 100644
--- a/packages/renderer/src/components/locationBar/GoAdornment.tsx
+++ b/packages/renderer/src/components/locationBar/GoAdornment.tsx
@@ -20,11 +20,15 @@
20 20
21import IconGo from '@mui/icons-material/Send'; 21import IconGo from '@mui/icons-material/Send';
22import Button from '@mui/material/Button'; 22import Button from '@mui/material/Button';
23import React from 'react'; 23import React, { MouseEventHandler } from 'react';
24 24
25import ButtonAdornment, { NO_LABEL_BUTTON_CLASS_NAME } from './ButtonAdornment'; 25import ButtonAdornment, { NO_LABEL_BUTTON_CLASS_NAME } from './ButtonAdornment';
26 26
27export default function GoAdornment(): JSX.Element { 27export default function GoAdornment({
28 onClick,
29}: {
30 onClick: MouseEventHandler<HTMLButtonElement>;
31}): JSX.Element {
28 return ( 32 return (
29 <ButtonAdornment position="end"> 33 <ButtonAdornment position="end">
30 <Button 34 <Button
@@ -32,6 +36,7 @@ export default function GoAdornment(): JSX.Element {
32 color="inherit" 36 color="inherit"
33 startIcon={<IconGo />} 37 startIcon={<IconGo />}
34 className={NO_LABEL_BUTTON_CLASS_NAME} 38 className={NO_LABEL_BUTTON_CLASS_NAME}
39 onClick={onClick}
35 /> 40 />
36 </ButtonAdornment> 41 </ButtonAdornment>
37 ); 42 );
diff --git a/packages/renderer/src/components/locationBar/LocationTextField.tsx b/packages/renderer/src/components/locationBar/LocationTextField.tsx
index e6da59f..e711abc 100644
--- a/packages/renderer/src/components/locationBar/LocationTextField.tsx
+++ b/packages/renderer/src/components/locationBar/LocationTextField.tsx
@@ -94,9 +94,18 @@ function LocationTextField({
94 setChanged(true); 94 setChanged(true);
95 }} 95 }}
96 onKeyUp={(event) => { 96 onKeyUp={(event) => {
97 if (event.key === 'Escape') { 97 switch (event.key) {
98 resetValue(); 98 case 'Escape':
99 event.preventDefault(); 99 resetValue();
100 event.preventDefault();
101 break;
102 case 'Enter':
103 service?.go(value);
104 event.preventDefault();
105 break;
106 default:
107 // Nothing to do, let the key event through.
108 break;
100 } 109 }
101 }} 110 }}
102 size="small" 111 size="small"
@@ -106,7 +115,9 @@ function LocationTextField({
106 startAdornment={ 115 startAdornment={
107 <UrlAdornment changed={changed} splitResult={splitResult} /> 116 <UrlAdornment changed={changed} splitResult={splitResult} />
108 } 117 }
109 endAdornment={changed ? <GoAdornment /> : undefined} 118 endAdornment={
119 changed ? <GoAdornment onClick={() => service?.go(value)} /> : undefined
120 }
110 value={value} 121 value={value}
111 /> 122 />
112 ); 123 );
diff --git a/packages/renderer/src/components/locationBar/NavigationButtons.tsx b/packages/renderer/src/components/locationBar/NavigationButtons.tsx
index ce59692..e71d3d8 100644
--- a/packages/renderer/src/components/locationBar/NavigationButtons.tsx
+++ b/packages/renderer/src/components/locationBar/NavigationButtons.tsx
@@ -48,25 +48,35 @@ function NavigationButtons({
48 <IconButton 48 <IconButton
49 aria-label="Back" 49 aria-label="Back"
50 disabled={service === undefined || !service.canGoBack} 50 disabled={service === undefined || !service.canGoBack}
51 onClick={() => service?.goBack()}
51 > 52 >
52 {direction === 'ltr' ? <IconArrowBack /> : <IconArrowForward />} 53 {direction === 'ltr' ? <IconArrowBack /> : <IconArrowForward />}
53 </IconButton> 54 </IconButton>
54 <IconButton 55 <IconButton
55 aria-label="Forward" 56 aria-label="Forward"
56 disabled={service === undefined || !service.canGoForward} 57 disabled={service === undefined || !service.canGoForward}
58 onClick={() => service?.goForward()}
57 > 59 >
58 {direction === 'ltr' ? <IconArrowForward /> : <IconArrowBack />} 60 {direction === 'ltr' ? <IconArrowForward /> : <IconArrowBack />}
59 </IconButton> 61 </IconButton>
60 {service?.state === 'loading' ? ( 62 {service?.state === 'loading' ? (
61 <IconButton aria-label="Stop"> 63 <IconButton aria-label="Stop" onClick={() => service?.stop()}>
62 <IconStop /> 64 <IconStop />
63 </IconButton> 65 </IconButton>
64 ) : ( 66 ) : (
65 <IconButton aria-label="Refresh" disabled={service === undefined}> 67 <IconButton
68 aria-label="Refresh"
69 disabled={service === undefined}
70 onClick={(event) => service?.reload(event.shiftKey)}
71 >
66 <IconRefresh /> 72 <IconRefresh />
67 </IconButton> 73 </IconButton>
68 )} 74 )}
69 <IconButton aria-label="Home" disabled={service === undefined}> 75 <IconButton
76 aria-label="Home"
77 disabled={service === undefined}
78 onClick={() => service?.goHome()}
79 >
70 <IconHome /> 80 <IconHome />
71 </IconButton> 81 </IconButton>
72 </Box> 82 </Box>
diff --git a/packages/renderer/src/stores/Service.ts b/packages/renderer/src/stores/Service.ts
index c2c938a..7878ea0 100644
--- a/packages/renderer/src/stores/Service.ts
+++ b/packages/renderer/src/stores/Service.ts
@@ -18,12 +18,54 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { defineServiceModel } from '@sophie/shared'; 21import { defineServiceModel, ServiceAction } from '@sophie/shared';
22import { Instance } from 'mobx-state-tree'; 22import { Instance } from 'mobx-state-tree';
23 23
24import getEnv from '../env/getEnv';
25
24import ServiceSettings from './ServiceSettings'; 26import ServiceSettings from './ServiceSettings';
25 27
26const Service = defineServiceModel(ServiceSettings); 28const Service = defineServiceModel(ServiceSettings).actions((self) => ({
29 dispatch(serviceAction: ServiceAction): void {
30 getEnv(self).dispatchMainAction({
31 action: 'dispatch-service-action',
32 serviceId: self.id,
33 serviceAction,
34 });
35 },
36 goBack(): void {
37 this.dispatch({
38 action: 'back',
39 });
40 },
41 goForward(): void {
42 this.dispatch({
43 action: 'forward',
44 });
45 },
46 reload(ignoreCache = false): void {
47 this.dispatch({
48 action: 'reload',
49 ignoreCache,
50 });
51 },
52 stop(): void {
53 this.dispatch({
54 action: 'stop',
55 });
56 },
57 go(url: string): void {
58 this.dispatch({
59 action: 'go',
60 url,
61 });
62 },
63 goHome(): void {
64 this.dispatch({
65 action: 'go-home',
66 });
67 },
68}));
27 69
28/* 70/*
29 eslint-disable-next-line @typescript-eslint/no-redeclare -- 71 eslint-disable-next-line @typescript-eslint/no-redeclare --
diff --git a/packages/shared/src/contextBridge/SophieRenderer.ts b/packages/shared/src/contextBridge/SophieRenderer.ts
index 9e087da..dc77c97 100644
--- a/packages/shared/src/contextBridge/SophieRenderer.ts
+++ b/packages/shared/src/contextBridge/SophieRenderer.ts
@@ -18,7 +18,7 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { Action } from '../schemas'; 21import { Action } from '../schemas/Action';
22import { SharedStoreListener } from '../stores/SharedStoreBase'; 22import { SharedStoreListener } from '../stores/SharedStoreBase';
23 23
24export default interface SophieRenderer { 24export default interface SophieRenderer {
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index 66debf7..fa3fbfd 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -22,7 +22,13 @@ export type { default as SophieRenderer } from './contextBridge/SophieRenderer';
22 22
23export { MainToRendererIpcMessage, RendererToMainIpcMessage } from './ipc'; 23export { MainToRendererIpcMessage, RendererToMainIpcMessage } from './ipc';
24 24
25export { Action, BrowserViewBounds, ThemeSource } from './schemas'; 25export { Action } from './schemas/Action';
26
27export { BrowserViewBounds } from './schemas/BrowserViewBounds';
28
29export { ServiceAction } from './schemas/ServiceAction';
30
31export { ThemeSource } from './schemas/ThemeSource';
26 32
27export type { 33export type {
28 GlobalSettingsSnapshotIn, 34 GlobalSettingsSnapshotIn,
diff --git a/packages/shared/src/schemas.ts b/packages/shared/src/schemas/Action.ts
index 9d87d10..d5d0a8d 100644
--- a/packages/shared/src/schemas.ts
+++ b/packages/shared/src/schemas/Action.ts
@@ -20,27 +20,9 @@
20 20
21import { z } from 'zod'; 21import { z } from 'zod';
22 22
23export const BrowserViewBounds = /* @__PURE__ */ (() => 23import { BrowserViewBounds } from './BrowserViewBounds';
24 z.object({ 24import { ServiceAction } from './ServiceAction';
25 x: z.number().int().nonnegative(), 25import { ThemeSource } from './ThemeSource';
26 y: z.number().int().nonnegative(),
27 width: z.number().int().nonnegative(),
28 height: z.number().int().nonnegative(),
29 }))();
30
31/*
32 eslint-disable-next-line @typescript-eslint/no-redeclare --
33 Intentionally naming the type the same as the schema definition.
34*/
35export type BrowserViewBounds = z.infer<typeof BrowserViewBounds>;
36
37export const ThemeSource = /* @__PURE__ */ z.enum(['system', 'light', 'dark']);
38
39/*
40 eslint-disable-next-line @typescript-eslint/no-redeclare --
41 Intentionally naming the type the same as the schema definition.
42*/
43export type ThemeSource = z.infer<typeof ThemeSource>;
44 26
45export const Action = /* @__PURE__ */ (() => 27export const Action = /* @__PURE__ */ (() =>
46 z.union([ 28 z.union([
@@ -63,6 +45,11 @@ export const Action = /* @__PURE__ */ (() =>
63 z.object({ 45 z.object({
64 action: z.literal('reload-all-services'), 46 action: z.literal('reload-all-services'),
65 }), 47 }),
48 z.object({
49 action: z.literal('dispatch-service-action'),
50 serviceId: z.string(),
51 serviceAction: ServiceAction,
52 }),
66 ]))(); 53 ]))();
67 54
68/* 55/*
diff --git a/packages/shared/src/schemas/BrowserViewBounds.ts b/packages/shared/src/schemas/BrowserViewBounds.ts
new file mode 100644
index 0000000..e668a4a
--- /dev/null
+++ b/packages/shared/src/schemas/BrowserViewBounds.ts
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { z } from 'zod';
22
23export const BrowserViewBounds = /* @__PURE__ */ (() =>
24 z.object({
25 x: z.number().int().nonnegative(),
26 y: z.number().int().nonnegative(),
27 width: z.number().int().nonnegative(),
28 height: z.number().int().nonnegative(),
29 }))();
30
31/*
32 eslint-disable-next-line @typescript-eslint/no-redeclare --
33 Intentionally naming the type the same as the schema definition.
34*/
35export type BrowserViewBounds = z.infer<typeof BrowserViewBounds>;
diff --git a/packages/shared/src/schemas/ServiceAction.ts b/packages/shared/src/schemas/ServiceAction.ts
new file mode 100644
index 0000000..a4a7049
--- /dev/null
+++ b/packages/shared/src/schemas/ServiceAction.ts
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { z } from 'zod';
22
23export const ServiceAction = /* @__PURE__ */ (() =>
24 z.union([
25 z.object({
26 action: z.literal('back'),
27 }),
28 z.object({
29 action: z.literal('forward'),
30 }),
31 z.object({
32 action: z.literal('reload'),
33 ignoreCache: z.boolean(),
34 }),
35 z.object({
36 action: z.literal('stop'),
37 }),
38 z.object({
39 action: z.literal('go-home'),
40 }),
41 z.object({
42 action: z.literal('go'),
43 url: z.string(),
44 }),
45 ]))();
46
47/*
48 eslint-disable-next-line @typescript-eslint/no-redeclare --
49 Intentionally naming the type the same as the schema definition.
50*/
51export type ServiceAction = z.infer<typeof ServiceAction>;
diff --git a/packages/shared/src/schemas/ThemeSource.ts b/packages/shared/src/schemas/ThemeSource.ts
new file mode 100644
index 0000000..6db5788
--- /dev/null
+++ b/packages/shared/src/schemas/ThemeSource.ts
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { z } from 'zod';
22
23export const ThemeSource = /* @__PURE__ */ z.enum(['system', 'light', 'dark']);
24
25/*
26 eslint-disable-next-line @typescript-eslint/no-redeclare --
27 Intentionally naming the type the same as the schema definition.
28*/
29export type ThemeSource = z.infer<typeof ThemeSource>;
diff --git a/packages/shared/src/stores/GlobalSettingsBase.ts b/packages/shared/src/stores/GlobalSettingsBase.ts
index 48092fd..1bd0628 100644
--- a/packages/shared/src/stores/GlobalSettingsBase.ts
+++ b/packages/shared/src/stores/GlobalSettingsBase.ts
@@ -26,7 +26,7 @@ import {
26 IAnyModelType, 26 IAnyModelType,
27} from 'mobx-state-tree'; 27} from 'mobx-state-tree';
28 28
29import { ThemeSource } from '../schemas'; 29import { ThemeSource } from '../schemas/ThemeSource';
30 30
31import ServiceBase from './ServiceBase'; 31import ServiceBase from './ServiceBase';
32 32