diff --git a/frontend/app/view/webview/webview.less b/frontend/app/view/webview/webview.less index ed104a478..d84d5ccda 100644 --- a/frontend/app/view/webview/webview.less +++ b/frontend/app/view/webview/webview.less @@ -9,6 +9,7 @@ overflow: hidden; padding: 0; margin: 0; + user-select: none; // try to force pixel alignment to prevent // subpixel rendering artifacts @@ -16,6 +17,24 @@ will-change: transform; } +.webview-error { + display: flex; + position: absolute; + background-color: black; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 100; + div { + font-size: x-large; + color: red; + display: flex; + margin: auto; + padding: 30px; + } +} + .block-frame-div-url { background: rgba(255, 255, 255, 0.1); diff --git a/frontend/app/view/webview/webview.tsx b/frontend/app/view/webview/webview.tsx index 376e8e9c5..d9f038a73 100644 --- a/frontend/app/view/webview/webview.tsx +++ b/frontend/app/view/webview/webview.tsx @@ -13,7 +13,7 @@ import { fireAndForget } from "@/util/util"; import clsx from "clsx"; import { WebviewTag } from "electron"; import { Atom, PrimitiveAtom, atom, useAtomValue } from "jotai"; -import React, { memo, useEffect, useState } from "react"; +import { Fragment, createRef, memo, useEffect, useRef, useState } from "react"; import "./webview.less"; let webviewPreloadUrl = null; @@ -68,8 +68,8 @@ export class WebViewModel implements ViewModel { this.refreshIcon = atom("rotate-right"); this.viewIcon = atom("globe"); this.viewName = atom("Web"); - this.urlInputRef = React.createRef(); - this.webviewRef = React.createRef(); + this.urlInputRef = createRef(); + this.webviewRef = createRef(); this.mediaPlaying = atom(false); this.mediaMuted = atom(false); @@ -477,7 +477,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => { const defaultSearch = useAtomValue(defaultSearchAtom); let metaUrl = blockData?.meta?.url || defaultUrl; metaUrl = model.ensureUrlScheme(metaUrl, defaultSearch); - const metaUrlRef = React.useRef(metaUrl); + const metaUrlRef = useRef(metaUrl); // The initial value of the block metadata URL when the component first renders. Used to set the starting src value for the webview. const [metaUrlInitial] = useState(metaUrl); @@ -485,6 +485,8 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => { const [webContentsId, setWebContentsId] = useState(null); const [domReady, setDomReady] = useState(false); + const [errorText, setErrorText] = useState(""); + function setBgColor() { const webview = model.webviewRef.current; if (!webview) { @@ -532,6 +534,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => { return; } const navigateListener = (e: any) => { + setErrorText(""); model.handleNavigate(e.url); }; const newWindowHandler = (e: any) => { @@ -554,7 +557,9 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => { if (e.errorCode === -3) { console.warn("Suppressed ERR_ABORTED error", e); } else { - console.error(`Failed to load ${e.validatedURL}: ${e.errorDescription}`); + const errorMessage = `Failed to load ${e.validatedURL}: ${e.errorDescription}`; + console.error(errorMessage); + setErrorText(errorMessage); if (onFailLoad) { const curUrl = model.webviewRef?.current.getURL(); onFailLoad(curUrl); @@ -608,17 +613,24 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => { }, []); return ( - + + + {errorText && ( +
+
{errorText}
+
+ )} +
); });