From d303f2e3415237e1a519db21ad4e089c2ba7e9f9 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 23 Dec 2021 21:29:26 +0100 Subject: feat: Add BrowserView and synchronize its position --- packages/renderer/src/components/App.tsx | 42 +++++++ .../src/components/BrowserViewPlaceholder.tsx | 128 +++++++++++++++++++++ packages/renderer/src/components/Sidebar.tsx | 42 +++++++ packages/renderer/src/components/ThemeProvider.tsx | 4 +- .../src/components/ToggleDarkModeButton.tsx | 40 +++++++ packages/renderer/src/index.tsx | 20 +--- packages/renderer/src/stores/RootStore.ts | 26 ++++- 7 files changed, 278 insertions(+), 24 deletions(-) create mode 100644 packages/renderer/src/components/App.tsx create mode 100644 packages/renderer/src/components/BrowserViewPlaceholder.tsx create mode 100644 packages/renderer/src/components/Sidebar.tsx create mode 100644 packages/renderer/src/components/ToggleDarkModeButton.tsx (limited to 'packages/renderer/src') diff --git a/packages/renderer/src/components/App.tsx b/packages/renderer/src/components/App.tsx new file mode 100644 index 0000000..b627fa7 --- /dev/null +++ b/packages/renderer/src/components/App.tsx @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021-2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import Box from '@mui/material/Box'; +import React from 'react'; + +import { BrowserViewPlaceholder } from './BrowserViewPlaceholder'; +import { Sidebar } from './Sidebar'; + +export function App(): JSX.Element { + return ( + + + + + ) +} diff --git a/packages/renderer/src/components/BrowserViewPlaceholder.tsx b/packages/renderer/src/components/BrowserViewPlaceholder.tsx new file mode 100644 index 0000000..06dc7fe --- /dev/null +++ b/packages/renderer/src/components/BrowserViewPlaceholder.tsx @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021-2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { throttle } from 'lodash'; +import { observer } from 'mobx-react-lite'; +import Box from '@mui/material/Box'; +import React, { + useCallback, + useEffect, + useRef, + useState, +} from 'react'; +import type { BrowserViewBounds } from '@sophie/shared'; + +import { useStore } from './StoreProvider'; + +export const BrowserViewPlaceholder = observer(function BrowserViewPlaceholder() { + const { + shared: { + browserViewBounds: { + x: storeX, + y: storeY, + width: storeWidth, + height: storeHeight, + }, + }, + setBrowserViewBounds, + } = useStore(); + + const [ + { + x: currentX, + y: currentY, + width: currentWidth, + height: currentHeight, + }, + setBounds, + ] = useState({ + x: 0, + y: 0, + width: 0, + height: 0, + }); + + useEffect(() => { + if (storeX !== currentX + || storeY !== currentY + || storeWidth !== currentWidth + || storeHeight !== currentHeight) { + setBrowserViewBounds({ + x: currentX, + y: currentY, + width: currentWidth, + height: currentHeight, + }); + } + }, [ + storeX, + storeY, + storeWidth, + storeHeight, + setBrowserViewBounds, + currentX, + currentY, + currentWidth, + currentHeight, + ]); + + const onResize = useCallback(throttle(([boxEntry]: ResizeObserverEntry[]) => { + if (boxEntry) { + const { + x, + y, + width, + height, + } = boxEntry.target.getBoundingClientRect(); + setBounds({ + x, + y, + width, + height, + }); + } + }, 100), [setBounds]); + + const resizeObserverRef = useRef(null); + + const ref = useCallback((box: HTMLElement | null) => { + if (resizeObserverRef.current !== null) { + resizeObserverRef.current.disconnect(); + } + if (box === null) { + resizeObserverRef.current = null; + return; + } + resizeObserverRef.current = new ResizeObserver(onResize); + resizeObserverRef.current.observe(box); + }, [onResize, resizeObserverRef]); + + return ( + + ) +}); diff --git a/packages/renderer/src/components/Sidebar.tsx b/packages/renderer/src/components/Sidebar.tsx new file mode 100644 index 0000000..6c79932 --- /dev/null +++ b/packages/renderer/src/components/Sidebar.tsx @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021-2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import Box from '@mui/material/Box'; +import React from 'react'; + +import { ToggleDarkModeButton } from './ToggleDarkModeButton'; + +export function Sidebar(): JSX.Element { + return ( + ({ + background: theme.palette.divider, + flex: 0, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'flex-end', + padding: 1, + })} + > + + + ); +} diff --git a/packages/renderer/src/components/ThemeProvider.tsx b/packages/renderer/src/components/ThemeProvider.tsx index 7173a9d..9215f5c 100644 --- a/packages/renderer/src/components/ThemeProvider.tsx +++ b/packages/renderer/src/components/ThemeProvider.tsx @@ -27,9 +27,9 @@ import React from 'react'; import { useStore } from './StoreProvider'; -export const ThemeProvider = observer(({ children }: { +export const ThemeProvider = observer(function ThemeProvider({ children }: { children: JSX.Element | JSX.Element[], -}): JSX.Element => { +}) { const { shared: { shouldUseDarkColors } } = useStore(); const theme = createTheme({ diff --git a/packages/renderer/src/components/ToggleDarkModeButton.tsx b/packages/renderer/src/components/ToggleDarkModeButton.tsx new file mode 100644 index 0000000..1b6757e --- /dev/null +++ b/packages/renderer/src/components/ToggleDarkModeButton.tsx @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021-2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { observer } from 'mobx-react-lite'; +import DarkModeIcon from '@mui/icons-material/DarkMode'; +import LightModeIcon from '@mui/icons-material/LightMode'; +import IconButton from '@mui/material/IconButton'; +import React from 'react'; + +import { useStore } from './StoreProvider'; + +export const ToggleDarkModeButton = observer(function ToggleDarkModeButton() { + const { shared: { shouldUseDarkColors }, toggleDarkMode } = useStore(); + + return ( + toggleDarkMode()} + > + {shouldUseDarkColors ? : } + + ); +}); diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx index 901d137..90cba2c 100644 --- a/packages/renderer/src/index.tsx +++ b/packages/renderer/src/index.tsx @@ -22,13 +22,12 @@ import '@fontsource/roboto/300.css'; import '@fontsource/roboto/400.css'; import '@fontsource/roboto/500.css'; import '@fontsource/roboto/700.css'; -import { observer } from 'mobx-react-lite'; -import Button from "@mui/material/Button"; import CssBaseline from "@mui/material/CssBaseline"; import React from 'react'; import { render } from 'react-dom'; -import { StoreProvider, useStore } from './components/StoreProvider'; +import { App } from './components/App'; +import { StoreProvider } from './components/StoreProvider'; import { ThemeProvider } from './components/ThemeProvider'; import { exposeToReduxDevtools } from './devTools'; import { createAndConnectRootStore } from './stores/RootStore'; @@ -41,26 +40,13 @@ if (isDevelopment) { exposeToReduxDevtools(store); } -const Example = observer(() => { - const { shared: { clickCount } } = useStore(); - - return ( - - ); -}); - function Root(): JSX.Element { return ( - + diff --git a/packages/renderer/src/stores/RootStore.ts b/packages/renderer/src/stores/RootStore.ts index f24ea4d..c6533ba 100644 --- a/packages/renderer/src/stores/RootStore.ts +++ b/packages/renderer/src/stores/RootStore.ts @@ -26,10 +26,16 @@ import { Instance, types } from 'mobx-state-tree'; -import { sharedStore, SophieRenderer } from '@sophie/shared'; +import { + BrowserViewBounds, + emptySharedStore, + PaletteMode, + sharedStore, + SophieRenderer, +} from '@sophie/shared'; export interface RootEnv { - ipc: SophieRenderer; + ipc: Omit; } /** @@ -46,8 +52,18 @@ export function getEnv(model: IAnyStateTreeNode): RootEnv { export const rootStore = types.model('RootStore', { shared: sharedStore, }).actions((self) => ({ - buttonClick() { - getEnv(self).ipc.buttonClick(); + setBrowserViewBounds(bounds: BrowserViewBounds) { + getEnv(self).ipc.setBrowserViewBounds(bounds); + }, + setPaletteMode(mode: PaletteMode) { + getEnv(self).ipc.setPaletteMode(mode); + }, + toggleDarkMode() { + if (self.shared.shouldUseDarkColors) { + this.setPaletteMode('light'); + } else { + this.setPaletteMode('dark'); + } }, })); @@ -63,7 +79,7 @@ export interface RootStore extends Instance {} */ export function createAndConnectRootStore(ipc: SophieRenderer): RootStore { const store = rootStore.create({ - shared: {}, + shared: emptySharedStore, }, { ipc, }); -- cgit v1.2.3-54-g00ecf