Specify preload types + centralize

This commit is contained in:
Dustin Brett 2024-10-25 15:34:03 -07:00
parent 7779adaa45
commit ae21174d58
10 changed files with 137 additions and 129 deletions

View File

@ -15,7 +15,6 @@ import {
type YouTubePlayer,
} from "components/apps/VideoPlayer/types";
import { type ContainerHookProps } from "components/system/Apps/AppContainer";
import { getMimeType } from "components/system/Files/FileEntry/functions";
import useTitle from "components/system/Window/useTitle";
import useWindowSize from "components/system/Window/useWindowSize";
import { useFileSystem } from "contexts/fileSystem";
@ -24,6 +23,7 @@ import { VIDEO_FALLBACK_MIME_TYPE } from "utils/constants";
import {
bufferToUrl,
cleanUpBufferUrl,
getMimeType,
isSafari,
isYouTubeUrl,
loadFiles,

View File

@ -13,6 +13,7 @@ import {
import {
getDpi,
getExtension,
getMimeType,
imageSrc,
imageSrcs,
imageToBufferUrl,
@ -148,6 +149,7 @@ const Metadata: FC = () => {
{desktopIcons.map((icon) => {
const isSubIcon = icon.includes("/16x16/");
const dynamicIcon = !isSubIcon && isDynamicIcon(icon);
const extension = getExtension(icon);
return (
<link
@ -156,12 +158,13 @@ const Metadata: FC = () => {
href={dynamicIcon || isSubIcon ? undefined : icon}
imageSrcSet={
dynamicIcon
? imageSrcs(icon, 48, ".webp")
? imageSrcs(icon, 48, extension)
: isSubIcon
? imageSrcs(icon.replace("16x16/", ""), 16, ".webp")
? imageSrcs(icon.replace("16x16/", ""), 16, extension)
: undefined
}
rel="preload"
type={getMimeType(extension)}
{...HIGH_PRIORITY_ELEMENT}
/>
);

View File

@ -103,3 +103,5 @@ export const BASE_CANVAS_SELECTOR = ":scope > canvas";
export const BASE_VIDEO_SELECTOR = ":scope > video";
export const STABLE_DIFFUSION_DELAY_IN_MIN = 10;
export const PRELOAD_ID = "preloadWallpaper";

View File

@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useRef } from "react";
import {
BASE_CANVAS_SELECTOR,
BASE_VIDEO_SELECTOR,
PRELOAD_ID,
REDUCED_MOTION_PERCENT,
STABLE_DIFFUSION_DELAY_IN_MIN,
WALLPAPER_PATHS,
@ -41,6 +42,7 @@ import {
isYouTubeUrl,
jsonFetch,
parseBgPosition,
preloadImage,
viewWidth,
} from "utils/functions";
@ -302,22 +304,18 @@ const useWallpaper = (
do {
wallpaperUrl = slideshowFiles.shift() || "";
let [nextWallpaper] = slideshowFiles;
const [nextWallpaper] = slideshowFiles;
if (nextWallpaper) {
const preloadLink = document.createElement("link");
document.querySelector(`#${PRELOAD_ID}`)?.remove();
if (nextWallpaper.startsWith("/")) {
nextWallpaper = `${window.location.origin}${nextWallpaper}`;
}
preloadLink.id = "preloadWallpaper";
preloadLink.href = nextWallpaper;
preloadLink.rel = "preload";
preloadLink.as = "image";
document.querySelector("#preloadWallpaper")?.remove();
document.head.append(preloadLink);
preloadImage(
nextWallpaper.startsWith("/")
? `${window.location.origin}${nextWallpaper}`
: nextWallpaper,
PRELOAD_ID,
"auto"
);
}
if (wallpaperUrl.startsWith("/")) {

View File

@ -49,6 +49,7 @@ import {
getExtension,
getGifJs,
getHtmlToImage,
getMimeType,
imageToBufferUrl,
isSafari,
isYouTubeUrl,
@ -146,61 +147,6 @@ export const getProcessByFileExtension = (extension: string): string => {
return defaultProcess;
};
export const getMimeType = (url: string): string => {
switch (getExtension(url)) {
case ".ani":
case ".cur":
case ".ico":
return "image/vnd.microsoft.icon";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".json":
return "application/json";
case ".html":
case ".htm":
case ".whtml":
return "text/html";
case ".m3u":
case ".m3u8":
return "application/x-mpegURL";
case ".m4v":
case ".mkv":
case ".mov":
case ".mp4":
return "video/mp4";
case ".mp3":
return "audio/mpeg";
case ".oga":
return "audio/ogg";
case ".ogg":
case ".ogm":
case ".ogv":
return "video/ogg";
case ".pdf":
return "application/pdf";
case ".png":
return "image/png";
case ".md":
case ".txt":
return "text/plain";
case ".wav":
return "audio/wav";
case ".webm":
return "video/webm";
case ".webp":
return "image/webp";
case ".xml":
return "application/xml";
case ".wsz":
case ".jsdos":
case ".zip":
return "application/zip";
default:
return "";
}
};
export const getShortcutInfo = (
contents?: Buffer,
shortcutData?: InternetShortcut

View File

@ -1,11 +1,11 @@
import { join } from "path";
import { type Position } from "react-rnd";
import { useCallback, useEffect, useRef, useState } from "react";
import { getMimeType } from "components/system/Files/FileEntry/functions";
import { type FocusEntryFunctions } from "components/system/Files/FileManager/useFocusableEntries";
import { useSession } from "contexts/session";
import {
getHtmlToImage,
getMimeType,
haltEvent,
trimCanvasToTopLeft,
updateIconPositions,

View File

@ -456,7 +456,7 @@ const useFolderContextMenu = (
if (isMusicVisualizationRunning) {
stopGlobalMusicVisualization?.();
}
if (item.id) setWallpaper(item.id);
setWallpaper(item.id);
},
label: item.name || item.id,
toggle: item.startsWith

View File

@ -4,13 +4,7 @@ import StyledTaskbarButton from "components/system/Taskbar/StyledTaskbarButton";
import { START_BUTTON_TITLE } from "components/system/Taskbar/functions";
import useTaskbarContextMenu from "components/system/Taskbar/useTaskbarContextMenu";
import { DIV_BUTTON_PROPS } from "utils/constants";
import {
getDpi,
imageSrc,
imageSrcs,
isDynamicIcon,
label,
} from "utils/functions";
import { label, preloadImage } from "utils/functions";
type StartButtonProps = {
startMenuVisible: boolean;
@ -27,47 +21,10 @@ const StartButton: FC<StartButtonProps> = ({
if (initalizedPreload.current) return;
initalizedPreload.current = true;
const supportsImageSrcSet = Object.prototype.hasOwnProperty.call(
HTMLLinkElement.prototype,
"imageSrcset"
);
const preloadedLinks = [
...document.querySelectorAll("link[rel=preload]"),
] as HTMLLinkElement[];
const startMenuIcons = (await import("public/.index/startMenuIcons.json"))
.default;
startMenuIcons?.forEach((icon) => {
const link = document.createElement("link");
link.as = "image";
link.fetchPriority = "high";
link.rel = "preload";
link.type = "image/webp";
if (isDynamicIcon(icon)) {
if (supportsImageSrcSet) {
link.imageSrcset = imageSrcs(icon, 48, ".webp");
} else {
const [href] = imageSrc(icon, 48, getDpi(), ".webp").split(" ");
link.href = href;
}
} else {
link.href = icon;
}
if (
!preloadedLinks.some(
(preloadedLink) =>
(link.imageSrcset &&
preloadedLink?.imageSrcset?.endsWith(link.imageSrcset)) ||
(link.href && preloadedLink?.href?.endsWith(link.href))
)
) {
document.head.append(link);
}
});
startMenuIcons?.forEach((icon) => preloadImage(icon));
setPreloaded(true);
}, []);

View File

@ -10,7 +10,6 @@ import type IZipFS from "browserfs/dist/node/backend/ZipFS";
import type IIsoFS from "browserfs/dist/node/backend/IsoFS";
import type * as IBrowserFS from "browserfs";
import useTransferDialog from "components/system/Dialogs/Transfer/useTransferDialog";
import { getMimeType } from "components/system/Files/FileEntry/functions";
import {
type InputChangeEvent,
getEventData,
@ -36,7 +35,7 @@ import {
PROCESS_DELIMITER,
TRANSITIONS_IN_MILLISECONDS,
} from "utils/constants";
import { bufferToBlob, getExtension } from "utils/functions";
import { bufferToBlob, getExtension, getMimeType } from "utils/functions";
type FilePasteOperations = Record<string, "copy" | "move">;

View File

@ -103,7 +103,7 @@ export const imageSrc = (
ratio: number,
extension: string
): string => {
const imageName = basename(imagePath, ".webp");
const imageName = basename(imagePath, extension);
const [expectedSize, maxIconSize] = MAX_RES_ICON_OVERRIDE[imageName] || [];
const ratioSize = size * ratio;
const imageSize = Math.min(
@ -804,11 +804,119 @@ export const getYouTubeUrlId = (url: string): string => {
return "";
};
export const getMimeType = (url: string): string => {
switch (getExtension(url)) {
case ".ani":
case ".cur":
case ".ico":
return "image/vnd.microsoft.icon";
case ".cache":
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".json":
return "application/json";
case ".html":
case ".htm":
case ".whtml":
return "text/html";
case ".m3u":
case ".m3u8":
return "application/x-mpegURL";
case ".m4v":
case ".mkv":
case ".mov":
case ".mp4":
return "video/mp4";
case ".mp3":
return "audio/mpeg";
case ".oga":
return "audio/ogg";
case ".ogg":
case ".ogm":
case ".ogv":
return "video/ogg";
case ".pdf":
return "application/pdf";
case ".png":
return "image/png";
case ".md":
case ".txt":
return "text/plain";
case ".wav":
return "audio/wav";
case ".webm":
return "video/webm";
case ".webp":
return "image/webp";
case ".xml":
return "application/xml";
case ".wsz":
case ".jsdos":
case ".zip":
return "application/zip";
default:
return "";
}
};
export const isDynamicIcon = (icon?: string): boolean =>
typeof icon === "string" &&
(icon.startsWith(ICON_PATH) ||
(icon.startsWith(USER_ICON_PATH) && !icon.startsWith(ICON_CACHE)));
const getPreloadedLinks = (): HTMLLinkElement[] => [
...document.querySelectorAll<HTMLLinkElement>("link[rel=preload]"),
];
export const preloadImage = (
image: string,
id?: string,
fetchPriority: "auto" | "high" | "low" = "high"
): void => {
const extension = getExtension(image);
const link = document.createElement("link");
link.as = "image";
if (id) link.id = id;
link.fetchPriority = fetchPriority;
link.rel = "preload";
link.type = getMimeType(extension);
if (isDynamicIcon(image)) {
const supportsImageSrcSet = Object.prototype.hasOwnProperty.call(
HTMLLinkElement.prototype,
"imageSrcset"
);
if (supportsImageSrcSet) {
link.imageSrcset = imageSrcs(image, 48, extension);
} else {
const [href] = imageSrc(image, 48, getDpi(), extension).split(" ");
link.href = href;
}
} else {
link.href = image;
}
const preloadedLinks = getPreloadedLinks();
if (
!preloadedLinks.some(
(preloadedLink) =>
(link.imageSrcset &&
preloadedLink?.imageSrcset?.endsWith(link.imageSrcset)) ||
(link.href && preloadedLink?.href?.endsWith(link.href))
)
) {
document.head.append(link);
}
};
export const preloadLibs = (libs: string[] = []): void => {
const scripts = [...document.scripts];
const preloadedLinks = [
...document.querySelectorAll("link[rel=preload]"),
] as HTMLLinkElement[];
const preloadedLinks = getPreloadedLinks();
// eslint-disable-next-line unicorn/no-array-callback-reference
libs.map(encodeURI).forEach((lib) => {
@ -877,11 +985,6 @@ export const generatePrettyTimestamp = (): string =>
export const isFileSystemMappingSupported = (): boolean =>
typeof FileSystemHandle === "function" && "showDirectoryPicker" in window;
export const isDynamicIcon = (icon?: string): boolean =>
typeof icon === "string" &&
(icon.startsWith(ICON_PATH) ||
(icon.startsWith(USER_ICON_PATH) && !icon.startsWith(ICON_CACHE)));
export const hasFinePointer = (): boolean =>
window.matchMedia("(pointer: fine)").matches;