From e060217ff9fa1b54bb51431bd44ff8db317d5e5d Mon Sep 17 00:00:00 2001 From: Edmundas Ramanauskas Date: Sun, 23 Jun 2024 23:06:46 +0300 Subject: [PATCH] Major refactoring --- .editorconfig | 3 + esbuild.js | 19 +- eslint.config.mjs => eslint.config.js | 1 + package.json | 11 +- pnpm-lock.yaml | 793 +++++++++++++++++++++++++- postcss.config.js | 9 + src/comms/child.ts | 9 +- src/comms/main.ts | 72 ++- src/content/iframe.ts | 52 +- src/content/main.ts | 74 ++- src/content/props.ts | 28 + src/css/index.ts | 1 + src/css/reset.css | 76 --- src/css/tailwind.css | 3 + src/declare.d.ts | 3 + src/devtools.ts | 7 + src/events.ts | 22 + src/libs/components/Toggle.svelte | 10 + src/libs/tabs.ts | 7 +- src/libs/utils.ts | 10 + src/panel/App.svelte | 26 + src/panel/context.ts | 33 ++ src/panel/main.ts | 19 + src/popup/App.svelte | 60 +- src/popup/context.ts | 16 +- src/popup/main.ts | 4 +- src/static/code.png | Bin 0 -> 460 bytes src/static/devpanel.html | 7 + src/static/devtools.html | 7 + src/static/manifest.json | 20 +- src/static/newtab.html | 8 + src/static/options.html | 7 + src/static/popup.html | 6 + src/static/sidepanel.html | 18 + src/store.ts | 100 +++- src/widget/App.svelte | 22 +- src/widget/context.ts | 19 +- src/widget/main.ts | 10 +- src/worker.ts | 88 ++- tailwind.config.js | 7 + tsconfig.json | 11 +- 41 files changed, 1442 insertions(+), 256 deletions(-) rename eslint.config.mjs => eslint.config.js (93%) create mode 100644 postcss.config.js create mode 100644 src/content/props.ts create mode 100644 src/css/index.ts delete mode 100644 src/css/reset.css create mode 100644 src/css/tailwind.css create mode 100644 src/declare.d.ts create mode 100644 src/devtools.ts create mode 100644 src/libs/components/Toggle.svelte create mode 100644 src/panel/App.svelte create mode 100644 src/panel/context.ts create mode 100644 src/panel/main.ts create mode 100644 src/static/code.png create mode 100644 src/static/devpanel.html create mode 100644 src/static/devtools.html create mode 100644 src/static/newtab.html create mode 100644 src/static/options.html create mode 100644 src/static/sidepanel.html create mode 100644 tailwind.config.js diff --git a/.editorconfig b/.editorconfig index d61da10..4d0f595 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,3 +9,6 @@ indent_style = space insert_final_newline = true max_line_length = 120 trim_trailing_whitespace = true + +[**.json] +insert_final_newline = true diff --git a/esbuild.js b/esbuild.js index d69846b..f38ee0d 100644 --- a/esbuild.js +++ b/esbuild.js @@ -2,8 +2,11 @@ import dotenv from 'dotenv'; import { build, context } from 'esbuild'; import clear from 'esbuild-plugin-clear'; import { copy } from 'esbuild-plugin-copy'; +import stylePlugin from 'esbuild-style-plugin'; import sveltePlugin from 'esbuild-svelte'; +import { sveltePreprocess } from 'svelte-preprocess'; import yargs from 'yargs'; +import path from 'node:path'; const { dev } = yargs(process.argv.slice(2)).argv; @@ -11,14 +14,26 @@ dotenv.config(); const options = { bundle: true, - entryPoints: ['src/content/main.ts', 'src/popup/main.ts', 'src/widget/main.ts', 'src/worker.ts'], + entryPoints: [ + 'src/content/main.ts', + 'src/panel/main.ts', + 'src/popup/main.ts', + 'src/widget/main.ts', + 'src/devtools.ts', + 'src/worker.ts', + ], target: ['esnext'], loader: { '.png': 'dataurl', '.svg': 'text', }, plugins: [ - sveltePlugin(), + sveltePlugin({ + preprocess: sveltePreprocess(), + }), + stylePlugin({ + postcssConfigFile: path.resolve('./postcss.config.js'), + }), copy({ assets: [ { diff --git a/eslint.config.mjs b/eslint.config.js similarity index 93% rename from eslint.config.mjs rename to eslint.config.js index 506cf11..a8e265a 100644 --- a/eslint.config.mjs +++ b/eslint.config.js @@ -15,6 +15,7 @@ export default tslint.config( globals: { ...globals.browser, ...globals.node, + chrome: 'readonly', }, }, }, diff --git a/package.json b/package.json index 798c167..e0b4cae 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "start": "node esbuild.js --dev", "build": "node esbuild.js", - "check": "pnpm run check:lint && pnpm run check:svelte && pnpm run check:tsc", + "check": "concurrently \"pnpm:check:*\"", "check:lint": "eslint .", "check:svelte": "svelte-check", "check:tsc": "tsc --noEmit", @@ -20,18 +20,25 @@ "@eslint/js": "^9.5.0", "@types/node": "^20.14.8", "@types/webextension-polyfill": "^0.10.7", + "autoprefixer": "^10.4.19", + "concurrently": "^8.2.2", "dotenv": "^16.4.5", "esbuild": "^0.21.5", "esbuild-plugin-clear": "^1.0.1", "esbuild-plugin-copy": "^2.1.1", + "esbuild-style-plugin": "^1.6.3", "esbuild-svelte": "^0.8.1", "eslint": "^9.5.0", "eslint-plugin-svelte": "^2.40.0", "globals": "^15.6.0", + "postcss": "^8.4.38", + "postcss-import": "^16.1.0", "prettier": "^3.3.2", "prettier-plugin-svelte": "^3.2.5", "svelte": "^4.2.18", "svelte-check": "^3.8.1", + "svelte-preprocess": "^6.0.1", + "tailwindcss": "^3.4.4", "typescript": "^5.5.2", "typescript-eslint": "^7.13.1", "yargs": "^17.7.2" @@ -41,4 +48,4 @@ "loglevel": "^1.9.1", "webextension-polyfill": "^0.12.0" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c94de6..dd729b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,12 @@ importers: '@types/webextension-polyfill': specifier: ^0.10.7 version: 0.10.7 + autoprefixer: + specifier: ^10.4.19 + version: 10.4.19(postcss@8.4.38) + concurrently: + specifier: ^8.2.2 + version: 8.2.2 dotenv: specifier: ^16.4.5 version: 16.4.5 @@ -39,6 +45,9 @@ importers: esbuild-plugin-copy: specifier: ^2.1.1 version: 2.1.1(esbuild@0.21.5) + esbuild-style-plugin: + specifier: ^1.6.3 + version: 1.6.3 esbuild-svelte: specifier: ^0.8.1 version: 0.8.1(esbuild@0.21.5)(svelte@4.2.18) @@ -51,6 +60,12 @@ importers: globals: specifier: ^15.6.0 version: 15.6.0 + postcss: + specifier: ^8.4.38 + version: 8.4.38 + postcss-import: + specifier: ^16.1.0 + version: 16.1.0(postcss@8.4.38) prettier: specifier: ^3.3.2 version: 3.3.2 @@ -62,7 +77,13 @@ importers: version: 4.2.18 svelte-check: specifier: ^3.8.1 - version: 3.8.1(postcss-load-config@3.1.4(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18) + version: 3.8.1(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18) + svelte-preprocess: + specifier: ^6.0.1 + version: 6.0.1(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18)(typescript@5.5.2) + tailwindcss: + specifier: ^3.4.4 + version: 3.4.4 typescript: specifier: ^5.5.2 version: 5.5.2 @@ -75,10 +96,18 @@ importers: packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@babel/runtime@7.24.4': + resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==} + engines: {node: '>=6.9.0'} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -251,6 +280,10 @@ packages: resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -281,15 +314,29 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/less@3.0.6': + resolution: {integrity: sha512-PecSzorDGdabF57OBeQO/xFbAkYWo88g4Xvnsx7LRwqLC17I7OoKtA3bQB9uXkY6UkMWCOsA8HSVpaoitscdXw==} + '@types/node@20.14.8': resolution: {integrity: sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==} '@types/pug@2.0.10': resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} + '@types/sass@1.45.0': + resolution: {integrity: sha512-jn7qwGFmJHwUSphV8zZneO3GmtlgLsmhs/LQyVvQbIIa+fzGMUiHI4HXJZL3FT8MJmgXWbLGiVVY7ElvHq6vDA==} + deprecated: This is a stub types definition. sass provides its own type definitions, so you do not need this installed. + + '@types/stylus@0.48.42': + resolution: {integrity: sha512-CPGlr5teL4sqdap+EOowMifLuNGeIoLwc0VQ7u/BPxo+ocqiNa5jeVt0H0IVBblEh6ZwX1sGpIQIFnSSr8NBQA==} + '@types/webextension-polyfill@0.10.7': resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==} @@ -368,14 +415,28 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -386,6 +447,13 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + autoprefixer@10.4.19: + resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + axobject-query@4.0.0: resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} @@ -410,6 +478,11 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.23.1: + resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} @@ -418,6 +491,13 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001636: + resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -444,9 +524,18 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + concurrently@8.2.2: + resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + engines: {node: ^14.13.0 || >=16.0.0} + hasBin: true + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -460,6 +549,10 @@ packages: engines: {node: '>=4'} hasBin: true + date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + debug@4.3.5: resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} @@ -480,14 +573,26 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.4.810: + resolution: {integrity: sha512-Kaxhu4T7SJGpRQx99tq216gCq2nMxJo+uuT6uzz9l8TVN2stL7M06MIIXAtr9jsrLs2Glflgf2vMQRepxawOdQ==} + emittery@1.0.3: resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} engines: {node: '>=14.16'} @@ -495,6 +600,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -506,6 +614,9 @@ packages: peerDependencies: esbuild: '>= 0.14.0' + esbuild-style-plugin@1.6.3: + resolution: {integrity: sha512-XPEKf4FjLjEVLv/dJH4UxDzXCrFHYpD93DBO8B+izdZARW5b7nNKQbnKv3J+7VDWJbgCU+hzfgIh2AuIZzlmXQ==} + esbuild-svelte@0.8.1: resolution: {integrity: sha512-iswZSetqRxYaQoWMd38Gu6AanIL6KFsVj8/unei7qTaxjAkRDulW62/Bc5nmeogKBWekBvrPOE106wui7gYARQ==} engines: {node: '>=14'} @@ -522,6 +633,10 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -633,6 +748,13 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + foreground-child@3.2.1: + resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} + engines: {node: '>=14'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -645,6 +767,12 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -657,6 +785,11 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.4.2: + resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==} + engines: {node: '>=16 || 14 >=14.18'} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -683,6 +816,16 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -691,6 +834,9 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + immutable@4.3.6: + resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -710,6 +856,10 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-core-module@2.14.0: + resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -736,6 +886,14 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jackspeak@3.4.0: + resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} + engines: {node: '>=14'} + + jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -766,6 +924,17 @@ packages: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} @@ -773,13 +942,23 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loglevel@1.9.1: resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==} engines: {node: '>= 0.6.0'} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} @@ -812,6 +991,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -823,6 +1006,9 @@ packages: ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -831,10 +1017,25 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -850,6 +1051,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -866,6 +1070,13 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -880,6 +1091,32 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-import@16.1.0: + resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==} + engines: {node: '>=18.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -892,6 +1129,53 @@ packages: ts-node: optional: true + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@4.0.5: + resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@3.2.0: + resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules@6.0.0: + resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==} + peerDependencies: + postcss: ^8.0.0 + + postcss-nested@6.0.1: + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + postcss-safe-parser@6.0.0: resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} @@ -908,6 +1192,9 @@ packages: resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} engines: {node: '>=4'} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} @@ -934,10 +1221,16 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -946,6 +1239,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -958,6 +1255,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -965,6 +1265,11 @@ packages: sander@0.5.1: resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} + sass@1.77.6: + resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} + engines: {node: '>=14.0.0'} + hasBin: true + semver@7.6.2: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} @@ -978,6 +1283,13 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -990,14 +1302,28 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + + string-hash@1.1.3: + resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -1006,10 +1332,23 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + svelte-check@3.8.1: resolution: {integrity: sha512-KlQ0TRVe01mdvh49Ylkr9FQxO/UWbQOtaIrccl3gjgkvby1TxY41VkT7ijCl6i29FjaJPE4m6YGmhdqov0MfkA==} hasBin: true @@ -1062,23 +1401,82 @@ packages: typescript: optional: true + svelte-preprocess@6.0.1: + resolution: {integrity: sha512-vNgXoyqWwahdpEX9XbQHcAHt41TkXnf8bRDxT5PjISHbZD1dVH4b2OsJ2fVQTBb3qP05x0GuYE9iS5vhD+Dniw==} + engines: {node: '>= 18.0.0'} + peerDependencies: + '@babel/core': ^7.10.2 + coffeescript: ^2.5.1 + less: ^3.11.3 || ^4.0.0 + postcss: ^7 || ^8 + postcss-load-config: '>=3' + pug: ^3.0.0 + sass: ^1.26.8 + stylus: '>=0.55' + sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 + svelte: ^4.0.0 || ^5.0.0-next.100 || ^5.0.0 + typescript: ^5.0.0 + peerDependenciesMeta: + '@babel/core': + optional: true + coffeescript: + optional: true + less: + optional: true + postcss: + optional: true + postcss-load-config: + optional: true + pug: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + typescript: + optional: true + svelte@4.2.18: resolution: {integrity: sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==} engines: {node: '>=16'} + tailwindcss@3.4.4: + resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==} + engines: {node: '>=14.0.0'} + hasBin: true + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + ts-api-utils@1.3.0: resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1105,6 +1503,12 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1127,6 +1531,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -1138,6 +1546,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.4.5: + resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + engines: {node: '>= 14'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -1152,11 +1565,17 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@babel/runtime@7.24.4': + dependencies: + regenerator-runtime: 0.14.1 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -1263,6 +1682,15 @@ snapshots: '@humanwhocodes/retry@0.3.0': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -1292,14 +1720,27 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + '@pkgjs/parseargs@0.11.0': + optional: true + '@types/estree@1.0.5': {} + '@types/less@3.0.6': {} + '@types/node@20.14.8': dependencies: undici-types: 5.26.5 '@types/pug@2.0.10': {} + '@types/sass@1.45.0': + dependencies: + sass: 1.77.6 + + '@types/stylus@0.48.42': + dependencies: + '@types/node': 20.14.8 + '@types/webextension-polyfill@0.10.7': {} '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.5.2))(eslint@9.5.0)(typescript@5.5.2)': @@ -1398,15 +1839,23 @@ snapshots: ansi-regex@5.0.1: {} + ansi-regex@6.0.1: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@5.0.2: {} + argparse@2.0.1: {} aria-query@5.3.0: @@ -1415,6 +1864,16 @@ snapshots: array-union@2.1.0: {} + autoprefixer@10.4.19(postcss@8.4.38): + dependencies: + browserslist: 4.23.1 + caniuse-lite: 1.0.30001636 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + axobject-query@4.0.0: dependencies: dequal: 2.0.3 @@ -1440,10 +1899,21 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.23.1: + dependencies: + caniuse-lite: 1.0.30001636 + electron-to-chromium: 1.4.810 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.1) + buffer-crc32@1.0.0: {} callsites@3.1.0: {} + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001636: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -1493,8 +1963,22 @@ snapshots: color-name@1.1.4: {} + commander@4.1.1: {} + concat-map@0.0.1: {} + concurrently@8.2.2: + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 @@ -1508,6 +1992,10 @@ snapshots: cssesc@3.0.0: {} + date-fns@2.30.0: + dependencies: + '@babel/runtime': 7.24.4 + debug@4.3.5: dependencies: ms: 2.1.2 @@ -1518,16 +2006,26 @@ snapshots: detect-indent@6.1.0: {} + didyoumean@1.2.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 + dlv@1.1.3: {} + dotenv@16.4.5: {} + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.4.810: {} + emittery@1.0.3: {} emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + es6-promise@3.3.1: {} esbuild-plugin-clear@1.0.1: {} @@ -1540,6 +2038,15 @@ snapshots: fs-extra: 10.1.0 globby: 11.1.0 + esbuild-style-plugin@1.6.3: + dependencies: + '@types/less': 3.0.6 + '@types/sass': 1.45.0 + '@types/stylus': 0.48.42 + glob: 10.4.2 + postcss: 8.4.38 + postcss-modules: 6.0.0(postcss@8.4.38) + esbuild-svelte@0.8.1(esbuild@0.21.5)(svelte@4.2.18): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -1574,6 +2081,8 @@ snapshots: escalade@3.1.1: {} + escalade@3.1.2: {} + escape-string-regexp@4.0.0: {} eslint-compat-utils@0.5.1(eslint@9.5.0): @@ -1731,6 +2240,13 @@ snapshots: flatted@3.3.1: {} + foreground-child@3.2.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + fraction.js@4.3.7: {} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -1742,6 +2258,12 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + generic-names@4.0.0: + dependencies: + loader-utils: 3.3.1 + get-caller-file@2.0.5: {} glob-parent@5.1.2: @@ -1752,6 +2274,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.4.2: + dependencies: + foreground-child: 3.2.1 + jackspeak: 3.4.0 + minimatch: 9.0.4 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -1780,10 +2311,20 @@ snapshots: has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + icss-utils@5.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + ignore@5.2.4: {} ignore@5.3.1: {} + immutable@4.3.6: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -1802,6 +2343,10 @@ snapshots: dependencies: binary-extensions: 2.2.0 + is-core-module@2.14.0: + dependencies: + hasown: 2.0.2 + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -1820,6 +2365,14 @@ snapshots: isexe@2.0.0: {} + jackspeak@3.4.0: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.6: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -1849,16 +2402,28 @@ snapshots: lilconfig@2.1.0: {} + lilconfig@3.1.2: {} + + lines-and-columns@1.2.4: {} + + loader-utils@3.3.1: {} + locate-character@3.0.0: {} locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loglevel@1.9.1: {} + lru-cache@10.2.2: {} + magic-string@0.30.10: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 @@ -1889,6 +2454,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: {} + mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -1897,12 +2464,26 @@ snapshots: ms@2.1.2: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.7: {} natural-compare@1.4.0: {} + node-releases@2.0.14: {} + normalize-path@3.0.0: {} + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -1924,6 +2505,8 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -1934,6 +2517,13 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.2 + minipass: 7.1.2 + path-type@4.0.0: {} periscopic@3.1.0: @@ -1946,6 +2536,29 @@ snapshots: picomatch@2.3.1: {} + pify@2.3.0: {} + + pirates@4.0.6: {} + + postcss-import@15.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-import@16.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.38): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.38 + postcss-load-config@3.1.4(postcss@8.4.38): dependencies: lilconfig: 2.1.0 @@ -1953,6 +2566,51 @@ snapshots: optionalDependencies: postcss: 8.4.38 + postcss-load-config@4.0.2(postcss@8.4.38): + dependencies: + lilconfig: 3.1.2 + yaml: 2.4.5 + optionalDependencies: + postcss: 8.4.38 + + postcss-modules-extract-imports@3.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-modules-local-by-default@4.0.5(postcss@8.4.38): + dependencies: + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@3.2.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 + + postcss-modules-values@4.0.0(postcss@8.4.38): + dependencies: + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + + postcss-modules@6.0.0(postcss@8.4.38): + dependencies: + generic-names: 4.0.0 + icss-utils: 5.1.0(postcss@8.4.38) + lodash.camelcase: 4.3.0 + postcss: 8.4.38 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.5(postcss@8.4.38) + postcss-modules-scope: 3.2.0(postcss@8.4.38) + postcss-modules-values: 4.0.0(postcss@8.4.38) + string-hash: 1.1.3 + + postcss-nested@6.0.1(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 + postcss-safe-parser@6.0.0(postcss@8.4.38): dependencies: postcss: 8.4.38 @@ -1966,6 +2624,8 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} + postcss@8.4.38: dependencies: nanoid: 3.3.7 @@ -1985,14 +2645,26 @@ snapshots: queue-microtask@1.2.3: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 + regenerator-runtime@0.14.1: {} + require-directory@2.1.1: {} resolve-from@4.0.0: {} + resolve@1.22.8: + dependencies: + is-core-module: 2.14.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.0.4: {} rimraf@2.7.1: @@ -2003,6 +2675,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.6.2 + sade@1.8.1: dependencies: mri: 1.2.0 @@ -2014,6 +2690,12 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.7.1 + sass@1.77.6: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.6 + source-map-js: 1.2.0 + semver@7.6.2: {} shebang-command@2.0.0: @@ -2022,6 +2704,10 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.1: {} + + signal-exit@4.1.0: {} + slash@3.0.0: {} sorcery@0.11.1: @@ -2033,27 +2719,57 @@ snapshots: source-map-js@1.2.0: {} + spawn-command@0.0.2: {} + + string-hash@1.1.3: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.0.1 + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 strip-json-comments@3.1.1: {} + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.2 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - svelte-check@3.8.1(postcss-load-config@3.1.4(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18): + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svelte-check@3.8.1(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 3.6.0 @@ -2062,7 +2778,7 @@ snapshots: picocolors: 1.0.1 sade: 1.8.1 svelte: 4.2.18 - svelte-preprocess: 5.1.4(postcss-load-config@3.1.4(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18)(typescript@5.5.2) + svelte-preprocess: 5.1.4(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18)(typescript@5.5.2) typescript: 5.5.2 transitivePeerDependencies: - '@babel/core' @@ -2085,7 +2801,7 @@ snapshots: optionalDependencies: svelte: 4.2.18 - svelte-preprocess@5.1.4(postcss-load-config@3.1.4(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18)(typescript@5.5.2): + svelte-preprocess@5.1.4(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18)(typescript@5.5.2): dependencies: '@types/pug': 2.0.10 detect-indent: 6.1.0 @@ -2095,7 +2811,19 @@ snapshots: svelte: 4.2.18 optionalDependencies: postcss: 8.4.38 - postcss-load-config: 3.1.4(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + sass: 1.77.6 + typescript: 5.5.2 + + svelte-preprocess@6.0.1(postcss-load-config@4.0.2(postcss@8.4.38))(postcss@8.4.38)(sass@1.77.6)(svelte@4.2.18)(typescript@5.5.2): + dependencies: + detect-indent: 6.1.0 + strip-indent: 3.0.0 + svelte: 4.2.18 + optionalDependencies: + postcss: 8.4.38 + postcss-load-config: 4.0.2(postcss@8.4.38) + sass: 1.77.6 typescript: 5.5.2 svelte@4.2.18: @@ -2115,16 +2843,57 @@ snapshots: magic-string: 0.30.10 periscopic: 3.1.0 + tailwindcss@3.4.4: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.7 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.1.0 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + text-table@0.2.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tree-kill@1.2.2: {} + ts-api-utils@1.3.0(typescript@5.5.2): dependencies: typescript: 5.5.2 + ts-interface-checker@0.1.13: {} + + tslib@2.6.2: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -2146,6 +2915,12 @@ snapshots: universalify@2.0.0: {} + update-browserslist-db@1.0.16(browserslist@4.23.1): + dependencies: + browserslist: 4.23.1 + escalade: 3.1.2 + picocolors: 1.0.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -2166,12 +2941,20 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + wrappy@1.0.2: {} y18n@5.0.8: {} yaml@1.10.2: {} + yaml@2.4.5: {} + yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..a1f5ef4 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,9 @@ +import autoprefixer from 'autoprefixer'; +import postcssImport from 'postcss-import'; +import tailwind from 'tailwindcss'; + +import tailwindConfig from './tailwind.config.js'; + +export default { + plugins: [postcssImport, tailwind(tailwindConfig), autoprefixer], +}; diff --git a/src/comms/child.ts b/src/comms/child.ts index 6a7b6d4..92dbb13 100644 --- a/src/comms/child.ts +++ b/src/comms/child.ts @@ -11,12 +11,15 @@ export default class ChildConnection { constructor(private name: string) { this.emitter.on('disconnected', () => { - this.createConnection(); + logger.debug('DISCONNECTED', this.name); + setTimeout(() => { + this.createConnection(); + }); }); this.createConnection(); } - public postMessage(type: string, data: MsgBody) { + public postMessage(type: string, data: MsgBody = {}) { try { this.port?.postMessage({ type, data }); } catch (error) { @@ -36,8 +39,8 @@ export default class ChildConnection { this.emitter.emit('connected'); this.port.onDisconnect.addListener(() => { - logger.debug('DISCONNECTED', this.name); this.emitter.emit('disconnected'); + this.port = undefined; }); this.port.onMessage.addListener((message: Message) => { diff --git a/src/comms/main.ts b/src/comms/main.ts index 698cd76..b127f19 100644 --- a/src/comms/main.ts +++ b/src/comms/main.ts @@ -1,5 +1,4 @@ import EventEmitter from 'emittery'; -import type { Runtime } from 'webextension-polyfill'; import browser from 'webextension-polyfill'; import logger from '../logger'; @@ -7,32 +6,81 @@ import type { Message, MsgBody } from './types'; export default class MainConnection { private emitter = new EventEmitter(); - private port: Runtime.Port | undefined; + private tabs: browser.Tabs.Tab[] = []; constructor(private name: string) { + this.emitter.on('connected', (sender: browser.Runtime.MessageSender) => { + logger.debug('CONNECTED', this.name, sender.tab?.id); + if (sender.tab) { + this.tabs.push(sender.tab); + } + }); + this.emitter.on('disconnected', (sender: browser.Runtime.MessageSender) => { + logger.debug('DISCONNECTED', this.name, sender.tab?.id); + if (sender.tab) { + const i = this.tabs.findIndex(({ id }) => id === sender.tab?.id); + if (i > -1) { + this.tabs.splice(i, 1); + } + } + }); + browser.runtime.onConnect.addListener((port) => { if (this.name !== port.name) return; - logger.debug('CONNECTED', port.name); - this.port = port; - this.port.onMessage.addListener((message: Message) => { + const tabId = port.sender?.tab?.id; + let connected = true; + this.emitter.emit('connected', port.sender); + const outListener = (msg: unknown) => { + if (!connected) return; + port.postMessage(msg); + }; + + this.emitter.on('message_out/*', outListener); + if (tabId) { + this.emitter.on(`message_out/${tabId}`, outListener); + } + port.onMessage.addListener; + + port.onMessage.addListener((message: Message) => { const { type } = message; - this.emitter.emit(`message/${type}`, message); - this.emitter.emit('message/*', message); + this.emitter.emit(`message_in/${type}`, message); + this.emitter.emit('message_in/*', message); }); - this.port.onDisconnect.addListener(() => { - logger.debug('DISCONNECTED', this.name); + port.onDisconnect.addListener(() => { + connected = false; + this.emitter.off('message_out/*', outListener); + if (tabId) { + this.emitter.off(`message_out/${tabId}`, outListener); + } + this.emitter.emit('disconnected', port.sender); }); }); } - public postMessage(type: string, data: MsgBody) { - this.port?.postMessage({ type, data }); + public onConnect(listener: () => void) { + this.emitter.on('connected', listener); + } + + public onDisconnect(listener: () => void) { + this.emitter.on('disconnected', listener); + } + + public postMessage(type: string, data: MsgBody = {}) { + this.emitter.emit('message_out/*', { type, data }); + } + + public postTabMessage(tabId: number, type: string, data: MsgBody = {}) { + this.emitter.emit(`message_out/${tabId}`, { type, data }); } public addListener(listener: (message: Message) => void): void; public addListener(listener: (message: Message) => void, type: string): void; public addListener(listener: (message: Message) => void, type = '*') { - this.emitter.on(`message/${type}`, listener); + this.emitter.on(`message_in/${type}`, listener); + } + + public isTabConnected(tabId: number) { + return this.tabs.some(({ id }) => id === tabId); } } diff --git a/src/content/iframe.ts b/src/content/iframe.ts index a7a2131..de2f217 100644 --- a/src/content/iframe.ts +++ b/src/content/iframe.ts @@ -1,28 +1,26 @@ -export const attributes = { - title: 'Extension', - scrolling: 'no', - frameborder: 'no', - allowtransparency: 'true', -}; +import { assignStyles, setAttributes } from '../libs/dom'; +import { getPath } from '../libs/utils'; +import { attributes, styles } from './props'; -export const styles = { - width: '400px', - height: 'auto', - minHeight: '40px', - maxHeight: 'calc(100vh - 50px)', - display: 'inline-block', - boxSizing: 'border-box', - margin: '0', - padding: '0', - position: 'fixed', - bottom: '30px', - right: '20px', - zIndex: '9999', - background: 'white', - border: 'solid 1px #dddddd', - borderRadius: '6px', - boxShadow: 'rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px', - transition: 'none', - transitionDelay: '0', - transitionDuration: '0', -}; +/** + * content script that is injected directly into other pages. + * it should be as minimal as possible so that it doesn't interfere with the page. + * that's why actual widget is displayed via an iframe. + */ + +export function create(): HTMLIFrameElement { + let iframe = document.getElementById('browser-extension'); + + if (iframe) { + return iframe as HTMLIFrameElement; + } + + const path = getPath('widget.html'); + iframe = document.createElement('iframe'); + setAttributes(iframe, { ...attributes, src: path, id: 'browser-extension' }); + assignStyles(iframe, styles); + + document.body.append(iframe); + + return iframe as HTMLIFrameElement; +} diff --git a/src/content/main.ts b/src/content/main.ts index 6079527..7107ab6 100644 --- a/src/content/main.ts +++ b/src/content/main.ts @@ -1,35 +1,53 @@ -import { assignStyles, setAttributes } from '../libs/dom'; -import { getPath } from '../libs/utils'; -import { attributes, styles } from './iframe'; - -/** - * content script that is injected directly into other pages. - * it should be as minimal as possible so that it doesn't interfere with the page. - * that's why actual widget is displayed via an iframe. - */ +import Connection from '../comms/child'; +import { assignStyles } from '../libs/dom'; +import { create } from './iframe'; start(); -function start() { - if (document.getElementById('browser-extension')) { - return; - } - - const path = getPath('widget.html'); - - const iframe = document.createElement('iframe'); - setAttributes(iframe, { ...attributes, src: path }); - assignStyles(iframe, styles); - - window.addEventListener('message', (event) => { - const { height } = event.data ?? {}; - - if (!height) return; +function getDimensions() { + const vw = Math.max(document.documentElement.clientWidth ?? 0, window.innerWidth ?? 0); + const vh = Math.max(document.documentElement.clientHeight ?? 0, window.innerHeight ?? 0); + return { vh, vw }; +} - assignStyles(iframe, { - height: `${height}px`, - }); +function start() { + const port = new Connection('content'); + let iframe: HTMLIFrameElement | undefined = create(); + + port.addListener(() => { + if (!iframe) { + // already disabled + return; + } + iframe.remove(); + iframe = undefined; + }, 'disable_widget'); + port.addListener(() => { + if (iframe) { + // already enabled + return; + } + iframe = create(); + }, 'enable_widget'); + + window.addEventListener('message', ({ data }) => { + if (!iframe) { + // shouldn't happen + return; + } + + if (data.type === 'init') { + iframe.contentWindow?.postMessage(getDimensions(), '*'); + } + if (data.type === 'height') { + const height = data.value; + assignStyles(iframe, { + height: `${height}px`, + }); + } }); - document.body.append(iframe); + window.onresize = () => { + iframe?.contentWindow?.postMessage(getDimensions(), '*'); + }; } diff --git a/src/content/props.ts b/src/content/props.ts new file mode 100644 index 0000000..22bf44d --- /dev/null +++ b/src/content/props.ts @@ -0,0 +1,28 @@ +export const attributes = { + title: 'Extension', + scrolling: 'no', + frameborder: 'no', + allowtransparency: 'true', +}; + +export const styles = { + width: '200px', + height: 'auto', + minHeight: '20px', + maxHeight: 'calc(100vh - 50px)', + display: 'inline-block', + boxSizing: 'border-box', + margin: '0', + padding: '0', + position: 'fixed', + bottom: '20px', + right: '20px', + zIndex: '9999', + background: 'white', + border: 'solid 1px #dddddd', + borderRadius: '6px', + boxShadow: '0px 0px 10px 5px rgba(0,0,0,0.1)', + transition: 'none', + transitionDelay: '0', + transitionDuration: '0', +}; diff --git a/src/css/index.ts b/src/css/index.ts new file mode 100644 index 0000000..195b052 --- /dev/null +++ b/src/css/index.ts @@ -0,0 +1 @@ +import './tailwind.css'; diff --git a/src/css/reset.css b/src/css/reset.css deleted file mode 100644 index db9a584..0000000 --- a/src/css/reset.css +++ /dev/null @@ -1,76 +0,0 @@ -/* https://andy-bell.co.uk/a-modern-css-reset/ */ - -/* Box sizing rules */ -*, -*::before, -*::after { - box-sizing: border-box; -} - -/* Remove default margin */ -body, -h1, -h2, -h3, -h4, -p, -figure, -blockquote, -dl, -dd { - margin: 0; -} - -/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ -ul[role='list'], -ol[role='list'] { - list-style: none; -} - -/* Set core root defaults */ -html:focus-within { - scroll-behavior: smooth; -} - -/* Set core body defaults */ -body { - min-height: 100vh; - text-rendering: optimizeSpeed; - line-height: 1.5; -} - -/* A elements that don't have a class get default styles */ -a:not([class]) { - text-decoration-skip-ink: auto; -} - -/* Make images easier to work with */ -img, -picture { - max-width: 100%; - display: block; -} - -/* Inherit fonts for inputs and buttons */ -input, -button, -textarea, -select { - font: inherit; -} - -/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */ -@media (prefers-reduced-motion: reduce) { - html:focus-within { - scroll-behavior: auto; - } - - *, - *::before, - *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - scroll-behavior: auto !important; - } -} diff --git a/src/css/tailwind.css b/src/css/tailwind.css new file mode 100644 index 0000000..a31e444 --- /dev/null +++ b/src/css/tailwind.css @@ -0,0 +1,3 @@ +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; diff --git a/src/declare.d.ts b/src/declare.d.ts new file mode 100644 index 0000000..c2fce33 --- /dev/null +++ b/src/declare.d.ts @@ -0,0 +1,3 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +declare const chrome: any; diff --git a/src/devtools.ts b/src/devtools.ts new file mode 100644 index 0000000..849e220 --- /dev/null +++ b/src/devtools.ts @@ -0,0 +1,7 @@ +import browser from 'webextension-polyfill'; + +start(); + +async function start() { + await browser.devtools.panels.create('Extension Panel', 'code.png', 'devpanel.html'); +} diff --git a/src/events.ts b/src/events.ts index 50ca33e..28e0cad 100644 --- a/src/events.ts +++ b/src/events.ts @@ -5,12 +5,16 @@ import browser from 'webextension-polyfill'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type EventData = any; export type EventType = + | 'action_clicked' | 'dom_content_loaded' | 'navigation_committed' + | 'permissions_granted' + | 'permissions_revoked' | 'tab_activated' | 'tab_created' | 'tab_removed' | 'tab_updated'; +export type ActionClickedData = { info: browser.Action.OnClickData | undefined; tab: Tabs.Tab }; export type DomContentLoadedData = WebNavigation.OnDOMContentLoadedDetailsType; export type NavigationCommittedData = WebNavigation.OnCommittedDetailsType; export type TabActivatedData = Tabs.OnActivatedActiveInfoType; @@ -18,8 +22,11 @@ export type TabCreatedData = Tabs.Tab; export type TabRemovedData = { tabId: number; info: Tabs.OnRemovedRemoveInfoType }; export type TabUpdatedData = { tabId: number; info: Tabs.OnUpdatedChangeInfoType; tab: Tabs.Tab }; +export function addEventListener(type: 'action_clicked', listener: (data: ActionClickedData) => void): void; export function addEventListener(type: 'dom_content_loaded', listener: (data: DomContentLoadedData) => void): void; export function addEventListener(type: 'navigation_committed', listener: (data: NavigationCommittedData) => void): void; +export function addEventListener(type: 'permissions_granted', listener: (data: string[]) => void): void; +export function addEventListener(type: 'permissions_revoked', listener: (data: string[]) => void): void; export function addEventListener(type: 'tab_activated', listener: (data: TabActivatedData) => void): void; export function addEventListener(type: 'tab_created', listener: (data: TabCreatedData) => void): void; export function addEventListener(type: 'tab_removed', listener: (data: TabRemovedData) => void): void; @@ -28,8 +35,11 @@ export function addEventListener(type: EventType, listener: (data: EventData) => emitter.on(type, listener); } +export function dispatchEvent(type: 'action_clicked', data: ActionClickedData): void; export function dispatchEvent(type: 'dom_content_loaded', data: DomContentLoadedData): void; export function dispatchEvent(type: 'navigation_committed', data: NavigationCommittedData): void; +export function dispatchEvent(type: 'permissions_granted', data: string[]): void; +export function dispatchEvent(type: 'permissions_revoked', data: string[]): void; export function dispatchEvent(type: 'tab_activated', data: TabActivatedData): void; export function dispatchEvent(type: 'tab_created', data: TabCreatedData): void; export function dispatchEvent(type: 'tab_removed', data: TabRemovedData): void; @@ -73,3 +83,15 @@ browser.tabs.onRemoved.addListener((tabId: number, info: Tabs.OnRemovedRemoveInf browser.tabs.onUpdated.addListener((tabId: number, info: Tabs.OnUpdatedChangeInfoType, tab: Tabs.Tab) => { dispatchEvent('tab_updated', { tabId, info, tab }); }); + +browser.permissions.onAdded.addListener(({ permissions = [] }) => { + dispatchEvent('permissions_granted', permissions); +}); + +browser.permissions.onRemoved.addListener(({ permissions = [] }) => { + dispatchEvent('permissions_revoked', permissions); +}); + +browser.action.onClicked.addListener((tab: Tabs.Tab, info: browser.Action.OnClickData | undefined) => { + dispatchEvent('action_clicked', { info, tab }); +}); diff --git a/src/libs/components/Toggle.svelte b/src/libs/components/Toggle.svelte new file mode 100644 index 0000000..d122586 --- /dev/null +++ b/src/libs/components/Toggle.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/libs/tabs.ts b/src/libs/tabs.ts index 132647a..2ee8b5f 100644 --- a/src/libs/tabs.ts +++ b/src/libs/tabs.ts @@ -5,5 +5,10 @@ export async function getActiveTabs() { } export async function getCurrentTab() { - return browser.tabs.getCurrent(); + const current = await browser.tabs.getCurrent(); + if (current) { + return current; + } + const [active] = await browser.tabs.query({ active: true }); + return active; } diff --git a/src/libs/utils.ts b/src/libs/utils.ts index 493c877..fa92d31 100644 --- a/src/libs/utils.ts +++ b/src/libs/utils.ts @@ -25,3 +25,13 @@ export async function injectStyles(tabId: number, files: ContentStyle[]) { files, }); } + +export async function getPermissions(names: string[]) { + const { permissions = [] } = await browser.permissions.getAll(); + return names.reduce( + (result, name) => { + return { ...result, [name]: permissions.includes(name) }; + }, + {} as Record, + ); +} diff --git a/src/panel/App.svelte b/src/panel/App.svelte new file mode 100644 index 0000000..b38612a --- /dev/null +++ b/src/panel/App.svelte @@ -0,0 +1,26 @@ + + +
+

Side panel

+
+ {#each $urls as { url }} +
+ {url} +
+ {/each} +
+
+ +
+
diff --git a/src/panel/context.ts b/src/panel/context.ts new file mode 100644 index 0000000..615f8b6 --- /dev/null +++ b/src/panel/context.ts @@ -0,0 +1,33 @@ +import { getContext as getCtx } from 'svelte'; +import type { Readable } from 'svelte/store'; +import { readable } from 'svelte/store'; + +import Connection from '../comms/child'; +import type { Store, UrlData } from '../store'; + +/** + * context object for svelte app + */ + +export type Context = { + port: Connection; + urls: Readable; +}; + +export function makeContext(name: string, store: Store) { + const port = new Connection(name); + const urls = readable(store.urls, (set) => { + store.subscribe('urls', (value) => { + set(value); + }); + }); + + const context = new Map(); + context.set('app', { port, urls }); + + return context; +} + +export function getContext() { + return getCtx('app'); +} diff --git a/src/panel/main.ts b/src/panel/main.ts new file mode 100644 index 0000000..adaaa72 --- /dev/null +++ b/src/panel/main.ts @@ -0,0 +1,19 @@ +import '../css'; + +import { Store } from '../store'; +import App from './App.svelte'; +import { makeContext } from './context'; + +start(); + +async function start() { + const store = new Store(); + await store.init(); + const context = makeContext('panel', store); + + new App({ + context, + target: document.body, + props: {}, + }); +} diff --git a/src/popup/App.svelte b/src/popup/App.svelte index 612a44d..8f38e73 100644 --- a/src/popup/App.svelte +++ b/src/popup/App.svelte @@ -1,33 +1,41 @@ -
-
Saved urls:
- {#each urls as { id, url } (id)} -
{url}
- {/each} -
- - +
+

Popover

+
+
+
+
Panel
+ +
+
+
Widget
+ +
+
+
+
diff --git a/src/popup/context.ts b/src/popup/context.ts index 4a5c17c..e346fa6 100644 --- a/src/popup/context.ts +++ b/src/popup/context.ts @@ -1,28 +1,28 @@ import { getContext as getCtx } from 'svelte'; -import { type Readable, readable } from 'svelte/store'; +import { readable, type Readable } from 'svelte/store'; import Connection from '../comms/child'; -import type { UrlData, Store } from '../store'; +import type { Components, Store } from '../store'; /** * context object for svelte app */ export type Context = { + components: Readable; port: Connection; - urls: Readable; }; -export function makeContext(name: string, store: Store) { +export async function makeContext(name: string, store: Store) { const port = new Connection(name); - const urls = readable(store.urls, (set) => { - store.subscribe('urls', (data) => { - set(data); + const components = readable(store.components, (set) => { + store.subscribe('components', (value) => { + set(value); }); }); const context = new Map(); - context.set('app', { port, urls }); + context.set('app', { components, port }); return context; } diff --git a/src/popup/main.ts b/src/popup/main.ts index 1c3cd1f..ace13eb 100644 --- a/src/popup/main.ts +++ b/src/popup/main.ts @@ -1,4 +1,4 @@ -import '../css/reset.css'; +import '../css'; import { Store } from '../store'; import App from './App.svelte'; @@ -9,7 +9,7 @@ start(); async function start() { const store = new Store(); await store.init(); - const context = makeContext('popup', store); + const context = await makeContext('popup', store); new App({ context, diff --git a/src/static/code.png b/src/static/code.png new file mode 100644 index 0000000000000000000000000000000000000000..b5886c921c58198520df8a502dabcb836681d747 GIT binary patch literal 460 zcmV;-0W`X=e`@3`(sQU2S5*)0~zpR z$pZKUE;Z*c4wQK>AfaLe?35AeIh4tHC?ho&8l}J$&^Dy+LrUB;ZOgSyjZk4Ju|dnR z5b|g% + + + + Dev Tools + + diff --git a/src/static/devtools.html b/src/static/devtools.html new file mode 100644 index 0000000..0ff5c32 --- /dev/null +++ b/src/static/devtools.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/static/manifest.json b/src/static/manifest.json index 4cad63e..ff0d35d 100644 --- a/src/static/manifest.json +++ b/src/static/manifest.json @@ -1,10 +1,9 @@ { "manifest_version": 3, "name": "Extension", - "short_name": "Extension", - "version": "0.0.1", + "version": "1.0.0", + "description": "Extension description", "icons": {}, - "description": "Extension", "permissions": [ "activeTab", "alarms", @@ -13,7 +12,8 @@ "storage", "tabs", "unlimitedStorage", - "webNavigation" + "webNavigation", + "sidePanel" ], "host_permissions": ["*://*/*"], "web_accessible_resources": [ @@ -26,8 +26,18 @@ "service_worker": "worker.js" }, "action": { - "default_icon": {}, "default_title": "Extension", "default_popup": "popup.html" + }, + "options_ui": { + "page": "options.html", + "open_in_tab": false + }, + "side_panel": { + "default_path": "sidepanel.html" + }, + "devtools_page": "devtools.html", + "chrome_url_overrides": { + "newtab": "newtab.html" } } diff --git a/src/static/newtab.html b/src/static/newtab.html new file mode 100644 index 0000000..2739c3c --- /dev/null +++ b/src/static/newtab.html @@ -0,0 +1,8 @@ + + + + New Tab + + + + diff --git a/src/static/options.html b/src/static/options.html new file mode 100644 index 0000000..d745841 --- /dev/null +++ b/src/static/options.html @@ -0,0 +1,7 @@ + + + + + Options page + + diff --git a/src/static/popup.html b/src/static/popup.html index 8c37877..2b9e94d 100644 --- a/src/static/popup.html +++ b/src/static/popup.html @@ -3,6 +3,12 @@ Extension + diff --git a/src/static/sidepanel.html b/src/static/sidepanel.html new file mode 100644 index 0000000..d228775 --- /dev/null +++ b/src/static/sidepanel.html @@ -0,0 +1,18 @@ + + + + Extension + + + + + + + + diff --git a/src/store.ts b/src/store.ts index a779a57..77d95eb 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,22 +2,45 @@ import browser from 'webextension-polyfill'; import { uuid } from './libs/uuid'; +export type Component = 'panel' | 'widget'; +export type Components = Partial>; +export type Permissions = Record; export type UrlData = { id: string; url: string; }; export class Store { - private _urls: { id: string; url: string }[] = []; + private _components: Components = {}; + private _permissions: Permissions = {}; + private _urls: UrlData[] = []; constructor(private engine = browser.storage.local) {} + get components() { + return this._components; + } + + get permissions() { + return this._permissions; + } + get urls() { return this._urls; } - public async init() { - this._urls = await this.getItem<{ id: string; url: string }[]>('urls', this._urls); + public async init(reset = false) { + const [components, permissions, urls] = await Promise.all([ + this.getItem('components', this._components), + this.getItem('permissions', this._permissions), + this.getItem('urls', this._urls), + ]); + this._components = components; + this._permissions = permissions; + this._urls = urls; + if (reset) { + await this.reset(); + } } public async addUrl(url: string) { @@ -25,14 +48,79 @@ export class Store { await this.persistUrls(); } - public subscribe(key: 'urls', callback: (value: T) => void) { - this.engine.onChanged.addListener((changes) => { + public async enableComponent(name: Component) { + this._components[name] = true; + await this.persistComponents(); + } + + public async disableComponent(name: Component) { + this._components[name] = false; + await this.persistComponents(); + } + + public async toggleComponent(name: Component) { + this._components[name] = !this._components[name]; + await this.persistComponents(); + } + + public isComponentEnabled(name: Component) { + return this._components[name]; + } + + public isComponentDisabled(name: Component) { + return !this._components[name]; + } + + public async setPermissions(permissions: Permissions) { + this._permissions = permissions; + await this.persistPermissions(); + } + + public async updatePermission(name: string, granted: boolean) { + this._permissions[name] = granted; + await this.persistPermissions(); + } + + public async grantPermissions(names: string[]) { + for (const name of names) { + this._permissions[name] = true; + } + await this.persistPermissions(); + } + + public async revokePermissions(names: string[]) { + for (const name of names) { + this._permissions[name] = false; + } + await this.persistPermissions(); + } + + public subscribe( + key: 'components' | 'permissions' | 'urls', + callback: (newValue: T, oldValue: T) => void, + ) { + this.engine.onChanged.addListener((changes: browser.Storage.StorageAreaOnChangedChangesType) => { if (key in changes) { - callback(changes[key].newValue); + const { newValue, oldValue } = changes[key]; + callback(newValue, oldValue); } }); } + private async reset() { + const { widget } = this._components; + this._components = { widget }; + await this.persistComponents(); + } + + private async persistComponents() { + await this.engine.set({ components: this._components }); + } + + private async persistPermissions() { + await this.engine.set({ permissions: this._permissions }); + } + private async persistUrls() { await this.engine.set({ urls: this._urls }); } diff --git a/src/widget/App.svelte b/src/widget/App.svelte index 2704799..6564dba 100644 --- a/src/widget/App.svelte +++ b/src/widget/App.svelte @@ -1,24 +1,10 @@ -
-

Current url: {url}

- -
- - +
{vw} ✗ {vh}
diff --git a/src/widget/context.ts b/src/widget/context.ts index aa21a4c..77ccebc 100644 --- a/src/widget/context.ts +++ b/src/widget/context.ts @@ -1,8 +1,7 @@ import { getContext as getCtx } from 'svelte'; -import { type Readable, readable } from 'svelte/store'; -import type { Tabs } from 'webextension-polyfill'; import Connection from '../comms/child'; +import { writable, type Writable } from 'svelte/store'; /** * context object for svelte app @@ -10,16 +9,22 @@ import Connection from '../comms/child'; export type Context = { port: Connection; - url: Readable; + size: Writable<{ + vh: number; + vw: number; + }>; }; -export function makeContext(name: string, tab: Tabs.Tab) { +export function makeContext(name: string) { const port = new Connection(name); - - const url = readable(tab.url); + const size = writable({ vh: 0, vw: 0 }); const context = new Map(); - context.set('app', { port, url }); + context.set('app', { port, size }); + + window.addEventListener('message', (event) => { + size.set(event.data); + }); return context; } diff --git a/src/widget/main.ts b/src/widget/main.ts index 7734d75..47f8ff1 100644 --- a/src/widget/main.ts +++ b/src/widget/main.ts @@ -1,15 +1,13 @@ -import '../css/reset.css'; +import '../css'; import heightObserver from '../libs/height'; -import { getCurrentTab } from '../libs/tabs'; import App from './App.svelte'; import { makeContext } from './context'; start(); async function start() { - const tab = await getCurrentTab(); - const context = makeContext('widget', tab); + const context = makeContext('widget'); const container = document.createElement('div'); document.body.append(container); @@ -19,8 +17,10 @@ async function start() { props: {}, }); + window.parent.postMessage({ type: 'init' }, '*'); + const observer = heightObserver((height) => { - window.parent.postMessage({ height }, '*'); + window.parent.postMessage({ type: 'height', value: height }, '*'); }); observer.observe(container); } diff --git a/src/worker.ts b/src/worker.ts index da6f60a..aa081a8 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -2,38 +2,84 @@ import browser from 'webextension-polyfill'; import Connection from './comms/main'; import { addEventListener, type DomContentLoadedData } from './events'; -import { injectScript } from './libs/utils'; +import { getActiveTabs, getCurrentTab } from './libs/tabs'; +import { getPermissions, injectScript } from './libs/utils'; import logger from './logger'; -import { Store } from './store'; +import { type Components, Store } from './store'; start(); async function start() { const store = new Store(); - await store.init(); + await store.init(true); - // listen for messages from popup + const permissions = await getPermissions(['history']); + store.setPermissions(permissions); + + const content = new Connection('content'); + const panel = new Connection('panel'); const popup = new Connection('popup'); - // log all incoming messages - popup.addListener((message) => { - logger.debug('POPUP_MESSAGE', message); - }); + // const widget = new Connection('widget'); - // listen for messages from widget - const widget = new Connection('widget'); - // log all incoming messages - widget.addListener((message) => { - logger.debug('WIDGET_MESSAGE', message); + // listen for messages from panel + panel.onConnect(() => { + store.enableComponent('panel'); }); + panel.onDisconnect(() => { + store.disableComponent('panel'); + }); + panel.addListener(async () => { + const tab = await getCurrentTab(); + if (!tab?.url?.startsWith('http')) { + // only allow storing public urls + return; + } + if (store.urls.some(({ url }) => url === tab.url)) { + // already stored + return; + } + await store.addUrl(tab.url); + }, 'persist_url'); - // listen for store_url messages - widget.addListener(async ({ data }) => { - await store.addUrl(data); - }, 'store_url'); + // listen for messages from popup + popup.addListener(async ({ data }) => { + await browser.permissions.request({ permissions: [data.name] }); + }, 'request_permission'); + popup.addListener(({ data }) => { + if (data.name === 'panel') { + panel.postMessage('close_window'); + } + }, 'disable_component'); + popup.addListener(({ data }) => { + if (data.name === 'widget') { + store.toggleComponent('widget'); + } + }, 'toggle_component'); + + // listed for messages in store + store.subscribe('components', async (newComponents, oldComponents) => { + if (!oldComponents.widget && newComponents.widget) { + const tabs = await getActiveTabs(); + await Promise.all( + tabs + .filter(({ status, url }) => status === 'complete' && url?.startsWith('http')) + .map(async ({ id }) => { + if (content.isTabConnected(id!)) { + content.postTabMessage(id!, 'enable_widget'); + } else { + await injectScript(id!, 'content/main.js'); + } + }), + ); + } else if (oldComponents.widget && !newComponents.widget) { + content.postMessage('disable_widget'); + } + }); // inject content script into third party pages addEventListener('dom_content_loaded', async ({ frameId, tabId, url }: DomContentLoadedData) => { if (frameId !== 0) return; + if (store.isComponentDisabled('widget')) return; const frame = await browser.webNavigation.getFrame({ frameId, @@ -45,4 +91,12 @@ async function start() { await injectScript(tabId, 'content/main.js'); logger.debug('CONTENT_SCRIPT_INJECTED', tabId, url); }); + + addEventListener('permissions_granted', async (names) => { + await store.grantPermissions(names); + }); + + addEventListener('permissions_revoked', async (names) => { + await store.revokePermissions(names); + }); } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..ea604f6 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,7 @@ +export default { + content: ['./src/**/*.{html,js,svelte,ts}', '../../libs/ui/src/**/*.{js,svelte,ts}'], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/tsconfig.json b/tsconfig.json index 09d41fe..8c9df67 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "importsNotUsedAsValues": "error", "isolatedModules": true, "moduleResolution": "node", "noEmit": true, @@ -13,10 +12,10 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "target": "esnext", - "module": "esnext", - "preserveValueImports": true, - "ignoreDeprecations": "5.0" + "target": "ESNext", + "module": "ESNext", + "ignoreDeprecations": "5.0", + "verbatimModuleSyntax": true }, "include": ["src/**/*"], "exclude": ["node_modules/*", "dist/*"]