Compare commits

...

3 Commits

Author SHA1 Message Date
Dustin Brett
1be280c3ba Add more wallpapers w/handler
Some checks are pending
Tests / tests (push) Waiting to run
2025-10-08 23:14:14 -07:00
Dustin Brett
5c12a3aa2e No FF playwright webgpu 2025-10-08 22:24:28 -07:00
Dustin Brett
27cb267833 Pkg upgrades 2025-10-08 21:03:21 -07:00
10 changed files with 906 additions and 668 deletions

View File

@ -63,13 +63,23 @@ export const REDUCED_MOTION_PERCENT = 0.1;
export const WALLPAPER_MENU: WallpaperMenuItem[] = [
{
id: "ART_INSTITUTE_OF_CHICAGO",
name: "Art Institute of Chicago",
},
{
hasAlt: false,
id: "COASTAL_LANDSCAPE",
name: "Coastal Landscape",
},
{
hasAlt: false,
id: "HEXELLS",
name: "Hexells",
},
{
id: "LOREM_PICSUM",
name: "Lorem Picsum",
},
{
id: "MATRIX 2D",
name: "Matrix (2D)",
@ -81,13 +91,13 @@ export const WALLPAPER_MENU: WallpaperMenuItem[] = [
{
id: "APOD",
name: "NASA APOD",
startsWith: true,
},
{
id: "SLIDESHOW",
name: "Picture Slideshow",
},
{
hasAlt: false,
id: "STABLE_DIFFUSION",
name: "Stable Diffusion (beta)",
requiresWebGPU: true,
@ -95,7 +105,6 @@ export const WALLPAPER_MENU: WallpaperMenuItem[] = [
{
id: "VANTA",
name: "Vanta Waves",
startsWith: true,
},
];

View File

@ -0,0 +1,110 @@
import {
type WallpaperHandler,
type ApodResponse,
type ArtInstituteOfChicagoResponse,
} from "components/system/Desktop/Wallpapers/types";
import { type WallpaperFit } from "contexts/session/types";
import {
jsonFetch,
viewWidth,
isYouTubeUrl,
getYouTubeUrlId,
viewHeight,
} from "utils/functions";
const API_URL = {
APOD: "https://api.nasa.gov/planetary/apod",
ART_INSTITUTE_OF_CHICAGO: "https://api.artic.edu/api/v1/search",
};
export const wallpaperHandler: Record<string, WallpaperHandler> = {
APOD: async ({ isAlt }) => {
const response = await jsonFetch(
`${API_URL.APOD}?${isAlt ? "count=1&" : ""}api_key=DEMO_KEY`
);
const { hdurl, url } = (isAlt ? response[0] : response) as ApodResponse;
let wallpaperUrl = "";
let fallbackBackground = "";
let newWallpaperFit = "" as WallpaperFit;
if (hdurl || url) {
wallpaperUrl = (viewWidth() > 1024 ? hdurl : url) || url || "";
newWallpaperFit = "fit";
if (isYouTubeUrl(wallpaperUrl)) {
const ytBaseUrl = `https://i.ytimg.com/vi/${getYouTubeUrlId(
wallpaperUrl
)}`;
wallpaperUrl = `${ytBaseUrl}/maxresdefault.jpg`;
fallbackBackground = `${ytBaseUrl}/hqdefault.jpg`;
} else if (hdurl && url && hdurl !== url) {
fallbackBackground = wallpaperUrl === url ? hdurl : url;
}
}
return {
fallbackBackground,
newWallpaperFit,
wallpaperUrl,
};
},
ART_INSTITUTE_OF_CHICAGO: async () => {
const requestPayload = {
boost: false,
fields: ["image_id"],
limit: 1,
query: {
function_score: {
boost_mode: "replace",
query: {
bool: {
filter: [
{
term: {
is_public_domain: true,
},
},
{
exists: {
field: "image_id",
},
},
],
},
},
random_score: {
field: "id",
seed: Date.now(),
},
},
},
resources: "artworks",
};
const response = (await jsonFetch(API_URL.ART_INSTITUTE_OF_CHICAGO, {
body: JSON.stringify(requestPayload),
headers: {
"Content-Type": "application/json",
},
method: "POST",
})) as ArtInstituteOfChicagoResponse;
const imageUrl = (isMaxSize: boolean): string =>
response?.data?.[0]?.image_id
? `https://www.artic.edu/iiif/2/${response.data[0].image_id}/full/${
isMaxSize ? "1686" : "843"
},/0/default.jpg`
: "";
return {
fallbackBackground: imageUrl(false),
newWallpaperFit: "fit",
wallpaperUrl: imageUrl(true),
};
},
LOREM_PICSUM: () => ({
fallbackBackground: "",
newWallpaperFit: "fill",
wallpaperUrl: `https://picsum.photos/seed/${Date.now()}/${viewWidth()}/${viewHeight()}`,
}),
};

View File

@ -2,6 +2,7 @@ import { type StableDiffusionConfig } from "components/apps/StableDiffusion/type
import { type VantaWavesConfig } from "components/system/Desktop/Wallpapers/vantaWaves/types";
import { type Size } from "components/system/Window/RndWindow/useResizable";
import type MatrixConfig from "components/system/Desktop/Wallpapers/Matrix/config";
import { type WallpaperFit } from "contexts/session/types";
declare global {
interface Window {
@ -30,10 +31,30 @@ export type OffscreenRenderProps = {
};
export type WallpaperMenuItem = {
hasAlt?: boolean;
id: string;
name?: string;
requiresWebGPU?: boolean;
startsWith?: boolean;
};
export type WallpaperMessage = { message: string; type: string };
export type WallpaperData = {
fallbackBackground: string;
newWallpaperFit: WallpaperFit;
wallpaperUrl: string;
};
export type WallpaperHandler = (props: {
isAlt: boolean;
}) => Promise<WallpaperData> | WallpaperData;
export type ApodResponse = {
date: string;
hdurl?: string;
url?: string;
};
export type ArtInstituteOfChicagoResponse = {
data: { image_id: string }[];
};

View File

@ -1,6 +1,7 @@
import { join } from "path";
import { useTheme } from "styled-components";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { wallpaperHandler } from "components/system/Desktop/Wallpapers/handlers";
import {
BASE_CANVAS_SELECTOR,
BASE_VIDEO_SELECTOR,
@ -20,10 +21,8 @@ import { useFileSystem } from "contexts/fileSystem";
import { useSession } from "contexts/session";
import useWorker from "hooks/useWorker";
import {
DEFAULT_LOCALE,
DEFAULT_WALLPAPER,
IMAGE_FILE_EXTENSIONS,
MILLISECONDS_IN_DAY,
MILLISECONDS_IN_MINUTE,
NATIVE_IMAGE_FORMATS,
PICTURES_FOLDER,
@ -38,13 +37,9 @@ import {
cleanUpBufferUrl,
createOffscreenCanvas,
getExtension,
getYouTubeUrlId,
isBeforeBg,
isYouTubeUrl,
jsonFetch,
parseBgPosition,
preloadImage,
viewWidth,
} from "utils/functions";
const slideshowFiles: string[] = [];
@ -61,7 +56,7 @@ const useWallpaper = (
() => wallpaperImage.split(" "),
[wallpaperImage]
);
const vantaWireframe = wallpaperImage === "VANTA WIREFRAME";
const isAlt = wallpaperImage.endsWith(" ALT");
const wallpaperWorker = useWorker<void>(
sessionLoaded ? WALLPAPER_WORKERS[wallpaperName] : undefined
);
@ -107,7 +102,7 @@ const useWallpaper = (
config = {
material: {
options: {
wireframe: vantaWireframe || !isTopWindow,
wireframe: isAlt || !isTopWindow,
},
},
waveSpeed: prefersReducedMotion ? REDUCED_MOTION_PERCENT : 1,
@ -115,8 +110,8 @@ const useWallpaper = (
} else if (wallpaperImage.startsWith("MATRIX")) {
config = {
animationSpeed: prefersReducedMotion ? REDUCED_MOTION_PERCENT : 1,
volumetric: wallpaperImage.endsWith("3D"),
...(isTopWindow
volumetric: wallpaperImage.startsWith("MATRIX 3D"),
...(isTopWindow && !isAlt
? {}
: {
fallSpeed: -0.09,
@ -226,10 +221,10 @@ const useWallpaper = (
[
desktopRef,
exists,
isAlt,
readFile,
resetWallpaper,
setWallpaper,
vantaWireframe,
wallpaperImage,
wallpaperName,
wallpaperWorker,
@ -301,7 +296,7 @@ const useWallpaper = (
(await readFile(slideshowFilePath))?.toString() || "[]"
) as string[]
),
].sort(() => Math.random() - 0.5)
].sort(() => Math.random() - (isAlt ? 0.5 : -0.5))
);
}
@ -331,51 +326,15 @@ const useWallpaper = (
);
newWallpaperFit = "fill";
} else if (wallpaperName === "APOD") {
// eslint-disable-next-line unicorn/no-unreadable-array-destructuring
const [, , currentDate] = wallpaperImage.split(" ");
const [month, , day, , year] = new Intl.DateTimeFormat(DEFAULT_LOCALE, {
day: "2-digit",
month: "2-digit",
timeZone: "US/Eastern",
year: "numeric",
})
.formatToParts(Date.now())
.map(({ value }) => value);
if (currentDate === `${year}-${month}-${day}`) return;
} else if (wallpaperHandler[wallpaperName]) {
resetWallpaper();
const {
date = "",
hdurl = "",
url = "",
} = await jsonFetch(
"https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY"
);
const newWallpaper = await wallpaperHandler[wallpaperName]({ isAlt });
if (hdurl || url) {
wallpaperUrl = ((viewWidth() > 1024 ? hdurl : url) || url) as string;
newWallpaperFit = "fit";
if (isYouTubeUrl(wallpaperUrl)) {
const ytBaseUrl = `https://i.ytimg.com/vi/${getYouTubeUrlId(
wallpaperUrl
)}`;
wallpaperUrl = `${ytBaseUrl}/maxresdefault.jpg`;
fallbackBackground = `${ytBaseUrl}/hqdefault.jpg`;
} else if (hdurl && url && hdurl !== url) {
fallbackBackground = (wallpaperUrl === url ? hdurl : url) as string;
}
const newWallpaperImage = `APOD ${wallpaperUrl} ${date as string}`;
if (newWallpaperImage !== wallpaperImage) {
setWallpaper(newWallpaperImage, newWallpaperFit);
setTimeout(loadWallpaper, MILLISECONDS_IN_DAY);
}
if (newWallpaper) {
wallpaperUrl = newWallpaper.wallpaperUrl || "";
fallbackBackground = newWallpaper.fallbackBackground || "";
newWallpaperFit = newWallpaper.newWallpaperFit || newWallpaperFit;
}
} else if (await exists(wallpaperImage)) {
resetWallpaper();
@ -492,10 +451,10 @@ const useWallpaper = (
desktopRef,
exists,
getAllImages,
isAlt,
loadWallpaper,
readFile,
resetWallpaper,
setWallpaper,
updateFolder,
wallpaperFit,
wallpaperImage,

View File

@ -56,13 +56,10 @@ const updateSortBy =
sortBy === value ? !isAscending : defaultIsAscending,
];
const EASTER_EGG_CLICK_COUNT = 2;
const CAPTURE_FPS = 30;
const MIME_TYPE_VIDEO_WEBM = "video/webm";
const MIME_TYPE_VIDEO_MP4 = "video/mp4";
let triggerEasterEggCountdown = EASTER_EGG_CLICK_COUNT;
let currentMediaStream: MediaStream | undefined;
let currentMediaRecorder: MediaRecorder | undefined;
@ -96,26 +93,6 @@ const useFolderContextMenu = (
updateRecentFiles,
wallpaperImage,
} = useSession();
const setWallpaper = useCallback(
(wallpaper: string) => {
if (wallpaper === "VANTA") {
triggerEasterEggCountdown -= 1;
const triggerEasterEgg = triggerEasterEggCountdown === 0;
setSessionWallpaper(`VANTA${triggerEasterEgg ? " WIREFRAME" : ""}`);
if (triggerEasterEgg) {
triggerEasterEggCountdown = EASTER_EGG_CLICK_COUNT;
}
} else {
triggerEasterEggCountdown = EASTER_EGG_CLICK_COUNT;
setSessionWallpaper(wallpaper);
}
},
[setSessionWallpaper]
);
const { minimize, open } = useProcesses();
const updateSorting = useCallback(
(value: SortBy | "", defaultIsAscending: boolean): void => {
@ -459,19 +436,27 @@ const useFolderContextMenu = (
menu: WALLPAPER_MENU.filter(
({ requiresWebGPU }) => !requiresWebGPU || hasWebGPU
).reduce<MenuItem[]>(
(menu, item) => [
(menu, { hasAlt = true, id, name }) => [
...menu,
{
action: () => {
if (isMusicVisualizationRunning) {
stopGlobalMusicVisualization();
}
setWallpaper(item.id);
setSessionWallpaper(
`${id}${
hasAlt &&
wallpaperImage.startsWith(id) &&
!wallpaperImage.endsWith(" ALT")
? " ALT"
: ""
}`
);
},
label: item.name || item.id,
toggle: item.startsWith
? wallpaperImage.startsWith(item.id)
: wallpaperImage === item.id,
label: name || id,
toggle: hasAlt
? wallpaperImage.startsWith(id)
: wallpaperImage === id,
},
],
isMusicVisualizationRunning
@ -610,7 +595,7 @@ const useFolderContextMenu = (
processesRef,
rootFs?.mntMap,
setForegroundId,
setWallpaper,
setSessionWallpaper,
sortBy,
updateDesktopIconPositions,
updateFolder,

View File

@ -185,7 +185,10 @@ export const MEDIA_RECORDER_HEADLESS_NOT_SUPPORTED_BROWSERS = new Set([
"webkit",
]);
export const PYODIDE_HEADLESS_NOT_SUPPORTED_BROWSERS = new Set(["firefox"]);
export const WEBGPU_HEADLESS_NOT_SUPPORTED_BROWSERS = new Set(["webkit"]);
export const WEBGPU_HEADLESS_NOT_SUPPORTED_BROWSERS = new Set([
"firefox",
"webkit",
]);
export const FILE_MENU_ITEMS = [
/^Open$/,

View File

@ -1,6 +1,7 @@
import { readFileSync, readdirSync, statSync } from "fs";
import { join } from "path";
import {
type ConsoleMessage,
type Locator,
type Page,
type Response,
@ -84,11 +85,18 @@ type DocumentWithVendorFullscreen = Document & {
webkitFullscreenElement?: HTMLElement;
};
type MessageType = ReturnType<ConsoleMessage["type"]>;
export const captureConsoleLogs =
(testName = "") =>
({ browserName, page }: TestPropsWithBrowser): void => {
page.on("console", (msg) => {
if (testName === "apps" && (process.env.CI || msg.type() !== "error")) {
const messageType = msg.type();
if (
messageType === ("timeStamp" as MessageType) ||
(testName === "apps" && (process.env.CI || messageType !== "error"))
) {
return;
}

View File

@ -61,7 +61,7 @@
"gif.js": "^0.2.0",
"idb": "^8.0.3",
"ini": "^5.0.0",
"isomorphic-git": "^1.33.2",
"isomorphic-git": "^1.34.0",
"libheif-js": "^1.19.8",
"mediainfo.js": "0.3.6",
"minimist": "^1.2.8",
@ -75,8 +75,8 @@
"prettier": "^3.6.2",
"print-js": "^1.6.0",
"quickjs-emscripten": "^0.31.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-rnd": "^10.5.2",
"resedit": "^2.0.3",
"rtf.js": "^3.0.9",
@ -89,7 +89,7 @@
"@axe-core/playwright": "^4.10.2",
"@next/bundle-analyzer": "^15.5.4",
"@next/eslint-plugin-next": "^15.5.4",
"@playwright/test": "^1.55.1",
"@playwright/test": "^1.56.0",
"@types/canvas-confetti": "^1.9.0",
"@types/dom-chromium-ai": "0.0.6",
"@types/dompurify": "^3.2.0",
@ -98,16 +98,16 @@
"@types/jest": "^30.0.0",
"@types/lunr": "^2.3.7",
"@types/minimist": "^1.2.5",
"@types/node": "^24.5.2",
"@types/node": "^24.7.0",
"@types/offscreencanvas": "^2019.7.3",
"@types/opentype.js": "^1.3.8",
"@types/react": "^19.1.14",
"@types/react-dom": "^19.1.9",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
"@types/ua-parser-js": "^0.7.39",
"@types/video.js": "^7.3.58",
"@types/wicg-file-system-access": "^2023.10.6",
"@typescript-eslint/eslint-plugin": "^8.44.1",
"@typescript-eslint/parser": "^8.44.1",
"@types/wicg-file-system-access": "^2023.10.7",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/parser": "^8.46.0",
"emulators": "^8.3.9",
"emulators-ui": "^0.73.9",
"eruda": "^3.4.3",
@ -123,7 +123,7 @@
"eslint-plugin-playwright": "^2.2.2",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-hooks": "^6.1.1",
"eslint-plugin-react-hooks-addons": "^0.5.0",
"eslint-plugin-regexp": "^2.10.0",
"eslint-plugin-sonarjs": "^3.0.5",
@ -134,24 +134,24 @@
"html-minifier-terser": "^7.2.0",
"html-to-image": "^1.11.13",
"husky": "^9.1.7",
"jest": "^30.1.3",
"jest-environment-jsdom": "^30.1.2",
"lint-staged": "^16.2.1",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"lint-staged": "^16.2.3",
"lunr": "^2.3.9",
"monaco-editor": "^0.53.0",
"pdfjs-dist": "^5.4.149",
"playwright-core": "^1.55.1",
"monaco-editor": "^0.54.0",
"pdfjs-dist": "^5.4.296",
"playwright-core": "^1.56.0",
"postcss": "^8.5.6",
"postcss-styled-syntax": "^0.7.1",
"postcss-syntax": "^0.36.2",
"serve": "^14.2.5",
"stylelint": "^16.24.0",
"stylelint-config-standard": "^39.0.0",
"stylelint": "^16.25.0",
"stylelint-config-standard": "^39.0.1",
"stylelint-order": "^7.0.0",
"terser": "^5.44.0",
"tinymce": "^7.9.1",
"ts-prune": "^0.10.3",
"typescript": "^5.9.2",
"typescript": "^5.9.3",
"webamp": "^2.2.0",
"xlsx": "^0.18.5",
"xterm": "^5.3.0"

View File

@ -1160,9 +1160,10 @@ export const getGifJs = async (): Promise<GIFWithWorkers> => {
};
export const jsonFetch = async (
url: string
url: string,
options?: RequestInit
): Promise<Record<string, unknown>> => {
const response = await fetch(url, HIGH_PRIORITY_REQUEST);
const response = await fetch(url, { ...HIGH_PRIORITY_REQUEST, ...options });
const json = (await response.json()) as Record<string, unknown>;
return json || {};

1254
yarn.lock

File diff suppressed because it is too large Load Diff