mirror of
https://github.com/DustinBrett/daedalOS.git
synced 2025-12-06 00:20:05 +01:00
172 lines
4.9 KiB
TypeScript
172 lines
4.9 KiB
TypeScript
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
import Head from "next/head";
|
|
import { useFileSystem } from "contexts/fileSystem";
|
|
import { useProcesses } from "contexts/process";
|
|
import { useSession } from "contexts/session";
|
|
import desktopIcons from "public/.index/desktopIcons.json";
|
|
import {
|
|
FAVICON_BASE_PATH,
|
|
HIGH_PRIORITY_ELEMENT,
|
|
ONE_TIME_PASSIVE_EVENT,
|
|
PACKAGE_DATA,
|
|
} from "utils/constants";
|
|
import {
|
|
getDpi,
|
|
getExtension,
|
|
getMimeType,
|
|
imageSrc,
|
|
imageSrcs,
|
|
isDynamicIcon,
|
|
} from "utils/functions";
|
|
|
|
const { alias, author, description } = PACKAGE_DATA;
|
|
|
|
const Metadata: FC = () => {
|
|
const [title, setTitle] = useState(alias);
|
|
const [favIcon, setFavIcon] = useState("");
|
|
const { readFile } = useFileSystem();
|
|
const [customCursor, setCustomCursor] = useState("");
|
|
const { cursor, foregroundId } = useSession();
|
|
const { processes: { [foregroundId]: process } = {} } = useProcesses();
|
|
const {
|
|
icon: processIcon,
|
|
hideTaskbarEntry,
|
|
title: processTitle,
|
|
} = process || {};
|
|
const resetFaviconAndTitle = useCallback((): void => {
|
|
setTitle(alias);
|
|
setFavIcon((currentFavicon) =>
|
|
currentFavicon ? FAVICON_BASE_PATH : currentFavicon
|
|
);
|
|
}, []);
|
|
const currentFavIcon = useMemo(
|
|
() =>
|
|
isDynamicIcon(favIcon)
|
|
? imageSrc(favIcon, 16, getDpi(), getExtension(favIcon)).split(" ")[0]
|
|
: favIcon,
|
|
[favIcon]
|
|
);
|
|
const favIconMimeType = useMemo(
|
|
() => getMimeType(currentFavIcon),
|
|
[currentFavIcon]
|
|
);
|
|
const getCursor = useCallback(
|
|
async (path: string) => {
|
|
const imageBuffer = await readFile(path);
|
|
|
|
if (!imageBuffer?.length) return "";
|
|
|
|
const { cursorToCss } = await import("utils/imageDecoder");
|
|
|
|
return cursorToCss(imageBuffer, path);
|
|
},
|
|
[readFile]
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (!hideTaskbarEntry && (processIcon || processTitle)) {
|
|
const documentTitle = processTitle ? `${processTitle} - ${alias}` : alias;
|
|
|
|
if (title !== documentTitle) setTitle(documentTitle);
|
|
if (favIcon !== processIcon || !favIcon) {
|
|
setFavIcon(encodeURI(processIcon) || FAVICON_BASE_PATH);
|
|
}
|
|
} else {
|
|
resetFaviconAndTitle();
|
|
}
|
|
}, [
|
|
favIcon,
|
|
hideTaskbarEntry,
|
|
processIcon,
|
|
processTitle,
|
|
resetFaviconAndTitle,
|
|
title,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const onVisibilityChange = (): void => {
|
|
if (document.visibilityState === "visible") resetFaviconAndTitle();
|
|
};
|
|
const onBeforeUnload = (): void => {
|
|
const faviconLinkElement = document.querySelector("link[rel=icon]");
|
|
|
|
if (faviconLinkElement instanceof HTMLLinkElement) {
|
|
try {
|
|
faviconLinkElement.href = FAVICON_BASE_PATH;
|
|
} catch {
|
|
// Ignore failure to set link href
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addEventListener(
|
|
"beforeunload",
|
|
onBeforeUnload,
|
|
ONE_TIME_PASSIVE_EVENT
|
|
);
|
|
document.addEventListener("visibilitychange", onVisibilityChange, {
|
|
passive: true,
|
|
});
|
|
|
|
return () => {
|
|
window.removeEventListener("beforeunload", onBeforeUnload);
|
|
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
};
|
|
}, [resetFaviconAndTitle]);
|
|
|
|
useEffect(() => {
|
|
if (cursor) getCursor(cursor).then(setCustomCursor);
|
|
}, [cursor, getCursor]);
|
|
|
|
return (
|
|
<Head>
|
|
<title>{title}</title>
|
|
{currentFavIcon && (
|
|
<link href={currentFavIcon} rel="icon" type={favIconMimeType} />
|
|
)}
|
|
<meta
|
|
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, interactive-widget=resizes-content"
|
|
name="viewport"
|
|
/>
|
|
<meta content={description} name="description" />
|
|
<meta content={alias} property="og:title" />
|
|
<meta content="website" property="og:type" />
|
|
<meta content={author.url} property="og:url" />
|
|
<meta content={`${author.url}/screenshot.png`} property="og:image" />
|
|
<meta content={description} property="og:description" />
|
|
<link
|
|
href={`${author.url}/rss.xml`}
|
|
rel="alternate"
|
|
title={`RSS Feed for ${alias}`}
|
|
type="application/rss+xml"
|
|
/>
|
|
{desktopIcons.map((icon) => {
|
|
const isSubIcon = icon.includes("/16x16/");
|
|
const dynamicIcon = !isSubIcon && isDynamicIcon(icon);
|
|
const extension = getExtension(icon);
|
|
|
|
return (
|
|
<link
|
|
key={icon}
|
|
as="image"
|
|
href={dynamicIcon || isSubIcon ? undefined : icon}
|
|
imageSrcSet={
|
|
dynamicIcon
|
|
? imageSrcs(icon, 48, extension)
|
|
: isSubIcon
|
|
? imageSrcs(icon.replace("16x16/", ""), 16, extension)
|
|
: undefined
|
|
}
|
|
rel="preload"
|
|
type={getMimeType(extension)}
|
|
{...HIGH_PRIORITY_ELEMENT}
|
|
/>
|
|
);
|
|
})}
|
|
{customCursor && <style>{customCursor}</style>}
|
|
</Head>
|
|
);
|
|
};
|
|
|
|
export default memo(Metadata);
|