diff --git a/.editorconfig b/.editorconfig index b9c127d..c1e2c64 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,7 +6,7 @@ root = true [*] indent_style = space indent_size = 4 -end_of_line = crlf +end_of_line = lf charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47e0dc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +release +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/LICENSE b/LICENSE index 11b7226..662ea85 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License -Copyright (c) 2024 BanOcean +Copyright (c) 2024-2025 BanOcean +Copyright (c) 2024-2026 IFV & Hephaestus Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3cad0f1..1038872 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,100 @@ -# Improvements for VULCAN +# Hephaestus -Browser extension with improvements for eduVULCAN and Dziennik VULCAN. +Browser extension with improvements for █████████ and ████████ ██████. ## Installation + [Installation guide [PL]](https://ifv.banocean.com)
-[Adding extension to browsers for development](#development-workflow) +[Adding the extension to browsers for development](#development-workflow) ## Features
Mobile navigation -| Before: | After: | -| --------------------------------------------------------------- | -------------------------------------------------------------- | -| | | +| Before: | After: | +| -------------------------------------------------------------------- | ------------------------------------------------------------------- | +| | |
PWA support - +
- Attendance statistics in separate tab + Attendance statistics in a separate tab + +| Before: | After: | +| --------------------------------------------------------------------- | -------------------------------------------------------------------- | +| | | -| Before: | After: | -| ------------------------------------------------------------ | ----------------------------------------------------------- | -| | |
- Hiding weekends in monthy calendars - -| Before: | After: | -| ------------------------------------------------------------ | ----------------------------------------------------------- | -| | | + Hide weekends in monthly calendars + +| Before: | After: | +| ----------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| | | +
- Displaying full name + Display full name + +| Before: | After: | +| ---------------------------------------------------------------- | --------------------------------------------------------------- | +| | | -| Before: | After: | -| --------------------------------------------------------------- | -------------------------------------------------------------- | -| | |
- Clean student dashboard + A cleaner student dashboard Before: - + After: - +
- Clean eduVULCAN home + A cleaner █████████ home -| Before: | After: | -| ------------------------------------------------------------ | ----------------------------------------------------------- | -| | | +| Before: | After: | +| ----------------------------------------------------------------- | ---------------------------------------------------------------- | +| | |
- Other minor improvements - + Other minor enhancements + - Hiding WCAG controls - Aligning detailed grades button - Redirecting to board -- Auto redirecting to eduVULCAN login page -
+- Auto-redirecting to █████████ login page + ## Development Workflow + +### Build the extension + +1. Make sure you have [Bun](https://bun.sh/) installed. +2. Install required dependencies using `bun install`, then use `bun simple-git-hooks` to set up pre-commit hook, which formats your code using prettier and lints it with eslint. +3. Use `bun dev` to start development server or `bun build` to build a package. + ### Firefox -To load addon from files in Firefox, you need to go to `about:debugging#/runtime/this-firefox` and click `Load Temporary Add-on...`. After that you need to select manifest.json file in file picker.
- + +To load add-on from files in Firefox, you need to go to `about:debugging#/runtime/this-firefox` and click `Load Temporary Add-on...`. After that you need to select the `manifest.json` file from `dist/` folder in the file picker.
+ + ### Chrome -To load extension from files in Chrome, you need to go to `chrome://extensions/` and click `Load unpacked` (with developer mode enabled)
- + +To load extension from files in Chrome, you need to go to `chrome://extensions/` and click `Load unpacked` (with Developer mode enabled)
+ ## License @@ -88,4 +102,4 @@ This project is licensed under the [MIT License](./LICENSE). ## Contributions -Contributions to this project are welcome. Feel free to [open issues](https://github.com/banocean/ifv/issues) and [submit pull requests](https://github.com/banocean/ifv/pulls). +Contributions to this project are welcome. Feel free to [open issues](https://github.com/yoper12/ifv/issues) and [submit pull requests](https://github.com/yoper12/ifv/pulls). diff --git a/apply.js b/apply.js deleted file mode 100644 index 447af59..0000000 --- a/apply.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @typedef {Object} Patch - * @property {string} name - The name of the patch. - * @property {string} description - The description of the patch. - * @property {Object} files - The files to be injected. - * @property {string[]} [files.css] - An array of CSS file names (optional). - * @property {string[]} [files.js] - An array of JS file names (optional). - * @property {string} [devices] - Device type: "mobileOnly", "desktopOnly" or undefined for both - */ - -/** @returns {Promise} */ -const fetchPatches = async () => { - const patchesResponse = await fetch(chrome.runtime.getURL("patches.json")); - return await patchesResponse.json(); -}; - -const getConfig = async () => - (await chrome.storage.sync.get("options"))?.options ?? {}; - -chrome.storage.onChanged.addListener((changes, namespace) => { - if ( - !changes.options?.oldValue || - JSON.stringify(changes.options?.oldValue) === - JSON.stringify(changes.options?.newValue) - ) - return; - if (namespace !== "sync") return; - window.location.reload(); -}); - -const isMobileView = () => window.innerWidth < 1024; - -const shouldInjectPatchForDevice = (patchDeviceType) => { - if (!patchDeviceType) return true; - - if (patchDeviceType === "mobileOnly") return isMobileView(); - if (patchDeviceType === "desktopOnly") return !isMobileView(); - - return true; -}; - -const getPatchesFiles = (patches, config) => { - const result = []; - - patches.forEach((patch) => { - if (config[patch.name] === false) return; - if (!shouldInjectPatchForDevice(patch.devices)) return; - - if (patch.files?.js?.length) { - patch.files.js.forEach((file) => { - result.push({ - path: `patches/${file}`, - type: "js", - }); - }); - } - - if ( - patch.files?.css?.length && - (!patch.allowedHostsCss || - patch.allowedHostsCss.includes(window.location.hostname)) - ) { - patch.files.css.forEach((file) => { - result.push({ - path: `patches/${file}`, - type: "css", - device: patch.devices, - }); - }); - } - }); - - return result; -}; - -async function run() { - let config = await getConfig(); - const patches = await fetchPatches(); - - if ( - patches.length > 0 && - config[patches[0].name] && - typeof config[patches[0].name] === "object" && - config[patches[0].name].description - ) { - // użytkownik ma stary format configu - kasujemy go - config = {}; - } - - patches.forEach((patch) => { - if (config[patch.name] === undefined) { - config[patch.name] = true; - } - }); - - chrome.storage.sync.set({ options: config }); - - for (const file of getPatchesFiles(patches, config)) { - const element = document.createElement( - file.type === "js" ? "script" : "link" - ); - element.setAttribute( - file.type === "js" ? "src" : "href", - chrome.runtime.getURL(file.path) - ); - if (file.type === "css") { - element.setAttribute("rel", "stylesheet"); - } else { - element.setAttribute("type", "module"); - element.classList.add("injected-script"); - } - document.head.appendChild(element); - } -} - -run(); diff --git a/assets/logo/logo-128-blue.png b/assets/logo/logo-128-blue.png deleted file mode 100644 index f82c65e..0000000 Binary files a/assets/logo/logo-128-blue.png and /dev/null differ diff --git a/assets/logo/logo-128-red.png b/assets/logo/logo-128-red.png deleted file mode 100644 index 6de072c..0000000 Binary files a/assets/logo/logo-128-red.png and /dev/null differ diff --git a/assets/logo/logo-192-blue.png b/assets/logo/logo-192-blue.png deleted file mode 100644 index 8b15f6b..0000000 Binary files a/assets/logo/logo-192-blue.png and /dev/null differ diff --git a/assets/logo/logo-192-red.png b/assets/logo/logo-192-red.png deleted file mode 100644 index ee39cc4..0000000 Binary files a/assets/logo/logo-192-red.png and /dev/null differ diff --git a/assets/logo/logo-512-blue.png b/assets/logo/logo-512-blue.png deleted file mode 100644 index 00accc6..0000000 Binary files a/assets/logo/logo-512-blue.png and /dev/null differ diff --git a/assets/logo/logo-512-red.png b/assets/logo/logo-512-red.png deleted file mode 100644 index 22389e1..0000000 Binary files a/assets/logo/logo-512-red.png and /dev/null differ diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..d9703f2 --- /dev/null +++ b/bun.lock @@ -0,0 +1,529 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "hephaestus", + "devDependencies": { + "@crxjs/vite-plugin": "^2.0.3", + "@eslint/js": "^9.39.2", + "@types/chrome": "^0.1.1", + "@types/node": "^24.0.15", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "globals": "^17.3.0", + "prettier": "^3.8.1", + "pretty-quick": "^4.2.2", + "simple-git-hooks": "^2.13.1", + "typescript-eslint": "^8.54.0", + "vite": "^7.0.5", + "vite-plugin-zip-pack": "^1.2.4", + }, + }, + }, + "packages": { + "@crxjs/vite-plugin": ["@crxjs/vite-plugin@2.3.0", "", { "dependencies": { "@rollup/pluginutils": "^4.1.2", "@webcomponents/custom-elements": "^1.5.0", "acorn-walk": "^8.2.0", "cheerio": "^1.0.0-rc.10", "convert-source-map": "^1.7.0", "debug": "^4.3.3", "es-module-lexer": "^0.10.0", "fast-glob": "^3.2.11", "fs-extra": "^10.0.1", "jsesc": "^3.0.2", "magic-string": "^0.30.12", "pathe": "^2.0.1", "picocolors": "^1.1.1", "react-refresh": "^0.13.0", "rollup": "2.79.2", "rxjs": "7.5.7" } }, "sha512-+0CNVGS4bB30OoaF1vUsHVwWU1Lm7MxI0XWY9Fd/Ob+ZVTZgEFNqJ1ZC69IVwQsoYhY0sMQLvpLWiFIuDz8htg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], + + "@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], + + "@types/chrome": ["@types/chrome@0.1.36", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-BvHbuyGttYXnGt5Gpwa4769KIinKHY1iLjlAPrrMBS2GI9m/XNMPtdsq0NgQalyuUdxvlMN/0OyGw0shFVIoUQ=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/filesystem": ["@types/filesystem@0.0.36", "", { "dependencies": { "@types/filewriter": "*" } }, "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA=="], + + "@types/filewriter": ["@types/filewriter@0.0.33", "", {}, "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g=="], + + "@types/har-format": ["@types/har-format@1.2.16", "", {}, "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/node": ["@types/node@24.10.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], + + "@webcomponents/custom-elements": ["@webcomponents/custom-elements@1.6.0", "", {}, "sha512-CqTpxOlUCPWRNUPZDxT5v2NnHXA4oox612iUGnmTUGQFhZ1Gkj8kirtl/2wcF6MqX7+PqqicZzOCBKKfIn0dww=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "cheerio": ["cheerio@1.2.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="], + + "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], + + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "es-module-lexer": ["es-module-lexer@0.10.5", "", {}, "sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw=="], + + "esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], + + "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@17.3.0", "", {}, "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + + "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + + "pretty-quick": ["pretty-quick@4.2.2", "", { "dependencies": { "@pkgr/core": "^0.2.7", "ignore": "^7.0.5", "mri": "^1.2.0", "picocolors": "^1.1.1", "picomatch": "^4.0.2", "tinyexec": "^0.3.2", "tslib": "^2.8.1" }, "peerDependencies": { "prettier": "^3.0.0" }, "bin": { "pretty-quick": "lib/cli.mjs" } }, "sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "react-refresh": ["react-refresh@0.13.0", "", {}, "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "rxjs": ["rxjs@7.5.7", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA=="], + + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "simple-git-hooks": ["simple-git-hooks@2.13.1", "", { "bin": { "simple-git-hooks": "cli.js" } }, "sha512-WszCLXwT4h2k1ufIXAgsbiTOazqqevFCIncOuUBZJ91DdvWcC5+OFkluWRQPrcuSYd8fjq+o2y1QfWqYMoAToQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-eslint": ["typescript-eslint@8.54.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.54.0", "@typescript-eslint/parser": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ=="], + + "undici": ["undici@7.20.0", "", {}, "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + + "vite-plugin-zip-pack": ["vite-plugin-zip-pack@1.2.4", "", { "dependencies": { "jszip": "^3.10.1" }, "peerDependencies": { "vite": ">=2.x" } }, "sha512-QgZEeiWayE2ZvMbkvcqWf94p/Z5YeNHZlkwXWIkkoISjePiWVXKRX2xCGmsURe9acGVdkobZ31dFJuCp3j1hMg=="], + + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "pretty-quick/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "vite/rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + } +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..1f4b50c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,22 @@ +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; +import globals from "globals"; +import eslintConfigPrettier from "eslint-config-prettier/flat"; +import { defineConfig } from "eslint/config"; + +export default defineConfig([ + js.configs.recommended, + tseslint.configs.recommended, + { + ignores: ["dist/**", "node_modules/**", ".git/**"], + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.webextensions, + }, + }, + }, + eslintConfigPrettier, +]); diff --git a/execute.js b/execute.js deleted file mode 100644 index 34ea313..0000000 --- a/execute.js +++ /dev/null @@ -1,55 +0,0 @@ -const modules = []; -let loadedScripts = 0; - -const isEverythingLoaded = () => - document.querySelectorAll(".injected-script").length === loadedScripts; - -window.appendModule = (...args) => { - modules.push(...args); - loadedScripts++; - if (isEverythingLoaded()) execute(); -}; - -const execute = () => { - if (!modules.length) - console.warn( - "Script tried executing before all files loaded or all patches are disabled", - ); - - const isFirstRun = !window.iWasThere; // :) - window.iWasThere = true; - - for (const { onlyOnReloads, doesRunHere, isLoaded, run } of modules) { - if (onlyOnReloads && !isFirstRun) continue; - if (doesRunHere !== undefined && !doesRunHere()) continue; - - if (!isLoaded || isLoaded()) run(); - else { - const observer = new MutationObserver((mutationsList, observer) => { - if (!isLoaded()) return; - observer.disconnect(); - run(); - }); - observer.observe(document.body, { - subtree: true, - childList: true, - }); - } - } -}; - -let lastLocation = location.pathname; - -window.history.pushState = new Proxy(window.history.pushState, { - apply: (target, a, args) => { - const isPathnameChanged = args.length >= 3 ? location.pathname !== args[2].split("#")[0] : true - if(args.length >= 3) lastLocation = args[2].split("#")[0] - target.apply(a, args); - if (modules.length !== 0 && isEverythingLoaded() && isPathnameChanged) execute(); - }, -}); - -window.addEventListener("popstate", (event) => { - const isPathnameChanged = location.pathname !== lastLocation - if (modules.length !== 0 && isEverythingLoaded() && isPathnameChanged) execute(); -}) \ No newline at end of file diff --git a/manifest.config.ts b/manifest.config.ts new file mode 100644 index 0000000..d4f6d55 --- /dev/null +++ b/manifest.config.ts @@ -0,0 +1,32 @@ +import { defineManifest } from "@crxjs/vite-plugin"; +import pkg from "./package.json"; + +export default defineManifest({ + manifest_version: 3, + name: "Hephaestus", + description: + "Poprawia uciążliwe elementy stron usług █████████ oraz ████████ ██████", + version: pkg.version, + icons: { + 128: "logo/logo-128.png", + 192: "logo/logo-192.png", + 512: "logo/logo-512.png", + }, + action: { + default_icon: { + 128: "logo/logo-128.png", + 192: "logo/logo-192.png", + 512: "logo/logo-512.png", + }, + default_popup: "src/popup/index.html", + }, + permissions: ["storage"], + host_permissions: [ + "*://dziennik-uczen.vulcan.net.pl/*", + "*://dziennik-wiadomosci.vulcan.net.pl/*", + "*://uczen.eduvulcan.pl/*", + "*://wiadomosci.eduvulcan.pl/*", + "*://dziennik-logowanie.vulcan.net.pl/*", + "*://eduvulcan.pl/*", + ], +}); diff --git a/manifest.json b/manifest.json deleted file mode 100644 index 0087c2a..0000000 --- a/manifest.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "manifest_version": 3, - "description": "Poprawia uciążliwe elementy stron usług eduVULCAN oraz Dziennik Vulcan", - "version": "0.4", - "name": "Improvements for Vulcan", - - "permissions": ["storage"], - "host_permissions": [ - "*://dziennik-uczen.vulcan.net.pl/*", - "*://dziennik-wiadomosci.vulcan.net.pl/*", - "*://uczen.eduvulcan.pl/*", - "*://wiadomosci.eduvulcan.pl/*", - "*://dziennik-logowanie.vulcan.net.pl/*", - "*://eduvulcan.pl/*" - ], - - "browser_specific_settings": { - "gecko": { - "id": "j.skup.test@gmail.com", - "strict_min_version": "128.0", - "update_url": "https://ifv.banocean.com/updates.json" - }, - "gecko_android": { - "id": "j.skup.test@gmail.com", - "strict_min_version": "128.0", - "update_url": "https://ifv.banocean.com/updates.json" - } - }, - - "web_accessible_resources": [ - { - "resources": ["patches/*", "patches.json"], - "matches": [ - "*://dziennik-uczen.vulcan.net.pl/*", - "*://dziennik-wiadomosci.vulcan.net.pl/*", - "*://uczen.eduvulcan.pl/*", - "*://wiadomosci.eduvulcan.pl/*", - "*://dziennik-logowanie.vulcan.net.pl/*", - "*://eduvulcan.pl/*" - ] - } - ], - "content_scripts": [ - { - "js": ["execute.js"], - "matches": [ - "*://dziennik-uczen.vulcan.net.pl/*", - "*://dziennik-wiadomosci.vulcan.net.pl/*", - "*://uczen.eduvulcan.pl/*", - "*://wiadomosci.eduvulcan.pl/*", - "*://dziennik-logowanie.vulcan.net.pl/*", - "*://eduvulcan.pl/*" - ], - "world": "MAIN" - }, - { - "js": ["apply.js", "settingsSaver.js"], - "matches": [ - "*://dziennik-uczen.vulcan.net.pl/*", - "*://dziennik-wiadomosci.vulcan.net.pl/*", - "*://uczen.eduvulcan.pl/*", - "*://wiadomosci.eduvulcan.pl/*", - "*://dziennik-logowanie.vulcan.net.pl/*", - "*://eduvulcan.pl/*" - ] - } - ], - "action": { - "default_popup": "popup/index.html" - }, - - "icons": { - "128": "assets/logo/logo-128-red.png", - "192": "assets/logo/logo-192-red.png", - "512": "assets/logo/logo-512-red.png" - } -} diff --git a/package.json b/package.json new file mode 100644 index 0000000..2bf9191 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "hephaestus", + "version": "1.0.0", + "devDependencies": { + "@crxjs/vite-plugin": "^2.0.3", + "@eslint/js": "^9.39.2", + "@types/chrome": "^0.1.1", + "@types/node": "^24.0.15", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "globals": "^17.3.0", + "prettier": "^3.8.1", + "pretty-quick": "^4.2.2", + "simple-git-hooks": "^2.13.1", + "typescript-eslint": "^8.54.0", + "vite": "^7.0.5", + "vite-plugin-zip-pack": "^1.2.4" + }, + "private": true, + "scripts": { + "dev": "vite", + "build": "tsc && vite build" + }, + "simple-git-hooks": { + "pre-commit": "bun pretty-quick --staged; bun eslint . --fix" + }, + "type": "module" +} diff --git a/patches.json b/patches.json deleted file mode 100644 index 79760bf..0000000 --- a/patches.json +++ /dev/null @@ -1,258 +0,0 @@ -[ - { - "name": "Move title to header", - "description": "Moves title to header", - "files": { - "css": ["moveTitleToHeader/style.css"], - "js": ["moveTitleToHeader/index.js"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl", "wiadomosci.eduvulcan.pl", "dziennik-wiadomosci.vulcan.net.pl"] - }, - { - "name": "Change close button icon", - "description": "Replaces close buttons with back buttons to indicate more accurately what action it corresponds to.", - "files": { - "css": ["arrows.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl", "wiadomosci.eduvulcan.pl", "dziennik-wiadomosci.vulcan.net.pl"], - "devices": "mobileOnly" - }, - { - "name": "Move messages button", - "description": "Moves messages button to header.", - "files": { - "js": ["messagesButton.js"] - }, - "devices": "mobileOnly" - }, - { - "name": "Cleanup grades table", - "description": "Hides subjects without any grades and columns without content.", - "files": { - "js": ["hideSubjectsWithNoGrades/finalGrades.js"], - "css": ["hideSubjectsWithNoGrades/normalGrades.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Hide empty exam results", - "description": "Hides exam results instead of showing no data.", - "files": { - "css": ["hideEmptyExamResults.css"] - }, - "devices": "mobileOnly" - }, - { - "name": "Hide footer", - "description": "Hides footer.", - "files": { - "css": ["hideFooter.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl", "wiadomosci.eduvulcan.pl", "dziennik-wiadomosci.vulcan.net.pl"], - "devices": "mobileOnly" - }, - { - "name": "Hide WCAG", - "description": "Hide WCAG buttons.", - "files": { - "css": ["hideWCAG.css"] - } - }, - { - "name": "Align Detailed Grades Button", - "description": "Aligns detailed grades button with other buttons.", - "files": { - "css": ["alignDetailedGradesButton.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Hide Tutors From Board", - "description": "Hides tutors from board.", - "files": { - "css": ["hideTutorsFromBoard.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Display Full Name", - "description": "Shows the user's name under the nickname.", - "files": { - "js": ["displayFullName.js"] - }, - "devices": "desktopOnly" - }, - { - "name": "Redirect To Board", - "description": "Redirects to board after login.", - "files": { - "js": ["redirectToBoard/script.js"], - "css": ["redirectToBoard/styles.css"] - }, - "allowedHostsCss": [ - "uczen.eduvulcan.pl", - "wiadomosci.eduvulcan.pl", - "dziennik-uczen.vulcan.net.pl", - "dziennik-wiadomosci.vulcan.net.pl" - ] - }, - { - "name": "Auto redirect to login page in eduVulcan", - "description": "Auto redirect to login page in eduVulcan.", - "files": { - "js": ["redirectToEVLogin.js"] - } - }, - { - "name": "Auto redirect to login page in Dziennik Vulcan", - "description": "Auto redirect to login page in Dziennik Vulcan.", - "files": { - "js": ["redirectToDVLogin.js"] - } - }, - { - "name": "Hide unneeded tiles in eduVulcan home", - "description": "Hides eduVulcan app download links tile, eduVulcan banner and ribbon.", - "files": { - "css": ["cleanUpEduVulcanHome.css"] - }, - "allowedHostsCss": ["eduvulcan.pl"] - }, - { - "name": "Hide Help On Dashboard", - "description": "Hides \"Do you need help\" tile.", - "files": { - "css": ["hideHelpOnDashboard.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "PWA Support", - "description": "Gives ability to install page as PWA.", - "files": { - "js": ["pwa.js"] - } - }, - { - "name": "Reload on resize", - "description": "Reloads page while changing between desktop and mobile layouts.", - "files": { - "js": ["fixResizing.js"] - } - }, - { - "name": "Mobile Navigation", - "description": "Replaces aside with more readable bottom navigation bar designed.", - "files": { - "css": ["newMobileNavbar/styles.css"], - "js": ["newMobileNavbar/index.js", "newMobileNavbar/highlights.js"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"], - "devices": "mobileOnly" - }, - { - "name": "Hide weekends in monthly calendars", - "description": "Hides weekends in monthly calendars in timetable, exams and homework views.", - "files": { - "css": ["hideWeekends.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Login and password together", - "description": "Show login and password inputs together on login page.", - "files": { - "js": ["loginPasswordTogether/script.js"], - "css": ["loginPasswordTogether/styles.css"] - }, - "allowedHostsCss": ["eduvulcan.pl", "dziennik-logowanie.vulcan.net.pl"] - }, - { - "name": "Move user options to header", - "description": "Moves user avatar to header that opens dropdown with user options.", - "files": { - "js": ["moveUserOptionsToHeader/script.js"], - "css": ["moveUserOptionsToHeader/styles.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl", "wiadomosci.eduvulcan.pl", "dziennik-wiadomosci.vulcan.net.pl"], - "devices": "mobileOnly" - }, - { - "name": "Resigned timetable", - "description": "Changes styles and navigation on timetable page.", - "files": { - "js": ["newTimetable/script.js"], - "css": ["newTimetable/styles.css", "apis/bottomDateSelector/styles.css"] - }, - "devices": "mobileOnly" - }, - { - "name": "Redisigned attendance", - "description": "Changes styles and navigation on attendance page.", - "files": { - "js": ["newAttendance/justifyButton.js", "newAttendance/tabs.js"], - "css": ["newAttendance/style.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Redesigned dashboard", - "description": "Changes styles of the home (dashboard) page.", - "files": { - "js": ["newDashboard/index.js"], - "css": ["newDashboard/styles.css"] - }, - "devices": "mobileOnly", - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Fix going back in history", - "description": "Allows to use the browser's back button to return to the expected location. (firefox only)", - "files": { - "js": ["fixGoingBack.js"] - }, - "devices": "mobileOnly" - }, - { - "name": "Highlight today", - "description": "Highlights today's date in the calendar.", - "files": { - "css": ["highlightToday.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"] - }, - { - "name": "Count averages", - "description": "Counts averages in grades table and gives access to \"Uczeń na tle klasy\".", - "files": { - "js": ["countAverage.js"] - }, - "settings": [ - { - "id": "plusValue", - "name": "Plus value", - "description": "Value to add when the grade has a plus (e.g. 3+).", - "type": "number", - "default": 0.3, - "step": 0.1 - }, - { - "id": "minusValue", - "name": "Minus value", - "description": "Value to be deducted when the grade has a minus (e.g. 3-).", - "type": "number", - "default": 0.3, - "step": 0.1 - } - ] - }, - { - "name": "Display settings on the website", - "description": "Makes patches settings accessible.", - "files": { - "js": ["patchesSettings/desktop.js", "patchesSettings/mobile.js"], - "css": ["patchesSettings/style.css"] - }, - "allowedHostsCss": ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl", "wiadomosci.eduvulcan.pl", "dziennik-wiadomosci.vulcan.net.pl"] - } -] \ No newline at end of file diff --git a/patches/fixGoingBack.js b/patches/fixGoingBack.js deleted file mode 100644 index c332a15..0000000 --- a/patches/fixGoingBack.js +++ /dev/null @@ -1,55 +0,0 @@ -import { waitForRender } from './apis/waitForElement.js'; - -const fixGoingBack = async () => { - const observer = new MutationObserver(mutationHandler); - observer.observe(document.body, { - childList: true - }); -}; - -const mutationHandler = async (mutationList) => { - for (const mutation of mutationList) { - const modals = document.querySelectorAll('.MuiDrawer-modal'); - const modal = modals[modals.length - 1] || undefined; - - if (modal && modal.getAttribute('data-has-listener') !== 'true') { - history.pushState({ ...history.state, details: true }, '', `${location.pathname}#`); - modal.setAttribute('data-has-listener', 'true'); - - for (const e of modals) { - if (e === modal) continue; - e.removeAttribute('data-has-listener'); - } - - await waitForRender(() => modal.querySelector('.modal-button--close')); - const closeButton = modal.querySelector('.modal-button--close'); - - addEventListener('popstate', popstateHandler(closeButton), { once: true }); - - closeButton?.addEventListener('click', () => { - if (history.state?.details) { - history.back(); - } - }); - } - } -}; - -const popstateHandler = (e) => () => { - if (e?.closest("div[role=presentation].MuiDrawer-modal")?.getAttribute('data-has-listener') !== 'true') return; - e?.click(); -}; - -window.appendModule({ - isLoaded: () => true, - onlyOnReloads: true, - run: fixGoingBack, - doesRunHere: () => - [ - "eduvulcan.pl", - "uczen.eduvulcan.pl", - "wiadomosci.eduvulcan.pl", - "dziennik-uczen.vulcan.net.pl", - "dziennik-wiadomosci.vulcan.net.pl" - ].includes(window.location.hostname) && typeof InstallTrigger !== 'undefined', -}); \ No newline at end of file diff --git a/patches/hideEmptyExamResults.css b/patches/hideEmptyExamResults.css deleted file mode 100644 index a515548..0000000 --- a/patches/hideEmptyExamResults.css +++ /dev/null @@ -1,9 +0,0 @@ -.accordion__full-width__one-item:has(#panel-content-egzaminy td[colspan="3"]) { - display: none !important; -} - - -main .app__content:has(.accordion__full-width__one-item #panel-content-egzaminy td[colspan="3"]) .content-container.content-container__pure > div:nth-child(2) { - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; -} \ No newline at end of file diff --git a/patches/hideHelpOnDashboard.css b/patches/hideHelpOnDashboard.css deleted file mode 100644 index 7041090..0000000 --- a/patches/hideHelpOnDashboard.css +++ /dev/null @@ -1,3 +0,0 @@ -#kafel-pomoc-pomigracyjna { - display: none !important; -} \ No newline at end of file diff --git a/patches/hideWCAG.css b/patches/hideWCAG.css deleted file mode 100644 index 15785a9..0000000 --- a/patches/hideWCAG.css +++ /dev/null @@ -1,3 +0,0 @@ -.wcag-mobile, .wcag-tools, .wcag-controls { - display: none !important; -} \ No newline at end of file diff --git a/patches/highlightToday.css b/patches/highlightToday.css deleted file mode 100644 index efb4d2b..0000000 --- a/patches/highlightToday.css +++ /dev/null @@ -1,17 +0,0 @@ -.scheduler-simple-cell--current, .scheduler-cell--current, .frequency-scheduler-cell--current, .plan-scheduler-cell__current { - background-color: rgba(200, 200, 210, 0.25); -} -.scheduler-simple-cell--current .scheduler-simple-cell__number, .scheduler-cell--current .scheduler-cell__number, .frequency-scheduler-cell--current .frequency-scheduler-cell__footer, .plan-scheduler-cell__current .plan-scheduler-cell__footer-day { - background-color: #e12d39; - color: #ffffff !important; - display: inline-flex; - justify-content: center; - align-items: center; - width: 43px; - height: 43px; - border-radius: 50px; -} -.scheduler-simple-cell--current .scheduler-simple-cell__number { - width: 30px; - height: 30px; -} \ No newline at end of file diff --git a/patches/newMobileNavbar/index.js b/patches/newMobileNavbar/index.js deleted file mode 100644 index 2627900..0000000 --- a/patches/newMobileNavbar/index.js +++ /dev/null @@ -1,170 +0,0 @@ -import { getFromAside } from "../apis/aside.js"; -import { waitForRender } from "../apis/waitForElement.js"; -import { setHighlights } from "./highlights.js"; - -if (window.location.hostname.match(/^(dziennik-)?(uczen).*/)) window.asideMode = "hidden" - -const getPages = (selector = "aside > section > .MuiList-root > ul") => { - if (!document.querySelector("aside")) return [] - return Array.from( - document.querySelector(selector).children - ).map((item) => { - const isDirectLink = item.classList.contains("MuiListItem-gutters") - const icon = getComputedStyle( - isDirectLink ? item : item.querySelector("div > button"), ":before" - ).getPropertyValue("content"); - const name = item.querySelector( - isDirectLink ? "a" : ".accordion__title__content" - )?.innerText - - const items = isDirectLink ? undefined : - Array.from(item.querySelector(".items").children) - - return { - type: isDirectLink ? 1 : 2, - element: item, - items, - icon, - name - } - }) -} - -const BACK_ICON_URL = "https://raw.githubusercontent.com/banocean/ifv/new-navbar/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg" - -const navIcons = { - "tablica": "dashboard", - "oceny": "counter_6", - "frekwencja": "event_available", - "planZajec": "calendar_clock" -} - -const run = async () => { - const nav = document.createElement("nav") - nav.classList.add("bottom-navigation-bar") - - const more = document.createElement("div") - more.classList.add("more-popup") - more.classList.add("list-modal") - more.innerHTML = `

Więcej

` - more.style.display = "none" - - more.querySelector("img").addEventListener("click", () => { - more.style.display = "none"; - history.back() - setHighlights() - }) - - await getFromAside(() => null) // We need aside to just load - await waitForRender(() => getPages().length > 1) - - const navPages = ["tablica", "oceny", "frekwencja", "planZajec"] - const pages = getPages() - for (const page of pages) { - const itemClass = Array.from(page.element.classList) - .find((c) => !["MuiListItem-root", "MuiListItem-gutters", "selected"].includes(c)) - const item = document.createElement("div") - - if (!navPages.includes(itemClass)) { - item.innerHTML = "
" - item.querySelector(".icon").style.content = page.icon - item.querySelector(".name").innerText = page.name - more.querySelector("div:last-of-type").appendChild(item) - } else { - item.innerHTML = `
` - item.querySelector("div:last-of-type").innerText = page.name - nav.appendChild(item) - } - - if (page.type === 1) { - item.addEventListener("click", () => { - document.querySelector(`.${itemClass} a`).click() - more.style.display = "none" - document.querySelector(".header__hamburger__icon button").click() - document.querySelector("div#root").scroll(0,0) - setHighlights() - }) - } else { - const detailedOptionsPage = document.createElement("div") - detailedOptionsPage.innerHTML = `

` - detailedOptionsPage.style.zIndex = "4002" - detailedOptionsPage.style.display = "none" - detailedOptionsPage.classList.add("list-modal") - - detailedOptionsPage.querySelector("h1").innerText = page.name - detailedOptionsPage.querySelector("img").addEventListener("click", () => { - history.back() - }) - - for (let i = 0; i < page.items.length; i++) { - const option = page.items[i] - const element = document.createElement("div") - element.innerHTML = "
" - element.querySelector(".icon").style.content = page.icon - element.querySelector(".name").innerText = option.firstChild.innerText - element.addEventListener("click", () => { - detailedOptionsPage.style.display = "none" - more.style.display = "none" - Array.from(document.querySelectorAll(`.${itemClass} .items a`))[i].click() - document.querySelector(".header__hamburger__icon button").click() - document.querySelector("div#root").scroll(0,0) - }) - detailedOptionsPage.lastElementChild.appendChild(element) - } - - item.addEventListener("click", () => { - detailedOptionsPage.style.display = "block" - history.pushState({ ...history.state, moreDetails: true }, "", `${location.pathname}#${itemClass}`) - }) - - addEventListener('popstate', (e) => { - if (e.state?.moreDetails) { - detailedOptionsPage.style.display = "block" - } else { - detailedOptionsPage.style.display = "none" - } - }) - - document.body.appendChild(detailedOptionsPage) - } - } - - const moreButton = document.createElement("div") - moreButton.innerHTML = ` -
- -
-
Więcej
- ` - - moreButton.addEventListener("click", () => { - more.style.display = "block" - history.pushState({ ...history.state, more: true }, "", `${location.pathname}#more`) - setHighlights() - }) - - nav.appendChild(moreButton) - - document.body.appendChild(nav) - document.body.appendChild(more) -} - -addEventListener('popstate', (e) => { - if (e.state?.moreDetails !== true) { - if (e.state?.more) { - document.querySelector('.more-popup').style.display = "block"; - } else { - document.querySelectorAll('.list-modal').forEach((e) => { - e.style.display = "none"; - }); - } - } - setHighlights() -}) - -window.appendModule({ - run, - doesRunHere: () => window.location.hostname.match(/^(dziennik-)?(uczen).*/), - onlyOnReloads: true, - isLoaded: () => !!document.querySelector(".header__hamburger__icon") -}) \ No newline at end of file diff --git a/patches/redirectToDVLogin.js b/patches/redirectToDVLogin.js deleted file mode 100644 index e9bd7c8..0000000 --- a/patches/redirectToDVLogin.js +++ /dev/null @@ -1,26 +0,0 @@ -function redirectToLoginPage() { - window.location.pathname = `/${ - window.location.pathname.split("/")[1] - }/LoginEndpoint.aspx`; -} - -window.appendModule({ - onlyOnReloads: true, - run: redirectToLoginPage, - doesRunHere: () => - window.location.hostname === "dziennik-uczen.vulcan.net.pl" && - !window.location.pathname.split("/")[2], -}); - -const pathSegment = window.location.pathname.split("/")[1]; - -const targetSpan = document.querySelector( - ".input-components ~ .form-gap > span" -); - -if (targetSpan) { - const spanHTML = targetSpan.innerHTML; - const newHTML = spanHTML.slice(0, -1); - const additionalText = `lub użyj innej metody logowania`; - targetSpan.innerHTML = `${newHTML} ${additionalText}`; -} diff --git a/assets/add to chrome.svg b/public/add to chrome.svg similarity index 100% rename from assets/add to chrome.svg rename to public/add to chrome.svg diff --git a/assets/add to firefox.svg b/public/add to firefox.svg similarity index 100% rename from assets/add to firefox.svg rename to public/add to firefox.svg diff --git a/assets/discord.svg b/public/discord.svg similarity index 100% rename from assets/discord.svg rename to public/discord.svg diff --git a/assets/github.svg b/public/github.svg similarity index 100% rename from assets/github.svg rename to public/github.svg diff --git a/public/logo/logo-128.png b/public/logo/logo-128.png new file mode 100644 index 0000000..8580ccd Binary files /dev/null and b/public/logo/logo-128.png differ diff --git a/public/logo/logo-192.png b/public/logo/logo-192.png new file mode 100644 index 0000000..36bf566 Binary files /dev/null and b/public/logo/logo-192.png differ diff --git a/public/logo/logo-512.png b/public/logo/logo-512.png new file mode 100644 index 0000000..cf84c80 Binary files /dev/null and b/public/logo/logo-512.png differ diff --git a/public/screenshots/attendanceAfter.png b/public/screenshots/attendanceAfter.png new file mode 100644 index 0000000..13642f2 Binary files /dev/null and b/public/screenshots/attendanceAfter.png differ diff --git a/public/screenshots/attendanceBefore.png b/public/screenshots/attendanceBefore.png new file mode 100644 index 0000000..9dffa44 Binary files /dev/null and b/public/screenshots/attendanceBefore.png differ diff --git a/screenshots/chromeDebug.png b/public/screenshots/chromeDebug.png similarity index 100% rename from screenshots/chromeDebug.png rename to public/screenshots/chromeDebug.png diff --git a/public/screenshots/evHomeAfter.png b/public/screenshots/evHomeAfter.png new file mode 100644 index 0000000..eb06273 Binary files /dev/null and b/public/screenshots/evHomeAfter.png differ diff --git a/public/screenshots/evHomeBefore.png b/public/screenshots/evHomeBefore.png new file mode 100644 index 0000000..e9b7b6b Binary files /dev/null and b/public/screenshots/evHomeBefore.png differ diff --git a/screenshots/firefoxDebug.png b/public/screenshots/firefoxDebug.png similarity index 100% rename from screenshots/firefoxDebug.png rename to public/screenshots/firefoxDebug.png diff --git a/public/screenshots/fnameAfter.png b/public/screenshots/fnameAfter.png new file mode 100644 index 0000000..be612d8 Binary files /dev/null and b/public/screenshots/fnameAfter.png differ diff --git a/public/screenshots/fnameBefore.png b/public/screenshots/fnameBefore.png new file mode 100644 index 0000000..6a8b79e Binary files /dev/null and b/public/screenshots/fnameBefore.png differ diff --git a/public/screenshots/hideWeekendsAfter.png b/public/screenshots/hideWeekendsAfter.png new file mode 100644 index 0000000..9b0561c Binary files /dev/null and b/public/screenshots/hideWeekendsAfter.png differ diff --git a/public/screenshots/hideWeekendsBefore.png b/public/screenshots/hideWeekendsBefore.png new file mode 100644 index 0000000..996b11c Binary files /dev/null and b/public/screenshots/hideWeekendsBefore.png differ diff --git a/public/screenshots/mobileNavAfter.png b/public/screenshots/mobileNavAfter.png new file mode 100644 index 0000000..04b4587 Binary files /dev/null and b/public/screenshots/mobileNavAfter.png differ diff --git a/public/screenshots/mobileNavBefore.png b/public/screenshots/mobileNavBefore.png new file mode 100644 index 0000000..655061a Binary files /dev/null and b/public/screenshots/mobileNavBefore.png differ diff --git a/public/screenshots/pwa.png b/public/screenshots/pwa.png new file mode 100644 index 0000000..fdecf8f Binary files /dev/null and b/public/screenshots/pwa.png differ diff --git a/public/screenshots/whiteboardAfter.png b/public/screenshots/whiteboardAfter.png new file mode 100644 index 0000000..fd54b55 Binary files /dev/null and b/public/screenshots/whiteboardAfter.png differ diff --git a/public/screenshots/whiteboardBefore.png b/public/screenshots/whiteboardBefore.png new file mode 100644 index 0000000..194fb68 Binary files /dev/null and b/public/screenshots/whiteboardBefore.png differ diff --git a/pwa/manifest-eduvulcan.json b/pwa/manifest-eduvulcan.json deleted file mode 100644 index 95ff903..0000000 --- a/pwa/manifest-eduvulcan.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "eduVULCAN", - "short_name": "eduVULCAN", - "start_url": "https://eduvulcan.pl/", - "display": "standalone", - "orientation": "portrait", - "background_color": "#006BD6", - "icons": [ - { - "src": "https://raw.githubusercontent.com/BanOcean/ifv/main/assets/logo/logo-128-blue.png", - "sizes": "128x128", - "type": "image/png" - }, - { - "src": "https://raw.githubusercontent.com/BanOcean/ifv/main/assets/logo/logo-192-blue.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "https://raw.githubusercontent.com/BanOcean/ifv/main/assets/logo/logo-512-blue.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "splash_pages": null, - "prefer-related-application": false - } \ No newline at end of file diff --git a/screenshots/attendanceAfter.png b/screenshots/attendanceAfter.png deleted file mode 100644 index 79823b1..0000000 Binary files a/screenshots/attendanceAfter.png and /dev/null differ diff --git a/screenshots/attendanceBefore.png b/screenshots/attendanceBefore.png deleted file mode 100644 index 96c4519..0000000 Binary files a/screenshots/attendanceBefore.png and /dev/null differ diff --git a/screenshots/evHomeAfter.png b/screenshots/evHomeAfter.png deleted file mode 100644 index f41072e..0000000 Binary files a/screenshots/evHomeAfter.png and /dev/null differ diff --git a/screenshots/evHomeBefore.png b/screenshots/evHomeBefore.png deleted file mode 100644 index c5c5370..0000000 Binary files a/screenshots/evHomeBefore.png and /dev/null differ diff --git a/screenshots/fnameAfter.png b/screenshots/fnameAfter.png deleted file mode 100644 index 41716fa..0000000 Binary files a/screenshots/fnameAfter.png and /dev/null differ diff --git a/screenshots/fnameBefore.png b/screenshots/fnameBefore.png deleted file mode 100644 index dd25f72..0000000 Binary files a/screenshots/fnameBefore.png and /dev/null differ diff --git a/screenshots/hideWeekendsAfter.png b/screenshots/hideWeekendsAfter.png deleted file mode 100644 index 714d99b..0000000 Binary files a/screenshots/hideWeekendsAfter.png and /dev/null differ diff --git a/screenshots/hideWeekendsBefore.png b/screenshots/hideWeekendsBefore.png deleted file mode 100644 index 8ad5ab1..0000000 Binary files a/screenshots/hideWeekendsBefore.png and /dev/null differ diff --git a/screenshots/mobileNavAfter.png b/screenshots/mobileNavAfter.png deleted file mode 100644 index dc44271..0000000 Binary files a/screenshots/mobileNavAfter.png and /dev/null differ diff --git a/screenshots/mobileNavBefore.png b/screenshots/mobileNavBefore.png deleted file mode 100644 index e18aea2..0000000 Binary files a/screenshots/mobileNavBefore.png and /dev/null differ diff --git a/screenshots/pwa.png b/screenshots/pwa.png deleted file mode 100644 index 22797ac..0000000 Binary files a/screenshots/pwa.png and /dev/null differ diff --git a/screenshots/whiteboardAfter.png b/screenshots/whiteboardAfter.png deleted file mode 100644 index ab9ce77..0000000 Binary files a/screenshots/whiteboardAfter.png and /dev/null differ diff --git a/screenshots/whiteboardBefore.png b/screenshots/whiteboardBefore.png deleted file mode 100644 index 10642fc..0000000 Binary files a/screenshots/whiteboardBefore.png and /dev/null differ diff --git a/settingsSaver.js b/settingsSaver.js deleted file mode 100644 index e7539be..0000000 --- a/settingsSaver.js +++ /dev/null @@ -1,40 +0,0 @@ -chrome.storage.sync.get("patchesSettings", (data) => { - if (data.patchesSettings) { - sessionStorage.setItem( - "ifv_patches_settings", - JSON.stringify(data.patchesSettings) - ); - } else { - sessionStorage.setItem("ifv_patches_settings", JSON.stringify([])); - } -}); - -chrome.storage.sync.get("options", (data) => { - if (data.options) { - sessionStorage.setItem("ifv_options", JSON.stringify(data.options)); - } else { - sessionStorage.setItem("ifv_options", JSON.stringify({})); - } -}); - -let lastContent = sessionStorage.getItem("ifv_patches_settings"); - -function saveSettingsToStorage() { - const newContent = sessionStorage.getItem("ifv_patches_settings"); - if (newContent === lastContent) return; - - chrome.storage.sync.set({ patchesSettings: JSON.parse(newContent) }); - - lastContent = newContent; -} - -window.addEventListener("ifv-settings-changed", saveSettingsToStorage); - -fetch(chrome.runtime.getURL("patches.json")) - .then((response) => response.json()) - .then((data) => - data.sort((a, b) => a.name.localeCompare(b.name, "pl")) - ) - .then((data) => { - sessionStorage.setItem("IFV_PATCHES", JSON.stringify(data)); - }); diff --git a/assets/icons/calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/chevron_left_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/chevron_left_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/chevron_left_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/chevron_left_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/chevron_right_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/chevron_right_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/chevron_right_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/chevron_right_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/clear.svg b/src/assets/icons/clear.svg similarity index 100% rename from assets/icons/clear.svg rename to src/assets/icons/clear.svg diff --git a/assets/icons/close.svg b/src/assets/icons/close.svg similarity index 100% rename from assets/icons/close.svg rename to src/assets/icons/close.svg diff --git a/assets/icons/counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/dashboard_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/dashboard_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/dashboard_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/dashboard_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/event_note_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/event_note_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/event_note_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/event_note_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/mail_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/mail_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/mail_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/mail_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/menu_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/menu_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/menu_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/menu_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/reply_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/reply_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/reply_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/reply_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/search.svg b/src/assets/icons/search.svg similarity index 100% rename from assets/icons/search.svg rename to src/assets/icons/search.svg diff --git a/assets/icons/settings.svg b/src/assets/icons/settings.svg similarity index 100% rename from assets/icons/settings.svg rename to src/assets/icons/settings.svg diff --git a/assets/icons/star_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/star_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/star_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/star_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/stylus_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/stylus_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/stylus_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/stylus_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/unfold_less_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/unfold_less_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/unfold_less_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/unfold_less_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/assets/icons/unfold_more_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/src/assets/icons/unfold_more_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg similarity index 100% rename from assets/icons/unfold_more_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg rename to src/assets/icons/unfold_more_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg diff --git a/src/content/isolatedDocumentEnd.ts b/src/content/isolatedDocumentEnd.ts new file mode 100644 index 0000000..8fa8275 --- /dev/null +++ b/src/content/isolatedDocumentEnd.ts @@ -0,0 +1,40 @@ +import type { Patch } from "../types/Patch.ts"; +import { loadPatchesForConfig } from "./loadPatches.ts"; + +const patches = import.meta.glob("../patches/**/index.ts", { + import: "default", + eager: true, +}); + +async function loadPatches() { + await loadPatchesForConfig(patches, { + world: "ISOLATED", + runAt: "document_end", + }); +} + +loadPatches(); + +// @ts-expect-error - navigation api is not yet included in lib.dom.ts +if (window.navigation) { + // @ts-expect-error - navigation api is not yet included in lib.dom.ts + window.navigation.addEventListener("navigatesuccess", loadPatches); +} else { + let lastUrl = location.href; + + function checkUrlChange() { + if (location.href !== lastUrl) { + lastUrl = location.href; + loadPatches(); + } + } + + const observer = new MutationObserver(checkUrlChange); + + observer.observe(document.documentElement, { + childList: true, + subtree: true, + }); + + window.addEventListener("popstate", checkUrlChange); +} diff --git a/src/content/isolatedDocumentStart.ts b/src/content/isolatedDocumentStart.ts new file mode 100644 index 0000000..335f49e --- /dev/null +++ b/src/content/isolatedDocumentStart.ts @@ -0,0 +1,40 @@ +import type { Patch } from "../types/Patch.ts"; +import { loadPatchesForConfig } from "./loadPatches.ts"; + +const patches = import.meta.glob("../patches/**/index.ts", { + import: "default", + eager: true, +}); + +async function loadPatches() { + await loadPatchesForConfig(patches, { + world: "ISOLATED", + runAt: "document_start", + }); +} + +loadPatches(); + +// @ts-expect-error - navigation api is not yet included in lib.dom.ts +if (window.navigation) { + // @ts-expect-error - navigation api is not yet included in lib.dom.ts + window.navigation.addEventListener("navigatesuccess", loadPatches); +} else { + let lastUrl = location.href; + + function checkUrlChange() { + if (location.href !== lastUrl) { + lastUrl = location.href; + loadPatches(); + } + } + + const observer = new MutationObserver(checkUrlChange); + + observer.observe(document.documentElement, { + childList: true, + subtree: true, + }); + + window.addEventListener("popstate", checkUrlChange); +} diff --git a/src/content/loadPatches.ts b/src/content/loadPatches.ts new file mode 100644 index 0000000..36bcbd3 --- /dev/null +++ b/src/content/loadPatches.ts @@ -0,0 +1,53 @@ +import type { Patch } from "../types/Patch.ts"; +import { SettingsManager } from "../util/SettingsManager.ts"; + +interface PatchLoaderConfig { + world: "MAIN" | "ISOLATED"; + runAt: "document_start" | "document_end" | "document_idle"; +} + +const loadedPatches = new Set(); + +/** + * Loads and initializes patches based on the provided configuration. + * + * @param patches A record of patch modules to be loaded. + * @param config The configuration specifying the world and runAt timing. + * @returns A promise that resolves when all applicable patches have been initialized. + */ +export async function loadPatchesForConfig( + patches: Record, + config: PatchLoaderConfig, +) { + const currentUrl = window.location.href; + + for (const path in patches) { + const patch = patches[path]; + const { meta, init } = patch; + + if ( + (meta.world ?? "ISOLATED" !== config.world) || + (meta.runAt ?? "document_idle" !== config.runAt) + ) + continue; + if (!meta.matches.some((pattern) => pattern.test(currentUrl))) continue; + + if (meta.runStrategy === "once") { + if (loadedPatches.has(meta.id)) continue; + loadedPatches.add(meta.id); + } + + if ((await SettingsManager.isPatchEnabled(meta.id)) === false) continue; + + const settings = await SettingsManager.getPatchSettings(meta); + + try { + await init(settings); + } catch (err) { + console.error( + `Error initializing patch "${meta.name}" (${meta.id}):`, + err, + ); + } + } +} diff --git a/patches/alignDetailedGradesButton.css b/src/patches/alignDetailedGradesButton.css similarity index 96% rename from patches/alignDetailedGradesButton.css rename to src/patches/alignDetailedGradesButton.css index 358c681..0c8c9d3 100644 --- a/patches/alignDetailedGradesButton.css +++ b/src/patches/alignDetailedGradesButton.css @@ -1,3 +1,3 @@ .grades__subject { justify-content: space-between; -} \ No newline at end of file +} diff --git a/patches/apis/aside.js b/src/patches/apis/aside.js similarity index 87% rename from patches/apis/aside.js rename to src/patches/apis/aside.js index 450a9cc..560ee09 100644 --- a/patches/apis/aside.js +++ b/src/patches/apis/aside.js @@ -1,42 +1,43 @@ -import { waitForRender } from "./waitForElement.js"; - -let asideReads = 0; - -const getAsideElement = async () => { - if (window.asideMode === "hidden" && document.querySelector("aside")) { - return document.querySelector("aside"); - } - - asideReads++; - if (!document.querySelector("aside")) - document.querySelector(".header__hamburger__icon button").click(); - await waitForRender(() => document.querySelector("aside")); - document.querySelector("aside").classList.add("hideAside"); - return document.querySelector("aside"); -}; - -const closeAside = () => { - const closeButton = document.querySelector(".aside-button--close"); - if (window.asideMode !== "hidden") { - asideReads--; - if (closeButton && asideReads <= 0) closeButton.click(); - document.querySelector("aside")?.classList?.remove("hideAside"); - } -}; - -export const executeActionOnAside = async (fn) => { - const aside = await getAsideElement(); - await fn(aside) - if (!document.querySelector("aside") && window.asideMode === "hidden") { - document.querySelector(".header__hamburger__icon button").click(); - } else asideReads--; -} - -export const clickOnAside = (selector) => executeActionOnAside((aside) => aside.querySelector(selector)?.click()); - -export const getFromAside = async (fn) => { - const aside = await getAsideElement(); - const result = await fn(aside); - closeAside(); - return result; -}; +import { waitForRender } from "./waitForElement.js"; + +let asideReads = 0; + +const getAsideElement = async () => { + if (window.asideMode === "hidden" && document.querySelector("aside")) { + return document.querySelector("aside"); + } + + asideReads++; + if (!document.querySelector("aside")) + document.querySelector(".header__hamburger__icon button").click(); + await waitForRender(() => document.querySelector("aside")); + document.querySelector("aside").classList.add("hideAside"); + return document.querySelector("aside"); +}; + +const closeAside = () => { + const closeButton = document.querySelector(".aside-button--close"); + if (window.asideMode !== "hidden") { + asideReads--; + if (closeButton && asideReads <= 0) closeButton.click(); + document.querySelector("aside")?.classList?.remove("hideAside"); + } +}; + +export const executeActionOnAside = async (fn) => { + const aside = await getAsideElement(); + await fn(aside); + if (!document.querySelector("aside") && window.asideMode === "hidden") { + document.querySelector(".header__hamburger__icon button").click(); + } else asideReads--; +}; + +export const clickOnAside = (selector) => + executeActionOnAside((aside) => aside.querySelector(selector)?.click()); + +export const getFromAside = async (fn) => { + const aside = await getAsideElement(); + const result = await fn(aside); + closeAside(); + return result; +}; diff --git a/patches/apis/bottomDateSelector/index.js b/src/patches/apis/bottomDateSelector/index.js similarity index 92% rename from patches/apis/bottomDateSelector/index.js rename to src/patches/apis/bottomDateSelector/index.js index fe1d654..2720301 100644 --- a/patches/apis/bottomDateSelector/index.js +++ b/src/patches/apis/bottomDateSelector/index.js @@ -1,218 +1,222 @@ -import { waitForRender } from "../waitForElement.js"; - -const dayNames = [ - "poniedziałek", - "wtorek", - "środa", - "czwartek", - "piątek", - "sobota", - "niedziela", -]; - -const getWeekStartingMonday = (i) => (i === 0 ? 6 : i - 1); - -const getWeek = (date) => { - const DAY = 24 * 60 * 60 * 1000; - const firstDay = new Date(`${date.getFullYear()}-01-01`); - return Math.floor((date.getTime() - firstDay.getTime()) / DAY / 7); -}; - -const isSameWeek = (date, comparedDate) => - getWeek(date) === getWeek(comparedDate); - -const updateReactInput = (input, value) => { - const setValue = Object.getOwnPropertyDescriptor( - Object.getPrototypeOf(input), - "value", - ).set; - const event = new Event("input", { bubbles: true }); - - setValue.call(input, value); - input.dispatchEvent(event); -}; - -export class SelectorRenderer { - constructor(renderContentFn) { - this.renderContent = renderContentFn; - - - this.#render().then(() => console.debug("Rendered date selector")); - } - - #createSelector(dayName) { - const element = document.createElement("div"); - element.innerHTML = ` - -
- - - -
- `; - - const dayDisplay = element.querySelector("span"); - dayDisplay.innerText = dayName; - dayDisplay.addEventListener("click", () => - element.querySelector("input").showPicker(), - ); - - const datePicker = element.querySelector("input"); - datePicker.addEventListener("change", () => - this.#setDay(datePicker.value, datePicker.valueAsDate), - ); - - element - .querySelector("img:first-of-type") - .addEventListener("click", () => this.#setSiblingDay(-1)); - element - .querySelector("img:last-of-type") - .addEventListener("click", () => this.#setSiblingDay(1)); - element.classList.add("date-selector"); - - return element; - } - - #updateSelectorDate(name) { - document.querySelector(".date-selector span").innerText = name; - } - - #getDaysDropdowns() { - return Array.from( - document.querySelectorAll(".app__content .MuiPaper-root"), - ).map((element) => ({ - element, - note: element.querySelector(".plan-zajec__accordion__wolne") - ?.innerText, - day: element.querySelector(".MuiAccordionSummary-content > h2") - ?.innerText, - })); - } - - #isDayListLoaded() { - return !document.querySelector(".spinner") && this.#isWeekChanged(); - } - - #isWeekChanged() { - return ( - !this.firstDayName || - document.querySelector( - ".app__content .MuiPaper-root .MuiAccordionSummary-content > h2", - )?.innerText !== this.firstDayName - ); - } - - async #setDay(value, valueDate) { - if ( - !isSameWeek( - document.querySelector(".week-selector input").valueAsDate, - valueDate, - ) - ) { - this.#setChecking(); - - if (!value || !valueDate) return; - updateReactInput( - document.querySelector(".week-selector input"), - value, - ); - - await waitForRender(() => this.#isDayListLoaded()); - } - - this.currentWeekDay = Math.min( - getWeekStartingMonday(valueDate.getDay()), - this.cachedWeek.length - 1, - ); - await this.#render(); - } - - async #setupAutoRender() { - if (this.observer) return; - this.observer = new MutationObserver(async () => { - const content = await this.renderContent( - this.cachedWeek[this.currentWeekDay], - ); - content.classList.add("day-content"); - document.querySelector(".day-content").replaceWith(content); - }); - - this.observer.observe( - document.querySelector( - ".content-container__tab-subheader:has(.week-selector) + div", - ), - { - childList: true, - subtree: true, - }, - ); - } - - async #render() { - let replaceable = document.querySelector(".day-content"); - if (!replaceable) { - replaceable = document.createElement("div"); - document - .querySelector("section.app__content .mobile__frame") - .appendChild(replaceable); - } - - this.cachedWeek = this.#getDaysDropdowns(); - - if (this.currentWeekDay === undefined) { - const today = new Date() - const day = getWeekStartingMonday(today.getDay()) - this.currentWeekDay = this.cachedWeek.findIndex((timetableDay) => (timetableDay.day || "-, ").split(", ")[0].toLowerCase() === dayNames[day]); - if (this.currentWeekDay === -1) this.currentWeekDay = this.cachedWeek.length - 1; - } - - const content = await this.renderContent( - this.cachedWeek[this.currentWeekDay], - ); - content.classList.add("day-content"); - replaceable.replaceWith(content); - - if (document.querySelector(".date-selector")) { - this.#updateSelectorDate(this.cachedWeek[this.currentWeekDay].day); - } else - document - .querySelector("section.app__content .mobile__frame") - .appendChild( - this.#createSelector( - this.cachedWeek[this.currentWeekDay].day, - ), - ); - - this.#setupAutoRender(); - } - - #setChecking() { - this.firstDayName = this.cachedWeek[0].day; - } - - async #setSiblingDay(direction = 1) { - this.#setChecking(); - document.querySelector("#root").scroll(0, 0); - - const target = this.currentWeekDay + direction; - if (target >= this.cachedWeek.length || target < 0) { - if (target < 0) { - this.currentWeekDay = 4; - document - .querySelector(".week-selector > button:first-of-type") - .click(); - } else { - this.currentWeekDay = 0; - document - .querySelector(".week-selector > button:last-of-type") - .click(); - } - - await waitForRender(() => this.#isDayListLoaded()); - } else { - this.currentWeekDay = target; - } - - await this.#render(); - } -} +import { waitForRender } from "../waitForElement.js"; + +const dayNames = [ + "poniedziałek", + "wtorek", + "środa", + "czwartek", + "piątek", + "sobota", + "niedziela", +]; + +const getWeekStartingMonday = (i) => (i === 0 ? 6 : i - 1); + +const getWeek = (date) => { + const DAY = 24 * 60 * 60 * 1000; + const firstDay = new Date(`${date.getFullYear()}-01-01`); + return Math.floor((date.getTime() - firstDay.getTime()) / DAY / 7); +}; + +const isSameWeek = (date, comparedDate) => + getWeek(date) === getWeek(comparedDate); + +const updateReactInput = (input, value) => { + const setValue = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(input), + "value", + ).set; + const event = new Event("input", { bubbles: true }); + + setValue.call(input, value); + input.dispatchEvent(event); +}; + +export class SelectorRenderer { + constructor(renderContentFn) { + this.renderContent = renderContentFn; + + this.#render().then(() => console.debug("Rendered date selector")); + } + + #createSelector(dayName) { + const element = document.createElement("div"); + element.innerHTML = ` + +
+ + + +
+ `; + + const dayDisplay = element.querySelector("span"); + dayDisplay.innerText = dayName; + dayDisplay.addEventListener("click", () => + element.querySelector("input").showPicker(), + ); + + const datePicker = element.querySelector("input"); + datePicker.addEventListener("change", () => + this.#setDay(datePicker.value, datePicker.valueAsDate), + ); + + element + .querySelector("img:first-of-type") + .addEventListener("click", () => this.#setSiblingDay(-1)); + element + .querySelector("img:last-of-type") + .addEventListener("click", () => this.#setSiblingDay(1)); + element.classList.add("date-selector"); + + return element; + } + + #updateSelectorDate(name) { + document.querySelector(".date-selector span").innerText = name; + } + + #getDaysDropdowns() { + return Array.from( + document.querySelectorAll(".app__content .MuiPaper-root"), + ).map((element) => ({ + element, + note: element.querySelector(".plan-zajec__accordion__wolne") + ?.innerText, + day: element.querySelector(".MuiAccordionSummary-content > h2") + ?.innerText, + })); + } + + #isDayListLoaded() { + return !document.querySelector(".spinner") && this.#isWeekChanged(); + } + + #isWeekChanged() { + return ( + !this.firstDayName || + document.querySelector( + ".app__content .MuiPaper-root .MuiAccordionSummary-content > h2", + )?.innerText !== this.firstDayName + ); + } + + async #setDay(value, valueDate) { + if ( + !isSameWeek( + document.querySelector(".week-selector input").valueAsDate, + valueDate, + ) + ) { + this.#setChecking(); + + if (!value || !valueDate) return; + updateReactInput( + document.querySelector(".week-selector input"), + value, + ); + + await waitForRender(() => this.#isDayListLoaded()); + } + + this.currentWeekDay = Math.min( + getWeekStartingMonday(valueDate.getDay()), + this.cachedWeek.length - 1, + ); + await this.#render(); + } + + async #setupAutoRender() { + if (this.observer) return; + this.observer = new MutationObserver(async () => { + const content = await this.renderContent( + this.cachedWeek[this.currentWeekDay], + ); + content.classList.add("day-content"); + document.querySelector(".day-content").replaceWith(content); + }); + + this.observer.observe( + document.querySelector( + ".content-container__tab-subheader:has(.week-selector) + div", + ), + { + childList: true, + subtree: true, + }, + ); + } + + async #render() { + let replaceable = document.querySelector(".day-content"); + if (!replaceable) { + replaceable = document.createElement("div"); + document + .querySelector("section.app__content .mobile__frame") + .appendChild(replaceable); + } + + this.cachedWeek = this.#getDaysDropdowns(); + + if (this.currentWeekDay === undefined) { + const today = new Date(); + const day = getWeekStartingMonday(today.getDay()); + this.currentWeekDay = this.cachedWeek.findIndex( + (timetableDay) => + (timetableDay.day || "-, ").split(", ")[0].toLowerCase() === + dayNames[day], + ); + if (this.currentWeekDay === -1) + this.currentWeekDay = this.cachedWeek.length - 1; + } + + const content = await this.renderContent( + this.cachedWeek[this.currentWeekDay], + ); + content.classList.add("day-content"); + replaceable.replaceWith(content); + + if (document.querySelector(".date-selector")) { + this.#updateSelectorDate(this.cachedWeek[this.currentWeekDay].day); + } else + document + .querySelector("section.app__content .mobile__frame") + .appendChild( + this.#createSelector( + this.cachedWeek[this.currentWeekDay].day, + ), + ); + + this.#setupAutoRender(); + } + + #setChecking() { + this.firstDayName = this.cachedWeek[0].day; + } + + async #setSiblingDay(direction = 1) { + this.#setChecking(); + document.querySelector("#root").scroll(0, 0); + + const target = this.currentWeekDay + direction; + if (target >= this.cachedWeek.length || target < 0) { + if (target < 0) { + this.currentWeekDay = 4; + document + .querySelector(".week-selector > button:first-of-type") + .click(); + } else { + this.currentWeekDay = 0; + document + .querySelector(".week-selector > button:last-of-type") + .click(); + } + + await waitForRender(() => this.#isDayListLoaded()); + } else { + this.currentWeekDay = target; + } + + await this.#render(); + } +} diff --git a/patches/apis/bottomDateSelector/styles.css b/src/patches/apis/bottomDateSelector/styles.css similarity index 95% rename from patches/apis/bottomDateSelector/styles.css rename to src/patches/apis/bottomDateSelector/styles.css index f817439..553bb8f 100644 --- a/patches/apis/bottomDateSelector/styles.css +++ b/src/patches/apis/bottomDateSelector/styles.css @@ -1,37 +1,37 @@ -.date-selector > div { - height: 40px; - position: fixed; - margin-bottom: var(--bottom-navbar-height); - bottom: 0; - width: 100vw; - left: 0; - display: flex; - justify-content: space-between; - background: var(--background-navigation); - border-top: 2px solid #e5e7e9; - z-index: 100; - align-items: center; -} - -.date-selector > input { - display: none; -} - -div#root:has(.date-selector) { - height: calc(100svh - 60px - var(--bottom-navbar-height) - 40px); -} - -.date-selector > div > img { - filter: invert(0.8); - height: 35px; - cursor: pointer; -} - -.date-selector > div > span { - font-size: 15px; - cursor: pointer; -} - -body:has(.date-selector):not(:has(.modal)) .bottom-navigation-bar { - border-top: 0 !important; -} +.date-selector > div { + height: 40px; + position: fixed; + margin-bottom: var(--bottom-navbar-height); + bottom: 0; + width: 100vw; + left: 0; + display: flex; + justify-content: space-between; + background: var(--background-navigation); + border-top: 2px solid #e5e7e9; + z-index: 100; + align-items: center; +} + +.date-selector > input { + display: none; +} + +div#root:has(.date-selector) { + height: calc(100svh - 60px - var(--bottom-navbar-height) - 40px); +} + +.date-selector > div > img { + filter: invert(0.8); + height: 35px; + cursor: pointer; +} + +.date-selector > div > span { + font-size: 15px; + cursor: pointer; +} + +body:has(.date-selector):not(:has(.modal)) .bottom-navigation-bar { + border-top: 0 !important; +} diff --git a/patches/apis/getUserData.js b/src/patches/apis/getUserData.js similarity index 97% rename from patches/apis/getUserData.js rename to src/patches/apis/getUserData.js index aa16750..7d129c4 100644 --- a/patches/apis/getUserData.js +++ b/src/patches/apis/getUserData.js @@ -1,28 +1,28 @@ -import { waitForRender } from "./waitForElement.js"; -import { getFromAside } from "./aside.js"; - -export const getUserData = async () => { - return await getFromAside(async () => { - await waitForRender( - () => - document.querySelector( - window.location.hostname.includes("wiadomosci") - ? ".account__name span" - : ".side_important-text.side_student", - ) && document.querySelector(".user div:nth-child(2)"), - ); - - return { - fullName: window.location.hostname.includes("wiadomosci") - ? document - .querySelector(".account__name span") - ?.firstChild?.textContent?.split(" ") - .reverse() - .join(" ") - : document.querySelector(".side_important-text.side_student") - ?.textContent, - username: document.querySelector(".user div:nth-child(2)").lastChild - .textContent, - }; - }); -}; +import { waitForRender } from "./waitForElement.js"; +import { getFromAside } from "./aside.js"; + +export const getUserData = async () => { + return await getFromAside(async () => { + await waitForRender( + () => + document.querySelector( + window.location.hostname.includes("wiadomosci") + ? ".account__name span" + : ".side_important-text.side_student", + ) && document.querySelector(".user div:nth-child(2)"), + ); + + return { + fullName: window.location.hostname.includes("wiadomosci") + ? document + .querySelector(".account__name span") + ?.firstChild?.textContent?.split(" ") + .reverse() + .join(" ") + : document.querySelector(".side_important-text.side_student") + ?.textContent, + username: document.querySelector(".user div:nth-child(2)").lastChild + .textContent, + }; + }); +}; diff --git a/patches/apis/mapTimetable.js b/src/patches/apis/mapTimetable.js similarity index 84% rename from patches/apis/mapTimetable.js rename to src/patches/apis/mapTimetable.js index fbbb77b..02001b5 100644 --- a/patches/apis/mapTimetable.js +++ b/src/patches/apis/mapTimetable.js @@ -1,50 +1,50 @@ -const normalizeLesson = (lesson) => { - const hoursText = ( - lesson.querySelector( - ".position__lesson__hours, .conflicted--details--hours", - )?.innerText || " " - ).split(" "); - const startingHour = hoursText[0]; - const endingHour = hoursText[2]; - - const subjectText = - lesson - .querySelector(".position__lesson__subject") - ?.innerText?.split(/ Grupa-| \|/) || []; - - const annotationText = lesson.querySelector( - ".plan-position__adnotation-title", - )?.innerText; - - const type = lesson.classList.contains("cell--multi--conflicted") - ? "conflicted" - : lesson.querySelector(".zastepstwo") - ? "substitute" - : lesson.querySelector(".odwolane") - ? "canceled" - : annotationText - ? "unknown" - : "normal"; - - return { - originalElement: lesson, - type, - subject: subjectText[0], - group: subjectText[1], - teacher: lesson.querySelector(".position__lesson__teacher")?.innerText, - classroom: [ - ...(lesson.querySelector(".position__lesson__subject + span") - ?.innerText || ""), - ] - .filter((c) => !"()".includes(c)) - .join("") - .trim(), - annotationText, - startingHour, - endingHour, - }; -}; -export const mapDay = (element) => - Array.from( - element.querySelectorAll(".cell--single, .cell--multi--conflicted"), - ).map(normalizeLesson); +const normalizeLesson = (lesson) => { + const hoursText = ( + lesson.querySelector( + ".position__lesson__hours, .conflicted--details--hours", + )?.innerText || " " + ).split(" "); + const startingHour = hoursText[0]; + const endingHour = hoursText[2]; + + const subjectText = + lesson + .querySelector(".position__lesson__subject") + ?.innerText?.split(/ Grupa-| \|/) || []; + + const annotationText = lesson.querySelector( + ".plan-position__adnotation-title", + )?.innerText; + + const type = lesson.classList.contains("cell--multi--conflicted") + ? "conflicted" + : lesson.querySelector(".zastepstwo") + ? "substitute" + : lesson.querySelector(".odwolane") + ? "canceled" + : annotationText + ? "unknown" + : "normal"; + + return { + originalElement: lesson, + type, + subject: subjectText[0], + group: subjectText[1], + teacher: lesson.querySelector(".position__lesson__teacher")?.innerText, + classroom: [ + ...(lesson.querySelector(".position__lesson__subject + span") + ?.innerText || ""), + ] + .filter((c) => !"()".includes(c)) + .join("") + .trim(), + annotationText, + startingHour, + endingHour, + }; +}; +export const mapDay = (element) => + Array.from( + element.querySelectorAll(".cell--single, .cell--multi--conflicted"), + ).map(normalizeLesson); diff --git a/patches/apis/settings.js b/src/patches/apis/settings.js similarity index 69% rename from patches/apis/settings.js rename to src/patches/apis/settings.js index cb5c57e..40dfe69 100644 --- a/patches/apis/settings.js +++ b/src/patches/apis/settings.js @@ -10,13 +10,17 @@ */ export function getSetting(patchName, settingId) { const patches = JSON.parse(sessionStorage.getItem("IFV_PATCHES")) || []; - const patch = patches.find(p => p.name === patchName); + const patch = patches.find((p) => p.name === patchName); if (!patch) throw new Error(`Patch with name ${patchName} not found.`); - const setting = patch.settings?.find(s => s.id === settingId); - if (!setting) throw new Error(`Setting with id ${settingId} not found in patch ${patchName}.`); + const setting = patch.settings?.find((s) => s.id === settingId); + if (!setting) + throw new Error( + `Setting with id ${settingId} not found in patch ${patchName}.`, + ); - const patchesSettings = JSON.parse(sessionStorage.getItem("ifv_patches_settings")) || {}; + const patchesSettings = + JSON.parse(sessionStorage.getItem("ifv_patches_settings")) || {}; const savedValue = patchesSettings[patchName]?.[settingId]; if (setting.type === "boolean") { @@ -27,10 +31,10 @@ export function getSetting(patchName, settingId) { } if (savedValue !== undefined) { - if (setting.type === "multiselect" && typeof savedValue === 'string') { - return savedValue.split(','); + if (setting.type === "multiselect" && typeof savedValue === "string") { + return savedValue.split(","); } - if (setting.type === "number" && typeof savedValue === 'string') { + if (setting.type === "number" && typeof savedValue === "string") { return parseFloat(savedValue); } return savedValue; @@ -38,7 +42,8 @@ export function getSetting(patchName, settingId) { if (setting.type === "multiselect") { if (Array.isArray(setting.default)) return setting.default; - if (typeof setting.default === 'string') return setting.default.split(','); + if (typeof setting.default === "string") + return setting.default.split(","); return []; } @@ -57,11 +62,14 @@ export function getSetting(patchName, settingId) { */ export function saveSetting(patchName, settingId, value) { const patches = JSON.parse(sessionStorage.getItem("IFV_PATCHES")) || []; - const patch = patches.find(p => p.name === patchName); + const patch = patches.find((p) => p.name === patchName); if (!patch) throw new Error(`Patch with name ${patchName} not found.`); - const setting = patch.settings?.find(s => s.id === settingId); - if (!setting) throw new Error(`Setting with id ${settingId} not found in patch ${patchName}.`); + const setting = patch.settings?.find((s) => s.id === settingId); + if (!setting) + throw new Error( + `Setting with id ${settingId} not found in patch ${patchName}.`, + ); let rawPatchesSettings = sessionStorage.getItem("ifv_patches_settings"); let patchesSettings; @@ -69,12 +77,19 @@ export function saveSetting(patchName, settingId, value) { if (rawPatchesSettings) { try { patchesSettings = JSON.parse(rawPatchesSettings); - if (Array.isArray(patchesSettings) || typeof patchesSettings !== 'object' || patchesSettings === null) { + if ( + Array.isArray(patchesSettings) || + typeof patchesSettings !== "object" || + patchesSettings === null + ) { patchesSettings = {}; } } catch (e) { patchesSettings = {}; - console.debug("Error parsing ifv_patches_settings from sessionStorage. Initializing to {}.", e); + console.debug( + "Error parsing ifv_patches_settings from sessionStorage. Initializing to {}.", + e, + ); } } else { patchesSettings = {}; @@ -85,7 +100,10 @@ export function saveSetting(patchName, settingId, value) { } patchesSettings[patchName][settingId] = value; - sessionStorage.setItem("ifv_patches_settings", JSON.stringify(patchesSettings)); + sessionStorage.setItem( + "ifv_patches_settings", + JSON.stringify(patchesSettings), + ); window.dispatchEvent(new CustomEvent("ifv-settings-changed")); } diff --git a/patches/apis/waitForElement.js b/src/patches/apis/waitForElement.js similarity index 96% rename from patches/apis/waitForElement.js rename to src/patches/apis/waitForElement.js index db152ae..fc1410c 100644 --- a/patches/apis/waitForElement.js +++ b/src/patches/apis/waitForElement.js @@ -1,39 +1,39 @@ -export const waitForRender = async (fn, target = document.body) => { - let resolve; - const wait = new Promise((r) => (resolve = r)); - const observer = new MutationObserver((mutations, observer) => { - if (!fn()) return; - resolve(); - observer.disconnect(); - }); - observer.observe(target, { subtree: true, childList: true }); - - const lastTry = fn(); - if (!lastTry) { - await wait; - } -}; - -export const waitForReplacement = async (fn, target = document.body) => { - const initialElement = fn(); - - if (!initialElement) { - return waitForRender(fn, target); - } - - let resolveDisappear; - const waitForDisappear = new Promise((r) => (resolveDisappear = r)); - - const disappearObserver = new MutationObserver((mutations, observer) => { - if (!document.body.contains(initialElement)) { - resolveDisappear(); - observer.disconnect(); - } - }); - - disappearObserver.observe(target, { subtree: true, childList: true }); - - await waitForDisappear; - - return waitForRender(fn, target); -}; +export const waitForRender = async (fn, target = document.body) => { + let resolve; + const wait = new Promise((r) => (resolve = r)); + const observer = new MutationObserver((mutations, observer) => { + if (!fn()) return; + resolve(); + observer.disconnect(); + }); + observer.observe(target, { subtree: true, childList: true }); + + const lastTry = fn(); + if (!lastTry) { + await wait; + } +}; + +export const waitForReplacement = async (fn, target = document.body) => { + const initialElement = fn(); + + if (!initialElement) { + return waitForRender(fn, target); + } + + let resolveDisappear; + const waitForDisappear = new Promise((r) => (resolveDisappear = r)); + + const disappearObserver = new MutationObserver((mutations, observer) => { + if (!document.body.contains(initialElement)) { + resolveDisappear(); + observer.disconnect(); + } + }); + + disappearObserver.observe(target, { subtree: true, childList: true }); + + await waitForDisappear; + + return waitForRender(fn, target); +}; diff --git a/patches/arrows.css b/src/patches/arrows.css similarity index 96% rename from patches/arrows.css rename to src/patches/arrows.css index 714b070..52223a1 100644 --- a/patches/arrows.css +++ b/src/patches/arrows.css @@ -1,51 +1,51 @@ -@media screen and (max-width: 1023px) { - .modal__header { - font-family: - "WorkSans", - Graphik, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Helvetica, - Arial, - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol" !important; - background: white !important; - border-bottom: 2px solid #e5e7e9 !important; - min-height: 60px !important; - color: black !important; - } - - .modal__title { - padding: 17.5px 48px !important; - } - - .modal-button--close { - background-color: white !important; - box-shadow: none !important; - position: absolute !important; - top: calc((60px - 40px) / 2) !important; - cursor: pointer; - padding: 0 !important; - margin: 0 0 0 10px !important; - border: none !important; - width: 40px !important; - height: 40px !important; - } - - .modal-button--close > span:first-of-type { - display: none !important; - } - - .modal-button--close > span:last-of-type { - content: url("https://raw.githubusercontent.com/banocean/ifv/main/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg"); - filter: invert(0.8); - height: 40px; - } - - .modal-button--close > span > svg { - display: none !important; - } -} +@media screen and (max-width: 1023px) { + .modal__header { + font-family: + "WorkSans", + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol" !important; + background: white !important; + border-bottom: 2px solid #e5e7e9 !important; + min-height: 60px !important; + color: black !important; + } + + .modal__title { + padding: 17.5px 48px !important; + } + + .modal-button--close { + background-color: white !important; + box-shadow: none !important; + position: absolute !important; + top: calc((60px - 40px) / 2) !important; + cursor: pointer; + padding: 0 !important; + margin: 0 0 0 10px !important; + border: none !important; + width: 40px !important; + height: 40px !important; + } + + .modal-button--close > span:first-of-type { + display: none !important; + } + + .modal-button--close > span:last-of-type { + content: url("https://raw.githubusercontent.com/banocean/ifv/main/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg"); + filter: invert(0.8); + height: 40px; + } + + .modal-button--close > span > svg { + display: none !important; + } +} diff --git a/patches/cleanUpEduVulcanHome.css b/src/patches/cleanUpEduVulcanHome.css similarity index 64% rename from patches/cleanUpEduVulcanHome.css rename to src/patches/cleanUpEduVulcanHome.css index c646483..c389f34 100644 --- a/patches/cleanUpEduVulcanHome.css +++ b/src/patches/cleanUpEduVulcanHome.css @@ -1,5 +1,7 @@ -/* app download links, eduvulcan banner, maziaj */ -.box-app, .carousel-area, .ribbon-bg { +/* app download links, banner, maziaj */ +.box-app, +.carousel-area, +.ribbon-bg { display: none !important; } @@ -12,13 +14,16 @@ flex: inherit !important; } -.part-constant, .part-business { +.part-constant, +.part-business { flex: 0 !important; padding: 0 !important; } -.part-business { display: none; } +.part-business { + display: none; +} .header-part-2 { min-width: inherit !important; -} \ No newline at end of file +} diff --git a/patches/countAverage.js b/src/patches/countAverage.js similarity index 76% rename from patches/countAverage.js rename to src/patches/countAverage.js index e75b9ce..b65d820 100644 --- a/patches/countAverage.js +++ b/src/patches/countAverage.js @@ -1,4 +1,4 @@ -import { getSetting } from './apis/settings.js'; +import { getSetting } from "./apis/settings.js"; function modifyGradesRequests() { const originalXHROpen = XMLHttpRequest.prototype.open; @@ -11,18 +11,19 @@ function modifyGradesRequests() { }; XMLHttpRequest.prototype.send = function () { - const xhr = this; + if (this._requestURL && this._requestURL.includes("/api/Oceny?")) { + const originalOnReadyStateChange = this.onreadystatechange; - if (xhr._requestURL && xhr._requestURL.includes("/api/Oceny?")) { - const originalOnReadyStateChange = xhr.onreadystatechange; - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4 && xhr.status === 200) { + this.onreadystatechange = function () { + if (this.readyState === 4 && this.status === 200) { try { - let data = JSON.parse(xhr.responseText); - const originalResponse = JSON.parse(xhr.responseText); + let data = JSON.parse(this.responseText); + const originalResponse = JSON.parse(this.responseText); - console.debug("Oryginalna odpowiedź:", originalResponse); + console.debug( + "Oryginalna odpowiedź:", + originalResponse, + ); if ( data && @@ -49,25 +50,33 @@ function modifyGradesRequests() { if ( grade.wpis && grade.wpis.match( - /^[0-6](\+|\-)?$/ + /^[0-6](\+|-)?$/, ) ) { let value = parseFloat( - grade.wpis + grade.wpis, ); if ( grade.wpis.includes( - "+" + "+", ) ) - value += getSetting("Count averages", "plusValue"); + value += + getSetting( + "Count averages", + "plusValue", + ); else if ( grade.wpis.includes( - "-" + "-", ) ) - value -= getSetting("Count averages", "minusValue"); + value -= + getSetting( + "Count averages", + "minusValue", + ); sum += value * @@ -75,10 +84,10 @@ function modifyGradesRequests() { totalWeight += grade.waga; } - } + }, ); } - } + }, ); } @@ -96,13 +105,13 @@ function modifyGradesRequests() { console.debug("Zmodyfikowana odpowiedź:", data); } - Object.defineProperty(xhr, "responseText", { + Object.defineProperty(this, "responseText", { get: function () { return data; }, }); - Object.defineProperty(xhr, "response", { + Object.defineProperty(this, "response", { get: function () { return data; }, diff --git a/patches/displayFullName.js b/src/patches/displayFullName.js similarity index 73% rename from patches/displayFullName.js rename to src/patches/displayFullName.js index 4b1a5bc..a4f5579 100644 --- a/patches/displayFullName.js +++ b/src/patches/displayFullName.js @@ -1,6 +1,5 @@ -const isMessagesPage = () => window.location.hostname.match( - /(dziennik-)?wiadomosci.*/, -); +const isMessagesPage = () => + window.location.hostname.match(/(dziennik-)?wiadomosci.*/); function getStudentData() { return isMessagesPage() @@ -34,10 +33,12 @@ function displayFullName() { } window.appendModule({ - isLoaded: () => document.querySelector( - `.${isMessagesPage() ? "account__name span" : "side_student"}`, - ), + isLoaded: () => + document.querySelector( + `.${isMessagesPage() ? "account__name span" : "side_student"}`, + ), onlyOnReloads: true, run: displayFullName, - doesRunHere: () => !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/) -}) + doesRunHere: () => + !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/), +}); diff --git a/src/patches/fixGoingBack.js b/src/patches/fixGoingBack.js new file mode 100644 index 0000000..84c61d2 --- /dev/null +++ b/src/patches/fixGoingBack.js @@ -0,0 +1,69 @@ +import { waitForRender } from "./apis/waitForElement.js"; + +const fixGoingBack = async () => { + const observer = new MutationObserver(mutationHandler); + observer.observe(document.body, { + childList: true, + }); +}; + +const mutationHandler = async (mutationList) => { + for (let i = 0; i < mutationList.length; i++) { + const modals = document.querySelectorAll(".MuiDrawer-modal"); + const modal = modals[modals.length - 1] || undefined; + + if (modal && modal.getAttribute("data-has-listener") !== "true") { + history.pushState( + { ...history.state, details: true }, + "", + `${location.pathname}#`, + ); + modal.setAttribute("data-has-listener", "true"); + + for (const e of modals) { + if (e === modal) continue; + e.removeAttribute("data-has-listener"); + } + + await waitForRender(() => + modal.querySelector(".modal-button--close"), + ); + const closeButton = modal.querySelector(".modal-button--close"); + + addEventListener("popstate", popstateHandler(closeButton), { + once: true, + }); + + closeButton?.addEventListener("click", () => { + if (history.state?.details) { + history.back(); + } + }); + } + } +}; + +const popstateHandler = (e) => () => { + if ( + e + ?.closest("div[role=presentation].MuiDrawer-modal") + ?.getAttribute("data-has-listener") !== "true" + ) + return; + e?.click(); +}; + +window.appendModule({ + isLoaded: () => true, + onlyOnReloads: true, + run: fixGoingBack, + doesRunHere: () => + [ + "eduvulcan.pl", + "uczen.eduvulcan.pl", + "wiadomosci.eduvulcan.pl", + "dziennik-uczen.vulcan.net.pl", + "dziennik-wiadomosci.vulcan.net.pl", + ].includes(window.location.hostname) && + typeof InstallTrigger !== "undefined", +}); diff --git a/patches/fixResizing.js b/src/patches/fixResizing.js similarity index 100% rename from patches/fixResizing.js rename to src/patches/fixResizing.js diff --git a/src/patches/hideEmptyExamResults.css b/src/patches/hideEmptyExamResults.css new file mode 100644 index 0000000..28ad036 --- /dev/null +++ b/src/patches/hideEmptyExamResults.css @@ -0,0 +1,13 @@ +.accordion__full-width__one-item:has(#panel-content-egzaminy td[colspan="3"]) { + display: none !important; +} + +main + .app__content:has( + .accordion__full-width__one-item #panel-content-egzaminy td[colspan="3"] + ) + .content-container.content-container__pure + > div:nth-child(2) { + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} diff --git a/patches/hideFooter.css b/src/patches/hideFooter.css similarity index 100% rename from patches/hideFooter.css rename to src/patches/hideFooter.css diff --git a/src/patches/hideHelpOnDashboard.css b/src/patches/hideHelpOnDashboard.css new file mode 100644 index 0000000..e04e4df --- /dev/null +++ b/src/patches/hideHelpOnDashboard.css @@ -0,0 +1,3 @@ +#kafel-pomoc-pomigracyjna { + display: none !important; +} diff --git a/patches/hideSubjectsWithNoGrades/finalGrades.js b/src/patches/hideSubjectsWithNoGrades/finalGrades.js similarity index 87% rename from patches/hideSubjectsWithNoGrades/finalGrades.js rename to src/patches/hideSubjectsWithNoGrades/finalGrades.js index 1525c9b..de45075 100644 --- a/patches/hideSubjectsWithNoGrades/finalGrades.js +++ b/src/patches/hideSubjectsWithNoGrades/finalGrades.js @@ -1,86 +1,86 @@ -import { waitForRender, waitForReplacement } from "../apis/waitForElement.js"; - -const hideEmptyColumns = async () => { - await waitForRender(() => - document.querySelector(".p-datatable-table .details-btn--appearance") - ); - - const headers = document.querySelectorAll(".p-datatable-table th"); - - headers.forEach((header, idx) => { - const cells = Array.from( - document.querySelectorAll( - "tbody tr td:nth-child(" + (idx + 1) + ")" - ) - ); - const check = cells.some((cell) => cell.textContent.trim().length > 0); - - const columnCells = document.querySelectorAll( - "tr th:nth-child(" + - (idx + 1) + - "), tr td:nth-child(" + - (idx + 1) + - ")" - ); - columnCells.forEach((cell) => { - cell.style.display = check ? "" : "none"; - }); - }); -}; - -async function prep() { - if (window.innerWidth > 1024) { - await waitForRender(() => - document.querySelector(".MuiTabs-flexContainer > button") - ); - - hideEmptyColumns(); - document - .querySelectorAll(".MuiTabs-flexContainer > button") - .forEach((e) => { - e.addEventListener("click", async () => { - await waitForReplacement(() => - document.querySelector( - ".p-datatable-table .details-btn--appearance" - ) - ); - hideEmptyColumns(); - }); - }); - } else { - await waitForRender(() => - document.querySelector( - ".MuiAccordionDetails-root.accordion__full-width__content > .mobile__frame .grades__box" - ) - ); - document - .querySelectorAll( - ".MuiAccordionDetails-root.accordion__full-width__content > .mobile__frame" - ) - .forEach(async (semester) => { - await waitForRender(() => - semester.querySelector( - ".MuiAccordionDetails-root .grades__box .info-row .info-text > span" - ) - ); - semester.querySelectorAll(".info-row").forEach((e) => { - if ( - e - .querySelector(".info-text > span") - .textContent.trim() === "" || - e - .querySelector(".info-text > span") - .textContent.trim() === "0" - ) { - e.remove(); - } - }); - }); - } -} - -window.appendModule({ - run: prep, - onlyOnReloads: false, - doesRunHere: () => window.location.pathname.endsWith("oceny"), -}); +import { waitForRender, waitForReplacement } from "../apis/waitForElement.js"; + +const hideEmptyColumns = async () => { + await waitForRender(() => + document.querySelector(".p-datatable-table .details-btn--appearance"), + ); + + const headers = document.querySelectorAll(".p-datatable-table th"); + + headers.forEach((header, idx) => { + const cells = Array.from( + document.querySelectorAll( + "tbody tr td:nth-child(" + (idx + 1) + ")", + ), + ); + const check = cells.some((cell) => cell.textContent.trim().length > 0); + + const columnCells = document.querySelectorAll( + "tr th:nth-child(" + + (idx + 1) + + "), tr td:nth-child(" + + (idx + 1) + + ")", + ); + columnCells.forEach((cell) => { + cell.style.display = check ? "" : "none"; + }); + }); +}; + +async function prep() { + if (window.innerWidth > 1024) { + await waitForRender(() => + document.querySelector(".MuiTabs-flexContainer > button"), + ); + + hideEmptyColumns(); + document + .querySelectorAll(".MuiTabs-flexContainer > button") + .forEach((e) => { + e.addEventListener("click", async () => { + await waitForReplacement(() => + document.querySelector( + ".p-datatable-table .details-btn--appearance", + ), + ); + hideEmptyColumns(); + }); + }); + } else { + await waitForRender(() => + document.querySelector( + ".MuiAccordionDetails-root.accordion__full-width__content > .mobile__frame .grades__box", + ), + ); + document + .querySelectorAll( + ".MuiAccordionDetails-root.accordion__full-width__content > .mobile__frame", + ) + .forEach(async (semester) => { + await waitForRender(() => + semester.querySelector( + ".MuiAccordionDetails-root .grades__box .info-row .info-text > span", + ), + ); + semester.querySelectorAll(".info-row").forEach((e) => { + if ( + e + .querySelector(".info-text > span") + .textContent.trim() === "" || + e + .querySelector(".info-text > span") + .textContent.trim() === "0" + ) { + e.remove(); + } + }); + }); + } +} + +window.appendModule({ + run: prep, + onlyOnReloads: false, + doesRunHere: () => window.location.pathname.endsWith("oceny"), +}); diff --git a/patches/hideSubjectsWithNoGrades/normalGrades.css b/src/patches/hideSubjectsWithNoGrades/normalGrades.css similarity index 80% rename from patches/hideSubjectsWithNoGrades/normalGrades.css rename to src/patches/hideSubjectsWithNoGrades/normalGrades.css index 9797d09..92608af 100644 --- a/patches/hideSubjectsWithNoGrades/normalGrades.css +++ b/src/patches/hideSubjectsWithNoGrades/normalGrades.css @@ -1,27 +1,28 @@ -article.grades__box:has(.tile__content:first-of-type:empty) { - display: none !important; -} -tbody.p-datatable-tbody > tr:has(.wider--oceny:empty) { - display: none !important; -} -.grades__box > .tile__content:empty { - display: none !important; -} -.grades__box > .tile__content:has(~ .tile__content:empty) { - border-bottom: 0 !important; -} -.mobile__frame .grades__box .info-label { - min-width: 100% !important; -} -.content-container .grades__box .info-row { - padding-top: 5px; - padding-bottom: 5px; - margin-bottom: 0; - margin-inline: auto; -} -.content-container .grades__box .tile__content { - padding: 5px 20px; -} -.p-datatable-wrapper table .p-datatable-thead th.wider--oceny, .p-datatable-wrapper table .p-datatable-tbody td.wider--oceny { - width: auto; -} \ No newline at end of file +article.grades__box:has(.tile__content:first-of-type:empty) { + display: none !important; +} +tbody.p-datatable-tbody > tr:has(.wider--oceny:empty) { + display: none !important; +} +.grades__box > .tile__content:empty { + display: none !important; +} +.grades__box > .tile__content:has(~ .tile__content:empty) { + border-bottom: 0 !important; +} +.mobile__frame .grades__box .info-label { + min-width: 100% !important; +} +.content-container .grades__box .info-row { + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + margin-inline: auto; +} +.content-container .grades__box .tile__content { + padding: 5px 20px; +} +.p-datatable-wrapper table .p-datatable-thead th.wider--oceny, +.p-datatable-wrapper table .p-datatable-tbody td.wider--oceny { + width: auto; +} diff --git a/patches/hideTutorsFromBoard.css b/src/patches/hideTutorsFromBoard.css similarity index 97% rename from patches/hideTutorsFromBoard.css rename to src/patches/hideTutorsFromBoard.css index 0903ea0..753dc1a 100644 --- a/patches/hideTutorsFromBoard.css +++ b/src/patches/hideTutorsFromBoard.css @@ -1,3 +1,3 @@ .tile:has(.tile__content .tile__teachers) { display: none !important; -} \ No newline at end of file +} diff --git a/src/patches/hideWCAG.css b/src/patches/hideWCAG.css new file mode 100644 index 0000000..8ee767b --- /dev/null +++ b/src/patches/hideWCAG.css @@ -0,0 +1,5 @@ +.wcag-mobile, +.wcag-tools, +.wcag-controls { + display: none !important; +} diff --git a/patches/hideWeekends.css b/src/patches/hideWeekends.css similarity index 100% rename from patches/hideWeekends.css rename to src/patches/hideWeekends.css diff --git a/src/patches/highlightToday.css b/src/patches/highlightToday.css new file mode 100644 index 0000000..70dfe90 --- /dev/null +++ b/src/patches/highlightToday.css @@ -0,0 +1,23 @@ +.scheduler-simple-cell--current, +.scheduler-cell--current, +.frequency-scheduler-cell--current, +.plan-scheduler-cell__current { + background-color: rgba(200, 200, 210, 0.25); +} +.scheduler-simple-cell--current .scheduler-simple-cell__number, +.scheduler-cell--current .scheduler-cell__number, +.frequency-scheduler-cell--current .frequency-scheduler-cell__footer, +.plan-scheduler-cell__current .plan-scheduler-cell__footer-day { + background-color: #e12d39; + color: #ffffff !important; + display: inline-flex; + justify-content: center; + align-items: center; + width: 43px; + height: 43px; + border-radius: 50px; +} +.scheduler-simple-cell--current .scheduler-simple-cell__number { + width: 30px; + height: 30px; +} diff --git a/patches/loginPasswordTogether/script.js b/src/patches/loginPasswordTogether/script.js similarity index 96% rename from patches/loginPasswordTogether/script.js rename to src/patches/loginPasswordTogether/script.js index 6dcdeb1..e123fd0 100644 --- a/patches/loginPasswordTogether/script.js +++ b/src/patches/loginPasswordTogether/script.js @@ -1,43 +1,44 @@ -function setAutocomplete() { - document.querySelector("#Login")?.setAttribute("autocomplete", "username"); - document - .querySelector("#Haslo") - ?.setAttribute("autocomplete", "current-password"); -} - -function hideBtNext() { - document.querySelector("#btNext").remove(); -} - -function moveEVLinks() { - const linksEl = document.querySelector("#wizard1 > div > .flex-row:has(a)"); - document.querySelector("#wizard2").appendChild(linksEl); -} - -function swapLoginInput() { - const wizard2 = document.querySelector("#wizard2"); - wizard2.parentElement.insertBefore( - document.querySelector("#wizard1"), - wizard2, - ); - // Force firefox to check inputs again - const centerBox = document.querySelector(".center-box"); - centerBox.innerHTML = centerBox.innerHTML; -} - -function fixLoginPage() { - setAutocomplete(); - hideBtNext(); - if (window.location.hostname === "eduvulcan.pl") moveEVLinks(); - swapLoginInput(); -} - -window.appendModule({ - isLoaded: () => document.querySelector("#Haslo"), - onlyOnReloads: true, - run: fixLoginPage, - doesRunHere: () => - ["eduvulcan.pl", "dziennik-logowanie.vulcan.net.pl"].includes( - window.location.hostname, - ), -}); +function setAutocomplete() { + document.querySelector("#Login")?.setAttribute("autocomplete", "username"); + document + .querySelector("#Haslo") + ?.setAttribute("autocomplete", "current-password"); +} + +function hideBtNext() { + document.querySelector("#btNext").remove(); +} + +function moveEVLinks() { + const linksEl = document.querySelector("#wizard1 > div > .flex-row:has(a)"); + document.querySelector("#wizard2").appendChild(linksEl); +} + +function swapLoginInput() { + const wizard2 = document.querySelector("#wizard2"); + wizard2.parentElement.insertBefore( + document.querySelector("#wizard1"), + wizard2, + ); + // Force firefox to check inputs again + const centerBox = document.querySelector(".center-box"); + // eslint-disable-next-line no-self-assign + centerBox.innerHTML = centerBox.innerHTML; +} + +function fixLoginPage() { + setAutocomplete(); + hideBtNext(); + if (window.location.hostname === "eduvulcan.pl") moveEVLinks(); + swapLoginInput(); +} + +window.appendModule({ + isLoaded: () => document.querySelector("#Haslo"), + onlyOnReloads: true, + run: fixLoginPage, + doesRunHere: () => + ["eduvulcan.pl", "dziennik-logowanie.vulcan.net.pl"].includes( + window.location.hostname, + ), +}); diff --git a/patches/loginPasswordTogether/styles.css b/src/patches/loginPasswordTogether/styles.css similarity index 93% rename from patches/loginPasswordTogether/styles.css rename to src/patches/loginPasswordTogether/styles.css index d0a0c78..fff6f90 100644 --- a/patches/loginPasswordTogether/styles.css +++ b/src/patches/loginPasswordTogether/styles.css @@ -1,20 +1,20 @@ -#wizard1 { - order: 2; - display: block !important; -} - -.form-focused-subtitle, -.form-subtitle, -#wizard1 > .flex-col.form-gap.form-margin, -#wizard1 > .flex-col.gap-3.my-2 { - display: none !important; -} - -#wizard2 { - order: 3; - display: block !important; -} - -#btPrev { - display: none; -} +#wizard1 { + order: 2; + display: block !important; +} + +.form-focused-subtitle, +.form-subtitle, +#wizard1 > .flex-col.form-gap.form-margin, +#wizard1 > .flex-col.gap-3.my-2 { + display: none !important; +} + +#wizard2 { + order: 3; + display: block !important; +} + +#btPrev { + display: none; +} diff --git a/patches/messagesButton.js b/src/patches/messagesButton.js similarity index 66% rename from patches/messagesButton.js rename to src/patches/messagesButton.js index 3df64f6..7378df9 100644 --- a/patches/messagesButton.js +++ b/src/patches/messagesButton.js @@ -1,32 +1,29 @@ -import { waitForRender } from "./apis/waitForElement.js"; -import { getFromAside } from "./apis/aside.js"; - -async function move() { - const inner = await getFromAside( - async () => { - await waitForRender(() => document.querySelector(".messages")); - return document.querySelector(".messages")?.innerHTML; - } - ); - - const messages = document.createElement("div"); - messages.innerHTML = inner; - messages.style.float = "right"; - messages.style.padding = "20px"; - messages.style.marginLeft = "auto"; - messages.querySelector( - ".MuiBadge-anchorOriginTopRightRectangle", - ).style.transitionDuration = "0ms"; - - document - .querySelector(".header_logo_tools-container") - .appendChild(messages); -} - -window.appendModule({ - run: move, - doesRunHere: () => - window.location.hostname.match(/^(dziennik-)?(uczen).*/), - onlyOnReloads: true, - isLoaded: () => !!document.querySelector(".header__hamburger__icon") -}); +import { waitForRender } from "./apis/waitForElement.js"; +import { getFromAside } from "./apis/aside.js"; + +async function move() { + const inner = await getFromAside(async () => { + await waitForRender(() => document.querySelector(".messages")); + return document.querySelector(".messages")?.innerHTML; + }); + + const messages = document.createElement("div"); + messages.innerHTML = inner; + messages.style.float = "right"; + messages.style.padding = "20px"; + messages.style.marginLeft = "auto"; + messages.querySelector( + ".MuiBadge-anchorOriginTopRightRectangle", + ).style.transitionDuration = "0ms"; + + document + .querySelector(".header_logo_tools-container") + .appendChild(messages); +} + +window.appendModule({ + run: move, + doesRunHere: () => window.location.hostname.match(/^(dziennik-)?(uczen).*/), + onlyOnReloads: true, + isLoaded: () => !!document.querySelector(".header__hamburger__icon"), +}); diff --git a/patches/moveTitleToHeader/index.js b/src/patches/moveTitleToHeader/index.js similarity index 93% rename from patches/moveTitleToHeader/index.js rename to src/patches/moveTitleToHeader/index.js index 18686fa..c90b35b 100644 --- a/patches/moveTitleToHeader/index.js +++ b/src/patches/moveTitleToHeader/index.js @@ -1,61 +1,61 @@ -import { clickOnAside } from "../apis/aside.js"; - -function createButton() { - const button = document.createElement("span"); - button.className = "go_to_dashboard"; - return button; -} - -function updateTitle() { - const header = document.querySelector(".header__logo-product > span"); - const title = document.querySelector( - ".app__content__header__h1_subtitle > h1", - ); - if (header && title?.innerText && header.innerText !== title.innerText) - header.innerText = title.innerText; -} - -function move() { - const header = document.querySelector(".header__logo-product"); - header.appendChild(document.createElement("span")); - updateTitle(); - - const observer = new MutationObserver(updateTitle); - observer.observe(document.querySelector(".app__content"), { - characterData: true, - childList: true, - subtree: true, - }); - - const button = document.querySelector(".go_to_dashboard") || createButton(); - button.innerHTML = - " Tablica"; - button.classList.add("hidden"); - document.body.appendChild(button); - - header.addEventListener("click", () => { - button.classList.toggle("hidden"); - }); - - button.addEventListener("click", async () => { - button.classList.toggle("hidden"); - if (!!window.location.hostname.match(/^(dziennik-)?wiadomosci.*/)) { - location.replace( - `https://${window.location.hostname.replace( - "wiadomosci", - "uczen", - )}/${window.location.pathname.split("/")[1]}/App`, - ); - } else await clickOnAside(".tablica a"); - }); -} - -window.appendModule({ - run: move, - doesRunHere: () => - window.location.hostname.match(/^(dziennik-)?(uczen|wiadomosci).*/), - onlyOnReloads: true, - isLoaded: () => - !!document.querySelector(".header_logo_tools-container") && - document.querySelector(".app__content__header__h1_subtitle > h1"), -}); +import { clickOnAside } from "../apis/aside.js"; + +function createButton() { + const button = document.createElement("span"); + button.className = "go_to_dashboard"; + return button; +} + +function updateTitle() { + const header = document.querySelector(".header__logo-product > span"); + const title = document.querySelector( + ".app__content__header__h1_subtitle > h1", + ); + if (header && title?.innerText && header.innerText !== title.innerText) + header.innerText = title.innerText; +} + +function move() { + const header = document.querySelector(".header__logo-product"); + header.appendChild(document.createElement("span")); + updateTitle(); + + const observer = new MutationObserver(updateTitle); + observer.observe(document.querySelector(".app__content"), { + characterData: true, + childList: true, + subtree: true, + }); + + const button = document.querySelector(".go_to_dashboard") || createButton(); + button.innerHTML = + " Tablica"; + button.classList.add("hidden"); + document.body.appendChild(button); + + header.addEventListener("click", () => { + button.classList.toggle("hidden"); + }); + + button.addEventListener("click", async () => { + button.classList.toggle("hidden"); + if (window.location.hostname.match(/^(dziennik-)?wiadomosci.*/)) { + location.replace( + `https://${window.location.hostname.replace( + "wiadomosci", + "uczen", + )}/${window.location.pathname.split("/")[1]}/App`, + ); + } else await clickOnAside(".tablica a"); + }); +} + +window.appendModule({ + run: move, + doesRunHere: () => + window.location.hostname.match(/^(dziennik-)?(uczen|wiadomosci).*/), + onlyOnReloads: true, + isLoaded: () => + !!document.querySelector(".header_logo_tools-container") && + document.querySelector(".app__content__header__h1_subtitle > h1"), +}); diff --git a/patches/moveTitleToHeader/style.css b/src/patches/moveTitleToHeader/style.css similarity index 95% rename from patches/moveTitleToHeader/style.css rename to src/patches/moveTitleToHeader/style.css index 67b2a72..1332bcd 100644 --- a/patches/moveTitleToHeader/style.css +++ b/src/patches/moveTitleToHeader/style.css @@ -1,79 +1,79 @@ -.header__logo-product > a > svg, -.header__logo-product > img { - display: none; -} - -.header__logo-product { - font-family: - WorkSans, - Graphik, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Helvetica, - Arial, - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol"; - margin-left: 16px !important; -} - -.header__logo-product > span { - font-size: 24px; - text-wrap: nowrap; - max-width: calc(100vw - 128px - 16px); - text-overflow: ellipsis !important; - white-space: nowrap; - overflow: hidden; -} - -.app__content__header { - display: none; -} - -.go_to_dashboard { - font-family: - WorkSans, - Graphik, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Helvetica, - Arial, - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol"; - font-size: 24px; - color: #3d4455; - position: fixed; - top: 50px; - left: 16px; - z-index: 6942000; - background-color: white; - padding: 4px; - border-radius: 0 0 10px 10px; - border-color: #e5e7e9; - border-style: solid; - border-width: 0 2px 2px 2px; -} - -@media screen and (max-width: 1023px) { - header.app__header { - border-width: 0 !important; - box-shadow: none !important; - } -} - -.go_to_dashboard > img { - rotate: 180deg; - height: 24px; - width: 24px; - opacity: 70%; - transform: translateY(-3px); -} - -.hidden { - display: none; -} +.header__logo-product > a > svg, +.header__logo-product > img { + display: none; +} + +.header__logo-product { + font-family: + WorkSans, + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; + margin-left: 16px !important; +} + +.header__logo-product > span { + font-size: 24px; + text-wrap: nowrap; + max-width: calc(100vw - 128px - 16px); + text-overflow: ellipsis !important; + white-space: nowrap; + overflow: hidden; +} + +.app__content__header { + display: none; +} + +.go_to_dashboard { + font-family: + WorkSans, + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; + font-size: 24px; + color: #3d4455; + position: fixed; + top: 50px; + left: 16px; + z-index: 6942000; + background-color: white; + padding: 4px; + border-radius: 0 0 10px 10px; + border-color: #e5e7e9; + border-style: solid; + border-width: 0 2px 2px 2px; +} + +@media screen and (max-width: 1023px) { + header.app__header { + border-width: 0 !important; + box-shadow: none !important; + } +} + +.go_to_dashboard > img { + rotate: 180deg; + height: 24px; + width: 24px; + opacity: 70%; + transform: translateY(-3px); +} + +.hidden { + display: none; +} diff --git a/patches/moveUserOptionsToHeader/script.js b/src/patches/moveUserOptionsToHeader/script.js similarity index 86% rename from patches/moveUserOptionsToHeader/script.js rename to src/patches/moveUserOptionsToHeader/script.js index 2891f29..dd85576 100644 --- a/patches/moveUserOptionsToHeader/script.js +++ b/src/patches/moveUserOptionsToHeader/script.js @@ -1,104 +1,110 @@ -import { waitForRender } from "../apis/waitForElement.js"; -import { executeActionOnAside, getFromAside } from "../apis/aside.js"; -import { getUserData } from "../apis/getUserData.js"; - -const toggleModal = () => { - document.querySelector(".modal-background").classList.toggle("active"); - document.querySelector(".modal-user").classList.toggle("active"); -}; - -const moveUserOptionsToHeader = async () => { - const userLinks = await getFromAside(async () => { - const user = document.querySelector(".user"); - if (user) { - user.click(); - await waitForRender(() => - document.querySelector(".user__links a"), - ); - return document.querySelectorAll(".user__links a"); - } - }); - const userData = await getUserData(); - - const modalBackground = document.createElement("div"); - const modalElement = document.createElement("div"); - - modalBackground.classList.add("modal-background"); - modalElement.classList.add("modal-user"); - - const userDataElement = document.createElement("div"); - userDataElement.classList.add("modal-data"); - - const userAvatar = document.createElement("div"); - userAvatar.innerHTML = `${userData.fullName[0]}`; - userAvatar.classList.add("user-avatar"); - userDataElement.appendChild(userAvatar.cloneNode(true)); - - const nameElement = document.createElement("div"); - nameElement.classList.add("modal-name"); - nameElement.innerHTML = `${userData?.fullName}${userData?.username}`; - userDataElement.appendChild(nameElement); - - modalElement.appendChild(userDataElement); - - userLinks.forEach((link, i) => { - const linkContainer = document.createElement("div"); - linkContainer.classList.add("modal-link-container"); - - const linkText = document.createElement("span"); - linkText.innerHTML = link.textContent; - - linkText.addEventListener("click", () => { - executeActionOnAside(async () => { - document.querySelector(".user").click(); - await waitForRender(() => document.querySelector(".user__links")); - document.querySelectorAll(".user__links a")[i].click(); - }); - toggleModal(); - }); - - linkContainer.appendChild(linkText); - modalElement.appendChild(linkContainer); - }); - - const backButtonContainer = document.createElement("div"); - backButtonContainer.classList.add("modal-back-container"); - const backButton = document.createElement("span"); - backButton.classList.add("modal-cancel"); - backButton.innerHTML = "Anuluj"; - backButtonContainer.appendChild(backButton); - modalElement.appendChild(backButtonContainer); - - modalBackground.addEventListener("click", () => { - history.back(); - }); - backButton.addEventListener("click", () => { - history.back(); - }); - userAvatar.addEventListener("click", () => { - toggleModal(); - history.pushState({ ...history.state, userModal: true }, "", `${location.pathname}#user-modal`); - }); - - document.body.appendChild(modalElement); - document.body.appendChild(modalBackground); - document - .querySelector(".header_logo_tools_user-wrapper") - .appendChild(userAvatar); - - addEventListener('popstate', (e) => { - if (document.querySelector(".modal-user").classList.contains("active")) { - toggleModal(); - } - }); -}; - -window.appendModule({ - isLoaded: () => - document.querySelector(".header__logo-product")?.firstChild && - document.querySelector(".header__hamburger__icon button"), - onlyOnReloads: true, - run: moveUserOptionsToHeader, - doesRunHere: () => - !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/), -}); +import { waitForRender } from "../apis/waitForElement.js"; +import { executeActionOnAside, getFromAside } from "../apis/aside.js"; +import { getUserData } from "../apis/getUserData.js"; + +const toggleModal = () => { + document.querySelector(".modal-background").classList.toggle("active"); + document.querySelector(".modal-user").classList.toggle("active"); +}; + +const moveUserOptionsToHeader = async () => { + const userLinks = await getFromAside(async () => { + const user = document.querySelector(".user"); + if (user) { + user.click(); + await waitForRender(() => document.querySelector(".user__links a")); + return document.querySelectorAll(".user__links a"); + } + }); + const userData = await getUserData(); + + const modalBackground = document.createElement("div"); + const modalElement = document.createElement("div"); + + modalBackground.classList.add("modal-background"); + modalElement.classList.add("modal-user"); + + const userDataElement = document.createElement("div"); + userDataElement.classList.add("modal-data"); + + const userAvatar = document.createElement("div"); + userAvatar.innerHTML = `${userData.fullName[0]}`; + userAvatar.classList.add("user-avatar"); + userDataElement.appendChild(userAvatar.cloneNode(true)); + + const nameElement = document.createElement("div"); + nameElement.classList.add("modal-name"); + nameElement.innerHTML = `${userData?.fullName}${userData?.username}`; + userDataElement.appendChild(nameElement); + + modalElement.appendChild(userDataElement); + + userLinks.forEach((link, i) => { + const linkContainer = document.createElement("div"); + linkContainer.classList.add("modal-link-container"); + + const linkText = document.createElement("span"); + linkText.innerHTML = link.textContent; + + linkText.addEventListener("click", () => { + executeActionOnAside(async () => { + document.querySelector(".user").click(); + await waitForRender(() => + document.querySelector(".user__links"), + ); + document.querySelectorAll(".user__links a")[i].click(); + }); + toggleModal(); + }); + + linkContainer.appendChild(linkText); + modalElement.appendChild(linkContainer); + }); + + const backButtonContainer = document.createElement("div"); + backButtonContainer.classList.add("modal-back-container"); + const backButton = document.createElement("span"); + backButton.classList.add("modal-cancel"); + backButton.innerHTML = "Anuluj"; + backButtonContainer.appendChild(backButton); + modalElement.appendChild(backButtonContainer); + + modalBackground.addEventListener("click", () => { + history.back(); + }); + backButton.addEventListener("click", () => { + history.back(); + }); + userAvatar.addEventListener("click", () => { + toggleModal(); + history.pushState( + { ...history.state, userModal: true }, + "", + `${location.pathname}#user-modal`, + ); + }); + + document.body.appendChild(modalElement); + document.body.appendChild(modalBackground); + document + .querySelector(".header_logo_tools_user-wrapper") + .appendChild(userAvatar); + + addEventListener("popstate", () => { + if ( + document.querySelector(".modal-user").classList.contains("active") + ) { + toggleModal(); + } + }); +}; + +window.appendModule({ + isLoaded: () => + document.querySelector(".header__logo-product")?.firstChild && + document.querySelector(".header__hamburger__icon button"), + onlyOnReloads: true, + run: moveUserOptionsToHeader, + doesRunHere: () => + !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/), +}); diff --git a/patches/moveUserOptionsToHeader/styles.css b/src/patches/moveUserOptionsToHeader/styles.css similarity index 95% rename from patches/moveUserOptionsToHeader/styles.css rename to src/patches/moveUserOptionsToHeader/styles.css index a2aab12..be4d0d0 100644 --- a/patches/moveUserOptionsToHeader/styles.css +++ b/src/patches/moveUserOptionsToHeader/styles.css @@ -1,130 +1,130 @@ -@media screen and (max-width: 1023px) { - .user__section, - div:has(.user__links__conatainer) { - display: none !important; - } - - .app.hideAside aside { - display: none !important; - } - - .header_logo_tools_user-wrapper img { - width: 45px; - height: 45px; - margin-right: 10px; - cursor: pointer; - } - - .modal-background { - display: none; - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - z-index: 9999; - } - - .modal-background.active { - display: block !important; - } - - .modal-user { - display: none; - top: 50%; - left: 50%; - position: absolute; - overflow: hidden; - transform: translate(-50%, -50%); - width: 80vw; - max-width: 400px; - height: min-content !important; - max-height: min-content !important; - border-radius: 10px; - background-color: #fff; - z-index: 10000; - padding: 10px; - } - - .modal-user.active { - display: block !important; - } - - .modal-data { - display: flex; - align-items: center; - gap: 10px; - padding: 10px 20px; - margin-bottom: 10px; - } - - .modal-name { - display: flex; - flex-direction: column; - padding-left: 0; - gap: 5px; - } - - .modal-name > span { - font-size: 20px; - overflow: hidden; - width: calc(80vw - 116px); - text-wrap: nowrap; - text-overflow: ellipsis; - } - - .modal-link-container, - .modal-back-container { - display: flex; - align-items: center; - padding: 10px 20px; - cursor: pointer; - } - - .modal-back-container { - justify-content: flex-end; - } - - .modal-link-container span { - padding: 0; - font-size: 1.2rem; - font-weight: 500; - text-decoration: none; - color: #3d4455; - } - - .modal-cancel { - text-align: right; - color: #e33f4a; - font-size: 1.2rem; - font-weight: 500; - cursor: pointer; - } - - .header__logo-product > img { - width: auto !important; - } - - header.app__header { - height: 60px; - } - - body.blue .user-avatar { - background: #38817f !important; - color: #ffffff; - } - - .user-avatar { - background: #f8d6d8; - height: 40px; - min-width: 40px; - border-radius: 50%; - margin-right: 16px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - font-size: 1.8rem; - } -} +@media screen and (max-width: 1023px) { + .user__section, + div:has(.user__links__conatainer) { + display: none !important; + } + + .app.hideAside aside { + display: none !important; + } + + .header_logo_tools_user-wrapper img { + width: 45px; + height: 45px; + margin-right: 10px; + cursor: pointer; + } + + .modal-background { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 9999; + } + + .modal-background.active { + display: block !important; + } + + .modal-user { + display: none; + top: 50%; + left: 50%; + position: absolute; + overflow: hidden; + transform: translate(-50%, -50%); + width: 80vw; + max-width: 400px; + height: min-content !important; + max-height: min-content !important; + border-radius: 10px; + background-color: #fff; + z-index: 10000; + padding: 10px; + } + + .modal-user.active { + display: block !important; + } + + .modal-data { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 20px; + margin-bottom: 10px; + } + + .modal-name { + display: flex; + flex-direction: column; + padding-left: 0; + gap: 5px; + } + + .modal-name > span { + font-size: 20px; + overflow: hidden; + width: calc(80vw - 116px); + text-wrap: nowrap; + text-overflow: ellipsis; + } + + .modal-link-container, + .modal-back-container { + display: flex; + align-items: center; + padding: 10px 20px; + cursor: pointer; + } + + .modal-back-container { + justify-content: flex-end; + } + + .modal-link-container span { + padding: 0; + font-size: 1.2rem; + font-weight: 500; + text-decoration: none; + color: #3d4455; + } + + .modal-cancel { + text-align: right; + color: #e33f4a; + font-size: 1.2rem; + font-weight: 500; + cursor: pointer; + } + + .header__logo-product > img { + width: auto !important; + } + + header.app__header { + height: 60px; + } + + body.blue .user-avatar { + background: #38817f !important; + color: #ffffff; + } + + .user-avatar { + background: #f8d6d8; + height: 40px; + min-width: 40px; + border-radius: 50%; + margin-right: 16px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + font-size: 1.8rem; + } +} diff --git a/patches/newAttendance/justifyButton.js b/src/patches/newAttendance/justifyButton.js similarity index 97% rename from patches/newAttendance/justifyButton.js rename to src/patches/newAttendance/justifyButton.js index 5d79530..9286a96 100644 --- a/patches/newAttendance/justifyButton.js +++ b/src/patches/newAttendance/justifyButton.js @@ -1,29 +1,29 @@ -const createButton = () => { - const button = document.createElement("button"); - button.classList.add("justify-abstence"); - button.innerHTML = ` Usprawiedliw`; - button.addEventListener("click", () => { - document - .querySelector(".app__content__header > .toolbar > button") - .click(); - }); - document - .querySelector( - window.innerWidth < 1024 - ? ".app__content > .mobile__frame" - : ".app__content > .desktop__frame", - ) - .appendChild(button); -}; - -window.appendModule({ - run: createButton, - doesRunHere: () => window.location.href.endsWith("frekwencja"), - onlyOnReloads: false, - isLoaded: () => - document.querySelector( - ".app__content > .mobile__frame, .app__content > .desktop__frame", - ) && - document.querySelector(".app__content__header > .toolbar > button") && - !document.querySelector(".spinner"), -}); +const createButton = () => { + const button = document.createElement("button"); + button.classList.add("justify-abstence"); + button.innerHTML = ` Usprawiedliw`; + button.addEventListener("click", () => { + document + .querySelector(".app__content__header > .toolbar > button") + .click(); + }); + document + .querySelector( + window.innerWidth < 1024 + ? ".app__content > .mobile__frame" + : ".app__content > .desktop__frame", + ) + .appendChild(button); +}; + +window.appendModule({ + run: createButton, + doesRunHere: () => window.location.href.endsWith("frekwencja"), + onlyOnReloads: false, + isLoaded: () => + document.querySelector( + ".app__content > .mobile__frame, .app__content > .desktop__frame", + ) && + document.querySelector(".app__content__header > .toolbar > button") && + !document.querySelector(".spinner"), +}); diff --git a/patches/newAttendance/style.css b/src/patches/newAttendance/style.css similarity index 95% rename from patches/newAttendance/style.css rename to src/patches/newAttendance/style.css index ff2416e..5d4452e 100644 --- a/patches/newAttendance/style.css +++ b/src/patches/newAttendance/style.css @@ -1,131 +1,131 @@ -.justify-abstence { - padding-inline: 15px; - border-radius: 15px; - border: 0; - position: fixed; - z-index: 100; - color: white; - background: #314578; - font-weight: 500; - font-family: - "WorkSans", - Graphik, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Helvetica, - Arial, - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol"; - padding-block: 20px; - display: flex; - justify-content: center; - align-items: center; - bottom: 80px; - right: 10px; - cursor: pointer; - font-size: 16px; -} - -.justify-abstence > img { - margin-right: 10px; -} - -.content__header > .toolbar { - display: none; -} - -.frequency__legend { - display: none !important; -} - -@media screen and (min-width: 1024px) { - .attendance-tabs > button:first-of-type { - margin-right: 10px; - } - - .attendance-tabs > button:disabled { - opacity: 50%; - } -} - -.tabsview.stats > div:first-of-type { - display: none !important; -} - -.tabsview.stats > .tabsview__tabs > div > div > div:not(:last-of-type) { - display: none; -} - -.tabsview.attendance-init:not(.stats) - > .tabsview__tabs - > div - > div - > div:last-of-type { - display: none; -} - -.tabsview.attendance-init > div:first-of-type { - margin-top: 10px; -} - -@media screen and (max-width: 1023px) { - .app__content:has(.attendance-tabs) { - margin-top: 0; - padding-top: 0; - } - - .attendance-tabs { - position: fixed; - background: white; - top: 60px; - z-index: 100; - transform: translateX(-5px); - width: 100vw; - } - - .attendance-tabs > button { - width: 50%; - color: var(--kolor-brand); - font-weight: 600; - padding: 0; - margin: 0; - background: none; - height: 40px; - border: 0; - cursor: pointer; - } - - .attendance-tabs > div:not(:last-of-type) { - width: 40vw; - margin-left: 5vw; - height: 3px; - background: var(--kolor-brand); - border-radius: 3px; - transition: 100ms all ease-in-out; - position: relative; - z-index: 101; - top: 1px; - } - - .attendance-tabs:has(button:first-of-type:not(:disabled)) - > div:not(:last-of-type) { - transform: translateX(50vw); - } - - .attendance-tabs > div:last-of-type { - position: relative; - width: 100vw; - border-bottom: 2px solid #e5e7e9; - cursor: pointer; - } - - div#root:has(.attendance-tabs) { - height: calc( - 100svh - 60px - 44px - var(--bottom-navbar-height) - ) !important; - top: 104px; - } -} +.justify-abstence { + padding-inline: 15px; + border-radius: 15px; + border: 0; + position: fixed; + z-index: 100; + color: white; + background: #314578; + font-weight: 500; + font-family: + "WorkSans", + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; + padding-block: 20px; + display: flex; + justify-content: center; + align-items: center; + bottom: 80px; + right: 10px; + cursor: pointer; + font-size: 16px; +} + +.justify-abstence > img { + margin-right: 10px; +} + +.content__header > .toolbar { + display: none; +} + +.frequency__legend { + display: none !important; +} + +@media screen and (min-width: 1024px) { + .attendance-tabs > button:first-of-type { + margin-right: 10px; + } + + .attendance-tabs > button:disabled { + opacity: 50%; + } +} + +.tabsview.stats > div:first-of-type { + display: none !important; +} + +.tabsview.stats > .tabsview__tabs > div > div > div:not(:last-of-type) { + display: none; +} + +.tabsview.attendance-init:not(.stats) + > .tabsview__tabs + > div + > div + > div:last-of-type { + display: none; +} + +.tabsview.attendance-init > div:first-of-type { + margin-top: 10px; +} + +@media screen and (max-width: 1023px) { + .app__content:has(.attendance-tabs) { + margin-top: 0; + padding-top: 0; + } + + .attendance-tabs { + position: fixed; + background: white; + top: 60px; + z-index: 100; + transform: translateX(-5px); + width: 100vw; + } + + .attendance-tabs > button { + width: 50%; + color: var(--kolor-brand); + font-weight: 600; + padding: 0; + margin: 0; + background: none; + height: 40px; + border: 0; + cursor: pointer; + } + + .attendance-tabs > div:not(:last-of-type) { + width: 40vw; + margin-left: 5vw; + height: 3px; + background: var(--kolor-brand); + border-radius: 3px; + transition: 100ms all ease-in-out; + position: relative; + z-index: 101; + top: 1px; + } + + .attendance-tabs:has(button:first-of-type:not(:disabled)) + > div:not(:last-of-type) { + transform: translateX(50vw); + } + + .attendance-tabs > div:last-of-type { + position: relative; + width: 100vw; + border-bottom: 2px solid #e5e7e9; + cursor: pointer; + } + + div#root:has(.attendance-tabs) { + height: calc( + 100svh - 60px - 44px - var(--bottom-navbar-height) + ) !important; + top: 104px; + } +} diff --git a/patches/newAttendance/tabs.js b/src/patches/newAttendance/tabs.js similarity index 97% rename from patches/newAttendance/tabs.js rename to src/patches/newAttendance/tabs.js index 49c3013..9c55ff2 100644 --- a/patches/newAttendance/tabs.js +++ b/src/patches/newAttendance/tabs.js @@ -1,57 +1,57 @@ -const selector = document.createElement("div"); -if (window.innerWidth >= 1024) - selector.innerHTML = - ''; -else - selector.innerHTML = - "
"; -selector.classList.add("attendance-tabs"); - -const createSelector = () => { - const container = - window.innerWidth < 1024 - ? ".app__content > .mobile__frame" - : ".app__content > .desktop__frame"; - document - .querySelector(container) - .insertBefore(selector, document.querySelector(container + "> *")); - changeStatsVisibility(false); -}; - -const changeStatsVisibility = (isStatsVisible) => { - const mainStats = document.querySelector( - ".content-container:has(.statistics)", - ); - mainStats.style.display = isStatsVisible ? "block" : "none"; - const element = document.querySelector(".tabsview"); - element.classList.add("attendance-init"); - if (isStatsVisible) element.classList.add("stats"); - else element.classList.remove("stats"); -}; - -selector.querySelector("button:first-of-type").addEventListener("click", () => { - changeStatsVisibility(false); - - selector.querySelector("button:first-of-type").disabled = true; - selector.querySelector("button:last-of-type").disabled = false; -}); - -selector.querySelector("button:last-of-type").addEventListener("click", () => { - changeStatsVisibility(true); - - selector.querySelector("button:first-of-type").disabled = false; - selector.querySelector("button:last-of-type").disabled = true; -}); - -const isAttendancePage = () => window.location.pathname.endsWith("frekwencja"); - -const isRendered = () => - !!document.querySelector(".content-container:has(.statistics)") && - !!document.querySelector(".tabsview"); - -window.appendModule({ - isLoaded: isRendered, - run: createSelector, - onlyOnReloads: false, - doesRunHere: isAttendancePage, -}); +const selector = document.createElement("div"); +if (window.innerWidth >= 1024) + selector.innerHTML = + ''; +else + selector.innerHTML = + "
"; +selector.classList.add("attendance-tabs"); + +const createSelector = () => { + const container = + window.innerWidth < 1024 + ? ".app__content > .mobile__frame" + : ".app__content > .desktop__frame"; + document + .querySelector(container) + .insertBefore(selector, document.querySelector(container + "> *")); + changeStatsVisibility(false); +}; + +const changeStatsVisibility = (isStatsVisible) => { + const mainStats = document.querySelector( + ".content-container:has(.statistics)", + ); + mainStats.style.display = isStatsVisible ? "block" : "none"; + const element = document.querySelector(".tabsview"); + element.classList.add("attendance-init"); + if (isStatsVisible) element.classList.add("stats"); + else element.classList.remove("stats"); +}; + +selector.querySelector("button:first-of-type").addEventListener("click", () => { + changeStatsVisibility(false); + + selector.querySelector("button:first-of-type").disabled = true; + selector.querySelector("button:last-of-type").disabled = false; +}); + +selector.querySelector("button:last-of-type").addEventListener("click", () => { + changeStatsVisibility(true); + + selector.querySelector("button:first-of-type").disabled = false; + selector.querySelector("button:last-of-type").disabled = true; +}); + +const isAttendancePage = () => window.location.pathname.endsWith("frekwencja"); + +const isRendered = () => + !!document.querySelector(".content-container:has(.statistics)") && + !!document.querySelector(".tabsview"); + +window.appendModule({ + isLoaded: isRendered, + run: createSelector, + onlyOnReloads: false, + doesRunHere: isAttendancePage, +}); diff --git a/patches/newDashboard/index.js b/src/patches/newDashboard/index.js similarity index 97% rename from patches/newDashboard/index.js rename to src/patches/newDashboard/index.js index 60d0806..6176c81 100644 --- a/patches/newDashboard/index.js +++ b/src/patches/newDashboard/index.js @@ -1,164 +1,164 @@ -import { waitForRender } from "../apis/waitForElement.js"; -import { mapDay } from "../apis/mapTimetable.js"; - -const doesHaveClickableParent = (element) => { - if (["a", "button"].includes(element.tagName.toLowerCase())) return true; - if (!element.parentElement) return false; - return doesHaveClickableParent(element.parentElement); -}; - -const icons = [ - [ - "Dzisiejszy plan zajęć", - "calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", - ], - [ - "Oceny od ostatniego logowania", - "counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", - ], - ["Sprawdziany", "quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], - ["Zadania domowe", "summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], - ["Informacje", "folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], - ["Ogłoszenia", "campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], - ["Ankiety", "feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], - [ - "Frekwencja", - "event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", - ], - [ - "Dyżurni", - "person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg", - ], - ["Ważne dzisiaj", "strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], -]; - -const applyIcons = () => { - for (const [tileTitle, fileName] of icons) { - const icon = document.createElement("img"); - icon.src = `https://raw.githubusercontent.com/banocean/ifv/refs/heads/main/assets/icons/${fileName}`; - const container = Array.from( - document.querySelectorAll(".content-container .tile.box"), - ) - ?.find((e) => e.querySelector("h2").textContent === tileTitle) - ?.querySelector(".tile__header.flex__items > .flex__item-auto"); - - if (container) container.insertBefore(icon, container.firstChild); - else return console.debug(`Tile ${tileTitle} not found`); - - container.parentElement?.parentElement?.addEventListener( - "click", - (e) => { - if (doesHaveClickableParent(e.target)) return; - container.parentElement.querySelector("a.tile__link")?.click(); - }, - ); - } -}; - -let maxLessons = 0; -const renderTimetable = () => { - const timetableElement = document.querySelector(".plan-zajec"); - const timetable = mapDay(timetableElement); - if (timetable.length < maxLessons) return; - maxLessons = timetable.length; - - const elements = timetable.map((lesson) => { - const element = document.createElement("li"); - if (lesson.type === "conflicted") { - element.innerText = `Więcej pozycji`; - } else { - element.classList.add(lesson.type); - element.innerText = `${lesson.subject} (${lesson.classroom}) ${ - lesson.type === "unknown" ? lesson.annotationText : "" - }`; - } - return element; - }); - - const container = document.createElement("ol"); - container.classList.add("lessons-container"); - container.append(...elements); - - const existingContainer = document.querySelector(".lessons-container"); - if (existingContainer) { - existingContainer.remove(); - } - - timetableElement.parentElement.insertBefore(container, timetableElement); -}; - -const replaceTimetable = async () => { - await waitForRender(() => document.querySelector(".plan-zajec")); - renderTimetable(); - const observer = new MutationObserver(renderTimetable); - observer.observe(document.querySelector(".plan-zajec"), { - childList: true, - subtree: true, - }); -}; - -const createToolbar = async () => { - const getContainer = () => - document.querySelector( - ".content-container > .tile-container > .tile-subcontainer", - ); - await waitForRender(getContainer); - - const element = document.createElement("div"); - element.classList.add("dashboard-info-toolbar"); - element.innerHTML = ` -
- - - -
-
- - - -
-
- - - -
- `; - - const container = getContainer(); - container.insertBefore(element, container.firstChild); - - const getLuckyNumber = () => - document.querySelector( - ".lucky-number__circle.lucky-number__number > span", - )?.innerText; - waitForRender(getLuckyNumber).then( - () => - (element.querySelector("div:first-of-type > span").innerText = - getLuckyNumber()), - ); - - const getAmountOfMessages = () => - document.querySelector( - 'a[title="Przejdź do modułu wiadomości"] .MuiBadge-anchorOriginTopRightRectangle', - ).innerText; - waitForRender(getAmountOfMessages).then( - () => - (element.querySelector("div:last-of-type > span").innerText = - getAmountOfMessages()), - ); - element.querySelector("div:last-of-type").addEventListener("click", () => { - document - .querySelector('a[title="Przejdź do modułu wiadomości"]') - ?.click(); - }); -}; - -window.appendModule({ - run: () => { - applyIcons(); - createToolbar(); - replaceTimetable(); - }, - doesRunHere: () => window.location.href.endsWith("tablica"), - onlyOnReloads: false, - isLoaded: () => - document.querySelector(".plan-zajec") && - !document.querySelector(".spinner"), -}); +import { waitForRender } from "../apis/waitForElement.js"; +import { mapDay } from "../apis/mapTimetable.js"; + +const doesHaveClickableParent = (element) => { + if (["a", "button"].includes(element.tagName.toLowerCase())) return true; + if (!element.parentElement) return false; + return doesHaveClickableParent(element.parentElement); +}; + +const icons = [ + [ + "Dzisiejszy plan zajęć", + "calendar_clock_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", + ], + [ + "Oceny od ostatniego logowania", + "counter_6_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", + ], + ["Sprawdziany", "quiz_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], + ["Zadania domowe", "summarize_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], + ["Informacje", "folder_info_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], + ["Ogłoszenia", "campaign_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], + ["Ankiety", "feedback_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], + [ + "Frekwencja", + "event_available_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg", + ], + [ + "Dyżurni", + "person_raised_hand_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg", + ], + ["Ważne dzisiaj", "strategy_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.svg"], +]; + +const applyIcons = () => { + for (const [tileTitle, fileName] of icons) { + const icon = document.createElement("img"); + icon.src = `https://raw.githubusercontent.com/banocean/ifv/refs/heads/main/assets/icons/${fileName}`; + const container = Array.from( + document.querySelectorAll(".content-container .tile.box"), + ) + ?.find((e) => e.querySelector("h2").textContent === tileTitle) + ?.querySelector(".tile__header.flex__items > .flex__item-auto"); + + if (container) container.insertBefore(icon, container.firstChild); + else return console.debug(`Tile ${tileTitle} not found`); + + container.parentElement?.parentElement?.addEventListener( + "click", + (e) => { + if (doesHaveClickableParent(e.target)) return; + container.parentElement.querySelector("a.tile__link")?.click(); + }, + ); + } +}; + +let maxLessons = 0; +const renderTimetable = () => { + const timetableElement = document.querySelector(".plan-zajec"); + const timetable = mapDay(timetableElement); + if (timetable.length < maxLessons) return; + maxLessons = timetable.length; + + const elements = timetable.map((lesson) => { + const element = document.createElement("li"); + if (lesson.type === "conflicted") { + element.innerText = `Więcej pozycji`; + } else { + element.classList.add(lesson.type); + element.innerText = `${lesson.subject} (${lesson.classroom}) ${ + lesson.type === "unknown" ? lesson.annotationText : "" + }`; + } + return element; + }); + + const container = document.createElement("ol"); + container.classList.add("lessons-container"); + container.append(...elements); + + const existingContainer = document.querySelector(".lessons-container"); + if (existingContainer) { + existingContainer.remove(); + } + + timetableElement.parentElement.insertBefore(container, timetableElement); +}; + +const replaceTimetable = async () => { + await waitForRender(() => document.querySelector(".plan-zajec")); + renderTimetable(); + const observer = new MutationObserver(renderTimetable); + observer.observe(document.querySelector(".plan-zajec"), { + childList: true, + subtree: true, + }); +}; + +const createToolbar = async () => { + const getContainer = () => + document.querySelector( + ".content-container > .tile-container > .tile-subcontainer", + ); + await waitForRender(getContainer); + + const element = document.createElement("div"); + element.classList.add("dashboard-info-toolbar"); + element.innerHTML = ` +
+ + - +
+
+ + - +
+
+ + - +
+ `; + + const container = getContainer(); + container.insertBefore(element, container.firstChild); + + const getLuckyNumber = () => + document.querySelector( + ".lucky-number__circle.lucky-number__number > span", + )?.innerText; + waitForRender(getLuckyNumber).then( + () => + (element.querySelector("div:first-of-type > span").innerText = + getLuckyNumber()), + ); + + const getAmountOfMessages = () => + document.querySelector( + 'a[title="Przejdź do modułu wiadomości"] .MuiBadge-anchorOriginTopRightRectangle', + ).innerText; + waitForRender(getAmountOfMessages).then( + () => + (element.querySelector("div:last-of-type > span").innerText = + getAmountOfMessages()), + ); + element.querySelector("div:last-of-type").addEventListener("click", () => { + document + .querySelector('a[title="Przejdź do modułu wiadomości"]') + ?.click(); + }); +}; + +window.appendModule({ + run: () => { + applyIcons(); + createToolbar(); + replaceTimetable(); + }, + doesRunHere: () => window.location.href.endsWith("tablica"), + onlyOnReloads: false, + isLoaded: () => + document.querySelector(".plan-zajec") && + !document.querySelector(".spinner"), +}); diff --git a/patches/newDashboard/styles.css b/src/patches/newDashboard/styles.css similarity index 95% rename from patches/newDashboard/styles.css rename to src/patches/newDashboard/styles.css index 7666147..152b1f9 100644 --- a/patches/newDashboard/styles.css +++ b/src/patches/newDashboard/styles.css @@ -1,115 +1,115 @@ -@media screen and (max-width: 1023px) { - .content-container:has(.plan-zajec) { - margin: 0 !important; - } - - .content-container:has(.plan-zajec), - .content-container:has(.plan-zajec) > .tile-container { - padding: 0 !important; - background: none !important; - box-shadow: none !important; - } - - .box-shaded { - background-color: #f8f9fc !important; - box-shadow: none !important; - border-width: 0 !important; - } - - .tile__header h2 { - font-weight: bold; - } - - .tile__header .toolbar { - display: none; - } - - .tile__header.flex__items > .flex__item-auto { - display: flex; - align-items: center; - } - - .tile__header.flex__items > .flex__item-auto > img { - filter: invert(0.8); - margin-right: 5px; - } - - .content-container .tile .tile__header { - padding-top: 10px; - padding-left: 10px; - border-bottom: 0; - padding-bottom: 0; - } - - .tile.box.tile__lucky-number, - .tile.box:has(.lucky-number__circle.lucky-number__circle-1), - .tile.box:has(.tile__lucky-number) { - display: none !important; - } - - .dashboard-info-toolbar { - display: flex; - height: 50px; - gap: 10px; - } - - .dashboard-info-toolbar > div { - padding: 10px; - background: #f8f9fc; - border-radius: 10px; - width: 100%; - display: flex; - align-items: center; - justify-content: center; - font-size: 22px; - } - - .dashboard-info-toolbar > div > img { - filter: invert(0.8); - margin-right: 5px; - height: 28px; - } - - .dashboard-info-toolbar > div > span { - margin-right: 5px; - } - - .content-container > .tile-container, - .content-container > .tile-container > .tile-subcontainer { - gap: 10px !important; - } - - body:has(.dashboard-info-toolbar) .plan-zajec, - body:has(.dashboard-info-toolbar) - .tile__content:has(.plan-zajec) - > .tile__content__title { - display: none !important; - } - - .lessons-container { - margin-left: 15px; - font-family: - "WorkSans", - Graphik, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Helvetica, - Arial, - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol"; - font-size: 14px; - text-wrap: wrap; - } - - .lessons-container .canceled { - color: #e12d39 !important; - text-decoration: line-through !important; - } - - .lessons-container .substitute { - color: #6d5e0f !important; - } -} +@media screen and (max-width: 1023px) { + .content-container:has(.plan-zajec) { + margin: 0 !important; + } + + .content-container:has(.plan-zajec), + .content-container:has(.plan-zajec) > .tile-container { + padding: 0 !important; + background: none !important; + box-shadow: none !important; + } + + .box-shaded { + background-color: #f8f9fc !important; + box-shadow: none !important; + border-width: 0 !important; + } + + .tile__header h2 { + font-weight: bold; + } + + .tile__header .toolbar { + display: none; + } + + .tile__header.flex__items > .flex__item-auto { + display: flex; + align-items: center; + } + + .tile__header.flex__items > .flex__item-auto > img { + filter: invert(0.8); + margin-right: 5px; + } + + .content-container .tile .tile__header { + padding-top: 10px; + padding-left: 10px; + border-bottom: 0; + padding-bottom: 0; + } + + .tile.box.tile__lucky-number, + .tile.box:has(.lucky-number__circle.lucky-number__circle-1), + .tile.box:has(.tile__lucky-number) { + display: none !important; + } + + .dashboard-info-toolbar { + display: flex; + height: 50px; + gap: 10px; + } + + .dashboard-info-toolbar > div { + padding: 10px; + background: #f8f9fc; + border-radius: 10px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; + } + + .dashboard-info-toolbar > div > img { + filter: invert(0.8); + margin-right: 5px; + height: 28px; + } + + .dashboard-info-toolbar > div > span { + margin-right: 5px; + } + + .content-container > .tile-container, + .content-container > .tile-container > .tile-subcontainer { + gap: 10px !important; + } + + body:has(.dashboard-info-toolbar) .plan-zajec, + body:has(.dashboard-info-toolbar) + .tile__content:has(.plan-zajec) + > .tile__content__title { + display: none !important; + } + + .lessons-container { + margin-left: 15px; + font-family: + "WorkSans", + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; + font-size: 14px; + text-wrap: wrap; + } + + .lessons-container .canceled { + color: #e12d39 !important; + text-decoration: line-through !important; + } + + .lessons-container .substitute { + color: #6d5e0f !important; + } +} diff --git a/patches/newMobileNavbar/highlights.js b/src/patches/newMobileNavbar/highlights.js similarity index 79% rename from patches/newMobileNavbar/highlights.js rename to src/patches/newMobileNavbar/highlights.js index e5f4302..5b064ce 100644 --- a/patches/newMobileNavbar/highlights.js +++ b/src/patches/newMobileNavbar/highlights.js @@ -6,7 +6,9 @@ export const setHighlights = () => { else if (window.location.pathname.endsWith("frekwencja")) i = 2; else if (window.location.pathname.endsWith("planZajec")) i = 3; - const buttons = Array.from(document.querySelector(".bottom-navigation-bar").children); + const buttons = Array.from( + document.querySelector(".bottom-navigation-bar").children, + ); for (let j = 0; j < buttons.length; j++) { const button = buttons[j]; const img = button.querySelector("div > img"); @@ -18,6 +20,7 @@ export const setHighlights = () => { window.appendModule({ run: setHighlights, onlyOnReloads: false, - isLoaded: () => document.querySelector(".bottom-navigation-bar")?.children?.length, + isLoaded: () => + document.querySelector(".bottom-navigation-bar")?.children?.length, doesRunHere: () => window.location.hostname.match(/^(dziennik-)?(uczen).*/), -}); \ No newline at end of file +}); diff --git a/src/patches/newMobileNavbar/index.js b/src/patches/newMobileNavbar/index.js new file mode 100644 index 0000000..a9c704e --- /dev/null +++ b/src/patches/newMobileNavbar/index.js @@ -0,0 +1,197 @@ +import { getFromAside } from "../apis/aside.js"; +import { waitForRender } from "../apis/waitForElement.js"; +import { setHighlights } from "./highlights.js"; + +if (window.location.hostname.match(/^(dziennik-)?(uczen).*/)) + window.asideMode = "hidden"; + +const getPages = (selector = "aside > section > .MuiList-root > ul") => { + if (!document.querySelector("aside")) return []; + return Array.from(document.querySelector(selector).children).map((item) => { + const isDirectLink = item.classList.contains("MuiListItem-gutters"); + const icon = getComputedStyle( + isDirectLink ? item : item.querySelector("div > button"), + ":before", + ).getPropertyValue("content"); + const name = item.querySelector( + isDirectLink ? "a" : ".accordion__title__content", + )?.innerText; + + const items = isDirectLink + ? undefined + : Array.from(item.querySelector(".items").children); + + return { + type: isDirectLink ? 1 : 2, + element: item, + items, + icon, + name, + }; + }); +}; + +const BACK_ICON_URL = + "https://raw.githubusercontent.com/banocean/ifv/new-navbar/assets/icons/keyboard_backspace_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg"; + +const navIcons = { + tablica: "dashboard", + oceny: "counter_6", + frekwencja: "event_available", + planZajec: "calendar_clock", +}; + +const run = async () => { + const nav = document.createElement("nav"); + nav.classList.add("bottom-navigation-bar"); + + const more = document.createElement("div"); + more.classList.add("more-popup"); + more.classList.add("list-modal"); + more.innerHTML = `

Więcej

`; + more.style.display = "none"; + + more.querySelector("img").addEventListener("click", () => { + more.style.display = "none"; + history.back(); + setHighlights(); + }); + + await getFromAside(() => null); // We need aside to just load + await waitForRender(() => getPages().length > 1); + + const navPages = ["tablica", "oceny", "frekwencja", "planZajec"]; + const pages = getPages(); + for (const page of pages) { + const itemClass = Array.from(page.element.classList).find( + (c) => + ![ + "MuiListItem-root", + "MuiListItem-gutters", + "selected", + ].includes(c), + ); + const item = document.createElement("div"); + + if (!navPages.includes(itemClass)) { + item.innerHTML = + "
"; + item.querySelector(".icon").style.content = page.icon; + item.querySelector(".name").innerText = page.name; + more.querySelector("div:last-of-type").appendChild(item); + } else { + item.innerHTML = `
`; + item.querySelector("div:last-of-type").innerText = page.name; + nav.appendChild(item); + } + + if (page.type === 1) { + item.addEventListener("click", () => { + document.querySelector(`.${itemClass} a`).click(); + more.style.display = "none"; + document + .querySelector(".header__hamburger__icon button") + .click(); + document.querySelector("div#root").scroll(0, 0); + setHighlights(); + }); + } else { + const detailedOptionsPage = document.createElement("div"); + detailedOptionsPage.innerHTML = `

`; + detailedOptionsPage.style.zIndex = "4002"; + detailedOptionsPage.style.display = "none"; + detailedOptionsPage.classList.add("list-modal"); + + detailedOptionsPage.querySelector("h1").innerText = page.name; + detailedOptionsPage + .querySelector("img") + .addEventListener("click", () => { + history.back(); + }); + + for (let i = 0; i < page.items.length; i++) { + const option = page.items[i]; + const element = document.createElement("div"); + element.innerHTML = + "
"; + element.querySelector(".icon").style.content = page.icon; + element.querySelector(".name").innerText = + option.firstChild.innerText; + element.addEventListener("click", () => { + detailedOptionsPage.style.display = "none"; + more.style.display = "none"; + Array.from( + document.querySelectorAll(`.${itemClass} .items a`), + )[i].click(); + document + .querySelector(".header__hamburger__icon button") + .click(); + document.querySelector("div#root").scroll(0, 0); + }); + detailedOptionsPage.lastElementChild.appendChild(element); + } + + item.addEventListener("click", () => { + detailedOptionsPage.style.display = "block"; + history.pushState( + { ...history.state, moreDetails: true }, + "", + `${location.pathname}#${itemClass}`, + ); + }); + + addEventListener("popstate", (e) => { + if (e.state?.moreDetails) { + detailedOptionsPage.style.display = "block"; + } else { + detailedOptionsPage.style.display = "none"; + } + }); + + document.body.appendChild(detailedOptionsPage); + } + } + + const moreButton = document.createElement("div"); + moreButton.innerHTML = ` +
+ +
+
Więcej
+ `; + + moreButton.addEventListener("click", () => { + more.style.display = "block"; + history.pushState( + { ...history.state, more: true }, + "", + `${location.pathname}#more`, + ); + setHighlights(); + }); + + nav.appendChild(moreButton); + + document.body.appendChild(nav); + document.body.appendChild(more); +}; + +addEventListener("popstate", (e) => { + if (e.state?.moreDetails !== true) { + if (e.state?.more) { + document.querySelector(".more-popup").style.display = "block"; + } else { + document.querySelectorAll(".list-modal").forEach((e) => { + e.style.display = "none"; + }); + } + } + setHighlights(); +}); + +window.appendModule({ + run, + doesRunHere: () => window.location.hostname.match(/^(dziennik-)?(uczen).*/), + onlyOnReloads: true, + isLoaded: () => !!document.querySelector(".header__hamburger__icon"), +}); diff --git a/patches/newMobileNavbar/styles.css b/src/patches/newMobileNavbar/styles.css similarity index 83% rename from patches/newMobileNavbar/styles.css rename to src/patches/newMobileNavbar/styles.css index ce99144..2019fdb 100644 --- a/patches/newMobileNavbar/styles.css +++ b/src/patches/newMobileNavbar/styles.css @@ -10,7 +10,18 @@ left: 0; z-index: 4000; background: #eff2f7; - font-family: "WorkSans", Graphik, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-family: + "WorkSans", + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; } .list-modal > div:first-of-type { @@ -30,7 +41,6 @@ height: 40px; } - .list-modal > div:first-of-type > h1 { width: 100%; font-size: 1.8rem; @@ -64,8 +74,6 @@ align-content: center; } - - @media screen and (max-width: 1023px) { .modal { width: 100vw !important; @@ -74,10 +82,11 @@ .modal__footer { background: none !important; - border-top: 0 !important + border-top: 0 !important; } - aside, .header__hamburger__icon { + aside, + .header__hamburger__icon { display: none !important; } @@ -143,7 +152,18 @@ } .bottom-navigation-bar > div > div:has(img.highlight) { - font-family: "WorkSans", Graphik, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-family: + "WorkSans", + Graphik, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; background: var(--kolor-wcag); } @@ -164,4 +184,4 @@ main.app__main { .app__mobile { flex: 1; min-height: 100%; -} \ No newline at end of file +} diff --git a/patches/newTimetable/script.js b/src/patches/newTimetable/script.js similarity index 97% rename from patches/newTimetable/script.js rename to src/patches/newTimetable/script.js index 32964d7..935c1a3 100644 --- a/patches/newTimetable/script.js +++ b/src/patches/newTimetable/script.js @@ -1,140 +1,140 @@ -import { waitForRender } from "../apis/waitForElement.js"; -import { SelectorRenderer } from "../apis/bottomDateSelector/index.js"; -import { mapDay } from "../apis/mapTimetable.js"; - -const mapData = () => - Array.from(document.querySelectorAll(".app__content .MuiPaper-root")).map( - (element) => { - return { - note: element.querySelector(".plan-zajec__accordion__wolne") - ?.innerText, - day: element.querySelector(".MuiAccordionSummary-content > h2") - ?.innerText, - lessons: mapDay(element), - }; - }, - ); -const isOpened = (element) => - element.querySelector(".MuiCollapse-root")?.style?.height !== "0px"; - -const openAll = async () => { - const container = document.querySelectorAll(".app__content .MuiPaper-root"); - for (const element of container) { - if (!isOpened(element)) - element.querySelector(".accordion__full-width__header h2")?.click(); - await waitForRender(() => isOpened(element), element); - } -}; - -const mapStartingHours = (data) => { - const all = new Set(); - for (const day of data) - if (day.lessons) - for (const lesson of day.lessons) - if (lesson.startingHour) all.add(lesson.startingHour); - const result = [...all].sort(); - const [firstHour, firstMinutes] = (result[0] || "08:00").split(":"); - return Number(firstHour) <= 7 && Number(firstMinutes) <= 30 - ? result - : ["7:00", ...result]; -}; - -const getStartingHours = () => - JSON.parse(localStorage.getItem("startingHours") || "[]"); - -const renderDay = async (data) => { - await openAll(); - - if (!data.note) { - await waitForRender(() => - document.querySelector(".details-btn--position-r-bottom"), - ); - } - - const startingHours = getStartingHours(); - const lessons = mapDay(data.element); - const element = document.createElement("section"); - element.classList.add("timetable"); - - if (lessons.length < 1) { - const infoElement = document.createElement("div"); - infoElement.innerHTML = - "
Nie ma lekcji 😎
"; - if (data.note) - infoElement.querySelector("span:last-of-type").innerText = - data.note; - element.appendChild(infoElement); - } else { - for (const lesson of lessons) { - const lessonElement = document.createElement("div"); - lessonElement.innerHTML = ` -
${startingHours.findIndex((h) => h === lesson.startingHour)}
-
-
-
-
- `; - const lessonDataElement = lessonElement.querySelector(".data"); - - const timeContainer = lessonElement.querySelector(".info"); - timeContainer.firstElementChild.innerText = lesson.startingHour; - timeContainer.lastElementChild.innerText = lesson.endingHour; - - lessonElement.classList.add("lesson"); - lessonElement.classList.add(lesson.type); - - if (lesson.type === "conflicted") { - lessonDataElement.innerHTML = ` -
Wpisana jest więcej niż jedna lekcja
-
Kliknij, aby wyświetlić
- `; - } else { - lessonDataElement.innerHTML = `
`; - lessonDataElement.querySelector(".subject").innerText = - lesson.subject; - lessonDataElement.querySelector(".additional-info").innerText = - `${lesson.classroom} ${lesson.teacher?.split(" ")?.reverse()?.join(" ")}`; - } - - lessonElement.addEventListener("click", () => - lesson.originalElement.querySelector("button").click(), - ); - element.appendChild(lessonElement); - } - } - - return element; -}; - -const run = async () => { - document.querySelector( - "section.app__content .app__content__header", - ).style.display = "none"; - document.querySelector( - "section.app__content .mobile__frame > div", - ).style.display = "none"; - - await openAll(); - localStorage.setItem( - "startingHours", - JSON.stringify(mapStartingHours(mapData())), - ); - - new SelectorRenderer(renderDay); -}; - -const isLoaded = () => - document.querySelector(".app__content .MuiCollapse-root")?.style - ?.minHeight && - document.querySelector("section.app__content .mobile__frame .plan-zajec") && - !document.querySelector(".spinner") && - document.querySelector( - ".position__lesson__hours, .conflicted--details--hours", - ); - -window.appendModule({ - isLoaded, - onlyOnReloads: false, - run, - doesRunHere: () => window.location.pathname.endsWith("planZajec"), -}); +import { waitForRender } from "../apis/waitForElement.js"; +import { SelectorRenderer } from "../apis/bottomDateSelector/index.js"; +import { mapDay } from "../apis/mapTimetable.js"; + +const mapData = () => + Array.from(document.querySelectorAll(".app__content .MuiPaper-root")).map( + (element) => { + return { + note: element.querySelector(".plan-zajec__accordion__wolne") + ?.innerText, + day: element.querySelector(".MuiAccordionSummary-content > h2") + ?.innerText, + lessons: mapDay(element), + }; + }, + ); +const isOpened = (element) => + element.querySelector(".MuiCollapse-root")?.style?.height !== "0px"; + +const openAll = async () => { + const container = document.querySelectorAll(".app__content .MuiPaper-root"); + for (const element of container) { + if (!isOpened(element)) + element.querySelector(".accordion__full-width__header h2")?.click(); + await waitForRender(() => isOpened(element), element); + } +}; + +const mapStartingHours = (data) => { + const all = new Set(); + for (const day of data) + if (day.lessons) + for (const lesson of day.lessons) + if (lesson.startingHour) all.add(lesson.startingHour); + const result = [...all].sort(); + const [firstHour, firstMinutes] = (result[0] || "08:00").split(":"); + return Number(firstHour) <= 7 && Number(firstMinutes) <= 30 + ? result + : ["7:00", ...result]; +}; + +const getStartingHours = () => + JSON.parse(localStorage.getItem("startingHours") || "[]"); + +const renderDay = async (data) => { + await openAll(); + + if (!data.note) { + await waitForRender(() => + document.querySelector(".details-btn--position-r-bottom"), + ); + } + + const startingHours = getStartingHours(); + const lessons = mapDay(data.element); + const element = document.createElement("section"); + element.classList.add("timetable"); + + if (lessons.length < 1) { + const infoElement = document.createElement("div"); + infoElement.innerHTML = + "
Nie ma lekcji 😎
"; + if (data.note) + infoElement.querySelector("span:last-of-type").innerText = + data.note; + element.appendChild(infoElement); + } else { + for (const lesson of lessons) { + const lessonElement = document.createElement("div"); + lessonElement.innerHTML = ` +
${startingHours.findIndex((h) => h === lesson.startingHour)}
+
+
+
+
+ `; + const lessonDataElement = lessonElement.querySelector(".data"); + + const timeContainer = lessonElement.querySelector(".info"); + timeContainer.firstElementChild.innerText = lesson.startingHour; + timeContainer.lastElementChild.innerText = lesson.endingHour; + + lessonElement.classList.add("lesson"); + lessonElement.classList.add(lesson.type); + + if (lesson.type === "conflicted") { + lessonDataElement.innerHTML = ` +
Wpisana jest więcej niż jedna lekcja
+
Kliknij, aby wyświetlić
+ `; + } else { + lessonDataElement.innerHTML = `
`; + lessonDataElement.querySelector(".subject").innerText = + lesson.subject; + lessonDataElement.querySelector(".additional-info").innerText = + `${lesson.classroom} ${lesson.teacher?.split(" ")?.reverse()?.join(" ")}`; + } + + lessonElement.addEventListener("click", () => + lesson.originalElement.querySelector("button").click(), + ); + element.appendChild(lessonElement); + } + } + + return element; +}; + +const run = async () => { + document.querySelector( + "section.app__content .app__content__header", + ).style.display = "none"; + document.querySelector( + "section.app__content .mobile__frame > div", + ).style.display = "none"; + + await openAll(); + localStorage.setItem( + "startingHours", + JSON.stringify(mapStartingHours(mapData())), + ); + + new SelectorRenderer(renderDay); +}; + +const isLoaded = () => + document.querySelector(".app__content .MuiCollapse-root")?.style + ?.minHeight && + document.querySelector("section.app__content .mobile__frame .plan-zajec") && + !document.querySelector(".spinner") && + document.querySelector( + ".position__lesson__hours, .conflicted--details--hours", + ); + +window.appendModule({ + isLoaded, + onlyOnReloads: false, + run, + doesRunHere: () => window.location.pathname.endsWith("planZajec"), +}); diff --git a/patches/newTimetable/styles.css b/src/patches/newTimetable/styles.css similarity index 95% rename from patches/newTimetable/styles.css rename to src/patches/newTimetable/styles.css index 51c1458..d60256c 100644 --- a/patches/newTimetable/styles.css +++ b/src/patches/newTimetable/styles.css @@ -1,111 +1,111 @@ -:root { - --background-primary: light-dark(white, #0b1517); - --background-navigation: light-dark(white, #152528); -} - -body { - color-scheme: only light; -} - -.app__main { - background: var(--background-primary) !important; - height: auto; -} - -.timetable { - padding: 0 !important; - margin-inline: 10px !important; -} - -.timetable:not(:has(.lesson)) { - display: flex; - justify-content: center; - align-items: center; - height: calc(100svh - 62px - 40px - 20px - var(--bottom-navbar-height)); - text-align: center; -} - -.timetable .no-lessons-title { - font-size: 24px; -} - -.timetable .lesson { - display: flex; - margin-bottom: 5px; - line-height: 16px; -} - -.lesson > div:first-of-type { - font-size: 30px; - display: flex; - align-items: center; - color: light-dark(#1b1b1f, #f5feff); - min-width: 18px; -} - -.lesson > article { - display: flex; - padding: 15px; - align-content: center; - border-radius: 10px; - width: 100%; - margin-left: 10px; - cursor: pointer; - background: light-dark(#efedf1, #192123); - overflow: hidden; -} - -.lesson .subject { - color: light-dark(#1b1b1f, #dbe4e7); - font-size: 13px; - overflow: hidden; - text-overflow: ellipsis; - text-wrap: nowrap !important; -} - -.lesson .data { - overflow: inherit; -} - -.lesson .info { - display: flex; - flex-direction: column; - margin-right: 10px; - color: #a1aaac; -} - -.lesson .additional-info { - color: #a1aaac; - font-size: smaller; -} - -.lesson.canceled > article { - background: light-dark(#f9dedc, #8c1d18); -} - -.lesson.canceled .subject { - text-decoration: line-through; - color: light-dark(#410e0b, #f9dedc); -} - -.lesson.canceled .info, -.lesson.canceled .additional-info { - color: light-dark(#784c4a, #d9a5a1); -} - -.lesson.canceled > div:first-of-type { - color: light-dark(#b3261e, #f2b8b5); -} - -.lesson.substitute > article { - background: light-dark(#e7e4bd, #65683c); -} - -.lesson.substitute .info, -.lesson.substitute .additional-info { - color: light-dark(#58574e, #b8bfb4); -} - -.lesson.substitute > div:first-of-type { - color: light-dark(#6d5e0f, #65683c); -} +:root { + --background-primary: light-dark(white, #0b1517); + --background-navigation: light-dark(white, #152528); +} + +body { + color-scheme: only light; +} + +.app__main { + background: var(--background-primary) !important; + height: auto; +} + +.timetable { + padding: 0 !important; + margin-inline: 10px !important; +} + +.timetable:not(:has(.lesson)) { + display: flex; + justify-content: center; + align-items: center; + height: calc(100svh - 62px - 40px - 20px - var(--bottom-navbar-height)); + text-align: center; +} + +.timetable .no-lessons-title { + font-size: 24px; +} + +.timetable .lesson { + display: flex; + margin-bottom: 5px; + line-height: 16px; +} + +.lesson > div:first-of-type { + font-size: 30px; + display: flex; + align-items: center; + color: light-dark(#1b1b1f, #f5feff); + min-width: 18px; +} + +.lesson > article { + display: flex; + padding: 15px; + align-content: center; + border-radius: 10px; + width: 100%; + margin-left: 10px; + cursor: pointer; + background: light-dark(#efedf1, #192123); + overflow: hidden; +} + +.lesson .subject { + color: light-dark(#1b1b1f, #dbe4e7); + font-size: 13px; + overflow: hidden; + text-overflow: ellipsis; + text-wrap: nowrap !important; +} + +.lesson .data { + overflow: inherit; +} + +.lesson .info { + display: flex; + flex-direction: column; + margin-right: 10px; + color: #a1aaac; +} + +.lesson .additional-info { + color: #a1aaac; + font-size: smaller; +} + +.lesson.canceled > article { + background: light-dark(#f9dedc, #8c1d18); +} + +.lesson.canceled .subject { + text-decoration: line-through; + color: light-dark(#410e0b, #f9dedc); +} + +.lesson.canceled .info, +.lesson.canceled .additional-info { + color: light-dark(#784c4a, #d9a5a1); +} + +.lesson.canceled > div:first-of-type { + color: light-dark(#b3261e, #f2b8b5); +} + +.lesson.substitute > article { + background: light-dark(#e7e4bd, #65683c); +} + +.lesson.substitute .info, +.lesson.substitute .additional-info { + color: light-dark(#58574e, #b8bfb4); +} + +.lesson.substitute > div:first-of-type { + color: light-dark(#6d5e0f, #65683c); +} diff --git a/patches/patchesSettings/desktop.js b/src/patches/patchesSettings/desktop.js similarity index 100% rename from patches/patchesSettings/desktop.js rename to src/patches/patchesSettings/desktop.js diff --git a/patches/patchesSettings/generateSettingsList.js b/src/patches/patchesSettings/generateSettingsList.js similarity index 97% rename from patches/patchesSettings/generateSettingsList.js rename to src/patches/patchesSettings/generateSettingsList.js index b28661a..515b7b2 100644 --- a/patches/patchesSettings/generateSettingsList.js +++ b/src/patches/patchesSettings/generateSettingsList.js @@ -64,7 +64,7 @@ export async function generateSettingsList() { settingInputDiv.innerHTML = renderer( setting, patch.name, - currentValue + currentValue, ); } @@ -92,7 +92,7 @@ function setupSearchbar(patchesSettingsDiv) { searchInput.addEventListener("input", () => { const query = searchInput.value.trim().toLowerCase(); const noResultsMessageDiv = patchesSettingsDiv.querySelector( - ".no-results-message" + ".no-results-message", ); let visiblePatchesCount = 0; @@ -139,11 +139,11 @@ function setupSearchbar(patchesSettingsDiv) { patchDiv.querySelectorAll(".setting").forEach((settingDiv) => { markTextInElement( settingDiv.querySelector(".setting-name"), - query + query, ); markTextInElement( settingDiv.querySelector(".setting-description"), - query + query, ); }); } else { @@ -185,21 +185,21 @@ function addListenersToInputs(patchesSettingsDiv) { saveSetting( toggle.querySelector(".toggle-input").dataset.patch, toggle.querySelector(".toggle-input").dataset.setting, - toggle.querySelector(".toggle-input").checked + toggle.querySelector(".toggle-input").checked, ); }); }); patchesSettingsDiv .querySelectorAll( - ".setting-select, .setting-text, .setting-color, .setting-number" + ".setting-select, .setting-text, .setting-color, .setting-number", ) .forEach((input) => { input.addEventListener("change", () => { saveSetting( input.dataset.patch, input.dataset.setting, - input.value + input.value, ); }); }); @@ -212,8 +212,8 @@ function addListenersToInputs(patchesSettingsDiv) { const settingId = checkbox.dataset.setting; const selectedValues = Array.from( patchesSettingsDiv.querySelectorAll( - `.setting-multiselect-checkbox[data-patch='${patchName}'][data-setting='${settingId}']:checked` - ) + `.setting-multiselect-checkbox[data-patch='${patchName}'][data-setting='${settingId}']:checked`, + ), ).map((cb) => cb.value); saveSetting(patchName, settingId, selectedValues); }); diff --git a/patches/patchesSettings/markers.js b/src/patches/patchesSettings/markers.js similarity index 94% rename from patches/patchesSettings/markers.js rename to src/patches/patchesSettings/markers.js index f72ce9b..673a216 100644 --- a/patches/patchesSettings/markers.js +++ b/src/patches/patchesSettings/markers.js @@ -50,12 +50,12 @@ export async function markTextInElement(element, textQueryToHighlight) { while (matchIndex !== -1) { fragment.appendChild( - document.createTextNode(text.substring(lastIndex, matchIndex)) + document.createTextNode(text.substring(lastIndex, matchIndex)), ); const mark = document.createElement("mark"); mark.textContent = text.substring( matchIndex, - matchIndex + query.length + matchIndex + query.length, ); fragment.appendChild(mark); @@ -63,7 +63,7 @@ export async function markTextInElement(element, textQueryToHighlight) { matchIndex = lowerText.indexOf(query, lastIndex); } fragment.appendChild( - document.createTextNode(text.substring(lastIndex)) + document.createTextNode(text.substring(lastIndex)), ); node.parentNode.replaceChild(fragment, node); diff --git a/patches/patchesSettings/mobile.js b/src/patches/patchesSettings/mobile.js similarity index 97% rename from patches/patchesSettings/mobile.js rename to src/patches/patchesSettings/mobile.js index 17a63aa..96cce1c 100644 --- a/patches/patchesSettings/mobile.js +++ b/src/patches/patchesSettings/mobile.js @@ -27,7 +27,7 @@ function addMobileSettings() { }); waitForRender( - () => document.querySelectorAll(".more-popup.list-modal div")[1] + () => document.querySelectorAll(".more-popup.list-modal div")[1], ).then(() => { document .querySelectorAll(".more-popup.list-modal div")[1] @@ -40,6 +40,6 @@ window.appendModule({ onlyOnReloads: true, doesRunHere: () => ["uczen.eduvulcan.pl", "dziennik-uczen.vulcan.net.pl"].includes( - window.location.hostname + window.location.hostname, ) && window.innerWidth < 1024, }); diff --git a/patches/patchesSettings/settingRenderers.js b/src/patches/patchesSettings/settingRenderers.js similarity index 92% rename from patches/patchesSettings/settingRenderers.js rename to src/patches/patchesSettings/settingRenderers.js index 2e6610b..876e7cf 100644 --- a/patches/patchesSettings/settingRenderers.js +++ b/src/patches/patchesSettings/settingRenderers.js @@ -30,15 +30,15 @@ export const settingRenderers = { */ select: (setting, patchName, currentValue) => ` @@ -64,8 +64,8 @@ export const settingRenderers = {
+ setting.id + }" ${currentValue ? "checked" : ""}>
@@ -81,8 +81,8 @@ export const settingRenderers = { const selectedValues = Array.isArray(currentValue) ? currentValue : typeof currentValue === "string" && currentValue.length > 0 - ? currentValue.split(",") - : []; + ? currentValue.split(",") + : []; return `
${setting.options @@ -103,7 +103,7 @@ export const settingRenderers = { option.value }">${option.name}
- ` + `, ) .join("")} @@ -128,9 +128,9 @@ export const settingRenderers = { */ number: (setting, patchName, currentValue) => ` + setting.id + }" value="${currentValue}" step="${setting.step || 1}" placeholder="${ + setting.default + }"> `, }; diff --git a/patches/patchesSettings/style.css b/src/patches/patchesSettings/style.css similarity index 91% rename from patches/patchesSettings/style.css rename to src/patches/patchesSettings/style.css index 6de7105..a71bb4e 100644 --- a/patches/patchesSettings/style.css +++ b/src/patches/patchesSettings/style.css @@ -19,10 +19,13 @@ transform: translate(-50%, 200%); opacity: 0.3; z-index: -1; - transition: transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), + transition: + transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.3s ease-in-out; - box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.2), - 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12); + box-shadow: + 0 8px 10px -5px rgba(0, 0, 0, 0.2), + 0 16px 24px 2px rgba(0, 0, 0, 0.14), + 0 6px 30px 5px rgba(0, 0, 0, 0.12); } .search-bar { @@ -35,7 +38,9 @@ height: 40px; box-sizing: border-box; border: 1px solid #ecedf7; - transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + transition: + border-color 0.2s ease-in-out, + box-shadow 0.2s ease-in-out; } .search-bar:has(input[type="text"]:focus) { @@ -104,7 +109,9 @@ height: 100%; z-index: -1; background: #00000000; - transition: backdrop-filter 0.3s ease-in-out, background 0.3s ease-in-out; + transition: + backdrop-filter 0.3s ease-in-out, + background 0.3s ease-in-out; } .ifv-patches-modal-header { @@ -205,7 +212,9 @@ font-size: 14px; color: #202022; box-sizing: border-box; - transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + transition: + border-color 0.2s ease-in-out, + box-shadow 0.2s ease-in-out; margin-top: 5px; width: 100%; } @@ -252,7 +261,9 @@ cursor: pointer; position: relative; margin-right: 10px; - transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out; + transition: + background-color 0.2s ease-in-out, + border-color 0.2s ease-in-out; } .checkbox-item input[type="checkbox"]:checked { @@ -308,8 +319,11 @@ font-size: 14px; font-weight: 500; cursor: pointer; - transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out, - border-color 0.2s ease-in-out, color 0.2s ease-in-out; + transition: + background-color 0.2s ease-in-out, + box-shadow 0.2s ease-in-out, + border-color 0.2s ease-in-out, + color 0.2s ease-in-out; border: 1px solid transparent; outline: none; line-height: 1.5; diff --git a/patches/pwa.js b/src/patches/pwa.js similarity index 100% rename from patches/pwa.js rename to src/patches/pwa.js diff --git a/patches/redirectToBoard/script.js b/src/patches/redirectToBoard/script.js similarity index 65% rename from patches/redirectToBoard/script.js rename to src/patches/redirectToBoard/script.js index 6e92be0..bf71e29 100644 --- a/patches/redirectToBoard/script.js +++ b/src/patches/redirectToBoard/script.js @@ -1,27 +1,27 @@ import { clickOnAside } from "../apis/aside.js"; -const isEduVulcan = () => !window.location.hostname.startsWith("dziennik"); +const isEV = () => !window.location.hostname.startsWith("dziennik"); const getLogoElement = () => document.querySelector(".header__logo-product")?.firstChild; function setUpRedirectToBoard() { const logoElement = getLogoElement(); - if (!!window.location.hostname.match(/^(dziennik-)?wiadomosci.*/)) { + if (window.location.hostname.match(/^(dziennik-)?wiadomosci.*/)) { const url = `https://${window.location.hostname.replace( "wiadomosci", - "uczen" + "uczen", )}/${window.location.pathname.split("/")[1]}/App`; - if (isEduVulcan()) logoElement.href = url; + if (isEV()) logoElement.href = url; else { logoElement.onclick = () => (window.location.href = url); logoElement.style = "cursor: pointer;"; } } else { - if (isEduVulcan()) logoElement.href = "javascript:void(0)"; + if (isEV()) logoElement.href = "javascript:void(0)"; else logoElement.style = "cursor: pointer;"; - logoElement.addEventListener("click", () => clickOnAside(".tablica a")) + logoElement.addEventListener("click", () => clickOnAside(".tablica a")); } } @@ -29,5 +29,6 @@ window.appendModule({ isLoaded: getLogoElement, onlyOnReloads: true, run: setUpRedirectToBoard, - doesRunHere: () => !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/) -}) + doesRunHere: () => + !!window.location.hostname.match(/^(dziennik-)?(wiadomosci|uczen).*/), +}); diff --git a/patches/redirectToBoard/styles.css b/src/patches/redirectToBoard/styles.css similarity index 95% rename from patches/redirectToBoard/styles.css rename to src/patches/redirectToBoard/styles.css index dbddce5..b3d5fe5 100644 --- a/patches/redirectToBoard/styles.css +++ b/src/patches/redirectToBoard/styles.css @@ -1,3 +1,3 @@ .app.hideAside aside { display: none; -} \ No newline at end of file +} diff --git a/src/patches/redirectToDVLogin.js b/src/patches/redirectToDVLogin.js new file mode 100644 index 0000000..67057ef --- /dev/null +++ b/src/patches/redirectToDVLogin.js @@ -0,0 +1,28 @@ +function redirectToLoginPage() { + window.location.pathname = `/${ + window.location.pathname.split("/")[1] + }/LoginEndpoint.aspx`; +} + +window.appendModule({ + onlyOnReloads: true, + run: redirectToLoginPage, + doesRunHere: () => + window.location.hostname === "dziennik-uczen.vulcan.net.pl" && + !window.location.pathname.split("/")[2], +}); + +const pathSegment = encodeURIComponent( + window.location.pathname.split("/")[1] ?? "", +); + +const targetSpan = document.querySelector( + ".input-components ~ .form-gap > span", +); + +if (targetSpan) { + const spanHTML = targetSpan.innerHTML; + const newHTML = spanHTML.slice(0, -1); + const additionalText = `lub użyj innej metody logowania`; + targetSpan.innerHTML = `${newHTML} ${additionalText}`; +} diff --git a/patches/redirectToEVLogin.js b/src/patches/redirectToEVLogin.js similarity index 54% rename from patches/redirectToEVLogin.js rename to src/patches/redirectToEVLogin.js index 918edf3..988f8a9 100644 --- a/patches/redirectToEVLogin.js +++ b/src/patches/redirectToEVLogin.js @@ -6,7 +6,7 @@ window.appendModule({ onlyOnReloads: true, run: redirectToLoginPage, doesRunHere: () => - window.location.hostname === "eduvulcan.pl" - && window.location.pathname === "/" - && !!document.querySelector("#panelLoginButton") + window.location.hostname === "eduvulcan.pl" && + window.location.pathname === "/" && + !!document.querySelector("#panelLoginButton"), }); diff --git a/popup/index.html b/src/popup/index.html similarity index 91% rename from popup/index.html rename to src/popup/index.html index 1e42f84..2e6d9e0 100644 --- a/popup/index.html +++ b/src/popup/index.html @@ -1,70 +1,70 @@ - - - - - - - - Improvements for Vulcan - - - -

Improvements for Vulcan

-

- Changing any option below will refresh opened pages.
We are not affiliated, associated, authorized, endorsed by, or - in any way officially connected with VULCAN sp. z o.o., or any - of its subsidiaries or its affiliates. -

-
-
- - - - - -
- -
- -
- - - - + + + + + + + + Hephaestus + + + +

Hephaestus

+

+ Changing any option below will refresh opened pages.
We are not affiliated, associated, authorized, endorsed by, or + in any way officially connected with ██████ ███ █ ████, or any + of its subsidiaries or its affiliates. +

+
+
+ + + + + +
+ +
+ +
+ + + + diff --git a/popup/main.js b/src/popup/main.js similarity index 96% rename from popup/main.js rename to src/popup/main.js index bca4122..3a81843 100644 --- a/popup/main.js +++ b/src/popup/main.js @@ -1,158 +1,158 @@ -const fetchPatches = async () => { - const patchesResponse = await fetch(chrome.runtime.getURL("patches.json")); - return await patchesResponse.json(); -}; - -if (/\bMobile\b/.test(navigator.userAgent)) - document.body.classList.add("mobile"); - -const filterInput = document.querySelector(".filter > div > input"); -const categories = document.querySelector(".categories"); - -filterInput.addEventListener("input", () => { - const filter = filterInput.value.toLowerCase(); - - Array.from(document.querySelectorAll(".options > *")).forEach((option) => { - if ( - option - .querySelector(".title") - .innerText.toLowerCase() - .includes(filter) || - option - .querySelector(".desc") - .innerText.toLowerCase() - .includes(filter) - ) { - option.classList.remove("search-hidden"); - } else { - option.classList.add("search-hidden"); - } - }); -}); - -categories.addEventListener("input", () => { - if (categories.value === "mobile") { - document - .querySelectorAll(".mobileOnly") - .forEach((e) => e.classList.remove("category-hidden")); - document - .querySelectorAll(".desktopOnly") - .forEach((e) => e.classList.add("category-hidden")); - } else if (categories.value === "desktop") { - document - .querySelectorAll(".mobileOnly") - .forEach((e) => e.classList.add("category-hidden")); - document - .querySelectorAll(".desktopOnly") - .forEach((e) => e.classList.remove("category-hidden")); - } else { - document - .querySelectorAll("label") - .forEach((e) => e.classList.remove("category-hidden")); - } - chrome.storage.local.set({ category: categories.value }); -}); - -document.querySelector("#clear").addEventListener("click", async () => { - filterInput.value = ""; - filterInput.dispatchEvent(new Event("input")); -}); - -const render = async () => { - let config = (await chrome.storage.sync.get("options"))?.options ?? {}; - const patches = await fetchPatches(); - - chrome.storage.sync.set({ options: config }); - - const optionsDOM = document.querySelector(".options"); - optionsDOM.innerHTML = ""; - - const sortedPatches = [...patches].sort((a, b) => - a.name.localeCompare(b.name, "pl") - ); - - for (const patch of sortedPatches) { - const isEnabled = config[patch.name] !== false; - - const option = document.createElement("label"); - option.innerHTML = ` -
-

${patch.name}

-

${patch.description}

-
- ${ - patch.devices === "mobileOnly" - ? `` - : "" - } - ${ - patch.devices === "desktopOnly" - ? `` - : "" - } -
- -
-
- `; - option.querySelector("input").id = patch.name; - if (patch.devices === "mobileOnly") option.classList.add("mobileOnly"); - if (patch.devices === "desktopOnly") - option.classList.add("desktopOnly"); - optionsDOM.appendChild(option); - } - - optionsDOM.addEventListener("change", async (e) => { - const target = e.target; - if (target.tagName === "INPUT") { - config[target.id] = target.checked; - await chrome.storage.sync.set({ options: config }); - } - }); - - const { category } = (await chrome.storage.local.get(["category"])) || {}; - if (category) { - categories.value = category; - categories.dispatchEvent(new Event("input")); - } else if (document.body.classList.contains("mobile")) { - categories.value = "mobile"; - categories.dispatchEvent(new Event("input")); - } else { - categories.value = "desktop"; - categories.dispatchEvent(new Event("input")); - } -}; - -(async () => { - const changeAllButton = document.querySelector(".filter > button"); - let nextApplyAllAction = - (await chrome.storage.sync.get("nextApplyAllAction")) - .nextApplyAllAction || false; - - const toggleAllButton = async () => { - chrome.storage.sync.set({ nextApplyAllAction: !nextApplyAllAction }); - - const patches = await fetchPatches(); - const config = {}; - - patches.forEach((patch) => { - config[patch.name] = nextApplyAllAction; - }); - - await chrome.storage.sync.set({ options: config }); - await render(); - nextApplyAllAction = !nextApplyAllAction; - setButtonName(); - }; - - const setButtonName = () => - (document.querySelector(".filter > button").innerHTML = - nextApplyAllAction ? "Enable All" : "Disable All"); - - setButtonName(); - changeAllButton.addEventListener("click", toggleAllButton); -})(); - -document.addEventListener("DOMContentLoaded", render); +const fetchPatches = async () => { + const patchesResponse = await fetch(chrome.runtime.getURL("patches.json")); + return await patchesResponse.json(); +}; + +if (/\bMobile\b/.test(navigator.userAgent)) + document.body.classList.add("mobile"); + +const filterInput = document.querySelector(".filter > div > input"); +const categories = document.querySelector(".categories"); + +filterInput.addEventListener("input", () => { + const filter = filterInput.value.toLowerCase(); + + Array.from(document.querySelectorAll(".options > *")).forEach((option) => { + if ( + option + .querySelector(".title") + .innerText.toLowerCase() + .includes(filter) || + option + .querySelector(".desc") + .innerText.toLowerCase() + .includes(filter) + ) { + option.classList.remove("search-hidden"); + } else { + option.classList.add("search-hidden"); + } + }); +}); + +categories.addEventListener("input", () => { + if (categories.value === "mobile") { + document + .querySelectorAll(".mobileOnly") + .forEach((e) => e.classList.remove("category-hidden")); + document + .querySelectorAll(".desktopOnly") + .forEach((e) => e.classList.add("category-hidden")); + } else if (categories.value === "desktop") { + document + .querySelectorAll(".mobileOnly") + .forEach((e) => e.classList.add("category-hidden")); + document + .querySelectorAll(".desktopOnly") + .forEach((e) => e.classList.remove("category-hidden")); + } else { + document + .querySelectorAll("label") + .forEach((e) => e.classList.remove("category-hidden")); + } + chrome.storage.local.set({ category: categories.value }); +}); + +document.querySelector("#clear").addEventListener("click", async () => { + filterInput.value = ""; + filterInput.dispatchEvent(new Event("input")); +}); + +const render = async () => { + let config = (await chrome.storage.sync.get("options"))?.options ?? {}; + const patches = await fetchPatches(); + + chrome.storage.sync.set({ options: config }); + + const optionsDOM = document.querySelector(".options"); + optionsDOM.innerHTML = ""; + + const sortedPatches = [...patches].sort((a, b) => + a.name.localeCompare(b.name, "pl"), + ); + + for (const patch of sortedPatches) { + const isEnabled = config[patch.name] !== false; + + const option = document.createElement("label"); + option.innerHTML = ` +
+

${patch.name}

+

${patch.description}

+
+ ${ + patch.devices === "mobileOnly" + ? `` + : "" + } + ${ + patch.devices === "desktopOnly" + ? `` + : "" + } +
+ +
+
+ `; + option.querySelector("input").id = patch.name; + if (patch.devices === "mobileOnly") option.classList.add("mobileOnly"); + if (patch.devices === "desktopOnly") + option.classList.add("desktopOnly"); + optionsDOM.appendChild(option); + } + + optionsDOM.addEventListener("change", async (e) => { + const target = e.target; + if (target.tagName === "INPUT") { + config[target.id] = target.checked; + await chrome.storage.sync.set({ options: config }); + } + }); + + const { category } = (await chrome.storage.local.get(["category"])) || {}; + if (category) { + categories.value = category; + categories.dispatchEvent(new Event("input")); + } else if (document.body.classList.contains("mobile")) { + categories.value = "mobile"; + categories.dispatchEvent(new Event("input")); + } else { + categories.value = "desktop"; + categories.dispatchEvent(new Event("input")); + } +}; + +(async () => { + const changeAllButton = document.querySelector(".filter > button"); + let nextApplyAllAction = + (await chrome.storage.sync.get("nextApplyAllAction")) + .nextApplyAllAction || false; + + const toggleAllButton = async () => { + chrome.storage.sync.set({ nextApplyAllAction: !nextApplyAllAction }); + + const patches = await fetchPatches(); + const config = {}; + + patches.forEach((patch) => { + config[patch.name] = nextApplyAllAction; + }); + + await chrome.storage.sync.set({ options: config }); + await render(); + nextApplyAllAction = !nextApplyAllAction; + setButtonName(); + }; + + const setButtonName = () => + (document.querySelector(".filter > button").innerHTML = + nextApplyAllAction ? "Enable All" : "Disable All"); + + setButtonName(); + changeAllButton.addEventListener("click", toggleAllButton); +})(); + +document.addEventListener("DOMContentLoaded", render); diff --git a/popup/style.css b/src/popup/style.css similarity index 94% rename from popup/style.css rename to src/popup/style.css index e92472c..71a490e 100644 --- a/popup/style.css +++ b/src/popup/style.css @@ -1,230 +1,230 @@ -body { - background: #18181b; - font-family: Cantarell, Arial, sans-serif; - color: white; - width: 350px; - padding: 10px; -} - -body.mobile { - width: calc(100% - (2 * 18px)) !important; -} - -.filter > div { - box-sizing: border-box; - width: 100%; - color: white; - border: none; - border-radius: 5px; - background: #27272a; - padding-left: 5px; - display: flex; - align-items: center; -} - -.filter > div > input::placeholder { - color: #8e8e8e; -} - -.filter > div > input { - box-sizing: border-box; - width: 100%; - color: white; - border: none; - background: transparent; - padding-block: 7px; -} - -.filter > div:focus-within, -.filter > div:hover { - background: #3f3f46; -} - -.filter > div > input:focus, -.filter > div > input:hover { - outline: none; -} - -.filter > button { - box-sizing: border-box; - width: min-content; - height: 100%; - padding: 5px 10px; - background: #27272a; - color: white; - margin-left: 5px; - border: none; - cursor: pointer; - border-radius: 5px; -} - -.filter > button:hover { - background: #3f3f46; -} - -.filter { - width: 100%; - height: 30px; - display: flex; - align-items: flex-start; - margin-bottom: 5px; -} - -.categories { - box-sizing: border-box; - width: 100%; - height: 30px; - margin-bottom: 15px; - background: #27272a; - color: white; - border: none; - border-radius: 5px; - text-align: center; -} - -.categories:hover { - background: #3f3f46; -} - -label.category-hidden { - display: none; -} - -label.search-hidden { - display: none !important; -} - -#clear { - background: none; - border: none; - cursor: pointer; - display: flex; - align-items: center; - padding-block: 6px; - padding-left: 2px; - padding-right: 5px; - border-radius: 50%; -} - -#clear > svg { - transition: fill 100ms; -} - -#clear:hover > svg { - fill: #c2c2c2; -} - -/* Main */ - -h1 { - margin: 5px 0; - color: #fafafa; - text-align: center; -} - -h2 { - color: #d4d4d8; - font-size: small; - font-weight: normal; - text-align: center; -} - -.options { - display: flex; - flex-direction: column; - gap: 8px; -} - -/* Option */ - -label { - display: flex; - justify-content: space-between; - align-items: center; - margin: 2px 0; - padding: 10px; - border-radius: 7px; - background: #27272a; - gap: 10px; - cursor: pointer; -} - -label:hover { - background: #3f3f46; -} - -label .desc { - margin: 5px 0 0 0; - font-size: 14px; - color: #a1a1aa; - line-height: 16px; -} - -label .title { - font-size: 15px; - color: #f4f4f5; - line-height: 18px; - font-weight: 500; - margin: 0; -} - -/* Toggle */ -/* https://uiverse.io/ClawHack1/itchy-bobcat-18 */ - -.toggle-wrapper { - position: relative; - display: inline-block; - width: 40px; - height: 24px; -} - -.toggle-wrapper .toggle-switch { - position: absolute; - top: 0; - left: 0; - width: 40px; - height: 24px; - background-color: #52525b; - border-radius: 34px; - cursor: pointer; - transition: background-color 0.3s; -} - -.toggle-wrapper .toggle-switch::before { - content: ""; - position: absolute; - width: 20px; - height: 20px; - border-radius: 50%; - top: 2px; - left: 2px; - background-color: #fff; - box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.3); - transition: transform 0.3s; -} - -.toggle-wrapper .toggle-input:checked + .toggle-switch::before { - transform: translateX(16px); -} - -.toggle-wrapper .toggle-input:checked + .toggle-switch { - background-color: #16a34a; -} - -.toggle-wrapper .toggle-input:checked + .toggle-switch::before { - transform: translateX(16px); -} - -/* Footer */ - -.footer { - padding: 10px; - display: flex; - justify-content: center; - align-items: center; - gap: 20px; -} - -.footer a { - color: #a1a1aa; -} +body { + background: #18181b; + font-family: Cantarell, Arial, sans-serif; + color: white; + width: 350px; + padding: 10px; +} + +body.mobile { + width: calc(100% - (2 * 18px)) !important; +} + +.filter > div { + box-sizing: border-box; + width: 100%; + color: white; + border: none; + border-radius: 5px; + background: #27272a; + padding-left: 5px; + display: flex; + align-items: center; +} + +.filter > div > input::placeholder { + color: #8e8e8e; +} + +.filter > div > input { + box-sizing: border-box; + width: 100%; + color: white; + border: none; + background: transparent; + padding-block: 7px; +} + +.filter > div:focus-within, +.filter > div:hover { + background: #3f3f46; +} + +.filter > div > input:focus, +.filter > div > input:hover { + outline: none; +} + +.filter > button { + box-sizing: border-box; + width: min-content; + height: 100%; + padding: 5px 10px; + background: #27272a; + color: white; + margin-left: 5px; + border: none; + cursor: pointer; + border-radius: 5px; +} + +.filter > button:hover { + background: #3f3f46; +} + +.filter { + width: 100%; + height: 30px; + display: flex; + align-items: flex-start; + margin-bottom: 5px; +} + +.categories { + box-sizing: border-box; + width: 100%; + height: 30px; + margin-bottom: 15px; + background: #27272a; + color: white; + border: none; + border-radius: 5px; + text-align: center; +} + +.categories:hover { + background: #3f3f46; +} + +label.category-hidden { + display: none; +} + +label.search-hidden { + display: none !important; +} + +#clear { + background: none; + border: none; + cursor: pointer; + display: flex; + align-items: center; + padding-block: 6px; + padding-left: 2px; + padding-right: 5px; + border-radius: 50%; +} + +#clear > svg { + transition: fill 100ms; +} + +#clear:hover > svg { + fill: #c2c2c2; +} + +/* Main */ + +h1 { + margin: 5px 0; + color: #fafafa; + text-align: center; +} + +h2 { + color: #d4d4d8; + font-size: small; + font-weight: normal; + text-align: center; +} + +.options { + display: flex; + flex-direction: column; + gap: 8px; +} + +/* Option */ + +label { + display: flex; + justify-content: space-between; + align-items: center; + margin: 2px 0; + padding: 10px; + border-radius: 7px; + background: #27272a; + gap: 10px; + cursor: pointer; +} + +label:hover { + background: #3f3f46; +} + +label .desc { + margin: 5px 0 0 0; + font-size: 14px; + color: #a1a1aa; + line-height: 16px; +} + +label .title { + font-size: 15px; + color: #f4f4f5; + line-height: 18px; + font-weight: 500; + margin: 0; +} + +/* Toggle */ +/* https://uiverse.io/ClawHack1/itchy-bobcat-18 */ + +.toggle-wrapper { + position: relative; + display: inline-block; + width: 40px; + height: 24px; +} + +.toggle-wrapper .toggle-switch { + position: absolute; + top: 0; + left: 0; + width: 40px; + height: 24px; + background-color: #52525b; + border-radius: 34px; + cursor: pointer; + transition: background-color 0.3s; +} + +.toggle-wrapper .toggle-switch::before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + border-radius: 50%; + top: 2px; + left: 2px; + background-color: #fff; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.3); + transition: transform 0.3s; +} + +.toggle-wrapper .toggle-input:checked + .toggle-switch::before { + transform: translateX(16px); +} + +.toggle-wrapper .toggle-input:checked + .toggle-switch { + background-color: #16a34a; +} + +.toggle-wrapper .toggle-input:checked + .toggle-switch::before { + transform: translateX(16px); +} + +/* Footer */ + +.footer { + padding: 10px; + display: flex; + justify-content: center; + align-items: center; + gap: 20px; +} + +.footer a { + color: #a1a1aa; +} diff --git a/src/types/Meta.ts b/src/types/Meta.ts new file mode 100644 index 0000000..031af81 --- /dev/null +++ b/src/types/Meta.ts @@ -0,0 +1,48 @@ +import type { Setting } from "./Setting.ts"; + +/** + * Metadata information for a patch. + */ +export interface Meta { + /** + * The name of the patch. + */ + name: string; + /** + * The unique identifier of the patch. + */ + id: string; + /** + * A brief description of what the patch does. + */ + description: string; + /** + * The URL pattern where the patch should be applied. + */ + matches: Array; + /** + * The settings associated with the patch. + */ + settings?: Array; + /** + * The strategy for running the patch. + * Want to run on every DOM change? Use `once` here and `watchElement.ts` from `utils/` in your `init()` function. + * + * @default "onUrlChange" + */ + runStrategy?: "once" | "onUrlChange"; + /** + * The execution timing of the patch. + * + * @default "document_idle" + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#:~:text=only%20mandatory%20key.-,run_at,-String|Check on MDN} + */ + runAt?: "document_start" | "document_end" | "document_idle"; + /** + * The JavaScript execution context for the patch. + * + * @default "ISOLATED" + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#:~:text=The%20JavaScript%20world%20the%20script%20executes%20in.|Check on MDN} + */ + world?: "MAIN" | "ISOLATED"; +} diff --git a/src/types/Patch.ts b/src/types/Patch.ts new file mode 100644 index 0000000..78dcc27 --- /dev/null +++ b/src/types/Patch.ts @@ -0,0 +1,20 @@ +import type { Meta } from "./Meta.ts"; +import type { Setting } from "./Setting.ts"; + +/** + * A patch that can be applied to a webpage. + */ +export interface Patch< + SettingsType = Record | undefined, +> { + /** + * Metadata information for a patch. + */ + meta: Meta; + /** + * The initialization function for the patch. + * + * @param settings The configuration settings for the patch. + */ + init: (settings?: SettingsType) => void | Promise; +} diff --git a/src/types/Setting.ts b/src/types/Setting.ts new file mode 100644 index 0000000..dfb3f7d --- /dev/null +++ b/src/types/Setting.ts @@ -0,0 +1,130 @@ +/** + * The union type for all possible settings. + */ +export type Setting = + | TextSetting + | BooleanSetting + | ColorSetting + | NumberSetting + | SelectSetting + | MultiSelectSetting; + +/** + * The base structure for all settings. + */ +interface BaseSetting { + /** + * The name of the setting. + */ + name: string; + /** + * The unique identifier of the setting. + */ + id: string; + /** + * A brief description of what the setting changes. + */ + description: string; + /** + * The type of the setting. + */ + type: T; +} + +/** + * A text input setting. + */ +interface TextSetting extends BaseSetting<"text"> { + /** + * The default value of the setting. + */ + defaultValue: string; +} + +/** + * A boolean (switch) setting. + */ +interface BooleanSetting extends BaseSetting<"boolean"> { + /** + * The default value of the setting. + */ + defaultValue: boolean; +} + +/** + * A color picker setting. + */ +interface ColorSetting extends BaseSetting<"color"> { + /** + * The default value of the setting. + */ + defaultValue: string; +} + +/** + * A number input setting. + */ +interface NumberSetting extends BaseSetting<"number"> { + /** + * The default value of the setting. + */ + defaultValue: number; + /** + * The minimum value of the setting. + */ + min?: number; + /** + * The maximum value of the setting. + */ + max?: number; + /** + * The step value of the setting. + */ + step?: number; +} + +/** + * A select dropdown setting. + */ +interface SelectSetting extends BaseSetting<"select"> { + /** + * The default value of the setting. + */ + defaultValue: string; + /** + * The options available for selection. + */ + options: Array<{ + /** + * The label displayed to the user. + */ + label: string; + /** + * The value passed to the patch. + */ + value: string; + }>; +} + +/** + * A multi-select (multiple switches) setting. + */ +interface MultiSelectSetting extends BaseSetting<"multiselect"> { + /** + * The default value of the setting. + */ + defaultValue: Array; + /** + * The options available for selection. + */ + options: Array<{ + /** + * The label displayed to the user. + */ + label: string; + /** + * The value passed to the patch. + */ + value: string; + }>; +} diff --git a/src/util/SettingsManager.ts b/src/util/SettingsManager.ts new file mode 100644 index 0000000..c992eaf --- /dev/null +++ b/src/util/SettingsManager.ts @@ -0,0 +1,112 @@ +import type { Meta } from "../types/Meta.ts"; +import type { Setting } from "../types/Setting.ts"; + +interface PatchSettings { + [key: string]: Setting["defaultValue"]; +} + +export class SettingsManager { + /** + * Retrieves the configuration settings for a given patch. + * + * @param patchMeta Metadata defined in patch definition. + * @returns A promise that resolves to the configuration object for the patch. + */ + static async getPatchSettings(patchMeta: Meta): Promise { + const storageKey = `patch_settings_${patchMeta.id}`; + const data = (await chrome.storage.sync.get(storageKey)) as Record< + string, + PatchSettings + >; + const storedData: PatchSettings = data[storageKey] ?? {}; + + const settings: PatchSettings = {}; + + if (patchMeta.settings) { + for (const setting of patchMeta.settings) { + settings[setting.id] = + storedData[setting.id] ?? setting.defaultValue; + } + } + + return settings; + } + + /** + * Saves a new value for a specific setting of a patch. + * + * @param patchId ID of the patch. + * @param settingId ID of the setting. + * @param newValue The new value to be saved. + * @returns A promise that resolves when the setting has been saved. + */ + static async savePatchSetting( + patchId: string, + settingId: string, + newValue: Setting["defaultValue"], + ) { + const storageKey = `patch_settings_${patchId}`; + + const data = (await chrome.storage.sync.get(storageKey)) as Record< + string, + PatchSettings + >; + const existingSettings: PatchSettings = data[storageKey] ?? {}; + + await chrome.storage.sync.set({ + [storageKey]: { ...existingSettings, [settingId]: newValue }, + }); + } + + /** + * Enables a specific patch. + * + * @param patchId ID of the patch to enable. + * @returns A promise that resolves when the patch has been enabled. + */ + static async enablePatch(patchId: string): Promise { + const storageKey = `patch_enabled_${patchId}`; + await chrome.storage.sync.set({ [storageKey]: true }); + } + + /** + * Disables a specific patch. + * + * @param patchId ID of the patch to disable. + * @returns A promise that resolves when the patch has been disabled. + */ + static async disablePatch(patchId: string): Promise { + const storageKey = `patch_enabled_${patchId}`; + await chrome.storage.sync.set({ [storageKey]: false }); + } + + /** + * Checks if a specific patch is currently enabled. + * + * @param patchId ID of the patch to check. + * @returns A promise that resolves to true if the patch is enabled, false otherwise. + */ + static async isPatchEnabled(patchId: string): Promise { + const storageKey = `patch_enabled_${patchId}`; + const result: Record = + await chrome.storage.sync.get(storageKey); + return result[storageKey] ?? true; + } + + /** + * Toggles the enabled state of a specific patch. + * + * @param patchId ID of the patch to toggle. + * @returns A promise that resolves to the new enabled state. + */ + static async togglePatch(patchId: string): Promise { + const isEnabled = await this.isPatchEnabled(patchId); + const newState = !isEnabled; + if (newState) { + await this.enablePatch(patchId); + } else { + await this.disablePatch(patchId); + } + return newState; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..97202bb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "moduleDetection": "force", + "useDefineForClassFields": true, + "baseUrl": ".", + "module": "ESNext", + "moduleResolution": "bundler", + "paths": { + "~/*": ["src/*"] + }, + "types": ["vite/client", "chrome"], + "allowImportingTsExtensions": true, + "alwaysStrict": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noEmit": true, + "isolatedModules": true, + "skipLibCheck": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..a2fdc05 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,23 @@ +import path from "node:path"; +import { crx } from "@crxjs/vite-plugin"; +import { defineConfig } from "vite"; +import zip from "vite-plugin-zip-pack"; +import manifest from "./manifest.config.js"; +import { name, version } from "./package.json"; + +export default defineConfig({ + resolve: { + alias: { + "@": `${path.resolve(__dirname, "src")}`, + }, + }, + plugins: [ + crx({ manifest }), + zip({ outDir: "release", outFileName: `crx-${name}-${version}.zip` }), + ], + server: { + cors: { + origin: [/chrome-extension:\/\//], + }, + }, +});