From b2b006fdc53889d01404fb7c190df95c538b064c Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:58:40 -0500 Subject: [PATCH 01/17] refactor hardpoint verification --- build.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/build.js b/build.js index 1e1150d..4e612e4 100644 --- a/build.js +++ b/build.js @@ -48,19 +48,24 @@ await copyOut("fonts/Sen-latin-ext.woff2"); import assert from "assert"; -function hardpoint(path) { - assert(existsSync(path), `Hardpoint asset "${path}" not present in output`); +function hardpoint(inPath) { + assert( + existsSync( + path.join(OUT_DIR, inPath), + `Hardpoint asset "${inPath}" not present in output`, + ), + ); } -hardpoint("dist/props.css"); +hardpoint("props.css"); -hardpoint("fonts/Fira_Code.woff2"); -hardpoint("fonts/Kenia.woff2"); -hardpoint("fonts/Nunito-cyrillic.woff2"); -hardpoint("fonts/Nunito-cyrillic-italic.woff2"); -hardpoint("fonts/Nunito-latin.woff2"); -hardpoint("fonts/Nunito-latin-ext.woff2"); -hardpoint("fonts/Nunito-latin-ext-italic.woff2"); -hardpoint("fonts/Nunito-latin-italic.woff2"); -hardpoint("fonts/Sen-latin.woff2"); -hardpoint("fonts/Sen-latin-ext.woff2"); +hardpoint("Fira_Code.woff2"); +hardpoint("Kenia.woff2"); +hardpoint("Nunito-cyrillic.woff2"); +hardpoint("Nunito-cyrillic-italic.woff2"); +hardpoint("Nunito-latin.woff2"); +hardpoint("Nunito-latin-ext.woff2"); +hardpoint("Nunito-latin-ext-italic.woff2"); +hardpoint("Nunito-latin-italic.woff2"); +hardpoint("Sen-latin.woff2"); +hardpoint("Sen-latin-ext.woff2"); From 07ecfd4c84a742e057cd2c38b892b8edb4f888e3 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:59:14 -0500 Subject: [PATCH 02/17] add favicon --- build.js | 10 ++++++++++ misc/favicon.ico | Bin 0 -> 38078 bytes 2 files changed, 10 insertions(+) create mode 100644 misc/favicon.ico diff --git a/build.js b/build.js index 4e612e4..f509bb0 100644 --- a/build.js +++ b/build.js @@ -39,6 +39,14 @@ await copyOut("fonts/Nunito-latin-italic.woff2"); await copyOut("fonts/Sen-latin.woff2"); await copyOut("fonts/Sen-latin-ext.woff2"); +// ============================================================================ +// Misc +// ============================================================================ +// +// This section handles one-off miscellaneous assets + +await copyOut("misc/favicon.ico"); + // ============================================================================ // Hardpoint Verification // ============================================================================ @@ -69,3 +77,5 @@ hardpoint("Nunito-latin-ext-italic.woff2"); hardpoint("Nunito-latin-italic.woff2"); hardpoint("Sen-latin.woff2"); hardpoint("Sen-latin-ext.woff2"); + +hardpoint("favicon.ico"); diff --git a/misc/favicon.ico b/misc/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..20f1dbc0543b908e0399dfb68bc9ab0a900da454 GIT binary patch literal 38078 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 literal 0 HcmV?d00001 From d8d49ec47ef178a9ed22c8bfd0acded9414032d1 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:33:25 -0500 Subject: [PATCH 03/17] add header.wc.js --- wc/header.wc.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 wc/header.wc.js diff --git a/wc/header.wc.js b/wc/header.wc.js new file mode 100644 index 0000000..8cb241e --- /dev/null +++ b/wc/header.wc.js @@ -0,0 +1,23 @@ +class EthmarksHeader extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+ Ethan Marks + +
`; + + const activeLink = this.getAttribute("active"); + if (activeLink) { + const targetLink = this.querySelector("#nav-" + activeLink.toLowerCase()); + if (targetLink) { + targetLink.classList.add("active"); + } + } + } +} From a38f4d106aa5ee8aeea2fc06471055136a2128b0 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:33:59 -0500 Subject: [PATCH 04/17] refactor header.wc.js --- wc/header.wc.js | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/wc/header.wc.js b/wc/header.wc.js index 8cb241e..61c6529 100644 --- a/wc/header.wc.js +++ b/wc/header.wc.js @@ -1,23 +1,31 @@ -class EthmarksHeader extends HTMLElement { +export default class EthmarksHeader extends HTMLElement { connectedCallback() { + const navItems = [ + { name: "Home", href: "https://ethmarks.github.io/" }, + { name: "About", href: "https://ethmarks.github.io/about/" }, + { name: "Posts", href: "https://ethmarks.github.io/posts/" }, + { name: "Blips", href: "https://ethmarks.github.io/blips/" }, + { name: "Projects", href: "https://ethmarks.github.io/tags/projects/" }, + ]; + + const activeLink = this.getAttribute("active"); + this.innerHTML = `
Ethan Marks
`; - - const activeLink = this.getAttribute("active"); - if (activeLink) { - const targetLink = this.querySelector("#nav-" + activeLink.toLowerCase()); - if (targetLink) { - targetLink.classList.add("active"); - } - } } } From 7430903fb7154b4922a15ce66453f15f41d24883 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:48:04 -0500 Subject: [PATCH 05/17] add birthday mode to header.wc.js --- wc/header.wc.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wc/header.wc.js b/wc/header.wc.js index 61c6529..d2d5147 100644 --- a/wc/header.wc.js +++ b/wc/header.wc.js @@ -10,8 +10,12 @@ export default class EthmarksHeader extends HTMLElement { const activeLink = this.getAttribute("active"); + const today = new Date(); + const isBirthday = today.getMonth() === 8 && today.getDate() === 13; // September 13 + const birthdayClass = isBirthday ? "birthday-mode" : ""; + this.innerHTML = ` -
+
Ethan Marks From 30500ea6e619b68cf6c4447b07b528d6b014e41c Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:58:29 -0500 Subject: [PATCH 06/17] add footer.wc.js --- wc/footer.wc.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 wc/footer.wc.js diff --git a/wc/footer.wc.js b/wc/footer.wc.js new file mode 100644 index 0000000..73e9137 --- /dev/null +++ b/wc/footer.wc.js @@ -0,0 +1,18 @@ +export default class EthmarksFooter extends HTMLElement { + connectedCallback() { + const sourceLink = + this.getAttribute("source") || + "https://github.com/ethmarks/ethmarks.github.io"; + + this.innerHTML = ` + `; + } +} From 8b03355d4b6285d148fa555f91e794c817d14a3f Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:58:54 -0500 Subject: [PATCH 07/17] remove target blank from footer --- wc/footer.wc.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wc/footer.wc.js b/wc/footer.wc.js index 73e9137..4f6d24f 100644 --- a/wc/footer.wc.js +++ b/wc/footer.wc.js @@ -7,11 +7,11 @@ export default class EthmarksFooter extends HTMLElement { this.innerHTML = ` `; } From fe04c67b4b52723038a56fdc723bebad909298c1 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 19:40:38 -0500 Subject: [PATCH 08/17] add height overflow handling to footer.wc.js --- wc/footer.wc.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/wc/footer.wc.js b/wc/footer.wc.js index 4f6d24f..2b7552c 100644 --- a/wc/footer.wc.js +++ b/wc/footer.wc.js @@ -4,15 +4,43 @@ export default class EthmarksFooter extends HTMLElement { this.getAttribute("source") || "https://github.com/ethmarks/ethmarks.github.io"; + function getOverflowClass() { + const contentHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight, + ); + if (contentHeight === 0 || contentHeight < window.innerHeight) { + return ""; + } else { + return "height-overflow"; + } + } + this.innerHTML = ` - `; - this.resizeHandler = () => { + this.resizeObserver = new ResizeObserver(() => { this.querySelector("footer").classList = getOverflowClass(); - }; + }); - window.visualViewport.addEventListener("resize", this.resizeHandler); + this.resizeObserver.observe(document.body); } disconnectedCallback() { - if (this.resizeHandler) { - window.visualViewport.removeEventListener("resize", this.resizeHandler); + if (this.resizeObserver) { + this.resizeObserver.disconnect(); } } } From 11cfad03ce5f6cfc22d65227fcc1f53b1ca18231 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:14:38 -0500 Subject: [PATCH 11/17] fix overflow handling in footer.wc.js --- wc/footer.wc.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/wc/footer.wc.js b/wc/footer.wc.js index 4d05e07..1525f4c 100644 --- a/wc/footer.wc.js +++ b/wc/footer.wc.js @@ -7,14 +7,13 @@ export default class EthmarksFooter extends HTMLElement { const currentYear = new Date().getFullYear(); function getOverflowClass() { - const contentHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight, - ); - if (contentHeight === 0 || contentHeight < window.innerHeight) { - return ""; - } else { + if ( + document.documentElement.scrollHeight > + document.documentElement.clientHeight + ) { return "height-overflow"; + } else { + return ""; } } @@ -33,14 +32,18 @@ export default class EthmarksFooter extends HTMLElement { `; - this.resizeObserver = new ResizeObserver(() => { + this.resizeHandler = () => { this.querySelector("footer").classList = getOverflowClass(); - }); - - this.resizeObserver.observe(document.body); + }; + window.visualViewport.addEventListener("resize", this.resizeHandler); + this.resizeObserver = new ResizeObserver(this.resizeHandler); + this.resizeObserver.observe(document.documentElement); } disconnectedCallback() { + if (this.resizeHandler) { + window.visualViewport.removeEventListener("resize", this.resizeHandler); + } if (this.resizeObserver) { this.resizeObserver.disconnect(); } From 4b2da4f12b1ca741b5551d8f052f1fee2ab6827d Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:33:57 -0500 Subject: [PATCH 12/17] add eth.wc.js barrel file --- wc/eth.wc.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 wc/eth.wc.js diff --git a/wc/eth.wc.js b/wc/eth.wc.js new file mode 100644 index 0000000..b9c7ec6 --- /dev/null +++ b/wc/eth.wc.js @@ -0,0 +1,5 @@ +import EthmarksHeader from "./header.wc"; +import EthmarksFooter from "./footer.wc"; + +customElements.define("eth-header", EthmarksHeader); +customElements.define("eth-footer", EthmarksFooter); From 8778a88d282af58bf0c098c64a1eeac99becf71b Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:40:29 -0500 Subject: [PATCH 13/17] refactor to use getOutPath() --- build.js | 9 ++++++--- scss.js | 8 ++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/build.js b/build.js index f509bb0..5285b3c 100644 --- a/build.js +++ b/build.js @@ -5,11 +5,14 @@ import * as path from "path"; export const OUT_DIR = "dist/"; fs.mkdir(OUT_DIR, { recursive: true }); -async function copyOut(inFile) { +export function getOutPath(inFile) { const pathParts = inFile.split(path.sep); pathParts[0] = OUT_DIR; - const outFile = pathParts.join(path.sep).replace(/\.scss$/, ".css"); - await fs.copyFile(inFile, outFile); + return pathParts.join(path.sep); +} + +async function copyOut(inFile) { + await fs.copyFile(inFile, getOutPath(inFile)); } // ============================================================================ diff --git a/scss.js b/scss.js index eee7687..ea60a1f 100644 --- a/scss.js +++ b/scss.js @@ -1,20 +1,16 @@ import * as sass from "sass"; import * as fs from "fs/promises"; import * as path from "path"; -import { OUT_DIR } from "./build.js"; +import { OUT_DIR, getOutPath } from "./build.js"; export async function processSCSS(inFile) { if (!path.extname(inFile)) { inFile += ".scss"; } - const pathParts = inFile.split(path.sep); - pathParts[0] = OUT_DIR; - const outFile = pathParts.join(path.sep).replace(/\.scss$/, ".css"); - const result = await sass.compileAsync(inFile, { style: "compressed", }); - await fs.writeFile(outFile, result.css); + await fs.writeFile(getOutPath(inFile).replace(/\.scss$/, ".css"), result.css); } From 0b330ba65f5212e741c06c8ea2e842e021e78833 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:41:16 -0500 Subject: [PATCH 14/17] add rollup deps --- package-lock.json | 721 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 + 2 files changed, 724 insertions(+) diff --git a/package-lock.json b/package-lock.json index 50e9b32..d9697dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "1.0.0", "license": "Apache-2.0", "devDependencies": { + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.54.0", "sass": "^1.97.1", "svelte": "^5.46.1" } @@ -45,6 +48,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -373,6 +387,440 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", @@ -390,6 +838,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -437,6 +892,13 @@ "node": ">=8" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -463,6 +925,23 @@ "node": ">=6" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -501,6 +980,13 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -515,6 +1001,44 @@ "node": ">=8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/immutable": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", @@ -522,6 +1046,22 @@ "dev": true, "license": "MIT" }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -547,6 +1087,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -608,6 +1155,13 @@ "license": "MIT", "optional": true }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -622,6 +1176,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -636,6 +1200,93 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/sass": { "version": "1.97.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz", @@ -657,6 +1308,33 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -667,6 +1345,30 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svelte": { "version": "5.46.1", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.1.tgz", @@ -694,6 +1396,25 @@ "node": ">=18" } }, + "node_modules/terser": { + "version": "5.44.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", + "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index c8c3cfe..35d7baf 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,9 @@ }, "homepage": "https://github.com/ethmarks/common#readme", "devDependencies": { + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.54.0", "sass": "^1.97.1", "svelte": "^5.46.1" } From 1610cb88192a533efe5522d9c324653b240b8fec Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:41:23 -0500 Subject: [PATCH 15/17] add rollup.js --- rollup.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 rollup.js diff --git a/rollup.js b/rollup.js new file mode 100644 index 0000000..e55de98 --- /dev/null +++ b/rollup.js @@ -0,0 +1,27 @@ +import { rollup } from "rollup"; +import resolve from "@rollup/plugin-node-resolve"; +import terser from "@rollup/plugin-terser"; +import * as fs from "fs/promises"; +import * as path from "path"; +import { getOutPath } from "./build.js"; + +export async function bundle(inFile, name) { + const bundle = await rollup({ + input: inFile, + plugins: [resolve(), terser()], + onwarn(warning, warn) { + // Suppress node-resolve warnings about unused exports + if (warning.code === "UNUSED_EXTERNAL_IMPORT") return; + if (warning.plugin === "node-resolve") return; + warn(warning); + }, + }); + + await bundle.write({ + file: getOutPath(inFile), + format: "iife", + name: name, + }); + + await bundle.close(); +} From 8e282a2e2c723c06eac9c7dbd9e0e00d6da49ac2 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:41:55 -0500 Subject: [PATCH 16/17] add web components section to build.js --- build.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build.js b/build.js index 5285b3c..0a72e0a 100644 --- a/build.js +++ b/build.js @@ -15,6 +15,18 @@ async function copyOut(inFile) { await fs.copyFile(inFile, getOutPath(inFile)); } +// ============================================================================ +// Web Components +// ============================================================================ +// +// This section bundles the .wc.js source into .js dist + +import { bundle } from "./rollup.js"; + +await bundle("wc/eth.wc.js", "ethComponents"); + +await processSCSS("scss/props"); + // ============================================================================ // SCSS // ============================================================================ From 4d4a78a062bfa49136e06fb523cf44fa65ad0b69 Mon Sep 17 00:00:00 2001 From: Ethan Marks <87040432+ethmarks@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:42:51 -0500 Subject: [PATCH 17/17] add eth.wc.js hardpoint --- build.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.js b/build.js index 0a72e0a..a7b019f 100644 --- a/build.js +++ b/build.js @@ -80,6 +80,8 @@ function hardpoint(inPath) { ); } +hardpoint("eth.wc.js"); + hardpoint("props.css"); hardpoint("Fira_Code.woff2");