Browser search, icon & html support

This commit is contained in:
Dustin Brett
2021-11-13 22:57:25 -08:00
parent 5b4e67b9b6
commit 447d8b47ca
4 changed files with 58 additions and 8 deletions

View File

@@ -2,13 +2,19 @@ import { config, 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 { useFileSystem } from "contexts/fileSystem";
import { useProcesses } from "contexts/process";
import processDirectory from "contexts/process/directory";
import { extname } from "path";
import { useCallback, useEffect, useRef, useState } from "react";
import Button from "styles/common/Button";
import { ONE_TIME_PASSIVE_EVENT } from "utils/constants";
import { isValidUrl } from "utils/functions";
import useHistory from "utils/useHistory";
const Browser = ({ id }: ComponentProcessProps): JSX.Element => {
const {
icon: setIcon,
url: changeUrl,
processes: { [id]: process },
} = useProcesses();
@@ -16,22 +22,49 @@ const Browser = ({ id }: ComponentProcessProps): JSX.Element => {
const initialUrl = url || HOME_PAGE;
const { canGoBack, canGoForward, history, moveHistory, position } =
useHistory(initialUrl, id);
const { exists, readFile } = useFileSystem();
const inputRef = useRef<HTMLInputElement | null>(null);
const iframeRef = useRef<HTMLIFrameElement | null>(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 setUrl = useCallback((newUrl: string): void => {
const { contentWindow } = iframeRef.current || {};
const setUrl = useCallback(
async (addressInput: string): Promise<void> => {
const { contentWindow } = iframeRef.current || {};
if (contentWindow?.location) {
setLoading(true);
contentWindow.location.replace(newUrl);
}
}, []);
if (contentWindow?.location) {
const isHtml =
extname(addressInput) === ".html" && (await exists(addressInput));
setLoading(true);
setSrcDoc(isHtml ? (await readFile(addressInput)).toString() : "");
setIcon(id, processDirectory["Browser"].icon);
if (!isHtml) {
const addressUrl = isValidUrl(addressInput)
? addressInput
: `https://www.google.com/search?igu=1&q=${addressInput}`;
contentWindow.location.replace(addressUrl);
const favicon = new Image();
const faviconUrl = `${new URL(addressUrl).origin}/favicon.ico`;
favicon.addEventListener(
"load",
() => setIcon(id, faviconUrl),
ONE_TIME_PASSIVE_EVENT
);
favicon.src = faviconUrl;
}
}
},
[exists, id, readFile, setIcon]
);
useEffect(() => {
setUrl(history[position]);
@@ -79,6 +112,8 @@ const Browser = ({ id }: ComponentProcessProps): JSX.Element => {
<iframe
ref={iframeRef}
onLoad={() => setLoading(false)}
srcDoc={srcDoc || undefined}
style={{ backgroundColor: srcDoc ? "#fff" : "initial" }}
title={id}
{...config}
/>

View File

@@ -5,6 +5,10 @@ type Extension = {
};
const extensions = {
".html": {
process: ["Browser", "MonacoEditor"],
type: "HTML Document",
},
".img": {
icon: "image",
process: ["V86"],

View File

@@ -14,7 +14,10 @@ const StyledIcon = styled.img.attrs<IconProps>(
draggable: false,
height: displaySize || imgSize,
src:
!src || src.startsWith("blob:")
!src ||
src.startsWith("blob:") ||
src.startsWith("http:") ||
src.startsWith("https:")
? src
: join(dirname(src), `${imgSize}x${imgSize}`, basename(src)),
width: displaySize || imgSize,

View File

@@ -98,3 +98,11 @@ export const getTimezoneOffsetISOString = (): string => {
date.getTime() - date.getTimezoneOffset() * 60000
).toISOString();
};
export const isValidUrl = (url: string): boolean => {
try {
return typeof new URL(url) === "object";
} catch {
return false;
}
};