diff --git a/.eslintrc.json b/.eslintrc.json index fbf658690c..0d9dede14a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -57,6 +57,7 @@ "@typescript-eslint/no-floating-promises": "off", "@typescript-eslint/no-invalid-void-type": "off", "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-misused-spread": "off", "@typescript-eslint/no-redeclare": "error", "@typescript-eslint/no-shadow": [ "error", @@ -139,7 +140,10 @@ "react/hook-use-state": "error", "react-hooks/exhaustive-deps": "error", "react/display-name": "off", - "react/jsx-filename-extension": ["error", { "extensions": [".tsx"] }], + "react/jsx-filename-extension": [ + "error", + { "allow": "as-needed", "extensions": [".tsx"] } + ], "react/jsx-props-no-spreading": "off", "react/jsx-sort-props": [ "error", @@ -224,7 +228,7 @@ }, "overrides": [ { - "files": ["__tests__/**/*.spec.tsx"], + "files": ["__tests__/**/*.spec.ts"], "rules": { "playwright/no-standalone-expect": "off" } diff --git a/.stylelintrc.json b/.stylelintrc.json index 938eb7f9c3..3a3686a71c 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -6,6 +6,7 @@ "alpha-value-notation": "percentage", "color-function-notation": "legacy", "hue-degree-notation": "number", + "no-empty-source": null, "order/properties-alphabetical-order": true, "value-keyword-case": [ "lower", diff --git a/IDEAS.md b/IDEAS.md index 5ed1f44183..e66538ae17 100644 --- a/IDEAS.md +++ b/IDEAS.md @@ -185,7 +185,7 @@ - [WebODF](https://webodf.org/) - [docx2html](https://github.com/lalalic/docx2html) -- [Pandoc](https://github.com/jgm/pandoc) +- [Pandoc](https://github.com/tweag/pandoc-wasm) - [gdal3.js](https://github.com/bugra9/gdal3.js) - [Epub.js](https://github.com/futurepress/epub.js/) - Barcode / QR @@ -292,6 +292,7 @@ - [fireworks.js](https://github.com/crashmax-dev/fireworks-js) - [Cursor Effects](https://tholman.com/cursor-effects/) - [Bobby Blue-Eyes](https://www.derschmale.com/lab/doodles/blueeyes/build/) +- [CODEF Demoscene Gallery](https://www.wab.com/) ## Games diff --git a/__tests__/utils/functions.spec.tsx b/__tests__/utils/functions.spec.ts similarity index 100% rename from __tests__/utils/functions.spec.tsx rename to __tests__/utils/functions.spec.ts diff --git a/components/apps/BoxedWine/useBoxedWine.ts b/components/apps/BoxedWine/useBoxedWine.ts index 71c23bf3b9..8b1a683e25 100644 --- a/components/apps/BoxedWine/useBoxedWine.ts +++ b/components/apps/BoxedWine/useBoxedWine.ts @@ -1,4 +1,4 @@ -import { basename } from "path"; +import { basename, extname } from "path"; import { useCallback, useEffect, useRef } from "react"; import { type Unzipped } from "fflate"; import { getConfig } from "components/apps/BoxedWine/config"; @@ -106,7 +106,10 @@ const useBoxedWine = ({ try { window.BoxedWineShell(() => { setLoading(false); - mountEmFs(window.FS as EmscriptenFS, "BoxedWine"); + mountEmFs( + window.FS as EmscriptenFS, + url ? `BoxedWine_${basename(url, extname(url))}` : id + ); }); } catch { // Ignore BoxedWine errors @@ -115,6 +118,7 @@ const useBoxedWine = ({ }, [ appendFileToTitle, containerRef, + id, libs, mountEmFs, readFile, diff --git a/components/apps/Browser/NavigationIcons.tsx b/components/apps/Browser/NavigationIcons.tsx index d374ccd141..9923b34028 100644 --- a/components/apps/Browser/NavigationIcons.tsx +++ b/components/apps/Browser/NavigationIcons.tsx @@ -28,3 +28,9 @@ export const Stop = memo(() => ( )); + +export const Network = memo(() => ( + + + +)); diff --git a/components/apps/Browser/StyledBrowser.ts b/components/apps/Browser/StyledBrowser.ts index 639b7e6344..9714bf655a 100644 --- a/components/apps/Browser/StyledBrowser.ts +++ b/components/apps/Browser/StyledBrowser.ts @@ -43,6 +43,16 @@ const StyledBrowser = styled.div` width: 20px; } + &.proxy { + margin: 0 10px 0 4px; + width: 40px; + + svg { + height: 15px; + width: 15px; + } + } + &:hover { background-color: rgb(103, 103, 103); } diff --git a/components/apps/Browser/config.ts b/components/apps/Browser/config.ts index e2e7c4a622..74bfc3e784 100644 --- a/components/apps/Browser/config.ts +++ b/components/apps/Browser/config.ts @@ -7,6 +7,10 @@ type Bookmark = { url: string; }; +export type WaybackUrlInfo = { + archived_snapshots: { closest: { url: string } }; +}; + export const DINO_GAME = { icon: "/System/Icons/Favicons/dino.webp", name: "T-Rex Chrome Dino Game", @@ -41,6 +45,11 @@ export const bookmarks: Bookmark[] = [ name: "Internet Archive", url: "https://archive.org/", }, + { + icon: "/System/Icons/webamp.webp", + name: "Winamp Skin Museum", + url: "https://skins.webamp.org/", + }, { icon: "/System/Icons/Favicons/win96.webp", name: "Windows 96", @@ -59,3 +68,13 @@ export const LOCAL_HOST = new Set(["127.0.0.1", "localhost"]); export const NOT_FOUND = '404 Not Found

Not Found

The requested URL was not found on this server.

'; + +export const OLD_NET_PROXY = + "https://theoldnet.com/get?scripts=true&decode=true&year=&url="; + +export const OLD_NET_SUPPORTED_YEARS = [ + 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, + 2009, 2010, 2011, 2012, +]; + +export const WAYBACK_URL_INFO = "https://archive.org/wayback/available?url="; diff --git a/components/apps/Browser/index.tsx b/components/apps/Browser/index.tsx index 968063e3fa..f4cd907b62 100644 --- a/components/apps/Browser/index.tsx +++ b/components/apps/Browser/index.tsx @@ -1,5 +1,8 @@ import { basename, join, resolve } from "path"; import { useCallback, useEffect, useRef, useState } from "react"; +import useProxyMenu, { + type ProxyState, +} from "components/apps/Browser/useProxyMenu"; import { ADDRESS_INPUT_PROPS } from "components/apps/FileExplorer/AddressBar"; import useHistoryMenu from "components/apps/Browser/useHistoryMenu"; import useBookmarkMenu from "components/apps/Browser/useBookmarkMenu"; @@ -7,13 +10,21 @@ import { createDirectoryIndex, type DirectoryEntries, } from "components/apps/Browser/directoryIndex"; -import { Arrow, Refresh, Stop } from "components/apps/Browser/NavigationIcons"; +import { + Arrow, + Network, + Refresh, + Stop, +} from "components/apps/Browser/NavigationIcons"; import StyledBrowser from "components/apps/Browser/StyledBrowser"; import { DINO_GAME, HOME_PAGE, LOCAL_HOST, NOT_FOUND, + OLD_NET_PROXY, + WAYBACK_URL_INFO, + type WaybackUrlInfo, bookmarks, } from "components/apps/Browser/config"; import { type ComponentProcessProps } from "components/system/Apps/RenderComponent"; @@ -102,6 +113,8 @@ const Browser: FC = ({ id }) => { position, moveHistory ); + const [proxyState, setProxyState] = useState("CORS"); + const proxyMenu = useProxyMenu(proxyState, setProxyState); const bookmarkMenu = useBookmarkMenu(); const setUrl = useCallback( async (addressInput: string): Promise => { @@ -302,7 +315,35 @@ const Browser: FC = ({ id }) => { setSrcDoc(newSrcDoc); prependFileToTitle(newTitle); } else { - const addressUrl = processedUrl.href; + let addressUrl = processedUrl.href; + + if (proxyState === "WAYBACK_MACHINE") { + try { + const urlInfoResponse = await fetch( + `${WAYBACK_URL_INFO}${addressUrl}` + ); + const { archived_snapshots } = + (await urlInfoResponse.json()) as WaybackUrlInfo; + + if (archived_snapshots.closest.url) { + addressUrl = archived_snapshots.closest.url; + + if ( + addressUrl.startsWith("http:") && + window.location.protocol === "https:" + ) { + addressUrl = addressUrl.replace("http:", "https:"); + } + } + } catch { + // Ignore failure to fetch url + } + } else if (proxyState.startsWith("OLD_NET_")) { + const year = proxyState.replace("OLD_NET_", ""); + const proxyUrl = OLD_NET_PROXY.replace("", year); + + addressUrl = `${proxyUrl}${processedUrl.href}`; + } changeIframeWindowLocation(addressUrl, contentWindow); @@ -357,6 +398,7 @@ const Browser: FC = ({ id }) => { initialTitle, open, prependFileToTitle, + proxyState, readFile, readdir, setIcon, @@ -423,6 +465,14 @@ const Browser: FC = ({ id }) => { }} {...ADDRESS_INPUT_PROPS} /> +