import { bookmarks, HOME_PAGE } from "components/apps/Browser/config"; import { Arrow, Refresh, Stop } from "components/apps/Browser/NavigationIcons"; import StyledBrowser from "components/apps/Browser/StyledBrowser"; import type { ComponentProcessProps } from "components/system/Apps/RenderComponent"; import useTitle from "components/system/Window/useTitle"; import { useFileSystem } from "contexts/fileSystem"; import { useProcesses } from "contexts/process"; import processDirectory from "contexts/process/directory"; import useHistory from "hooks/useHistory"; import { extname } from "path"; import { useCallback, useEffect, useRef, useState } from "react"; import Button from "styles/common/Button"; import Icon from "styles/common/Icon"; import { FAVICON_BASE_PATH, IFRAME_CONFIG, ONE_TIME_PASSIVE_EVENT, } from "utils/constants"; import { getUrlOrSearch, GOOGLE_SEARCH_QUERY, label } from "utils/functions"; const Browser: FC = ({ id }) => { const { icon: setIcon, linkElement, url: changeUrl, processes: { [id]: process }, } = useProcesses(); const { prependFileToTitle } = useTitle(id); const { url = "" } = process || {}; const initialUrl = url || HOME_PAGE; const { canGoBack, canGoForward, history, moveHistory, position } = useHistory(initialUrl, id); const { exists, readFile } = useFileSystem(); const inputRef = useRef(null); const iframeRef = useRef(null); const [loading, setLoading] = useState(false); const [srcDoc, setSrcDoc] = useState(""); const changeHistory = (step: number): void => { moveHistory(step); if (inputRef.current) inputRef.current.value = history[position + step]; }; const currentUrl = useRef(""); const setUrl = useCallback( async (addressInput: string): Promise => { const { contentWindow } = iframeRef.current || {}; if (contentWindow?.location) { const isHtml = [".htm", ".html"].includes(extname(addressInput).toLowerCase()) && (await exists(addressInput)); setLoading(true); setSrcDoc(""); if (isHtml) setSrcDoc((await readFile(addressInput)).toString()); setIcon(id, processDirectory.Browser.icon); if (!isHtml) { const addressUrl = await getUrlOrSearch(addressInput); contentWindow.location.replace(addressUrl); if (addressUrl.startsWith(GOOGLE_SEARCH_QUERY)) { prependFileToTitle(`${addressInput} - Google Search`); } else { const { name = "" } = bookmarks?.find( ({ url: bookmarkUrl }) => bookmarkUrl === addressInput ) || {}; prependFileToTitle(name); } if (addressInput.startsWith("ipfs://")) { setIcon(id, "/System/Icons/Favicons/ipfs.webp"); } else { const favicon = new Image(); const faviconUrl = `${ new URL(addressUrl).origin }${FAVICON_BASE_PATH}`; favicon.addEventListener( "error", () => { const { icon } = bookmarks?.find( ({ url: bookmarkUrl }) => bookmarkUrl === addressUrl ) || {}; if (icon) setIcon(id, icon); }, ONE_TIME_PASSIVE_EVENT ); favicon.addEventListener( "load", () => setIcon(id, faviconUrl), ONE_TIME_PASSIVE_EVENT ); favicon.src = faviconUrl; } } } }, [exists, id, prependFileToTitle, readFile, setIcon] ); useEffect(() => { if (process && history[position] !== currentUrl.current) { currentUrl.current = history[position]; setUrl(history[position]); } }, [history, position, process, setUrl]); useEffect(() => { if (iframeRef?.current) { linkElement(id, "peekElement", iframeRef.current); } }, [id, linkElement]); return (