diff --git a/desktop/main.cjs b/desktop/main.cjs --- a/desktop/main.cjs +++ b/desktop/main.cjs @@ -1,4 +1,4 @@ -const { app, BrowserWindow, shell, Menu } = require('electron'); +const { app, BrowserWindow, shell, Menu, ipcMain } = require('electron'); const fs = require('fs'); const path = require('path'); @@ -71,10 +71,23 @@ trafficLightPosition: { x: 20, y: 24 }, backgroundColor: '#0a0a0a', webPreferences: { + preload: path.join(__dirname, 'preload.cjs'), devTools: isDev, }, }); + const updateNavigationState = () => { + win.webContents.send('on-navigate', { + canGoBack: win.webContents.canGoBack(), + canGoForward: win.webContents.canGoForward(), + }); + }; + win.webContents.on('did-navigate-in-page', updateNavigationState); + ipcMain.on('clear-history', () => { + win.webContents.clearHistory(); + updateNavigationState(); + }); + win.webContents.setWindowOpenHandler(({ url: openURL }) => { shell.openExternal(openURL); // Returning 'deny' prevents a new electron window from being created diff --git a/desktop/preload.cjs b/desktop/preload.cjs new file mode 100644 --- /dev/null +++ b/desktop/preload.cjs @@ -0,0 +1,12 @@ +const { contextBridge, ipcRenderer } = require('electron'); + +const bridge = { + onNavigate: callback => { + const withEvent = (event, ...args) => callback(...args); + ipcRenderer.on('on-navigate', withEvent); + return () => ipcRenderer.removeListener('on-navigate', withEvent); + }, + clearHistory: () => ipcRenderer.send('clear-history'), +}; + +contextBridge.exposeInMainWorld('electronContextBridge', bridge); diff --git a/web/app.react.js b/web/app.react.js --- a/web/app.react.js +++ b/web/app.react.js @@ -32,6 +32,7 @@ import Chat from './chat/chat.react'; import { TooltipProvider } from './chat/tooltip-provider'; import NavigationArrows from './components/navigation-arrows.react'; +import electron from './electron'; import InputStateContainer from './input/input-state-container.react'; import LoadingIndicator from './loading-indicator.react'; import { MenuProvider } from './menu-provider.react'; @@ -127,6 +128,9 @@ history.replace(newURL); } } + if (loggedIn !== prevProps.loggedIn) { + electron?.clearHistory(); + } } onWordmarkClicked = () => { @@ -175,9 +179,8 @@ } } - const shouldShowNavigationArrows = false; let navigationArrows = null; - if (shouldShowNavigationArrows) { + if (electron) { navigationArrows = ; } diff --git a/web/components/navigation-arrows.css b/web/components/navigation-arrows.css --- a/web/components/navigation-arrows.css +++ b/web/components/navigation-arrows.css @@ -8,3 +8,8 @@ display: flex; align-items: center; } + +.disabled { + pointer-events: none; + color: var(--color-disabled); +} diff --git a/web/components/navigation-arrows.react.js b/web/components/navigation-arrows.react.js --- a/web/components/navigation-arrows.react.js +++ b/web/components/navigation-arrows.react.js @@ -1,7 +1,9 @@ // @flow +import classnames from 'classnames'; import * as React from 'react'; +import electron from '../electron.js'; import history from '../router-history.js'; import SWMansionIcon from '../SWMansionIcon.react.js'; import css from './navigation-arrows.css'; @@ -16,12 +18,33 @@ [], ); + const [disableBack, setDisableBack] = React.useState(false); + const [disableFoward, setDisableForward] = React.useState(false); + + React.useEffect( + () => + electron?.onNavigate(({ canGoBack, canGoForward }) => { + setDisableBack(!canGoBack); + setDisableForward(!canGoForward); + }), + [], + ); + + const goBackClasses = React.useMemo( + () => classnames(css.button, { [css.disabled]: disableBack }), + [disableBack], + ); + const goForwardClasses = React.useMemo( + () => classnames(css.button, { [css.disabled]: disableFoward }), + [disableFoward], + ); + return (
- + - +
diff --git a/web/electron.js b/web/electron.js new file mode 100644 --- /dev/null +++ b/web/electron.js @@ -0,0 +1,16 @@ +// @flow + +declare var electronContextBridge; + +type OnNavigateListener = ({ + canGoBack: boolean, + canGoForward: boolean, +}) => void; + +const electron: null | { + // Returns a callback that you can call to remove the listener + +onNavigate: OnNavigateListener => () => void, + +clearHistory: () => void, +} = typeof electronContextBridge === 'undefined' ? null : electronContextBridge; + +export default electron;