Replace Less with native CSS (#350)

The stylesheets only used Less for variables and nesting, both of which
are now native CSS features supported by Electron 41's bundled Chromium.

- src/less/ -> src/css/, all .less files renamed to .css
- @win-* variables -> :root custom properties + var()
- // comments -> /* */
- Dropped unused @win-silver
- Removed less devDependency and the dead 'less' npm script
  (pointed at a non-existent tools/lessc.js)
This commit is contained in:
Felix Rieseberg
2026-04-11 10:45:04 -07:00
committed by GitHub
parent e9ddfab65d
commit 3b62e1c9b5
15 changed files with 20 additions and 189 deletions

168
package-lock.json generated
View File

@@ -28,7 +28,6 @@
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"dotenv": "^17.3.1", "dotenv": "^17.3.1",
"electron": "41.2.0", "electron": "41.2.0",
"less": "^4.6.4",
"parcel-bundler": "^1.12.5", "parcel-bundler": "^1.12.5",
"patch-package": "^8.0.1", "patch-package": "^8.0.1",
"prettier": "^3.8.1", "prettier": "^3.8.1",
@@ -6073,22 +6072,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/copy-descriptor": { "node_modules/copy-descriptor": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -7966,20 +7949,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/errno": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"prr": "~1.0.1"
},
"bin": {
"errno": "cli.js"
}
},
"node_modules/error-ex": { "node_modules/error-ex": {
"version": "1.3.4", "version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
@@ -9949,20 +9918,6 @@
], ],
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
"dev": true,
"license": "MIT",
"optional": true,
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@@ -10707,19 +10662,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/is-windows": { "node_modules/is-windows": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -11098,32 +11040,6 @@
"graceful-fs": "^4.1.11" "graceful-fs": "^4.1.11"
} }
}, },
"node_modules/less": {
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz",
"integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"copy-anything": "^3.0.5",
"parse-node-version": "^1.0.1"
},
"bin": {
"lessc": "bin/lessc"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
"make-dir": "^2.1.0",
"mime": "^1.4.1",
"needle": "^3.1.0",
"source-map": "~0.6.0"
}
},
"node_modules/levn": { "node_modules/levn": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -11329,32 +11245,6 @@
"vlq": "^0.2.2" "vlq": "^0.2.2"
} }
}, },
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"pify": "^4.0.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/make-fetch-happen": { "node_modules/make-fetch-happen": {
"version": "10.2.1", "version": "10.2.1",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz",
@@ -11796,24 +11686,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/needle": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-3.5.0.tgz",
"integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"iconv-lite": "^0.6.3",
"sax": "^1.2.4"
},
"bin": {
"needle": "bin/needle"
},
"engines": {
"node": ">= 4.4.x"
}
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.4", "version": "0.6.4",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
@@ -13058,16 +12930,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/parse-node-version": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/parse5": { "node_modules/parse5": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
@@ -13310,17 +13172,6 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=6"
}
},
"node_modules/plist": { "node_modules/plist": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
@@ -14419,14 +14270,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/psl": { "node_modules/psl": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
@@ -15777,17 +15620,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/sax": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
"integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
"dev": true,
"license": "BlueOak-1.0.0",
"optional": true,
"engines": {
"node": ">=11.0.0"
}
},
"node_modules/saxes": { "node_modules/saxes": {
"version": "3.1.11", "version": "3.1.11",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",

View File

@@ -10,7 +10,6 @@
"make": "electron-forge make", "make": "electron-forge make",
"publish": "electron-forge publish", "publish": "electron-forge publish",
"lint": "prettier --write src/**/*.{ts,tsx} && npm run check-links", "lint": "prettier --write src/**/*.{ts,tsx} && npm run check-links",
"less": "node ./tools/lessc.js",
"tsc": "tsc -p tsconfig.json --noEmit", "tsc": "tsc -p tsconfig.json --noEmit",
"check-links": "node tools/check-links.js", "check-links": "node tools/check-links.js",
"postinstall": "patch-package" "postinstall": "patch-package"
@@ -40,7 +39,6 @@
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"dotenv": "^17.3.1", "dotenv": "^17.3.1",
"electron": "41.2.0", "electron": "41.2.0",
"less": "^4.6.4",
"parcel-bundler": "^1.12.5", "parcel-bundler": "^1.12.5",
"patch-package": "^8.0.1", "patch-package": "^8.0.1",
"prettier": "^3.8.1", "prettier": "^3.8.1",

View File

@@ -1,15 +1,16 @@
@import "./status.less"; @import "./status.css";
@import "./emulator.less"; @import "./emulator.css";
@import "./info.less"; @import "./info.css";
@import "./start.less"; @import "./start.css";
@import "./settings.less"; @import "./settings.css";
// 98.css uses the actual MS Sans Serif bitmap font and pixel-exact bevels. /* 98.css uses the actual MS Sans Serif bitmap font and pixel-exact bevels.
// Everything below is layout the chrome comes from 98.css. Everything below is layout the chrome comes from 98.css. */
@win-teal: #008080; :root {
@win-silver: silver; --win-teal: #008080;
@win-font: "Pixelated MS Sans Serif", Arial, sans-serif; --win-font: "Pixelated MS Sans Serif", Arial, sans-serif;
}
* { * {
user-select: none; user-select: none;
@@ -25,13 +26,13 @@ body {
body { body {
background: #000; background: #000;
font-family: @win-font; font-family: var(--win-font);
-webkit-font-smoothing: none; -webkit-font-smoothing: none;
image-rendering: pixelated; image-rendering: pixelated;
} }
body.paused { body.paused {
background: @win-teal; background: var(--win-teal);
> #emulator { > #emulator {
display: none; display: none;
@@ -48,8 +49,8 @@ button:focus {
outline: none; outline: none;
} }
// 98.css renders button text via text-shadow (color: transparent) so the /* 98.css renders button text via text-shadow (color: transparent) so the
// bitmap font stays crisp; <img> children need their own alignment. bitmap font stays crisp; <img> children need their own alignment. */
button img { button img {
height: 16px; height: 16px;
width: 16px; width: 16px;
@@ -58,7 +59,7 @@ button img {
} }
p { p {
font-family: @win-font; font-family: var(--win-font);
font-size: 11px; font-size: 11px;
line-height: 1.5; line-height: 1.5;
} }

View File

@@ -41,7 +41,7 @@
input[type="text"] { input[type="text"] {
width: 100%; width: 100%;
font-family: @win-font; font-family: var(--win-font);
} }
input[type="text"]:read-only { input[type="text"]:read-only {

View File

@@ -1,4 +1,4 @@
// "Welcome to Windows" splash modelled on the real first-boot dialog. /* "Welcome to Windows" splashmodelled on the real first-boot dialog. */
.welcome { .welcome {
width: 540px; width: 540px;

View File

@@ -5,8 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>windows95</title> <title>windows95</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../src/less/vendor/98.css"> <link rel="stylesheet" href="../src/css/vendor/98.css">
<link rel="stylesheet" href="../src/less/root.less"> <link rel="stylesheet" href="../src/css/root.css">
<!-- libv86 --> <!-- libv86 -->
</head> </head>
<body class="paused windows95"> <body class="paused windows95">