feat(gui): add complete svelte 5 gui with tailwind css and vite build system
- commit
- 22d75d9e604885a29b61e0aaa7c68392cffe836a
- author
- bamen · · 2025-09-15 05:21 UTC
- parent
- 79f9593
- signature
- unsigned
45 files · +9603 -0
A gui/bindings/database/sql/index.ts +8 -0
| @@ -0,0 +1,8 @@ | |||
| 1 | + | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | |
| 2 | + | // This file is automatically generated. DO NOT EDIT | |
| 3 | + | ||
| 4 | + | export { | |
| 5 | + | NullInt64, | |
| 6 | + | NullString, | |
| 7 | + | NullTime | |
| 8 | + | } from "./models.js"; | |
A gui/bindings/time/index.ts +10 -0
| @@ -0,0 +1,10 @@ | |||
| 1 | + | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | |
| 2 | + | // This file is automatically generated. DO NOT EDIT | |
| 3 | + | ||
| 4 | + | export { | |
| 5 | + | Duration | |
| 6 | + | } from "./models.js"; | |
| 7 | + | ||
| 8 | + | export type { | |
| 9 | + | Time | |
| 10 | + | } from "./models.js"; | |
A gui/eslint.config.js +35 -0
| @@ -0,0 +1,35 @@ | |||
| 1 | + | import js from '@eslint/js'; | |
| 2 | + | import tseslint from 'typescript-eslint'; | |
| 3 | + | ||
| 4 | + | export default tseslint.config( | |
| 5 | + | js.configs.recommended, | |
| 6 | + | ...tseslint.configs.recommended, | |
| 7 | + | { | |
| 8 | + | files: ['**/*.{js,mjs,cjs,ts}'], | |
| 9 | + | languageOptions: { | |
| 10 | + | ecmaVersion: 2024, | |
| 11 | + | sourceType: 'module', | |
| 12 | + | }, | |
| 13 | + | rules: { | |
| 14 | + | // Modern TypeScript best practices | |
| 15 | + | '@typescript-eslint/no-unused-vars': ['error', { | |
| 16 | + | 'argsIgnorePattern': '^_', | |
| 17 | + | 'varsIgnorePattern': '^_' | |
| 18 | + | }], | |
| 19 | + | '@typescript-eslint/no-explicit-any': 'warn', | |
| 20 | + | '@typescript-eslint/no-empty-function': 'off', | |
| 21 | + | '@typescript-eslint/consistent-type-imports': 'error', | |
| 22 | + | '@typescript-eslint/no-import-type-side-effects': 'error', | |
| 23 | + | ||
| 24 | + | // Modern JavaScript/TypeScript patterns | |
| 25 | + | 'prefer-const': 'error', | |
| 26 | + | 'no-var': 'error', | |
| 27 | + | 'object-shorthand': 'error', | |
| 28 | + | 'prefer-template': 'error', | |
| 29 | + | }, | |
| 30 | + | }, | |
| 31 | + | { | |
| 32 | + | files: ['**/*.js', '**/*.mjs'], | |
| 33 | + | ...tseslint.configs.disableTypeChecked, | |
| 34 | + | } | |
| 35 | + | );⏎̸ | |
A gui/package-lock.json +4576 -0
| @@ -0,0 +1,4576 @@ | |||
| 1 | + | { | |
| 2 | + | "name": "@dumber/gui", | |
| 3 | + | "version": "0.1.0", | |
| 4 | + | "lockfileVersion": 3, | |
| 5 | + | "requires": true, | |
| 6 | + | "packages": { | |
| 7 | + | "": { | |
| 8 | + | "name": "@dumber/gui", | |
| 9 | + | "version": "0.1.0", | |
| 10 | + | "devDependencies": { | |
| 11 | + | "@sveltejs/vite-plugin-svelte": "^4.0.0", | |
| 12 | + | "@tailwindcss/cli": "^4.0.0", | |
| 13 | + | "@tailwindcss/postcss": "^4.1.13", | |
| 14 | + | "@types/node": "^20.0.0", | |
| 15 | + | "@typescript-eslint/eslint-plugin": "^7.0.0", | |
| 16 | + | "@typescript-eslint/parser": "^7.0.0", | |
| 17 | + | "autoprefixer": "^10.4.20", | |
| 18 | + | "eslint": "^8.57.0", | |
| 19 | + | "postcss": "^8.4.47", | |
| 20 | + | "svelte": "^5.0.0", | |
| 21 | + | "svelte-check": "^4.0.0", | |
| 22 | + | "tailwindcss": "^4.0.0", | |
| 23 | + | "typescript": "^5.3.0", | |
| 24 | + | "typescript-eslint": "^8.43.0", | |
| 25 | + | "vite": "^5.0.0" | |
| 26 | + | } | |
| 27 | + | }, | |
| 28 | + | "node_modules/@alloc/quick-lru": { | |
| 29 | + | "version": "5.2.0", | |
| 30 | + | "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", | |
| 31 | + | "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", | |
| 32 | + | "dev": true, | |
| 33 | + | "license": "MIT", | |
| 34 | + | "engines": { | |
| 35 | + | "node": ">=10" | |
| 36 | + | }, | |
| 37 | + | "funding": { | |
| 38 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 39 | + | } | |
| 40 | + | }, | |
| 41 | + | "node_modules/@eslint-community/eslint-utils": { | |
| 42 | + | "version": "4.9.0", | |
| 43 | + | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", | |
| 44 | + | "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", | |
| 45 | + | "dev": true, | |
| 46 | + | "license": "MIT", | |
| 47 | + | "dependencies": { | |
| 48 | + | "eslint-visitor-keys": "^3.4.3" | |
| 49 | + | }, | |
| 50 | + | "engines": { | |
| 51 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 52 | + | }, | |
| 53 | + | "funding": { | |
| 54 | + | "url": "https://opencollective.com/eslint" | |
| 55 | + | }, | |
| 56 | + | "peerDependencies": { | |
| 57 | + | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" | |
| 58 | + | } | |
| 59 | + | }, | |
| 60 | + | "node_modules/@eslint-community/regexpp": { | |
| 61 | + | "version": "4.12.1", | |
| 62 | + | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", | |
| 63 | + | "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", | |
| 64 | + | "dev": true, | |
| 65 | + | "license": "MIT", | |
| 66 | + | "engines": { | |
| 67 | + | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" | |
| 68 | + | } | |
| 69 | + | }, | |
| 70 | + | "node_modules/@eslint/eslintrc": { | |
| 71 | + | "version": "2.1.4", | |
| 72 | + | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", | |
| 73 | + | "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", | |
| 74 | + | "dev": true, | |
| 75 | + | "license": "MIT", | |
| 76 | + | "dependencies": { | |
| 77 | + | "ajv": "^6.12.4", | |
| 78 | + | "debug": "^4.3.2", | |
| 79 | + | "espree": "^9.6.0", | |
| 80 | + | "globals": "^13.19.0", | |
| 81 | + | "ignore": "^5.2.0", | |
| 82 | + | "import-fresh": "^3.2.1", | |
| 83 | + | "js-yaml": "^4.1.0", | |
| 84 | + | "minimatch": "^3.1.2", | |
| 85 | + | "strip-json-comments": "^3.1.1" | |
| 86 | + | }, | |
| 87 | + | "engines": { | |
| 88 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 89 | + | }, | |
| 90 | + | "funding": { | |
| 91 | + | "url": "https://opencollective.com/eslint" | |
| 92 | + | } | |
| 93 | + | }, | |
| 94 | + | "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { | |
| 95 | + | "version": "1.1.12", | |
| 96 | + | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", | |
| 97 | + | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", | |
| 98 | + | "dev": true, | |
| 99 | + | "license": "MIT", | |
| 100 | + | "dependencies": { | |
| 101 | + | "balanced-match": "^1.0.0", | |
| 102 | + | "concat-map": "0.0.1" | |
| 103 | + | } | |
| 104 | + | }, | |
| 105 | + | "node_modules/@eslint/eslintrc/node_modules/minimatch": { | |
| 106 | + | "version": "3.1.2", | |
| 107 | + | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| 108 | + | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | |
| 109 | + | "dev": true, | |
| 110 | + | "license": "ISC", | |
| 111 | + | "dependencies": { | |
| 112 | + | "brace-expansion": "^1.1.7" | |
| 113 | + | }, | |
| 114 | + | "engines": { | |
| 115 | + | "node": "*" | |
| 116 | + | } | |
| 117 | + | }, | |
| 118 | + | "node_modules/@eslint/js": { | |
| 119 | + | "version": "8.57.1", | |
| 120 | + | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", | |
| 121 | + | "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", | |
| 122 | + | "dev": true, | |
| 123 | + | "license": "MIT", | |
| 124 | + | "engines": { | |
| 125 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 126 | + | } | |
| 127 | + | }, | |
| 128 | + | "node_modules/@humanwhocodes/config-array": { | |
| 129 | + | "version": "0.13.0", | |
| 130 | + | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", | |
| 131 | + | "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", | |
| 132 | + | "deprecated": "Use @eslint/config-array instead", | |
| 133 | + | "dev": true, | |
| 134 | + | "license": "Apache-2.0", | |
| 135 | + | "dependencies": { | |
| 136 | + | "@humanwhocodes/object-schema": "^2.0.3", | |
| 137 | + | "debug": "^4.3.1", | |
| 138 | + | "minimatch": "^3.0.5" | |
| 139 | + | }, | |
| 140 | + | "engines": { | |
| 141 | + | "node": ">=10.10.0" | |
| 142 | + | } | |
| 143 | + | }, | |
| 144 | + | "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { | |
| 145 | + | "version": "1.1.12", | |
| 146 | + | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", | |
| 147 | + | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", | |
| 148 | + | "dev": true, | |
| 149 | + | "license": "MIT", | |
| 150 | + | "dependencies": { | |
| 151 | + | "balanced-match": "^1.0.0", | |
| 152 | + | "concat-map": "0.0.1" | |
| 153 | + | } | |
| 154 | + | }, | |
| 155 | + | "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { | |
| 156 | + | "version": "3.1.2", | |
| 157 | + | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| 158 | + | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | |
| 159 | + | "dev": true, | |
| 160 | + | "license": "ISC", | |
| 161 | + | "dependencies": { | |
| 162 | + | "brace-expansion": "^1.1.7" | |
| 163 | + | }, | |
| 164 | + | "engines": { | |
| 165 | + | "node": "*" | |
| 166 | + | } | |
| 167 | + | }, | |
| 168 | + | "node_modules/@humanwhocodes/module-importer": { | |
| 169 | + | "version": "1.0.1", | |
| 170 | + | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", | |
| 171 | + | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", | |
| 172 | + | "dev": true, | |
| 173 | + | "license": "Apache-2.0", | |
| 174 | + | "engines": { | |
| 175 | + | "node": ">=12.22" | |
| 176 | + | }, | |
| 177 | + | "funding": { | |
| 178 | + | "type": "github", | |
| 179 | + | "url": "https://github.com/sponsors/nzakas" | |
| 180 | + | } | |
| 181 | + | }, | |
| 182 | + | "node_modules/@humanwhocodes/object-schema": { | |
| 183 | + | "version": "2.0.3", | |
| 184 | + | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", | |
| 185 | + | "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", | |
| 186 | + | "deprecated": "Use @eslint/object-schema instead", | |
| 187 | + | "dev": true, | |
| 188 | + | "license": "BSD-3-Clause" | |
| 189 | + | }, | |
| 190 | + | "node_modules/@isaacs/fs-minipass": { | |
| 191 | + | "version": "4.0.1", | |
| 192 | + | "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", | |
| 193 | + | "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", | |
| 194 | + | "dev": true, | |
| 195 | + | "license": "ISC", | |
| 196 | + | "dependencies": { | |
| 197 | + | "minipass": "^7.0.4" | |
| 198 | + | }, | |
| 199 | + | "engines": { | |
| 200 | + | "node": ">=18.0.0" | |
| 201 | + | } | |
| 202 | + | }, | |
| 203 | + | "node_modules/@jridgewell/gen-mapping": { | |
| 204 | + | "version": "0.3.13", | |
| 205 | + | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", | |
| 206 | + | "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", | |
| 207 | + | "dev": true, | |
| 208 | + | "license": "MIT", | |
| 209 | + | "dependencies": { | |
| 210 | + | "@jridgewell/sourcemap-codec": "^1.5.0", | |
| 211 | + | "@jridgewell/trace-mapping": "^0.3.24" | |
| 212 | + | } | |
| 213 | + | }, | |
| 214 | + | "node_modules/@jridgewell/remapping": { | |
| 215 | + | "version": "2.3.5", | |
| 216 | + | "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", | |
| 217 | + | "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", | |
| 218 | + | "dev": true, | |
| 219 | + | "license": "MIT", | |
| 220 | + | "dependencies": { | |
| 221 | + | "@jridgewell/gen-mapping": "^0.3.5", | |
| 222 | + | "@jridgewell/trace-mapping": "^0.3.24" | |
| 223 | + | } | |
| 224 | + | }, | |
| 225 | + | "node_modules/@jridgewell/resolve-uri": { | |
| 226 | + | "version": "3.1.2", | |
| 227 | + | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", | |
| 228 | + | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", | |
| 229 | + | "dev": true, | |
| 230 | + | "license": "MIT", | |
| 231 | + | "engines": { | |
| 232 | + | "node": ">=6.0.0" | |
| 233 | + | } | |
| 234 | + | }, | |
| 235 | + | "node_modules/@jridgewell/sourcemap-codec": { | |
| 236 | + | "version": "1.5.5", | |
| 237 | + | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", | |
| 238 | + | "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", | |
| 239 | + | "dev": true, | |
| 240 | + | "license": "MIT" | |
| 241 | + | }, | |
| 242 | + | "node_modules/@jridgewell/trace-mapping": { | |
| 243 | + | "version": "0.3.30", | |
| 244 | + | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", | |
| 245 | + | "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", | |
| 246 | + | "dev": true, | |
| 247 | + | "license": "MIT", | |
| 248 | + | "dependencies": { | |
| 249 | + | "@jridgewell/resolve-uri": "^3.1.0", | |
| 250 | + | "@jridgewell/sourcemap-codec": "^1.4.14" | |
| 251 | + | } | |
| 252 | + | }, | |
| 253 | + | "node_modules/@nodelib/fs.scandir": { | |
| 254 | + | "version": "2.1.5", | |
| 255 | + | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | |
| 256 | + | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", | |
| 257 | + | "dev": true, | |
| 258 | + | "license": "MIT", | |
| 259 | + | "dependencies": { | |
| 260 | + | "@nodelib/fs.stat": "2.0.5", | |
| 261 | + | "run-parallel": "^1.1.9" | |
| 262 | + | }, | |
| 263 | + | "engines": { | |
| 264 | + | "node": ">= 8" | |
| 265 | + | } | |
| 266 | + | }, | |
| 267 | + | "node_modules/@nodelib/fs.stat": { | |
| 268 | + | "version": "2.0.5", | |
| 269 | + | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", | |
| 270 | + | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", | |
| 271 | + | "dev": true, | |
| 272 | + | "license": "MIT", | |
| 273 | + | "engines": { | |
| 274 | + | "node": ">= 8" | |
| 275 | + | } | |
| 276 | + | }, | |
| 277 | + | "node_modules/@nodelib/fs.walk": { | |
| 278 | + | "version": "1.2.8", | |
| 279 | + | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", | |
| 280 | + | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", | |
| 281 | + | "dev": true, | |
| 282 | + | "license": "MIT", | |
| 283 | + | "dependencies": { | |
| 284 | + | "@nodelib/fs.scandir": "2.1.5", | |
| 285 | + | "fastq": "^1.6.0" | |
| 286 | + | }, | |
| 287 | + | "engines": { | |
| 288 | + | "node": ">= 8" | |
| 289 | + | } | |
| 290 | + | }, | |
| 291 | + | "node_modules/@parcel/watcher": { | |
| 292 | + | "version": "2.5.1", | |
| 293 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", | |
| 294 | + | "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", | |
| 295 | + | "dev": true, | |
| 296 | + | "hasInstallScript": true, | |
| 297 | + | "license": "MIT", | |
| 298 | + | "dependencies": { | |
| 299 | + | "detect-libc": "^1.0.3", | |
| 300 | + | "is-glob": "^4.0.3", | |
| 301 | + | "micromatch": "^4.0.5", | |
| 302 | + | "node-addon-api": "^7.0.0" | |
| 303 | + | }, | |
| 304 | + | "engines": { | |
| 305 | + | "node": ">= 10.0.0" | |
| 306 | + | }, | |
| 307 | + | "funding": { | |
| 308 | + | "type": "opencollective", | |
| 309 | + | "url": "https://opencollective.com/parcel" | |
| 310 | + | }, | |
| 311 | + | "optionalDependencies": { | |
| 312 | + | "@parcel/watcher-android-arm64": "2.5.1", | |
| 313 | + | "@parcel/watcher-darwin-arm64": "2.5.1", | |
| 314 | + | "@parcel/watcher-darwin-x64": "2.5.1", | |
| 315 | + | "@parcel/watcher-freebsd-x64": "2.5.1", | |
| 316 | + | "@parcel/watcher-linux-arm-glibc": "2.5.1", | |
| 317 | + | "@parcel/watcher-linux-arm-musl": "2.5.1", | |
| 318 | + | "@parcel/watcher-linux-arm64-glibc": "2.5.1", | |
| 319 | + | "@parcel/watcher-linux-arm64-musl": "2.5.1", | |
| 320 | + | "@parcel/watcher-linux-x64-glibc": "2.5.1", | |
| 321 | + | "@parcel/watcher-linux-x64-musl": "2.5.1", | |
| 322 | + | "@parcel/watcher-win32-arm64": "2.5.1", | |
| 323 | + | "@parcel/watcher-win32-ia32": "2.5.1", | |
| 324 | + | "@parcel/watcher-win32-x64": "2.5.1" | |
| 325 | + | } | |
| 326 | + | }, | |
| 327 | + | "node_modules/@parcel/watcher-android-arm64": { | |
| 328 | + | "version": "2.5.1", | |
| 329 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", | |
| 330 | + | "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", | |
| 331 | + | "cpu": [ | |
| 332 | + | "arm64" | |
| 333 | + | ], | |
| 334 | + | "dev": true, | |
| 335 | + | "license": "MIT", | |
| 336 | + | "optional": true, | |
| 337 | + | "os": [ | |
| 338 | + | "android" | |
| 339 | + | ], | |
| 340 | + | "engines": { | |
| 341 | + | "node": ">= 10.0.0" | |
| 342 | + | }, | |
| 343 | + | "funding": { | |
| 344 | + | "type": "opencollective", | |
| 345 | + | "url": "https://opencollective.com/parcel" | |
| 346 | + | } | |
| 347 | + | }, | |
| 348 | + | "node_modules/@parcel/watcher-darwin-arm64": { | |
| 349 | + | "version": "2.5.1", | |
| 350 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", | |
| 351 | + | "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", | |
| 352 | + | "cpu": [ | |
| 353 | + | "arm64" | |
| 354 | + | ], | |
| 355 | + | "dev": true, | |
| 356 | + | "license": "MIT", | |
| 357 | + | "optional": true, | |
| 358 | + | "os": [ | |
| 359 | + | "darwin" | |
| 360 | + | ], | |
| 361 | + | "engines": { | |
| 362 | + | "node": ">= 10.0.0" | |
| 363 | + | }, | |
| 364 | + | "funding": { | |
| 365 | + | "type": "opencollective", | |
| 366 | + | "url": "https://opencollective.com/parcel" | |
| 367 | + | } | |
| 368 | + | }, | |
| 369 | + | "node_modules/@parcel/watcher-darwin-x64": { | |
| 370 | + | "version": "2.5.1", | |
| 371 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", | |
| 372 | + | "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", | |
| 373 | + | "cpu": [ | |
| 374 | + | "x64" | |
| 375 | + | ], | |
| 376 | + | "dev": true, | |
| 377 | + | "license": "MIT", | |
| 378 | + | "optional": true, | |
| 379 | + | "os": [ | |
| 380 | + | "darwin" | |
| 381 | + | ], | |
| 382 | + | "engines": { | |
| 383 | + | "node": ">= 10.0.0" | |
| 384 | + | }, | |
| 385 | + | "funding": { | |
| 386 | + | "type": "opencollective", | |
| 387 | + | "url": "https://opencollective.com/parcel" | |
| 388 | + | } | |
| 389 | + | }, | |
| 390 | + | "node_modules/@parcel/watcher-freebsd-x64": { | |
| 391 | + | "version": "2.5.1", | |
| 392 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", | |
| 393 | + | "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", | |
| 394 | + | "cpu": [ | |
| 395 | + | "x64" | |
| 396 | + | ], | |
| 397 | + | "dev": true, | |
| 398 | + | "license": "MIT", | |
| 399 | + | "optional": true, | |
| 400 | + | "os": [ | |
| 401 | + | "freebsd" | |
| 402 | + | ], | |
| 403 | + | "engines": { | |
| 404 | + | "node": ">= 10.0.0" | |
| 405 | + | }, | |
| 406 | + | "funding": { | |
| 407 | + | "type": "opencollective", | |
| 408 | + | "url": "https://opencollective.com/parcel" | |
| 409 | + | } | |
| 410 | + | }, | |
| 411 | + | "node_modules/@parcel/watcher-linux-arm-glibc": { | |
| 412 | + | "version": "2.5.1", | |
| 413 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", | |
| 414 | + | "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", | |
| 415 | + | "cpu": [ | |
| 416 | + | "arm" | |
| 417 | + | ], | |
| 418 | + | "dev": true, | |
| 419 | + | "license": "MIT", | |
| 420 | + | "optional": true, | |
| 421 | + | "os": [ | |
| 422 | + | "linux" | |
| 423 | + | ], | |
| 424 | + | "engines": { | |
| 425 | + | "node": ">= 10.0.0" | |
| 426 | + | }, | |
| 427 | + | "funding": { | |
| 428 | + | "type": "opencollective", | |
| 429 | + | "url": "https://opencollective.com/parcel" | |
| 430 | + | } | |
| 431 | + | }, | |
| 432 | + | "node_modules/@parcel/watcher-linux-arm-musl": { | |
| 433 | + | "version": "2.5.1", | |
| 434 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", | |
| 435 | + | "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", | |
| 436 | + | "cpu": [ | |
| 437 | + | "arm" | |
| 438 | + | ], | |
| 439 | + | "dev": true, | |
| 440 | + | "license": "MIT", | |
| 441 | + | "optional": true, | |
| 442 | + | "os": [ | |
| 443 | + | "linux" | |
| 444 | + | ], | |
| 445 | + | "engines": { | |
| 446 | + | "node": ">= 10.0.0" | |
| 447 | + | }, | |
| 448 | + | "funding": { | |
| 449 | + | "type": "opencollective", | |
| 450 | + | "url": "https://opencollective.com/parcel" | |
| 451 | + | } | |
| 452 | + | }, | |
| 453 | + | "node_modules/@parcel/watcher-linux-arm64-glibc": { | |
| 454 | + | "version": "2.5.1", | |
| 455 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", | |
| 456 | + | "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", | |
| 457 | + | "cpu": [ | |
| 458 | + | "arm64" | |
| 459 | + | ], | |
| 460 | + | "dev": true, | |
| 461 | + | "license": "MIT", | |
| 462 | + | "optional": true, | |
| 463 | + | "os": [ | |
| 464 | + | "linux" | |
| 465 | + | ], | |
| 466 | + | "engines": { | |
| 467 | + | "node": ">= 10.0.0" | |
| 468 | + | }, | |
| 469 | + | "funding": { | |
| 470 | + | "type": "opencollective", | |
| 471 | + | "url": "https://opencollective.com/parcel" | |
| 472 | + | } | |
| 473 | + | }, | |
| 474 | + | "node_modules/@parcel/watcher-linux-arm64-musl": { | |
| 475 | + | "version": "2.5.1", | |
| 476 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", | |
| 477 | + | "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", | |
| 478 | + | "cpu": [ | |
| 479 | + | "arm64" | |
| 480 | + | ], | |
| 481 | + | "dev": true, | |
| 482 | + | "license": "MIT", | |
| 483 | + | "optional": true, | |
| 484 | + | "os": [ | |
| 485 | + | "linux" | |
| 486 | + | ], | |
| 487 | + | "engines": { | |
| 488 | + | "node": ">= 10.0.0" | |
| 489 | + | }, | |
| 490 | + | "funding": { | |
| 491 | + | "type": "opencollective", | |
| 492 | + | "url": "https://opencollective.com/parcel" | |
| 493 | + | } | |
| 494 | + | }, | |
| 495 | + | "node_modules/@parcel/watcher-linux-x64-glibc": { | |
| 496 | + | "version": "2.5.1", | |
| 497 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", | |
| 498 | + | "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", | |
| 499 | + | "cpu": [ | |
| 500 | + | "x64" | |
| 501 | + | ], | |
| 502 | + | "dev": true, | |
| 503 | + | "license": "MIT", | |
| 504 | + | "optional": true, | |
| 505 | + | "os": [ | |
| 506 | + | "linux" | |
| 507 | + | ], | |
| 508 | + | "engines": { | |
| 509 | + | "node": ">= 10.0.0" | |
| 510 | + | }, | |
| 511 | + | "funding": { | |
| 512 | + | "type": "opencollective", | |
| 513 | + | "url": "https://opencollective.com/parcel" | |
| 514 | + | } | |
| 515 | + | }, | |
| 516 | + | "node_modules/@parcel/watcher-linux-x64-musl": { | |
| 517 | + | "version": "2.5.1", | |
| 518 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", | |
| 519 | + | "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", | |
| 520 | + | "cpu": [ | |
| 521 | + | "x64" | |
| 522 | + | ], | |
| 523 | + | "dev": true, | |
| 524 | + | "license": "MIT", | |
| 525 | + | "optional": true, | |
| 526 | + | "os": [ | |
| 527 | + | "linux" | |
| 528 | + | ], | |
| 529 | + | "engines": { | |
| 530 | + | "node": ">= 10.0.0" | |
| 531 | + | }, | |
| 532 | + | "funding": { | |
| 533 | + | "type": "opencollective", | |
| 534 | + | "url": "https://opencollective.com/parcel" | |
| 535 | + | } | |
| 536 | + | }, | |
| 537 | + | "node_modules/@parcel/watcher-win32-arm64": { | |
| 538 | + | "version": "2.5.1", | |
| 539 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", | |
| 540 | + | "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", | |
| 541 | + | "cpu": [ | |
| 542 | + | "arm64" | |
| 543 | + | ], | |
| 544 | + | "dev": true, | |
| 545 | + | "license": "MIT", | |
| 546 | + | "optional": true, | |
| 547 | + | "os": [ | |
| 548 | + | "win32" | |
| 549 | + | ], | |
| 550 | + | "engines": { | |
| 551 | + | "node": ">= 10.0.0" | |
| 552 | + | }, | |
| 553 | + | "funding": { | |
| 554 | + | "type": "opencollective", | |
| 555 | + | "url": "https://opencollective.com/parcel" | |
| 556 | + | } | |
| 557 | + | }, | |
| 558 | + | "node_modules/@parcel/watcher-win32-ia32": { | |
| 559 | + | "version": "2.5.1", | |
| 560 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", | |
| 561 | + | "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", | |
| 562 | + | "cpu": [ | |
| 563 | + | "ia32" | |
| 564 | + | ], | |
| 565 | + | "dev": true, | |
| 566 | + | "license": "MIT", | |
| 567 | + | "optional": true, | |
| 568 | + | "os": [ | |
| 569 | + | "win32" | |
| 570 | + | ], | |
| 571 | + | "engines": { | |
| 572 | + | "node": ">= 10.0.0" | |
| 573 | + | }, | |
| 574 | + | "funding": { | |
| 575 | + | "type": "opencollective", | |
| 576 | + | "url": "https://opencollective.com/parcel" | |
| 577 | + | } | |
| 578 | + | }, | |
| 579 | + | "node_modules/@parcel/watcher-win32-x64": { | |
| 580 | + | "version": "2.5.1", | |
| 581 | + | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", | |
| 582 | + | "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", | |
| 583 | + | "cpu": [ | |
| 584 | + | "x64" | |
| 585 | + | ], | |
| 586 | + | "dev": true, | |
| 587 | + | "license": "MIT", | |
| 588 | + | "optional": true, | |
| 589 | + | "os": [ | |
| 590 | + | "win32" | |
| 591 | + | ], | |
| 592 | + | "engines": { | |
| 593 | + | "node": ">= 10.0.0" | |
| 594 | + | }, | |
| 595 | + | "funding": { | |
| 596 | + | "type": "opencollective", | |
| 597 | + | "url": "https://opencollective.com/parcel" | |
| 598 | + | } | |
| 599 | + | }, | |
| 600 | + | "node_modules/@rollup/rollup-android-arm-eabi": { | |
| 601 | + | "version": "4.50.1", | |
| 602 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", | |
| 603 | + | "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", | |
| 604 | + | "cpu": [ | |
| 605 | + | "arm" | |
| 606 | + | ], | |
| 607 | + | "dev": true, | |
| 608 | + | "license": "MIT", | |
| 609 | + | "optional": true, | |
| 610 | + | "os": [ | |
| 611 | + | "android" | |
| 612 | + | ] | |
| 613 | + | }, | |
| 614 | + | "node_modules/@rollup/rollup-android-arm64": { | |
| 615 | + | "version": "4.50.1", | |
| 616 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", | |
| 617 | + | "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", | |
| 618 | + | "cpu": [ | |
| 619 | + | "arm64" | |
| 620 | + | ], | |
| 621 | + | "dev": true, | |
| 622 | + | "license": "MIT", | |
| 623 | + | "optional": true, | |
| 624 | + | "os": [ | |
| 625 | + | "android" | |
| 626 | + | ] | |
| 627 | + | }, | |
| 628 | + | "node_modules/@rollup/rollup-darwin-arm64": { | |
| 629 | + | "version": "4.50.1", | |
| 630 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", | |
| 631 | + | "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", | |
| 632 | + | "cpu": [ | |
| 633 | + | "arm64" | |
| 634 | + | ], | |
| 635 | + | "dev": true, | |
| 636 | + | "license": "MIT", | |
| 637 | + | "optional": true, | |
| 638 | + | "os": [ | |
| 639 | + | "darwin" | |
| 640 | + | ] | |
| 641 | + | }, | |
| 642 | + | "node_modules/@rollup/rollup-darwin-x64": { | |
| 643 | + | "version": "4.50.1", | |
| 644 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", | |
| 645 | + | "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", | |
| 646 | + | "cpu": [ | |
| 647 | + | "x64" | |
| 648 | + | ], | |
| 649 | + | "dev": true, | |
| 650 | + | "license": "MIT", | |
| 651 | + | "optional": true, | |
| 652 | + | "os": [ | |
| 653 | + | "darwin" | |
| 654 | + | ] | |
| 655 | + | }, | |
| 656 | + | "node_modules/@rollup/rollup-freebsd-arm64": { | |
| 657 | + | "version": "4.50.1", | |
| 658 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", | |
| 659 | + | "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", | |
| 660 | + | "cpu": [ | |
| 661 | + | "arm64" | |
| 662 | + | ], | |
| 663 | + | "dev": true, | |
| 664 | + | "license": "MIT", | |
| 665 | + | "optional": true, | |
| 666 | + | "os": [ | |
| 667 | + | "freebsd" | |
| 668 | + | ] | |
| 669 | + | }, | |
| 670 | + | "node_modules/@rollup/rollup-freebsd-x64": { | |
| 671 | + | "version": "4.50.1", | |
| 672 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", | |
| 673 | + | "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", | |
| 674 | + | "cpu": [ | |
| 675 | + | "x64" | |
| 676 | + | ], | |
| 677 | + | "dev": true, | |
| 678 | + | "license": "MIT", | |
| 679 | + | "optional": true, | |
| 680 | + | "os": [ | |
| 681 | + | "freebsd" | |
| 682 | + | ] | |
| 683 | + | }, | |
| 684 | + | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { | |
| 685 | + | "version": "4.50.1", | |
| 686 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", | |
| 687 | + | "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", | |
| 688 | + | "cpu": [ | |
| 689 | + | "arm" | |
| 690 | + | ], | |
| 691 | + | "dev": true, | |
| 692 | + | "license": "MIT", | |
| 693 | + | "optional": true, | |
| 694 | + | "os": [ | |
| 695 | + | "linux" | |
| 696 | + | ] | |
| 697 | + | }, | |
| 698 | + | "node_modules/@rollup/rollup-linux-arm-musleabihf": { | |
| 699 | + | "version": "4.50.1", | |
| 700 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", | |
| 701 | + | "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", | |
| 702 | + | "cpu": [ | |
| 703 | + | "arm" | |
| 704 | + | ], | |
| 705 | + | "dev": true, | |
| 706 | + | "license": "MIT", | |
| 707 | + | "optional": true, | |
| 708 | + | "os": [ | |
| 709 | + | "linux" | |
| 710 | + | ] | |
| 711 | + | }, | |
| 712 | + | "node_modules/@rollup/rollup-linux-arm64-gnu": { | |
| 713 | + | "version": "4.50.1", | |
| 714 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", | |
| 715 | + | "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", | |
| 716 | + | "cpu": [ | |
| 717 | + | "arm64" | |
| 718 | + | ], | |
| 719 | + | "dev": true, | |
| 720 | + | "license": "MIT", | |
| 721 | + | "optional": true, | |
| 722 | + | "os": [ | |
| 723 | + | "linux" | |
| 724 | + | ] | |
| 725 | + | }, | |
| 726 | + | "node_modules/@rollup/rollup-linux-arm64-musl": { | |
| 727 | + | "version": "4.50.1", | |
| 728 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", | |
| 729 | + | "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", | |
| 730 | + | "cpu": [ | |
| 731 | + | "arm64" | |
| 732 | + | ], | |
| 733 | + | "dev": true, | |
| 734 | + | "license": "MIT", | |
| 735 | + | "optional": true, | |
| 736 | + | "os": [ | |
| 737 | + | "linux" | |
| 738 | + | ] | |
| 739 | + | }, | |
| 740 | + | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { | |
| 741 | + | "version": "4.50.1", | |
| 742 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", | |
| 743 | + | "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", | |
| 744 | + | "cpu": [ | |
| 745 | + | "loong64" | |
| 746 | + | ], | |
| 747 | + | "dev": true, | |
| 748 | + | "license": "MIT", | |
| 749 | + | "optional": true, | |
| 750 | + | "os": [ | |
| 751 | + | "linux" | |
| 752 | + | ] | |
| 753 | + | }, | |
| 754 | + | "node_modules/@rollup/rollup-linux-ppc64-gnu": { | |
| 755 | + | "version": "4.50.1", | |
| 756 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", | |
| 757 | + | "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", | |
| 758 | + | "cpu": [ | |
| 759 | + | "ppc64" | |
| 760 | + | ], | |
| 761 | + | "dev": true, | |
| 762 | + | "license": "MIT", | |
| 763 | + | "optional": true, | |
| 764 | + | "os": [ | |
| 765 | + | "linux" | |
| 766 | + | ] | |
| 767 | + | }, | |
| 768 | + | "node_modules/@rollup/rollup-linux-riscv64-gnu": { | |
| 769 | + | "version": "4.50.1", | |
| 770 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", | |
| 771 | + | "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", | |
| 772 | + | "cpu": [ | |
| 773 | + | "riscv64" | |
| 774 | + | ], | |
| 775 | + | "dev": true, | |
| 776 | + | "license": "MIT", | |
| 777 | + | "optional": true, | |
| 778 | + | "os": [ | |
| 779 | + | "linux" | |
| 780 | + | ] | |
| 781 | + | }, | |
| 782 | + | "node_modules/@rollup/rollup-linux-riscv64-musl": { | |
| 783 | + | "version": "4.50.1", | |
| 784 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", | |
| 785 | + | "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", | |
| 786 | + | "cpu": [ | |
| 787 | + | "riscv64" | |
| 788 | + | ], | |
| 789 | + | "dev": true, | |
| 790 | + | "license": "MIT", | |
| 791 | + | "optional": true, | |
| 792 | + | "os": [ | |
| 793 | + | "linux" | |
| 794 | + | ] | |
| 795 | + | }, | |
| 796 | + | "node_modules/@rollup/rollup-linux-s390x-gnu": { | |
| 797 | + | "version": "4.50.1", | |
| 798 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", | |
| 799 | + | "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", | |
| 800 | + | "cpu": [ | |
| 801 | + | "s390x" | |
| 802 | + | ], | |
| 803 | + | "dev": true, | |
| 804 | + | "license": "MIT", | |
| 805 | + | "optional": true, | |
| 806 | + | "os": [ | |
| 807 | + | "linux" | |
| 808 | + | ] | |
| 809 | + | }, | |
| 810 | + | "node_modules/@rollup/rollup-linux-x64-gnu": { | |
| 811 | + | "version": "4.50.1", | |
| 812 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", | |
| 813 | + | "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", | |
| 814 | + | "cpu": [ | |
| 815 | + | "x64" | |
| 816 | + | ], | |
| 817 | + | "dev": true, | |
| 818 | + | "license": "MIT", | |
| 819 | + | "optional": true, | |
| 820 | + | "os": [ | |
| 821 | + | "linux" | |
| 822 | + | ] | |
| 823 | + | }, | |
| 824 | + | "node_modules/@rollup/rollup-linux-x64-musl": { | |
| 825 | + | "version": "4.50.1", | |
| 826 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", | |
| 827 | + | "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", | |
| 828 | + | "cpu": [ | |
| 829 | + | "x64" | |
| 830 | + | ], | |
| 831 | + | "dev": true, | |
| 832 | + | "license": "MIT", | |
| 833 | + | "optional": true, | |
| 834 | + | "os": [ | |
| 835 | + | "linux" | |
| 836 | + | ] | |
| 837 | + | }, | |
| 838 | + | "node_modules/@rollup/rollup-openharmony-arm64": { | |
| 839 | + | "version": "4.50.1", | |
| 840 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", | |
| 841 | + | "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", | |
| 842 | + | "cpu": [ | |
| 843 | + | "arm64" | |
| 844 | + | ], | |
| 845 | + | "dev": true, | |
| 846 | + | "license": "MIT", | |
| 847 | + | "optional": true, | |
| 848 | + | "os": [ | |
| 849 | + | "openharmony" | |
| 850 | + | ] | |
| 851 | + | }, | |
| 852 | + | "node_modules/@rollup/rollup-win32-arm64-msvc": { | |
| 853 | + | "version": "4.50.1", | |
| 854 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", | |
| 855 | + | "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", | |
| 856 | + | "cpu": [ | |
| 857 | + | "arm64" | |
| 858 | + | ], | |
| 859 | + | "dev": true, | |
| 860 | + | "license": "MIT", | |
| 861 | + | "optional": true, | |
| 862 | + | "os": [ | |
| 863 | + | "win32" | |
| 864 | + | ] | |
| 865 | + | }, | |
| 866 | + | "node_modules/@rollup/rollup-win32-ia32-msvc": { | |
| 867 | + | "version": "4.50.1", | |
| 868 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", | |
| 869 | + | "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", | |
| 870 | + | "cpu": [ | |
| 871 | + | "ia32" | |
| 872 | + | ], | |
| 873 | + | "dev": true, | |
| 874 | + | "license": "MIT", | |
| 875 | + | "optional": true, | |
| 876 | + | "os": [ | |
| 877 | + | "win32" | |
| 878 | + | ] | |
| 879 | + | }, | |
| 880 | + | "node_modules/@rollup/rollup-win32-x64-msvc": { | |
| 881 | + | "version": "4.50.1", | |
| 882 | + | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", | |
| 883 | + | "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", | |
| 884 | + | "cpu": [ | |
| 885 | + | "x64" | |
| 886 | + | ], | |
| 887 | + | "dev": true, | |
| 888 | + | "license": "MIT", | |
| 889 | + | "optional": true, | |
| 890 | + | "os": [ | |
| 891 | + | "win32" | |
| 892 | + | ] | |
| 893 | + | }, | |
| 894 | + | "node_modules/@sveltejs/acorn-typescript": { | |
| 895 | + | "version": "1.0.5", | |
| 896 | + | "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", | |
| 897 | + | "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", | |
| 898 | + | "dev": true, | |
| 899 | + | "license": "MIT", | |
| 900 | + | "peerDependencies": { | |
| 901 | + | "acorn": "^8.9.0" | |
| 902 | + | } | |
| 903 | + | }, | |
| 904 | + | "node_modules/@sveltejs/vite-plugin-svelte": { | |
| 905 | + | "version": "4.0.4", | |
| 906 | + | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.4.tgz", | |
| 907 | + | "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", | |
| 908 | + | "dev": true, | |
| 909 | + | "license": "MIT", | |
| 910 | + | "dependencies": { | |
| 911 | + | "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0", | |
| 912 | + | "debug": "^4.3.7", | |
| 913 | + | "deepmerge": "^4.3.1", | |
| 914 | + | "kleur": "^4.1.5", | |
| 915 | + | "magic-string": "^0.30.12", | |
| 916 | + | "vitefu": "^1.0.3" | |
| 917 | + | }, | |
| 918 | + | "engines": { | |
| 919 | + | "node": "^18.0.0 || ^20.0.0 || >=22" | |
| 920 | + | }, | |
| 921 | + | "peerDependencies": { | |
| 922 | + | "svelte": "^5.0.0-next.96 || ^5.0.0", | |
| 923 | + | "vite": "^5.0.0" | |
| 924 | + | } | |
| 925 | + | }, | |
| 926 | + | "node_modules/@sveltejs/vite-plugin-svelte-inspector": { | |
| 927 | + | "version": "3.0.1", | |
| 928 | + | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz", | |
| 929 | + | "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", | |
| 930 | + | "dev": true, | |
| 931 | + | "license": "MIT", | |
| 932 | + | "dependencies": { | |
| 933 | + | "debug": "^4.3.7" | |
| 934 | + | }, | |
| 935 | + | "engines": { | |
| 936 | + | "node": "^18.0.0 || ^20.0.0 || >=22" | |
| 937 | + | }, | |
| 938 | + | "peerDependencies": { | |
| 939 | + | "@sveltejs/vite-plugin-svelte": "^4.0.0-next.0||^4.0.0", | |
| 940 | + | "svelte": "^5.0.0-next.96 || ^5.0.0", | |
| 941 | + | "vite": "^5.0.0" | |
| 942 | + | } | |
| 943 | + | }, | |
| 944 | + | "node_modules/@tailwindcss/cli": { | |
| 945 | + | "version": "4.1.13", | |
| 946 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.13.tgz", | |
| 947 | + | "integrity": "sha512-KEu/iL4CYBzGza/2yZBLXqjCCZB/eRWkRLP8Vg2kkEWk4usC8HLGJW0QAhLS7U5DsAWumsisxgabuppE6NinLw==", | |
| 948 | + | "dev": true, | |
| 949 | + | "license": "MIT", | |
| 950 | + | "dependencies": { | |
| 951 | + | "@parcel/watcher": "^2.5.1", | |
| 952 | + | "@tailwindcss/node": "4.1.13", | |
| 953 | + | "@tailwindcss/oxide": "4.1.13", | |
| 954 | + | "enhanced-resolve": "^5.18.3", | |
| 955 | + | "mri": "^1.2.0", | |
| 956 | + | "picocolors": "^1.1.1", | |
| 957 | + | "tailwindcss": "4.1.13" | |
| 958 | + | }, | |
| 959 | + | "bin": { | |
| 960 | + | "tailwindcss": "dist/index.mjs" | |
| 961 | + | } | |
| 962 | + | }, | |
| 963 | + | "node_modules/@tailwindcss/node": { | |
| 964 | + | "version": "4.1.13", | |
| 965 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz", | |
| 966 | + | "integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==", | |
| 967 | + | "dev": true, | |
| 968 | + | "license": "MIT", | |
| 969 | + | "dependencies": { | |
| 970 | + | "@jridgewell/remapping": "^2.3.4", | |
| 971 | + | "enhanced-resolve": "^5.18.3", | |
| 972 | + | "jiti": "^2.5.1", | |
| 973 | + | "lightningcss": "1.30.1", | |
| 974 | + | "magic-string": "^0.30.18", | |
| 975 | + | "source-map-js": "^1.2.1", | |
| 976 | + | "tailwindcss": "4.1.13" | |
| 977 | + | } | |
| 978 | + | }, | |
| 979 | + | "node_modules/@tailwindcss/oxide": { | |
| 980 | + | "version": "4.1.13", | |
| 981 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz", | |
| 982 | + | "integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==", | |
| 983 | + | "dev": true, | |
| 984 | + | "hasInstallScript": true, | |
| 985 | + | "license": "MIT", | |
| 986 | + | "dependencies": { | |
| 987 | + | "detect-libc": "^2.0.4", | |
| 988 | + | "tar": "^7.4.3" | |
| 989 | + | }, | |
| 990 | + | "engines": { | |
| 991 | + | "node": ">= 10" | |
| 992 | + | }, | |
| 993 | + | "optionalDependencies": { | |
| 994 | + | "@tailwindcss/oxide-android-arm64": "4.1.13", | |
| 995 | + | "@tailwindcss/oxide-darwin-arm64": "4.1.13", | |
| 996 | + | "@tailwindcss/oxide-darwin-x64": "4.1.13", | |
| 997 | + | "@tailwindcss/oxide-freebsd-x64": "4.1.13", | |
| 998 | + | "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13", | |
| 999 | + | "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13", | |
| 1000 | + | "@tailwindcss/oxide-linux-arm64-musl": "4.1.13", | |
| 1001 | + | "@tailwindcss/oxide-linux-x64-gnu": "4.1.13", | |
| 1002 | + | "@tailwindcss/oxide-linux-x64-musl": "4.1.13", | |
| 1003 | + | "@tailwindcss/oxide-wasm32-wasi": "4.1.13", | |
| 1004 | + | "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13", | |
| 1005 | + | "@tailwindcss/oxide-win32-x64-msvc": "4.1.13" | |
| 1006 | + | } | |
| 1007 | + | }, | |
| 1008 | + | "node_modules/@tailwindcss/oxide-android-arm64": { | |
| 1009 | + | "version": "4.1.13", | |
| 1010 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.13.tgz", | |
| 1011 | + | "integrity": "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==", | |
| 1012 | + | "cpu": [ | |
| 1013 | + | "arm64" | |
| 1014 | + | ], | |
| 1015 | + | "dev": true, | |
| 1016 | + | "license": "MIT", | |
| 1017 | + | "optional": true, | |
| 1018 | + | "os": [ | |
| 1019 | + | "android" | |
| 1020 | + | ], | |
| 1021 | + | "engines": { | |
| 1022 | + | "node": ">= 10" | |
| 1023 | + | } | |
| 1024 | + | }, | |
| 1025 | + | "node_modules/@tailwindcss/oxide-darwin-arm64": { | |
| 1026 | + | "version": "4.1.13", | |
| 1027 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.13.tgz", | |
| 1028 | + | "integrity": "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==", | |
| 1029 | + | "cpu": [ | |
| 1030 | + | "arm64" | |
| 1031 | + | ], | |
| 1032 | + | "dev": true, | |
| 1033 | + | "license": "MIT", | |
| 1034 | + | "optional": true, | |
| 1035 | + | "os": [ | |
| 1036 | + | "darwin" | |
| 1037 | + | ], | |
| 1038 | + | "engines": { | |
| 1039 | + | "node": ">= 10" | |
| 1040 | + | } | |
| 1041 | + | }, | |
| 1042 | + | "node_modules/@tailwindcss/oxide-darwin-x64": { | |
| 1043 | + | "version": "4.1.13", | |
| 1044 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.13.tgz", | |
| 1045 | + | "integrity": "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==", | |
| 1046 | + | "cpu": [ | |
| 1047 | + | "x64" | |
| 1048 | + | ], | |
| 1049 | + | "dev": true, | |
| 1050 | + | "license": "MIT", | |
| 1051 | + | "optional": true, | |
| 1052 | + | "os": [ | |
| 1053 | + | "darwin" | |
| 1054 | + | ], | |
| 1055 | + | "engines": { | |
| 1056 | + | "node": ">= 10" | |
| 1057 | + | } | |
| 1058 | + | }, | |
| 1059 | + | "node_modules/@tailwindcss/oxide-freebsd-x64": { | |
| 1060 | + | "version": "4.1.13", | |
| 1061 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.13.tgz", | |
| 1062 | + | "integrity": "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==", | |
| 1063 | + | "cpu": [ | |
| 1064 | + | "x64" | |
| 1065 | + | ], | |
| 1066 | + | "dev": true, | |
| 1067 | + | "license": "MIT", | |
| 1068 | + | "optional": true, | |
| 1069 | + | "os": [ | |
| 1070 | + | "freebsd" | |
| 1071 | + | ], | |
| 1072 | + | "engines": { | |
| 1073 | + | "node": ">= 10" | |
| 1074 | + | } | |
| 1075 | + | }, | |
| 1076 | + | "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { | |
| 1077 | + | "version": "4.1.13", | |
| 1078 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.13.tgz", | |
| 1079 | + | "integrity": "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==", | |
| 1080 | + | "cpu": [ | |
| 1081 | + | "arm" | |
| 1082 | + | ], | |
| 1083 | + | "dev": true, | |
| 1084 | + | "license": "MIT", | |
| 1085 | + | "optional": true, | |
| 1086 | + | "os": [ | |
| 1087 | + | "linux" | |
| 1088 | + | ], | |
| 1089 | + | "engines": { | |
| 1090 | + | "node": ">= 10" | |
| 1091 | + | } | |
| 1092 | + | }, | |
| 1093 | + | "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { | |
| 1094 | + | "version": "4.1.13", | |
| 1095 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.13.tgz", | |
| 1096 | + | "integrity": "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==", | |
| 1097 | + | "cpu": [ | |
| 1098 | + | "arm64" | |
| 1099 | + | ], | |
| 1100 | + | "dev": true, | |
| 1101 | + | "license": "MIT", | |
| 1102 | + | "optional": true, | |
| 1103 | + | "os": [ | |
| 1104 | + | "linux" | |
| 1105 | + | ], | |
| 1106 | + | "engines": { | |
| 1107 | + | "node": ">= 10" | |
| 1108 | + | } | |
| 1109 | + | }, | |
| 1110 | + | "node_modules/@tailwindcss/oxide-linux-arm64-musl": { | |
| 1111 | + | "version": "4.1.13", | |
| 1112 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.13.tgz", | |
| 1113 | + | "integrity": "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==", | |
| 1114 | + | "cpu": [ | |
| 1115 | + | "arm64" | |
| 1116 | + | ], | |
| 1117 | + | "dev": true, | |
| 1118 | + | "license": "MIT", | |
| 1119 | + | "optional": true, | |
| 1120 | + | "os": [ | |
| 1121 | + | "linux" | |
| 1122 | + | ], | |
| 1123 | + | "engines": { | |
| 1124 | + | "node": ">= 10" | |
| 1125 | + | } | |
| 1126 | + | }, | |
| 1127 | + | "node_modules/@tailwindcss/oxide-linux-x64-gnu": { | |
| 1128 | + | "version": "4.1.13", | |
| 1129 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.13.tgz", | |
| 1130 | + | "integrity": "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==", | |
| 1131 | + | "cpu": [ | |
| 1132 | + | "x64" | |
| 1133 | + | ], | |
| 1134 | + | "dev": true, | |
| 1135 | + | "license": "MIT", | |
| 1136 | + | "optional": true, | |
| 1137 | + | "os": [ | |
| 1138 | + | "linux" | |
| 1139 | + | ], | |
| 1140 | + | "engines": { | |
| 1141 | + | "node": ">= 10" | |
| 1142 | + | } | |
| 1143 | + | }, | |
| 1144 | + | "node_modules/@tailwindcss/oxide-linux-x64-musl": { | |
| 1145 | + | "version": "4.1.13", | |
| 1146 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.13.tgz", | |
| 1147 | + | "integrity": "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==", | |
| 1148 | + | "cpu": [ | |
| 1149 | + | "x64" | |
| 1150 | + | ], | |
| 1151 | + | "dev": true, | |
| 1152 | + | "license": "MIT", | |
| 1153 | + | "optional": true, | |
| 1154 | + | "os": [ | |
| 1155 | + | "linux" | |
| 1156 | + | ], | |
| 1157 | + | "engines": { | |
| 1158 | + | "node": ">= 10" | |
| 1159 | + | } | |
| 1160 | + | }, | |
| 1161 | + | "node_modules/@tailwindcss/oxide-wasm32-wasi": { | |
| 1162 | + | "version": "4.1.13", | |
| 1163 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.13.tgz", | |
| 1164 | + | "integrity": "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==", | |
| 1165 | + | "bundleDependencies": [ | |
| 1166 | + | "@napi-rs/wasm-runtime", | |
| 1167 | + | "@emnapi/core", | |
| 1168 | + | "@emnapi/runtime", | |
| 1169 | + | "@tybys/wasm-util", | |
| 1170 | + | "@emnapi/wasi-threads", | |
| 1171 | + | "tslib" | |
| 1172 | + | ], | |
| 1173 | + | "cpu": [ | |
| 1174 | + | "wasm32" | |
| 1175 | + | ], | |
| 1176 | + | "dev": true, | |
| 1177 | + | "license": "MIT", | |
| 1178 | + | "optional": true, | |
| 1179 | + | "dependencies": { | |
| 1180 | + | "@emnapi/core": "^1.4.5", | |
| 1181 | + | "@emnapi/runtime": "^1.4.5", | |
| 1182 | + | "@emnapi/wasi-threads": "^1.0.4", | |
| 1183 | + | "@napi-rs/wasm-runtime": "^0.2.12", | |
| 1184 | + | "@tybys/wasm-util": "^0.10.0", | |
| 1185 | + | "tslib": "^2.8.0" | |
| 1186 | + | }, | |
| 1187 | + | "engines": { | |
| 1188 | + | "node": ">=14.0.0" | |
| 1189 | + | } | |
| 1190 | + | }, | |
| 1191 | + | "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { | |
| 1192 | + | "version": "4.1.13", | |
| 1193 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz", | |
| 1194 | + | "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==", | |
| 1195 | + | "cpu": [ | |
| 1196 | + | "arm64" | |
| 1197 | + | ], | |
| 1198 | + | "dev": true, | |
| 1199 | + | "license": "MIT", | |
| 1200 | + | "optional": true, | |
| 1201 | + | "os": [ | |
| 1202 | + | "win32" | |
| 1203 | + | ], | |
| 1204 | + | "engines": { | |
| 1205 | + | "node": ">= 10" | |
| 1206 | + | } | |
| 1207 | + | }, | |
| 1208 | + | "node_modules/@tailwindcss/oxide-win32-x64-msvc": { | |
| 1209 | + | "version": "4.1.13", | |
| 1210 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz", | |
| 1211 | + | "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==", | |
| 1212 | + | "cpu": [ | |
| 1213 | + | "x64" | |
| 1214 | + | ], | |
| 1215 | + | "dev": true, | |
| 1216 | + | "license": "MIT", | |
| 1217 | + | "optional": true, | |
| 1218 | + | "os": [ | |
| 1219 | + | "win32" | |
| 1220 | + | ], | |
| 1221 | + | "engines": { | |
| 1222 | + | "node": ">= 10" | |
| 1223 | + | } | |
| 1224 | + | }, | |
| 1225 | + | "node_modules/@tailwindcss/oxide/node_modules/detect-libc": { | |
| 1226 | + | "version": "2.0.4", | |
| 1227 | + | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", | |
| 1228 | + | "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", | |
| 1229 | + | "dev": true, | |
| 1230 | + | "license": "Apache-2.0", | |
| 1231 | + | "engines": { | |
| 1232 | + | "node": ">=8" | |
| 1233 | + | } | |
| 1234 | + | }, | |
| 1235 | + | "node_modules/@tailwindcss/postcss": { | |
| 1236 | + | "version": "4.1.13", | |
| 1237 | + | "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz", | |
| 1238 | + | "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==", | |
| 1239 | + | "dev": true, | |
| 1240 | + | "license": "MIT", | |
| 1241 | + | "dependencies": { | |
| 1242 | + | "@alloc/quick-lru": "^5.2.0", | |
| 1243 | + | "@tailwindcss/node": "4.1.13", | |
| 1244 | + | "@tailwindcss/oxide": "4.1.13", | |
| 1245 | + | "postcss": "^8.4.41", | |
| 1246 | + | "tailwindcss": "4.1.13" | |
| 1247 | + | } | |
| 1248 | + | }, | |
| 1249 | + | "node_modules/@types/estree": { | |
| 1250 | + | "version": "1.0.8", | |
| 1251 | + | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", | |
| 1252 | + | "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", | |
| 1253 | + | "dev": true, | |
| 1254 | + | "license": "MIT" | |
| 1255 | + | }, | |
| 1256 | + | "node_modules/@types/node": { | |
| 1257 | + | "version": "20.19.13", | |
| 1258 | + | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz", | |
| 1259 | + | "integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==", | |
| 1260 | + | "dev": true, | |
| 1261 | + | "license": "MIT", | |
| 1262 | + | "dependencies": { | |
| 1263 | + | "undici-types": "~6.21.0" | |
| 1264 | + | } | |
| 1265 | + | }, | |
| 1266 | + | "node_modules/@typescript-eslint/eslint-plugin": { | |
| 1267 | + | "version": "7.18.0", | |
| 1268 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", | |
| 1269 | + | "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", | |
| 1270 | + | "dev": true, | |
| 1271 | + | "license": "MIT", | |
| 1272 | + | "dependencies": { | |
| 1273 | + | "@eslint-community/regexpp": "^4.10.0", | |
| 1274 | + | "@typescript-eslint/scope-manager": "7.18.0", | |
| 1275 | + | "@typescript-eslint/type-utils": "7.18.0", | |
| 1276 | + | "@typescript-eslint/utils": "7.18.0", | |
| 1277 | + | "@typescript-eslint/visitor-keys": "7.18.0", | |
| 1278 | + | "graphemer": "^1.4.0", | |
| 1279 | + | "ignore": "^5.3.1", | |
| 1280 | + | "natural-compare": "^1.4.0", | |
| 1281 | + | "ts-api-utils": "^1.3.0" | |
| 1282 | + | }, | |
| 1283 | + | "engines": { | |
| 1284 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1285 | + | }, | |
| 1286 | + | "funding": { | |
| 1287 | + | "type": "opencollective", | |
| 1288 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1289 | + | }, | |
| 1290 | + | "peerDependencies": { | |
| 1291 | + | "@typescript-eslint/parser": "^7.0.0", | |
| 1292 | + | "eslint": "^8.56.0" | |
| 1293 | + | }, | |
| 1294 | + | "peerDependenciesMeta": { | |
| 1295 | + | "typescript": { | |
| 1296 | + | "optional": true | |
| 1297 | + | } | |
| 1298 | + | } | |
| 1299 | + | }, | |
| 1300 | + | "node_modules/@typescript-eslint/parser": { | |
| 1301 | + | "version": "7.18.0", | |
| 1302 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", | |
| 1303 | + | "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", | |
| 1304 | + | "dev": true, | |
| 1305 | + | "license": "BSD-2-Clause", | |
| 1306 | + | "dependencies": { | |
| 1307 | + | "@typescript-eslint/scope-manager": "7.18.0", | |
| 1308 | + | "@typescript-eslint/types": "7.18.0", | |
| 1309 | + | "@typescript-eslint/typescript-estree": "7.18.0", | |
| 1310 | + | "@typescript-eslint/visitor-keys": "7.18.0", | |
| 1311 | + | "debug": "^4.3.4" | |
| 1312 | + | }, | |
| 1313 | + | "engines": { | |
| 1314 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1315 | + | }, | |
| 1316 | + | "funding": { | |
| 1317 | + | "type": "opencollective", | |
| 1318 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1319 | + | }, | |
| 1320 | + | "peerDependencies": { | |
| 1321 | + | "eslint": "^8.56.0" | |
| 1322 | + | }, | |
| 1323 | + | "peerDependenciesMeta": { | |
| 1324 | + | "typescript": { | |
| 1325 | + | "optional": true | |
| 1326 | + | } | |
| 1327 | + | } | |
| 1328 | + | }, | |
| 1329 | + | "node_modules/@typescript-eslint/project-service": { | |
| 1330 | + | "version": "8.43.0", | |
| 1331 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz", | |
| 1332 | + | "integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==", | |
| 1333 | + | "dev": true, | |
| 1334 | + | "license": "MIT", | |
| 1335 | + | "dependencies": { | |
| 1336 | + | "@typescript-eslint/tsconfig-utils": "^8.43.0", | |
| 1337 | + | "@typescript-eslint/types": "^8.43.0", | |
| 1338 | + | "debug": "^4.3.4" | |
| 1339 | + | }, | |
| 1340 | + | "engines": { | |
| 1341 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 1342 | + | }, | |
| 1343 | + | "funding": { | |
| 1344 | + | "type": "opencollective", | |
| 1345 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1346 | + | }, | |
| 1347 | + | "peerDependencies": { | |
| 1348 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 1349 | + | } | |
| 1350 | + | }, | |
| 1351 | + | "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { | |
| 1352 | + | "version": "8.43.0", | |
| 1353 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", | |
| 1354 | + | "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", | |
| 1355 | + | "dev": true, | |
| 1356 | + | "license": "MIT", | |
| 1357 | + | "engines": { | |
| 1358 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 1359 | + | }, | |
| 1360 | + | "funding": { | |
| 1361 | + | "type": "opencollective", | |
| 1362 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1363 | + | } | |
| 1364 | + | }, | |
| 1365 | + | "node_modules/@typescript-eslint/scope-manager": { | |
| 1366 | + | "version": "7.18.0", | |
| 1367 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", | |
| 1368 | + | "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", | |
| 1369 | + | "dev": true, | |
| 1370 | + | "license": "MIT", | |
| 1371 | + | "dependencies": { | |
| 1372 | + | "@typescript-eslint/types": "7.18.0", | |
| 1373 | + | "@typescript-eslint/visitor-keys": "7.18.0" | |
| 1374 | + | }, | |
| 1375 | + | "engines": { | |
| 1376 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1377 | + | }, | |
| 1378 | + | "funding": { | |
| 1379 | + | "type": "opencollective", | |
| 1380 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1381 | + | } | |
| 1382 | + | }, | |
| 1383 | + | "node_modules/@typescript-eslint/tsconfig-utils": { | |
| 1384 | + | "version": "8.43.0", | |
| 1385 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz", | |
| 1386 | + | "integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==", | |
| 1387 | + | "dev": true, | |
| 1388 | + | "license": "MIT", | |
| 1389 | + | "engines": { | |
| 1390 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 1391 | + | }, | |
| 1392 | + | "funding": { | |
| 1393 | + | "type": "opencollective", | |
| 1394 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1395 | + | }, | |
| 1396 | + | "peerDependencies": { | |
| 1397 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 1398 | + | } | |
| 1399 | + | }, | |
| 1400 | + | "node_modules/@typescript-eslint/type-utils": { | |
| 1401 | + | "version": "7.18.0", | |
| 1402 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", | |
| 1403 | + | "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", | |
| 1404 | + | "dev": true, | |
| 1405 | + | "license": "MIT", | |
| 1406 | + | "dependencies": { | |
| 1407 | + | "@typescript-eslint/typescript-estree": "7.18.0", | |
| 1408 | + | "@typescript-eslint/utils": "7.18.0", | |
| 1409 | + | "debug": "^4.3.4", | |
| 1410 | + | "ts-api-utils": "^1.3.0" | |
| 1411 | + | }, | |
| 1412 | + | "engines": { | |
| 1413 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1414 | + | }, | |
| 1415 | + | "funding": { | |
| 1416 | + | "type": "opencollective", | |
| 1417 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1418 | + | }, | |
| 1419 | + | "peerDependencies": { | |
| 1420 | + | "eslint": "^8.56.0" | |
| 1421 | + | }, | |
| 1422 | + | "peerDependenciesMeta": { | |
| 1423 | + | "typescript": { | |
| 1424 | + | "optional": true | |
| 1425 | + | } | |
| 1426 | + | } | |
| 1427 | + | }, | |
| 1428 | + | "node_modules/@typescript-eslint/types": { | |
| 1429 | + | "version": "7.18.0", | |
| 1430 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", | |
| 1431 | + | "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", | |
| 1432 | + | "dev": true, | |
| 1433 | + | "license": "MIT", | |
| 1434 | + | "engines": { | |
| 1435 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1436 | + | }, | |
| 1437 | + | "funding": { | |
| 1438 | + | "type": "opencollective", | |
| 1439 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1440 | + | } | |
| 1441 | + | }, | |
| 1442 | + | "node_modules/@typescript-eslint/typescript-estree": { | |
| 1443 | + | "version": "7.18.0", | |
| 1444 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", | |
| 1445 | + | "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", | |
| 1446 | + | "dev": true, | |
| 1447 | + | "license": "BSD-2-Clause", | |
| 1448 | + | "dependencies": { | |
| 1449 | + | "@typescript-eslint/types": "7.18.0", | |
| 1450 | + | "@typescript-eslint/visitor-keys": "7.18.0", | |
| 1451 | + | "debug": "^4.3.4", | |
| 1452 | + | "globby": "^11.1.0", | |
| 1453 | + | "is-glob": "^4.0.3", | |
| 1454 | + | "minimatch": "^9.0.4", | |
| 1455 | + | "semver": "^7.6.0", | |
| 1456 | + | "ts-api-utils": "^1.3.0" | |
| 1457 | + | }, | |
| 1458 | + | "engines": { | |
| 1459 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1460 | + | }, | |
| 1461 | + | "funding": { | |
| 1462 | + | "type": "opencollective", | |
| 1463 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1464 | + | }, | |
| 1465 | + | "peerDependenciesMeta": { | |
| 1466 | + | "typescript": { | |
| 1467 | + | "optional": true | |
| 1468 | + | } | |
| 1469 | + | } | |
| 1470 | + | }, | |
| 1471 | + | "node_modules/@typescript-eslint/utils": { | |
| 1472 | + | "version": "7.18.0", | |
| 1473 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", | |
| 1474 | + | "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", | |
| 1475 | + | "dev": true, | |
| 1476 | + | "license": "MIT", | |
| 1477 | + | "dependencies": { | |
| 1478 | + | "@eslint-community/eslint-utils": "^4.4.0", | |
| 1479 | + | "@typescript-eslint/scope-manager": "7.18.0", | |
| 1480 | + | "@typescript-eslint/types": "7.18.0", | |
| 1481 | + | "@typescript-eslint/typescript-estree": "7.18.0" | |
| 1482 | + | }, | |
| 1483 | + | "engines": { | |
| 1484 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1485 | + | }, | |
| 1486 | + | "funding": { | |
| 1487 | + | "type": "opencollective", | |
| 1488 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1489 | + | }, | |
| 1490 | + | "peerDependencies": { | |
| 1491 | + | "eslint": "^8.56.0" | |
| 1492 | + | } | |
| 1493 | + | }, | |
| 1494 | + | "node_modules/@typescript-eslint/visitor-keys": { | |
| 1495 | + | "version": "7.18.0", | |
| 1496 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", | |
| 1497 | + | "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", | |
| 1498 | + | "dev": true, | |
| 1499 | + | "license": "MIT", | |
| 1500 | + | "dependencies": { | |
| 1501 | + | "@typescript-eslint/types": "7.18.0", | |
| 1502 | + | "eslint-visitor-keys": "^3.4.3" | |
| 1503 | + | }, | |
| 1504 | + | "engines": { | |
| 1505 | + | "node": "^18.18.0 || >=20.0.0" | |
| 1506 | + | }, | |
| 1507 | + | "funding": { | |
| 1508 | + | "type": "opencollective", | |
| 1509 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 1510 | + | } | |
| 1511 | + | }, | |
| 1512 | + | "node_modules/@ungap/structured-clone": { | |
| 1513 | + | "version": "1.3.0", | |
| 1514 | + | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", | |
| 1515 | + | "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", | |
| 1516 | + | "dev": true, | |
| 1517 | + | "license": "ISC" | |
| 1518 | + | }, | |
| 1519 | + | "node_modules/acorn": { | |
| 1520 | + | "version": "8.15.0", | |
| 1521 | + | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", | |
| 1522 | + | "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", | |
| 1523 | + | "dev": true, | |
| 1524 | + | "license": "MIT", | |
| 1525 | + | "bin": { | |
| 1526 | + | "acorn": "bin/acorn" | |
| 1527 | + | }, | |
| 1528 | + | "engines": { | |
| 1529 | + | "node": ">=0.4.0" | |
| 1530 | + | } | |
| 1531 | + | }, | |
| 1532 | + | "node_modules/acorn-jsx": { | |
| 1533 | + | "version": "5.3.2", | |
| 1534 | + | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", | |
| 1535 | + | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", | |
| 1536 | + | "dev": true, | |
| 1537 | + | "license": "MIT", | |
| 1538 | + | "peerDependencies": { | |
| 1539 | + | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" | |
| 1540 | + | } | |
| 1541 | + | }, | |
| 1542 | + | "node_modules/ajv": { | |
| 1543 | + | "version": "6.12.6", | |
| 1544 | + | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", | |
| 1545 | + | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", | |
| 1546 | + | "dev": true, | |
| 1547 | + | "license": "MIT", | |
| 1548 | + | "dependencies": { | |
| 1549 | + | "fast-deep-equal": "^3.1.1", | |
| 1550 | + | "fast-json-stable-stringify": "^2.0.0", | |
| 1551 | + | "json-schema-traverse": "^0.4.1", | |
| 1552 | + | "uri-js": "^4.2.2" | |
| 1553 | + | }, | |
| 1554 | + | "funding": { | |
| 1555 | + | "type": "github", | |
| 1556 | + | "url": "https://github.com/sponsors/epoberezkin" | |
| 1557 | + | } | |
| 1558 | + | }, | |
| 1559 | + | "node_modules/ansi-regex": { | |
| 1560 | + | "version": "5.0.1", | |
| 1561 | + | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | |
| 1562 | + | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | |
| 1563 | + | "dev": true, | |
| 1564 | + | "license": "MIT", | |
| 1565 | + | "engines": { | |
| 1566 | + | "node": ">=8" | |
| 1567 | + | } | |
| 1568 | + | }, | |
| 1569 | + | "node_modules/ansi-styles": { | |
| 1570 | + | "version": "4.3.0", | |
| 1571 | + | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | |
| 1572 | + | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | |
| 1573 | + | "dev": true, | |
| 1574 | + | "license": "MIT", | |
| 1575 | + | "dependencies": { | |
| 1576 | + | "color-convert": "^2.0.1" | |
| 1577 | + | }, | |
| 1578 | + | "engines": { | |
| 1579 | + | "node": ">=8" | |
| 1580 | + | }, | |
| 1581 | + | "funding": { | |
| 1582 | + | "url": "https://github.com/chalk/ansi-styles?sponsor=1" | |
| 1583 | + | } | |
| 1584 | + | }, | |
| 1585 | + | "node_modules/argparse": { | |
| 1586 | + | "version": "2.0.1", | |
| 1587 | + | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", | |
| 1588 | + | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", | |
| 1589 | + | "dev": true, | |
| 1590 | + | "license": "Python-2.0" | |
| 1591 | + | }, | |
| 1592 | + | "node_modules/aria-query": { | |
| 1593 | + | "version": "5.3.2", | |
| 1594 | + | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", | |
| 1595 | + | "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", | |
| 1596 | + | "dev": true, | |
| 1597 | + | "license": "Apache-2.0", | |
| 1598 | + | "engines": { | |
| 1599 | + | "node": ">= 0.4" | |
| 1600 | + | } | |
| 1601 | + | }, | |
| 1602 | + | "node_modules/array-union": { | |
| 1603 | + | "version": "2.1.0", | |
| 1604 | + | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", | |
| 1605 | + | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", | |
| 1606 | + | "dev": true, | |
| 1607 | + | "license": "MIT", | |
| 1608 | + | "engines": { | |
| 1609 | + | "node": ">=8" | |
| 1610 | + | } | |
| 1611 | + | }, | |
| 1612 | + | "node_modules/autoprefixer": { | |
| 1613 | + | "version": "10.4.21", | |
| 1614 | + | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", | |
| 1615 | + | "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", | |
| 1616 | + | "dev": true, | |
| 1617 | + | "funding": [ | |
| 1618 | + | { | |
| 1619 | + | "type": "opencollective", | |
| 1620 | + | "url": "https://opencollective.com/postcss/" | |
| 1621 | + | }, | |
| 1622 | + | { | |
| 1623 | + | "type": "tidelift", | |
| 1624 | + | "url": "https://tidelift.com/funding/github/npm/autoprefixer" | |
| 1625 | + | }, | |
| 1626 | + | { | |
| 1627 | + | "type": "github", | |
| 1628 | + | "url": "https://github.com/sponsors/ai" | |
| 1629 | + | } | |
| 1630 | + | ], | |
| 1631 | + | "license": "MIT", | |
| 1632 | + | "dependencies": { | |
| 1633 | + | "browserslist": "^4.24.4", | |
| 1634 | + | "caniuse-lite": "^1.0.30001702", | |
| 1635 | + | "fraction.js": "^4.3.7", | |
| 1636 | + | "normalize-range": "^0.1.2", | |
| 1637 | + | "picocolors": "^1.1.1", | |
| 1638 | + | "postcss-value-parser": "^4.2.0" | |
| 1639 | + | }, | |
| 1640 | + | "bin": { | |
| 1641 | + | "autoprefixer": "bin/autoprefixer" | |
| 1642 | + | }, | |
| 1643 | + | "engines": { | |
| 1644 | + | "node": "^10 || ^12 || >=14" | |
| 1645 | + | }, | |
| 1646 | + | "peerDependencies": { | |
| 1647 | + | "postcss": "^8.1.0" | |
| 1648 | + | } | |
| 1649 | + | }, | |
| 1650 | + | "node_modules/axobject-query": { | |
| 1651 | + | "version": "4.1.0", | |
| 1652 | + | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", | |
| 1653 | + | "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", | |
| 1654 | + | "dev": true, | |
| 1655 | + | "license": "Apache-2.0", | |
| 1656 | + | "engines": { | |
| 1657 | + | "node": ">= 0.4" | |
| 1658 | + | } | |
| 1659 | + | }, | |
| 1660 | + | "node_modules/balanced-match": { | |
| 1661 | + | "version": "1.0.2", | |
| 1662 | + | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | |
| 1663 | + | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", | |
| 1664 | + | "dev": true, | |
| 1665 | + | "license": "MIT" | |
| 1666 | + | }, | |
| 1667 | + | "node_modules/baseline-browser-mapping": { | |
| 1668 | + | "version": "2.8.3", | |
| 1669 | + | "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.3.tgz", | |
| 1670 | + | "integrity": "sha512-mcE+Wr2CAhHNWxXN/DdTI+n4gsPc5QpXpWnyCQWiQYIYZX+ZMJ8juXZgjRa/0/YPJo/NSsgW15/YgmI4nbysYw==", | |
| 1671 | + | "dev": true, | |
| 1672 | + | "license": "Apache-2.0", | |
| 1673 | + | "bin": { | |
| 1674 | + | "baseline-browser-mapping": "dist/cli.js" | |
| 1675 | + | } | |
| 1676 | + | }, | |
| 1677 | + | "node_modules/brace-expansion": { | |
| 1678 | + | "version": "2.0.2", | |
| 1679 | + | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", | |
| 1680 | + | "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", | |
| 1681 | + | "dev": true, | |
| 1682 | + | "license": "MIT", | |
| 1683 | + | "dependencies": { | |
| 1684 | + | "balanced-match": "^1.0.0" | |
| 1685 | + | } | |
| 1686 | + | }, | |
| 1687 | + | "node_modules/braces": { | |
| 1688 | + | "version": "3.0.3", | |
| 1689 | + | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", | |
| 1690 | + | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", | |
| 1691 | + | "dev": true, | |
| 1692 | + | "license": "MIT", | |
| 1693 | + | "dependencies": { | |
| 1694 | + | "fill-range": "^7.1.1" | |
| 1695 | + | }, | |
| 1696 | + | "engines": { | |
| 1697 | + | "node": ">=8" | |
| 1698 | + | } | |
| 1699 | + | }, | |
| 1700 | + | "node_modules/browserslist": { | |
| 1701 | + | "version": "4.26.0", | |
| 1702 | + | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.0.tgz", | |
| 1703 | + | "integrity": "sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==", | |
| 1704 | + | "dev": true, | |
| 1705 | + | "funding": [ | |
| 1706 | + | { | |
| 1707 | + | "type": "opencollective", | |
| 1708 | + | "url": "https://opencollective.com/browserslist" | |
| 1709 | + | }, | |
| 1710 | + | { | |
| 1711 | + | "type": "tidelift", | |
| 1712 | + | "url": "https://tidelift.com/funding/github/npm/browserslist" | |
| 1713 | + | }, | |
| 1714 | + | { | |
| 1715 | + | "type": "github", | |
| 1716 | + | "url": "https://github.com/sponsors/ai" | |
| 1717 | + | } | |
| 1718 | + | ], | |
| 1719 | + | "license": "MIT", | |
| 1720 | + | "dependencies": { | |
| 1721 | + | "baseline-browser-mapping": "^2.8.2", | |
| 1722 | + | "caniuse-lite": "^1.0.30001741", | |
| 1723 | + | "electron-to-chromium": "^1.5.218", | |
| 1724 | + | "node-releases": "^2.0.21", | |
| 1725 | + | "update-browserslist-db": "^1.1.3" | |
| 1726 | + | }, | |
| 1727 | + | "bin": { | |
| 1728 | + | "browserslist": "cli.js" | |
| 1729 | + | }, | |
| 1730 | + | "engines": { | |
| 1731 | + | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" | |
| 1732 | + | } | |
| 1733 | + | }, | |
| 1734 | + | "node_modules/callsites": { | |
| 1735 | + | "version": "3.1.0", | |
| 1736 | + | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", | |
| 1737 | + | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", | |
| 1738 | + | "dev": true, | |
| 1739 | + | "license": "MIT", | |
| 1740 | + | "engines": { | |
| 1741 | + | "node": ">=6" | |
| 1742 | + | } | |
| 1743 | + | }, | |
| 1744 | + | "node_modules/caniuse-lite": { | |
| 1745 | + | "version": "1.0.30001741", | |
| 1746 | + | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", | |
| 1747 | + | "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", | |
| 1748 | + | "dev": true, | |
| 1749 | + | "funding": [ | |
| 1750 | + | { | |
| 1751 | + | "type": "opencollective", | |
| 1752 | + | "url": "https://opencollective.com/browserslist" | |
| 1753 | + | }, | |
| 1754 | + | { | |
| 1755 | + | "type": "tidelift", | |
| 1756 | + | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" | |
| 1757 | + | }, | |
| 1758 | + | { | |
| 1759 | + | "type": "github", | |
| 1760 | + | "url": "https://github.com/sponsors/ai" | |
| 1761 | + | } | |
| 1762 | + | ], | |
| 1763 | + | "license": "CC-BY-4.0" | |
| 1764 | + | }, | |
| 1765 | + | "node_modules/chalk": { | |
| 1766 | + | "version": "4.1.2", | |
| 1767 | + | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | |
| 1768 | + | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", | |
| 1769 | + | "dev": true, | |
| 1770 | + | "license": "MIT", | |
| 1771 | + | "dependencies": { | |
| 1772 | + | "ansi-styles": "^4.1.0", | |
| 1773 | + | "supports-color": "^7.1.0" | |
| 1774 | + | }, | |
| 1775 | + | "engines": { | |
| 1776 | + | "node": ">=10" | |
| 1777 | + | }, | |
| 1778 | + | "funding": { | |
| 1779 | + | "url": "https://github.com/chalk/chalk?sponsor=1" | |
| 1780 | + | } | |
| 1781 | + | }, | |
| 1782 | + | "node_modules/chokidar": { | |
| 1783 | + | "version": "4.0.3", | |
| 1784 | + | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", | |
| 1785 | + | "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", | |
| 1786 | + | "dev": true, | |
| 1787 | + | "license": "MIT", | |
| 1788 | + | "dependencies": { | |
| 1789 | + | "readdirp": "^4.0.1" | |
| 1790 | + | }, | |
| 1791 | + | "engines": { | |
| 1792 | + | "node": ">= 14.16.0" | |
| 1793 | + | }, | |
| 1794 | + | "funding": { | |
| 1795 | + | "url": "https://paulmillr.com/funding/" | |
| 1796 | + | } | |
| 1797 | + | }, | |
| 1798 | + | "node_modules/chownr": { | |
| 1799 | + | "version": "3.0.0", | |
| 1800 | + | "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", | |
| 1801 | + | "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", | |
| 1802 | + | "dev": true, | |
| 1803 | + | "license": "BlueOak-1.0.0", | |
| 1804 | + | "engines": { | |
| 1805 | + | "node": ">=18" | |
| 1806 | + | } | |
| 1807 | + | }, | |
| 1808 | + | "node_modules/clsx": { | |
| 1809 | + | "version": "2.1.1", | |
| 1810 | + | "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", | |
| 1811 | + | "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", | |
| 1812 | + | "dev": true, | |
| 1813 | + | "license": "MIT", | |
| 1814 | + | "engines": { | |
| 1815 | + | "node": ">=6" | |
| 1816 | + | } | |
| 1817 | + | }, | |
| 1818 | + | "node_modules/color-convert": { | |
| 1819 | + | "version": "2.0.1", | |
| 1820 | + | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | |
| 1821 | + | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | |
| 1822 | + | "dev": true, | |
| 1823 | + | "license": "MIT", | |
| 1824 | + | "dependencies": { | |
| 1825 | + | "color-name": "~1.1.4" | |
| 1826 | + | }, | |
| 1827 | + | "engines": { | |
| 1828 | + | "node": ">=7.0.0" | |
| 1829 | + | } | |
| 1830 | + | }, | |
| 1831 | + | "node_modules/color-name": { | |
| 1832 | + | "version": "1.1.4", | |
| 1833 | + | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | |
| 1834 | + | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | |
| 1835 | + | "dev": true, | |
| 1836 | + | "license": "MIT" | |
| 1837 | + | }, | |
| 1838 | + | "node_modules/concat-map": { | |
| 1839 | + | "version": "0.0.1", | |
| 1840 | + | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | |
| 1841 | + | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", | |
| 1842 | + | "dev": true, | |
| 1843 | + | "license": "MIT" | |
| 1844 | + | }, | |
| 1845 | + | "node_modules/cross-spawn": { | |
| 1846 | + | "version": "7.0.6", | |
| 1847 | + | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", | |
| 1848 | + | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", | |
| 1849 | + | "dev": true, | |
| 1850 | + | "license": "MIT", | |
| 1851 | + | "dependencies": { | |
| 1852 | + | "path-key": "^3.1.0", | |
| 1853 | + | "shebang-command": "^2.0.0", | |
| 1854 | + | "which": "^2.0.1" | |
| 1855 | + | }, | |
| 1856 | + | "engines": { | |
| 1857 | + | "node": ">= 8" | |
| 1858 | + | } | |
| 1859 | + | }, | |
| 1860 | + | "node_modules/debug": { | |
| 1861 | + | "version": "4.4.1", | |
| 1862 | + | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", | |
| 1863 | + | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", | |
| 1864 | + | "dev": true, | |
| 1865 | + | "license": "MIT", | |
| 1866 | + | "dependencies": { | |
| 1867 | + | "ms": "^2.1.3" | |
| 1868 | + | }, | |
| 1869 | + | "engines": { | |
| 1870 | + | "node": ">=6.0" | |
| 1871 | + | }, | |
| 1872 | + | "peerDependenciesMeta": { | |
| 1873 | + | "supports-color": { | |
| 1874 | + | "optional": true | |
| 1875 | + | } | |
| 1876 | + | } | |
| 1877 | + | }, | |
| 1878 | + | "node_modules/deep-is": { | |
| 1879 | + | "version": "0.1.4", | |
| 1880 | + | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", | |
| 1881 | + | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", | |
| 1882 | + | "dev": true, | |
| 1883 | + | "license": "MIT" | |
| 1884 | + | }, | |
| 1885 | + | "node_modules/deepmerge": { | |
| 1886 | + | "version": "4.3.1", | |
| 1887 | + | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", | |
| 1888 | + | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", | |
| 1889 | + | "dev": true, | |
| 1890 | + | "license": "MIT", | |
| 1891 | + | "engines": { | |
| 1892 | + | "node": ">=0.10.0" | |
| 1893 | + | } | |
| 1894 | + | }, | |
| 1895 | + | "node_modules/detect-libc": { | |
| 1896 | + | "version": "1.0.3", | |
| 1897 | + | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", | |
| 1898 | + | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", | |
| 1899 | + | "dev": true, | |
| 1900 | + | "license": "Apache-2.0", | |
| 1901 | + | "bin": { | |
| 1902 | + | "detect-libc": "bin/detect-libc.js" | |
| 1903 | + | }, | |
| 1904 | + | "engines": { | |
| 1905 | + | "node": ">=0.10" | |
| 1906 | + | } | |
| 1907 | + | }, | |
| 1908 | + | "node_modules/dir-glob": { | |
| 1909 | + | "version": "3.0.1", | |
| 1910 | + | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", | |
| 1911 | + | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", | |
| 1912 | + | "dev": true, | |
| 1913 | + | "license": "MIT", | |
| 1914 | + | "dependencies": { | |
| 1915 | + | "path-type": "^4.0.0" | |
| 1916 | + | }, | |
| 1917 | + | "engines": { | |
| 1918 | + | "node": ">=8" | |
| 1919 | + | } | |
| 1920 | + | }, | |
| 1921 | + | "node_modules/doctrine": { | |
| 1922 | + | "version": "3.0.0", | |
| 1923 | + | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", | |
| 1924 | + | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", | |
| 1925 | + | "dev": true, | |
| 1926 | + | "license": "Apache-2.0", | |
| 1927 | + | "dependencies": { | |
| 1928 | + | "esutils": "^2.0.2" | |
| 1929 | + | }, | |
| 1930 | + | "engines": { | |
| 1931 | + | "node": ">=6.0.0" | |
| 1932 | + | } | |
| 1933 | + | }, | |
| 1934 | + | "node_modules/electron-to-chromium": { | |
| 1935 | + | "version": "1.5.218", | |
| 1936 | + | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz", | |
| 1937 | + | "integrity": "sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==", | |
| 1938 | + | "dev": true, | |
| 1939 | + | "license": "ISC" | |
| 1940 | + | }, | |
| 1941 | + | "node_modules/enhanced-resolve": { | |
| 1942 | + | "version": "5.18.3", | |
| 1943 | + | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", | |
| 1944 | + | "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", | |
| 1945 | + | "dev": true, | |
| 1946 | + | "license": "MIT", | |
| 1947 | + | "dependencies": { | |
| 1948 | + | "graceful-fs": "^4.2.4", | |
| 1949 | + | "tapable": "^2.2.0" | |
| 1950 | + | }, | |
| 1951 | + | "engines": { | |
| 1952 | + | "node": ">=10.13.0" | |
| 1953 | + | } | |
| 1954 | + | }, | |
| 1955 | + | "node_modules/escalade": { | |
| 1956 | + | "version": "3.2.0", | |
| 1957 | + | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", | |
| 1958 | + | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", | |
| 1959 | + | "dev": true, | |
| 1960 | + | "license": "MIT", | |
| 1961 | + | "engines": { | |
| 1962 | + | "node": ">=6" | |
| 1963 | + | } | |
| 1964 | + | }, | |
| 1965 | + | "node_modules/escape-string-regexp": { | |
| 1966 | + | "version": "4.0.0", | |
| 1967 | + | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | |
| 1968 | + | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | |
| 1969 | + | "dev": true, | |
| 1970 | + | "license": "MIT", | |
| 1971 | + | "engines": { | |
| 1972 | + | "node": ">=10" | |
| 1973 | + | }, | |
| 1974 | + | "funding": { | |
| 1975 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 1976 | + | } | |
| 1977 | + | }, | |
| 1978 | + | "node_modules/eslint": { | |
| 1979 | + | "version": "8.57.1", | |
| 1980 | + | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", | |
| 1981 | + | "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", | |
| 1982 | + | "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", | |
| 1983 | + | "dev": true, | |
| 1984 | + | "license": "MIT", | |
| 1985 | + | "dependencies": { | |
| 1986 | + | "@eslint-community/eslint-utils": "^4.2.0", | |
| 1987 | + | "@eslint-community/regexpp": "^4.6.1", | |
| 1988 | + | "@eslint/eslintrc": "^2.1.4", | |
| 1989 | + | "@eslint/js": "8.57.1", | |
| 1990 | + | "@humanwhocodes/config-array": "^0.13.0", | |
| 1991 | + | "@humanwhocodes/module-importer": "^1.0.1", | |
| 1992 | + | "@nodelib/fs.walk": "^1.2.8", | |
| 1993 | + | "@ungap/structured-clone": "^1.2.0", | |
| 1994 | + | "ajv": "^6.12.4", | |
| 1995 | + | "chalk": "^4.0.0", | |
| 1996 | + | "cross-spawn": "^7.0.2", | |
| 1997 | + | "debug": "^4.3.2", | |
| 1998 | + | "doctrine": "^3.0.0", | |
| 1999 | + | "escape-string-regexp": "^4.0.0", | |
| 2000 | + | "eslint-scope": "^7.2.2", | |
| 2001 | + | "eslint-visitor-keys": "^3.4.3", | |
| 2002 | + | "espree": "^9.6.1", | |
| 2003 | + | "esquery": "^1.4.2", | |
| 2004 | + | "esutils": "^2.0.2", | |
| 2005 | + | "fast-deep-equal": "^3.1.3", | |
| 2006 | + | "file-entry-cache": "^6.0.1", | |
| 2007 | + | "find-up": "^5.0.0", | |
| 2008 | + | "glob-parent": "^6.0.2", | |
| 2009 | + | "globals": "^13.19.0", | |
| 2010 | + | "graphemer": "^1.4.0", | |
| 2011 | + | "ignore": "^5.2.0", | |
| 2012 | + | "imurmurhash": "^0.1.4", | |
| 2013 | + | "is-glob": "^4.0.0", | |
| 2014 | + | "is-path-inside": "^3.0.3", | |
| 2015 | + | "js-yaml": "^4.1.0", | |
| 2016 | + | "json-stable-stringify-without-jsonify": "^1.0.1", | |
| 2017 | + | "levn": "^0.4.1", | |
| 2018 | + | "lodash.merge": "^4.6.2", | |
| 2019 | + | "minimatch": "^3.1.2", | |
| 2020 | + | "natural-compare": "^1.4.0", | |
| 2021 | + | "optionator": "^0.9.3", | |
| 2022 | + | "strip-ansi": "^6.0.1", | |
| 2023 | + | "text-table": "^0.2.0" | |
| 2024 | + | }, | |
| 2025 | + | "bin": { | |
| 2026 | + | "eslint": "bin/eslint.js" | |
| 2027 | + | }, | |
| 2028 | + | "engines": { | |
| 2029 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 2030 | + | }, | |
| 2031 | + | "funding": { | |
| 2032 | + | "url": "https://opencollective.com/eslint" | |
| 2033 | + | } | |
| 2034 | + | }, | |
| 2035 | + | "node_modules/eslint-scope": { | |
| 2036 | + | "version": "7.2.2", | |
| 2037 | + | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", | |
| 2038 | + | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", | |
| 2039 | + | "dev": true, | |
| 2040 | + | "license": "BSD-2-Clause", | |
| 2041 | + | "dependencies": { | |
| 2042 | + | "esrecurse": "^4.3.0", | |
| 2043 | + | "estraverse": "^5.2.0" | |
| 2044 | + | }, | |
| 2045 | + | "engines": { | |
| 2046 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 2047 | + | }, | |
| 2048 | + | "funding": { | |
| 2049 | + | "url": "https://opencollective.com/eslint" | |
| 2050 | + | } | |
| 2051 | + | }, | |
| 2052 | + | "node_modules/eslint-visitor-keys": { | |
| 2053 | + | "version": "3.4.3", | |
| 2054 | + | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", | |
| 2055 | + | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", | |
| 2056 | + | "dev": true, | |
| 2057 | + | "license": "Apache-2.0", | |
| 2058 | + | "engines": { | |
| 2059 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 2060 | + | }, | |
| 2061 | + | "funding": { | |
| 2062 | + | "url": "https://opencollective.com/eslint" | |
| 2063 | + | } | |
| 2064 | + | }, | |
| 2065 | + | "node_modules/eslint/node_modules/brace-expansion": { | |
| 2066 | + | "version": "1.1.12", | |
| 2067 | + | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", | |
| 2068 | + | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", | |
| 2069 | + | "dev": true, | |
| 2070 | + | "license": "MIT", | |
| 2071 | + | "dependencies": { | |
| 2072 | + | "balanced-match": "^1.0.0", | |
| 2073 | + | "concat-map": "0.0.1" | |
| 2074 | + | } | |
| 2075 | + | }, | |
| 2076 | + | "node_modules/eslint/node_modules/minimatch": { | |
| 2077 | + | "version": "3.1.2", | |
| 2078 | + | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| 2079 | + | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | |
| 2080 | + | "dev": true, | |
| 2081 | + | "license": "ISC", | |
| 2082 | + | "dependencies": { | |
| 2083 | + | "brace-expansion": "^1.1.7" | |
| 2084 | + | }, | |
| 2085 | + | "engines": { | |
| 2086 | + | "node": "*" | |
| 2087 | + | } | |
| 2088 | + | }, | |
| 2089 | + | "node_modules/esm-env": { | |
| 2090 | + | "version": "1.2.2", | |
| 2091 | + | "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", | |
| 2092 | + | "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", | |
| 2093 | + | "dev": true, | |
| 2094 | + | "license": "MIT" | |
| 2095 | + | }, | |
| 2096 | + | "node_modules/espree": { | |
| 2097 | + | "version": "9.6.1", | |
| 2098 | + | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", | |
| 2099 | + | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", | |
| 2100 | + | "dev": true, | |
| 2101 | + | "license": "BSD-2-Clause", | |
| 2102 | + | "dependencies": { | |
| 2103 | + | "acorn": "^8.9.0", | |
| 2104 | + | "acorn-jsx": "^5.3.2", | |
| 2105 | + | "eslint-visitor-keys": "^3.4.1" | |
| 2106 | + | }, | |
| 2107 | + | "engines": { | |
| 2108 | + | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 2109 | + | }, | |
| 2110 | + | "funding": { | |
| 2111 | + | "url": "https://opencollective.com/eslint" | |
| 2112 | + | } | |
| 2113 | + | }, | |
| 2114 | + | "node_modules/esquery": { | |
| 2115 | + | "version": "1.6.0", | |
| 2116 | + | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", | |
| 2117 | + | "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", | |
| 2118 | + | "dev": true, | |
| 2119 | + | "license": "BSD-3-Clause", | |
| 2120 | + | "dependencies": { | |
| 2121 | + | "estraverse": "^5.1.0" | |
| 2122 | + | }, | |
| 2123 | + | "engines": { | |
| 2124 | + | "node": ">=0.10" | |
| 2125 | + | } | |
| 2126 | + | }, | |
| 2127 | + | "node_modules/esrap": { | |
| 2128 | + | "version": "2.1.0", | |
| 2129 | + | "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz", | |
| 2130 | + | "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==", | |
| 2131 | + | "dev": true, | |
| 2132 | + | "license": "MIT", | |
| 2133 | + | "dependencies": { | |
| 2134 | + | "@jridgewell/sourcemap-codec": "^1.4.15" | |
| 2135 | + | } | |
| 2136 | + | }, | |
| 2137 | + | "node_modules/esrecurse": { | |
| 2138 | + | "version": "4.3.0", | |
| 2139 | + | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", | |
| 2140 | + | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", | |
| 2141 | + | "dev": true, | |
| 2142 | + | "license": "BSD-2-Clause", | |
| 2143 | + | "dependencies": { | |
| 2144 | + | "estraverse": "^5.2.0" | |
| 2145 | + | }, | |
| 2146 | + | "engines": { | |
| 2147 | + | "node": ">=4.0" | |
| 2148 | + | } | |
| 2149 | + | }, | |
| 2150 | + | "node_modules/estraverse": { | |
| 2151 | + | "version": "5.3.0", | |
| 2152 | + | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", | |
| 2153 | + | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", | |
| 2154 | + | "dev": true, | |
| 2155 | + | "license": "BSD-2-Clause", | |
| 2156 | + | "engines": { | |
| 2157 | + | "node": ">=4.0" | |
| 2158 | + | } | |
| 2159 | + | }, | |
| 2160 | + | "node_modules/esutils": { | |
| 2161 | + | "version": "2.0.3", | |
| 2162 | + | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", | |
| 2163 | + | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", | |
| 2164 | + | "dev": true, | |
| 2165 | + | "license": "BSD-2-Clause", | |
| 2166 | + | "engines": { | |
| 2167 | + | "node": ">=0.10.0" | |
| 2168 | + | } | |
| 2169 | + | }, | |
| 2170 | + | "node_modules/fast-deep-equal": { | |
| 2171 | + | "version": "3.1.3", | |
| 2172 | + | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |
| 2173 | + | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", | |
| 2174 | + | "dev": true, | |
| 2175 | + | "license": "MIT" | |
| 2176 | + | }, | |
| 2177 | + | "node_modules/fast-glob": { | |
| 2178 | + | "version": "3.3.3", | |
| 2179 | + | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", | |
| 2180 | + | "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", | |
| 2181 | + | "dev": true, | |
| 2182 | + | "license": "MIT", | |
| 2183 | + | "dependencies": { | |
| 2184 | + | "@nodelib/fs.stat": "^2.0.2", | |
| 2185 | + | "@nodelib/fs.walk": "^1.2.3", | |
| 2186 | + | "glob-parent": "^5.1.2", | |
| 2187 | + | "merge2": "^1.3.0", | |
| 2188 | + | "micromatch": "^4.0.8" | |
| 2189 | + | }, | |
| 2190 | + | "engines": { | |
| 2191 | + | "node": ">=8.6.0" | |
| 2192 | + | } | |
| 2193 | + | }, | |
| 2194 | + | "node_modules/fast-glob/node_modules/glob-parent": { | |
| 2195 | + | "version": "5.1.2", | |
| 2196 | + | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | |
| 2197 | + | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | |
| 2198 | + | "dev": true, | |
| 2199 | + | "license": "ISC", | |
| 2200 | + | "dependencies": { | |
| 2201 | + | "is-glob": "^4.0.1" | |
| 2202 | + | }, | |
| 2203 | + | "engines": { | |
| 2204 | + | "node": ">= 6" | |
| 2205 | + | } | |
| 2206 | + | }, | |
| 2207 | + | "node_modules/fast-json-stable-stringify": { | |
| 2208 | + | "version": "2.1.0", | |
| 2209 | + | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", | |
| 2210 | + | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", | |
| 2211 | + | "dev": true, | |
| 2212 | + | "license": "MIT" | |
| 2213 | + | }, | |
| 2214 | + | "node_modules/fast-levenshtein": { | |
| 2215 | + | "version": "2.0.6", | |
| 2216 | + | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", | |
| 2217 | + | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", | |
| 2218 | + | "dev": true, | |
| 2219 | + | "license": "MIT" | |
| 2220 | + | }, | |
| 2221 | + | "node_modules/fastq": { | |
| 2222 | + | "version": "1.19.1", | |
| 2223 | + | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", | |
| 2224 | + | "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", | |
| 2225 | + | "dev": true, | |
| 2226 | + | "license": "ISC", | |
| 2227 | + | "dependencies": { | |
| 2228 | + | "reusify": "^1.0.4" | |
| 2229 | + | } | |
| 2230 | + | }, | |
| 2231 | + | "node_modules/file-entry-cache": { | |
| 2232 | + | "version": "6.0.1", | |
| 2233 | + | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", | |
| 2234 | + | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", | |
| 2235 | + | "dev": true, | |
| 2236 | + | "license": "MIT", | |
| 2237 | + | "dependencies": { | |
| 2238 | + | "flat-cache": "^3.0.4" | |
| 2239 | + | }, | |
| 2240 | + | "engines": { | |
| 2241 | + | "node": "^10.12.0 || >=12.0.0" | |
| 2242 | + | } | |
| 2243 | + | }, | |
| 2244 | + | "node_modules/fill-range": { | |
| 2245 | + | "version": "7.1.1", | |
| 2246 | + | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", | |
| 2247 | + | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", | |
| 2248 | + | "dev": true, | |
| 2249 | + | "license": "MIT", | |
| 2250 | + | "dependencies": { | |
| 2251 | + | "to-regex-range": "^5.0.1" | |
| 2252 | + | }, | |
| 2253 | + | "engines": { | |
| 2254 | + | "node": ">=8" | |
| 2255 | + | } | |
| 2256 | + | }, | |
| 2257 | + | "node_modules/find-up": { | |
| 2258 | + | "version": "5.0.0", | |
| 2259 | + | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", | |
| 2260 | + | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", | |
| 2261 | + | "dev": true, | |
| 2262 | + | "license": "MIT", | |
| 2263 | + | "dependencies": { | |
| 2264 | + | "locate-path": "^6.0.0", | |
| 2265 | + | "path-exists": "^4.0.0" | |
| 2266 | + | }, | |
| 2267 | + | "engines": { | |
| 2268 | + | "node": ">=10" | |
| 2269 | + | }, | |
| 2270 | + | "funding": { | |
| 2271 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 2272 | + | } | |
| 2273 | + | }, | |
| 2274 | + | "node_modules/flat-cache": { | |
| 2275 | + | "version": "3.2.0", | |
| 2276 | + | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", | |
| 2277 | + | "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", | |
| 2278 | + | "dev": true, | |
| 2279 | + | "license": "MIT", | |
| 2280 | + | "dependencies": { | |
| 2281 | + | "flatted": "^3.2.9", | |
| 2282 | + | "keyv": "^4.5.3", | |
| 2283 | + | "rimraf": "^3.0.2" | |
| 2284 | + | }, | |
| 2285 | + | "engines": { | |
| 2286 | + | "node": "^10.12.0 || >=12.0.0" | |
| 2287 | + | } | |
| 2288 | + | }, | |
| 2289 | + | "node_modules/flatted": { | |
| 2290 | + | "version": "3.3.3", | |
| 2291 | + | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", | |
| 2292 | + | "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", | |
| 2293 | + | "dev": true, | |
| 2294 | + | "license": "ISC" | |
| 2295 | + | }, | |
| 2296 | + | "node_modules/fraction.js": { | |
| 2297 | + | "version": "4.3.7", | |
| 2298 | + | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", | |
| 2299 | + | "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", | |
| 2300 | + | "dev": true, | |
| 2301 | + | "license": "MIT", | |
| 2302 | + | "engines": { | |
| 2303 | + | "node": "*" | |
| 2304 | + | }, | |
| 2305 | + | "funding": { | |
| 2306 | + | "type": "patreon", | |
| 2307 | + | "url": "https://github.com/sponsors/rawify" | |
| 2308 | + | } | |
| 2309 | + | }, | |
| 2310 | + | "node_modules/fs.realpath": { | |
| 2311 | + | "version": "1.0.0", | |
| 2312 | + | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", | |
| 2313 | + | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", | |
| 2314 | + | "dev": true, | |
| 2315 | + | "license": "ISC" | |
| 2316 | + | }, | |
| 2317 | + | "node_modules/fsevents": { | |
| 2318 | + | "version": "2.3.3", | |
| 2319 | + | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", | |
| 2320 | + | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", | |
| 2321 | + | "dev": true, | |
| 2322 | + | "hasInstallScript": true, | |
| 2323 | + | "license": "MIT", | |
| 2324 | + | "optional": true, | |
| 2325 | + | "os": [ | |
| 2326 | + | "darwin" | |
| 2327 | + | ], | |
| 2328 | + | "engines": { | |
| 2329 | + | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | |
| 2330 | + | } | |
| 2331 | + | }, | |
| 2332 | + | "node_modules/glob": { | |
| 2333 | + | "version": "7.2.3", | |
| 2334 | + | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", | |
| 2335 | + | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", | |
| 2336 | + | "deprecated": "Glob versions prior to v9 are no longer supported", | |
| 2337 | + | "dev": true, | |
| 2338 | + | "license": "ISC", | |
| 2339 | + | "dependencies": { | |
| 2340 | + | "fs.realpath": "^1.0.0", | |
| 2341 | + | "inflight": "^1.0.4", | |
| 2342 | + | "inherits": "2", | |
| 2343 | + | "minimatch": "^3.1.1", | |
| 2344 | + | "once": "^1.3.0", | |
| 2345 | + | "path-is-absolute": "^1.0.0" | |
| 2346 | + | }, | |
| 2347 | + | "engines": { | |
| 2348 | + | "node": "*" | |
| 2349 | + | }, | |
| 2350 | + | "funding": { | |
| 2351 | + | "url": "https://github.com/sponsors/isaacs" | |
| 2352 | + | } | |
| 2353 | + | }, | |
| 2354 | + | "node_modules/glob-parent": { | |
| 2355 | + | "version": "6.0.2", | |
| 2356 | + | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", | |
| 2357 | + | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", | |
| 2358 | + | "dev": true, | |
| 2359 | + | "license": "ISC", | |
| 2360 | + | "dependencies": { | |
| 2361 | + | "is-glob": "^4.0.3" | |
| 2362 | + | }, | |
| 2363 | + | "engines": { | |
| 2364 | + | "node": ">=10.13.0" | |
| 2365 | + | } | |
| 2366 | + | }, | |
| 2367 | + | "node_modules/glob/node_modules/brace-expansion": { | |
| 2368 | + | "version": "1.1.12", | |
| 2369 | + | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", | |
| 2370 | + | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", | |
| 2371 | + | "dev": true, | |
| 2372 | + | "license": "MIT", | |
| 2373 | + | "dependencies": { | |
| 2374 | + | "balanced-match": "^1.0.0", | |
| 2375 | + | "concat-map": "0.0.1" | |
| 2376 | + | } | |
| 2377 | + | }, | |
| 2378 | + | "node_modules/glob/node_modules/minimatch": { | |
| 2379 | + | "version": "3.1.2", | |
| 2380 | + | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| 2381 | + | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | |
| 2382 | + | "dev": true, | |
| 2383 | + | "license": "ISC", | |
| 2384 | + | "dependencies": { | |
| 2385 | + | "brace-expansion": "^1.1.7" | |
| 2386 | + | }, | |
| 2387 | + | "engines": { | |
| 2388 | + | "node": "*" | |
| 2389 | + | } | |
| 2390 | + | }, | |
| 2391 | + | "node_modules/globals": { | |
| 2392 | + | "version": "13.24.0", | |
| 2393 | + | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", | |
| 2394 | + | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", | |
| 2395 | + | "dev": true, | |
| 2396 | + | "license": "MIT", | |
| 2397 | + | "dependencies": { | |
| 2398 | + | "type-fest": "^0.20.2" | |
| 2399 | + | }, | |
| 2400 | + | "engines": { | |
| 2401 | + | "node": ">=8" | |
| 2402 | + | }, | |
| 2403 | + | "funding": { | |
| 2404 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 2405 | + | } | |
| 2406 | + | }, | |
| 2407 | + | "node_modules/globby": { | |
| 2408 | + | "version": "11.1.0", | |
| 2409 | + | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", | |
| 2410 | + | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", | |
| 2411 | + | "dev": true, | |
| 2412 | + | "license": "MIT", | |
| 2413 | + | "dependencies": { | |
| 2414 | + | "array-union": "^2.1.0", | |
| 2415 | + | "dir-glob": "^3.0.1", | |
| 2416 | + | "fast-glob": "^3.2.9", | |
| 2417 | + | "ignore": "^5.2.0", | |
| 2418 | + | "merge2": "^1.4.1", | |
| 2419 | + | "slash": "^3.0.0" | |
| 2420 | + | }, | |
| 2421 | + | "engines": { | |
| 2422 | + | "node": ">=10" | |
| 2423 | + | }, | |
| 2424 | + | "funding": { | |
| 2425 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 2426 | + | } | |
| 2427 | + | }, | |
| 2428 | + | "node_modules/graceful-fs": { | |
| 2429 | + | "version": "4.2.11", | |
| 2430 | + | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", | |
| 2431 | + | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", | |
| 2432 | + | "dev": true, | |
| 2433 | + | "license": "ISC" | |
| 2434 | + | }, | |
| 2435 | + | "node_modules/graphemer": { | |
| 2436 | + | "version": "1.4.0", | |
| 2437 | + | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", | |
| 2438 | + | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", | |
| 2439 | + | "dev": true, | |
| 2440 | + | "license": "MIT" | |
| 2441 | + | }, | |
| 2442 | + | "node_modules/has-flag": { | |
| 2443 | + | "version": "4.0.0", | |
| 2444 | + | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | |
| 2445 | + | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | |
| 2446 | + | "dev": true, | |
| 2447 | + | "license": "MIT", | |
| 2448 | + | "engines": { | |
| 2449 | + | "node": ">=8" | |
| 2450 | + | } | |
| 2451 | + | }, | |
| 2452 | + | "node_modules/ignore": { | |
| 2453 | + | "version": "5.3.2", | |
| 2454 | + | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", | |
| 2455 | + | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", | |
| 2456 | + | "dev": true, | |
| 2457 | + | "license": "MIT", | |
| 2458 | + | "engines": { | |
| 2459 | + | "node": ">= 4" | |
| 2460 | + | } | |
| 2461 | + | }, | |
| 2462 | + | "node_modules/import-fresh": { | |
| 2463 | + | "version": "3.3.1", | |
| 2464 | + | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", | |
| 2465 | + | "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", | |
| 2466 | + | "dev": true, | |
| 2467 | + | "license": "MIT", | |
| 2468 | + | "dependencies": { | |
| 2469 | + | "parent-module": "^1.0.0", | |
| 2470 | + | "resolve-from": "^4.0.0" | |
| 2471 | + | }, | |
| 2472 | + | "engines": { | |
| 2473 | + | "node": ">=6" | |
| 2474 | + | }, | |
| 2475 | + | "funding": { | |
| 2476 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 2477 | + | } | |
| 2478 | + | }, | |
| 2479 | + | "node_modules/imurmurhash": { | |
| 2480 | + | "version": "0.1.4", | |
| 2481 | + | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", | |
| 2482 | + | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", | |
| 2483 | + | "dev": true, | |
| 2484 | + | "license": "MIT", | |
| 2485 | + | "engines": { | |
| 2486 | + | "node": ">=0.8.19" | |
| 2487 | + | } | |
| 2488 | + | }, | |
| 2489 | + | "node_modules/inflight": { | |
| 2490 | + | "version": "1.0.6", | |
| 2491 | + | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", | |
| 2492 | + | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", | |
| 2493 | + | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", | |
| 2494 | + | "dev": true, | |
| 2495 | + | "license": "ISC", | |
| 2496 | + | "dependencies": { | |
| 2497 | + | "once": "^1.3.0", | |
| 2498 | + | "wrappy": "1" | |
| 2499 | + | } | |
| 2500 | + | }, | |
| 2501 | + | "node_modules/inherits": { | |
| 2502 | + | "version": "2.0.4", | |
| 2503 | + | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | |
| 2504 | + | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", | |
| 2505 | + | "dev": true, | |
| 2506 | + | "license": "ISC" | |
| 2507 | + | }, | |
| 2508 | + | "node_modules/is-extglob": { | |
| 2509 | + | "version": "2.1.1", | |
| 2510 | + | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | |
| 2511 | + | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", | |
| 2512 | + | "dev": true, | |
| 2513 | + | "license": "MIT", | |
| 2514 | + | "engines": { | |
| 2515 | + | "node": ">=0.10.0" | |
| 2516 | + | } | |
| 2517 | + | }, | |
| 2518 | + | "node_modules/is-glob": { | |
| 2519 | + | "version": "4.0.3", | |
| 2520 | + | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", | |
| 2521 | + | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", | |
| 2522 | + | "dev": true, | |
| 2523 | + | "license": "MIT", | |
| 2524 | + | "dependencies": { | |
| 2525 | + | "is-extglob": "^2.1.1" | |
| 2526 | + | }, | |
| 2527 | + | "engines": { | |
| 2528 | + | "node": ">=0.10.0" | |
| 2529 | + | } | |
| 2530 | + | }, | |
| 2531 | + | "node_modules/is-number": { | |
| 2532 | + | "version": "7.0.0", | |
| 2533 | + | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", | |
| 2534 | + | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | |
| 2535 | + | "dev": true, | |
| 2536 | + | "license": "MIT", | |
| 2537 | + | "engines": { | |
| 2538 | + | "node": ">=0.12.0" | |
| 2539 | + | } | |
| 2540 | + | }, | |
| 2541 | + | "node_modules/is-path-inside": { | |
| 2542 | + | "version": "3.0.3", | |
| 2543 | + | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", | |
| 2544 | + | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", | |
| 2545 | + | "dev": true, | |
| 2546 | + | "license": "MIT", | |
| 2547 | + | "engines": { | |
| 2548 | + | "node": ">=8" | |
| 2549 | + | } | |
| 2550 | + | }, | |
| 2551 | + | "node_modules/is-reference": { | |
| 2552 | + | "version": "3.0.3", | |
| 2553 | + | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", | |
| 2554 | + | "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", | |
| 2555 | + | "dev": true, | |
| 2556 | + | "license": "MIT", | |
| 2557 | + | "dependencies": { | |
| 2558 | + | "@types/estree": "^1.0.6" | |
| 2559 | + | } | |
| 2560 | + | }, | |
| 2561 | + | "node_modules/isexe": { | |
| 2562 | + | "version": "2.0.0", | |
| 2563 | + | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", | |
| 2564 | + | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", | |
| 2565 | + | "dev": true, | |
| 2566 | + | "license": "ISC" | |
| 2567 | + | }, | |
| 2568 | + | "node_modules/jiti": { | |
| 2569 | + | "version": "2.5.1", | |
| 2570 | + | "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", | |
| 2571 | + | "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", | |
| 2572 | + | "dev": true, | |
| 2573 | + | "license": "MIT", | |
| 2574 | + | "bin": { | |
| 2575 | + | "jiti": "lib/jiti-cli.mjs" | |
| 2576 | + | } | |
| 2577 | + | }, | |
| 2578 | + | "node_modules/js-yaml": { | |
| 2579 | + | "version": "4.1.0", | |
| 2580 | + | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", | |
| 2581 | + | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", | |
| 2582 | + | "dev": true, | |
| 2583 | + | "license": "MIT", | |
| 2584 | + | "dependencies": { | |
| 2585 | + | "argparse": "^2.0.1" | |
| 2586 | + | }, | |
| 2587 | + | "bin": { | |
| 2588 | + | "js-yaml": "bin/js-yaml.js" | |
| 2589 | + | } | |
| 2590 | + | }, | |
| 2591 | + | "node_modules/json-buffer": { | |
| 2592 | + | "version": "3.0.1", | |
| 2593 | + | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", | |
| 2594 | + | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", | |
| 2595 | + | "dev": true, | |
| 2596 | + | "license": "MIT" | |
| 2597 | + | }, | |
| 2598 | + | "node_modules/json-schema-traverse": { | |
| 2599 | + | "version": "0.4.1", | |
| 2600 | + | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | |
| 2601 | + | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", | |
| 2602 | + | "dev": true, | |
| 2603 | + | "license": "MIT" | |
| 2604 | + | }, | |
| 2605 | + | "node_modules/json-stable-stringify-without-jsonify": { | |
| 2606 | + | "version": "1.0.1", | |
| 2607 | + | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", | |
| 2608 | + | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", | |
| 2609 | + | "dev": true, | |
| 2610 | + | "license": "MIT" | |
| 2611 | + | }, | |
| 2612 | + | "node_modules/keyv": { | |
| 2613 | + | "version": "4.5.4", | |
| 2614 | + | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", | |
| 2615 | + | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", | |
| 2616 | + | "dev": true, | |
| 2617 | + | "license": "MIT", | |
| 2618 | + | "dependencies": { | |
| 2619 | + | "json-buffer": "3.0.1" | |
| 2620 | + | } | |
| 2621 | + | }, | |
| 2622 | + | "node_modules/kleur": { | |
| 2623 | + | "version": "4.1.5", | |
| 2624 | + | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", | |
| 2625 | + | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", | |
| 2626 | + | "dev": true, | |
| 2627 | + | "license": "MIT", | |
| 2628 | + | "engines": { | |
| 2629 | + | "node": ">=6" | |
| 2630 | + | } | |
| 2631 | + | }, | |
| 2632 | + | "node_modules/levn": { | |
| 2633 | + | "version": "0.4.1", | |
| 2634 | + | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", | |
| 2635 | + | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", | |
| 2636 | + | "dev": true, | |
| 2637 | + | "license": "MIT", | |
| 2638 | + | "dependencies": { | |
| 2639 | + | "prelude-ls": "^1.2.1", | |
| 2640 | + | "type-check": "~0.4.0" | |
| 2641 | + | }, | |
| 2642 | + | "engines": { | |
| 2643 | + | "node": ">= 0.8.0" | |
| 2644 | + | } | |
| 2645 | + | }, | |
| 2646 | + | "node_modules/lightningcss": { | |
| 2647 | + | "version": "1.30.1", | |
| 2648 | + | "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", | |
| 2649 | + | "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", | |
| 2650 | + | "dev": true, | |
| 2651 | + | "license": "MPL-2.0", | |
| 2652 | + | "dependencies": { | |
| 2653 | + | "detect-libc": "^2.0.3" | |
| 2654 | + | }, | |
| 2655 | + | "engines": { | |
| 2656 | + | "node": ">= 12.0.0" | |
| 2657 | + | }, | |
| 2658 | + | "funding": { | |
| 2659 | + | "type": "opencollective", | |
| 2660 | + | "url": "https://opencollective.com/parcel" | |
| 2661 | + | }, | |
| 2662 | + | "optionalDependencies": { | |
| 2663 | + | "lightningcss-darwin-arm64": "1.30.1", | |
| 2664 | + | "lightningcss-darwin-x64": "1.30.1", | |
| 2665 | + | "lightningcss-freebsd-x64": "1.30.1", | |
| 2666 | + | "lightningcss-linux-arm-gnueabihf": "1.30.1", | |
| 2667 | + | "lightningcss-linux-arm64-gnu": "1.30.1", | |
| 2668 | + | "lightningcss-linux-arm64-musl": "1.30.1", | |
| 2669 | + | "lightningcss-linux-x64-gnu": "1.30.1", | |
| 2670 | + | "lightningcss-linux-x64-musl": "1.30.1", | |
| 2671 | + | "lightningcss-win32-arm64-msvc": "1.30.1", | |
| 2672 | + | "lightningcss-win32-x64-msvc": "1.30.1" | |
| 2673 | + | } | |
| 2674 | + | }, | |
| 2675 | + | "node_modules/lightningcss-darwin-arm64": { | |
| 2676 | + | "version": "1.30.1", | |
| 2677 | + | "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", | |
| 2678 | + | "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", | |
| 2679 | + | "cpu": [ | |
| 2680 | + | "arm64" | |
| 2681 | + | ], | |
| 2682 | + | "dev": true, | |
| 2683 | + | "license": "MPL-2.0", | |
| 2684 | + | "optional": true, | |
| 2685 | + | "os": [ | |
| 2686 | + | "darwin" | |
| 2687 | + | ], | |
| 2688 | + | "engines": { | |
| 2689 | + | "node": ">= 12.0.0" | |
| 2690 | + | }, | |
| 2691 | + | "funding": { | |
| 2692 | + | "type": "opencollective", | |
| 2693 | + | "url": "https://opencollective.com/parcel" | |
| 2694 | + | } | |
| 2695 | + | }, | |
| 2696 | + | "node_modules/lightningcss-darwin-x64": { | |
| 2697 | + | "version": "1.30.1", | |
| 2698 | + | "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", | |
| 2699 | + | "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", | |
| 2700 | + | "cpu": [ | |
| 2701 | + | "x64" | |
| 2702 | + | ], | |
| 2703 | + | "dev": true, | |
| 2704 | + | "license": "MPL-2.0", | |
| 2705 | + | "optional": true, | |
| 2706 | + | "os": [ | |
| 2707 | + | "darwin" | |
| 2708 | + | ], | |
| 2709 | + | "engines": { | |
| 2710 | + | "node": ">= 12.0.0" | |
| 2711 | + | }, | |
| 2712 | + | "funding": { | |
| 2713 | + | "type": "opencollective", | |
| 2714 | + | "url": "https://opencollective.com/parcel" | |
| 2715 | + | } | |
| 2716 | + | }, | |
| 2717 | + | "node_modules/lightningcss-freebsd-x64": { | |
| 2718 | + | "version": "1.30.1", | |
| 2719 | + | "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", | |
| 2720 | + | "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", | |
| 2721 | + | "cpu": [ | |
| 2722 | + | "x64" | |
| 2723 | + | ], | |
| 2724 | + | "dev": true, | |
| 2725 | + | "license": "MPL-2.0", | |
| 2726 | + | "optional": true, | |
| 2727 | + | "os": [ | |
| 2728 | + | "freebsd" | |
| 2729 | + | ], | |
| 2730 | + | "engines": { | |
| 2731 | + | "node": ">= 12.0.0" | |
| 2732 | + | }, | |
| 2733 | + | "funding": { | |
| 2734 | + | "type": "opencollective", | |
| 2735 | + | "url": "https://opencollective.com/parcel" | |
| 2736 | + | } | |
| 2737 | + | }, | |
| 2738 | + | "node_modules/lightningcss-linux-arm-gnueabihf": { | |
| 2739 | + | "version": "1.30.1", | |
| 2740 | + | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", | |
| 2741 | + | "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", | |
| 2742 | + | "cpu": [ | |
| 2743 | + | "arm" | |
| 2744 | + | ], | |
| 2745 | + | "dev": true, | |
| 2746 | + | "license": "MPL-2.0", | |
| 2747 | + | "optional": true, | |
| 2748 | + | "os": [ | |
| 2749 | + | "linux" | |
| 2750 | + | ], | |
| 2751 | + | "engines": { | |
| 2752 | + | "node": ">= 12.0.0" | |
| 2753 | + | }, | |
| 2754 | + | "funding": { | |
| 2755 | + | "type": "opencollective", | |
| 2756 | + | "url": "https://opencollective.com/parcel" | |
| 2757 | + | } | |
| 2758 | + | }, | |
| 2759 | + | "node_modules/lightningcss-linux-arm64-gnu": { | |
| 2760 | + | "version": "1.30.1", | |
| 2761 | + | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", | |
| 2762 | + | "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", | |
| 2763 | + | "cpu": [ | |
| 2764 | + | "arm64" | |
| 2765 | + | ], | |
| 2766 | + | "dev": true, | |
| 2767 | + | "license": "MPL-2.0", | |
| 2768 | + | "optional": true, | |
| 2769 | + | "os": [ | |
| 2770 | + | "linux" | |
| 2771 | + | ], | |
| 2772 | + | "engines": { | |
| 2773 | + | "node": ">= 12.0.0" | |
| 2774 | + | }, | |
| 2775 | + | "funding": { | |
| 2776 | + | "type": "opencollective", | |
| 2777 | + | "url": "https://opencollective.com/parcel" | |
| 2778 | + | } | |
| 2779 | + | }, | |
| 2780 | + | "node_modules/lightningcss-linux-arm64-musl": { | |
| 2781 | + | "version": "1.30.1", | |
| 2782 | + | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", | |
| 2783 | + | "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", | |
| 2784 | + | "cpu": [ | |
| 2785 | + | "arm64" | |
| 2786 | + | ], | |
| 2787 | + | "dev": true, | |
| 2788 | + | "license": "MPL-2.0", | |
| 2789 | + | "optional": true, | |
| 2790 | + | "os": [ | |
| 2791 | + | "linux" | |
| 2792 | + | ], | |
| 2793 | + | "engines": { | |
| 2794 | + | "node": ">= 12.0.0" | |
| 2795 | + | }, | |
| 2796 | + | "funding": { | |
| 2797 | + | "type": "opencollective", | |
| 2798 | + | "url": "https://opencollective.com/parcel" | |
| 2799 | + | } | |
| 2800 | + | }, | |
| 2801 | + | "node_modules/lightningcss-linux-x64-gnu": { | |
| 2802 | + | "version": "1.30.1", | |
| 2803 | + | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", | |
| 2804 | + | "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", | |
| 2805 | + | "cpu": [ | |
| 2806 | + | "x64" | |
| 2807 | + | ], | |
| 2808 | + | "dev": true, | |
| 2809 | + | "license": "MPL-2.0", | |
| 2810 | + | "optional": true, | |
| 2811 | + | "os": [ | |
| 2812 | + | "linux" | |
| 2813 | + | ], | |
| 2814 | + | "engines": { | |
| 2815 | + | "node": ">= 12.0.0" | |
| 2816 | + | }, | |
| 2817 | + | "funding": { | |
| 2818 | + | "type": "opencollective", | |
| 2819 | + | "url": "https://opencollective.com/parcel" | |
| 2820 | + | } | |
| 2821 | + | }, | |
| 2822 | + | "node_modules/lightningcss-linux-x64-musl": { | |
| 2823 | + | "version": "1.30.1", | |
| 2824 | + | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", | |
| 2825 | + | "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", | |
| 2826 | + | "cpu": [ | |
| 2827 | + | "x64" | |
| 2828 | + | ], | |
| 2829 | + | "dev": true, | |
| 2830 | + | "license": "MPL-2.0", | |
| 2831 | + | "optional": true, | |
| 2832 | + | "os": [ | |
| 2833 | + | "linux" | |
| 2834 | + | ], | |
| 2835 | + | "engines": { | |
| 2836 | + | "node": ">= 12.0.0" | |
| 2837 | + | }, | |
| 2838 | + | "funding": { | |
| 2839 | + | "type": "opencollective", | |
| 2840 | + | "url": "https://opencollective.com/parcel" | |
| 2841 | + | } | |
| 2842 | + | }, | |
| 2843 | + | "node_modules/lightningcss-win32-arm64-msvc": { | |
| 2844 | + | "version": "1.30.1", | |
| 2845 | + | "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", | |
| 2846 | + | "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", | |
| 2847 | + | "cpu": [ | |
| 2848 | + | "arm64" | |
| 2849 | + | ], | |
| 2850 | + | "dev": true, | |
| 2851 | + | "license": "MPL-2.0", | |
| 2852 | + | "optional": true, | |
| 2853 | + | "os": [ | |
| 2854 | + | "win32" | |
| 2855 | + | ], | |
| 2856 | + | "engines": { | |
| 2857 | + | "node": ">= 12.0.0" | |
| 2858 | + | }, | |
| 2859 | + | "funding": { | |
| 2860 | + | "type": "opencollective", | |
| 2861 | + | "url": "https://opencollective.com/parcel" | |
| 2862 | + | } | |
| 2863 | + | }, | |
| 2864 | + | "node_modules/lightningcss-win32-x64-msvc": { | |
| 2865 | + | "version": "1.30.1", | |
| 2866 | + | "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", | |
| 2867 | + | "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", | |
| 2868 | + | "cpu": [ | |
| 2869 | + | "x64" | |
| 2870 | + | ], | |
| 2871 | + | "dev": true, | |
| 2872 | + | "license": "MPL-2.0", | |
| 2873 | + | "optional": true, | |
| 2874 | + | "os": [ | |
| 2875 | + | "win32" | |
| 2876 | + | ], | |
| 2877 | + | "engines": { | |
| 2878 | + | "node": ">= 12.0.0" | |
| 2879 | + | }, | |
| 2880 | + | "funding": { | |
| 2881 | + | "type": "opencollective", | |
| 2882 | + | "url": "https://opencollective.com/parcel" | |
| 2883 | + | } | |
| 2884 | + | }, | |
| 2885 | + | "node_modules/lightningcss/node_modules/detect-libc": { | |
| 2886 | + | "version": "2.0.4", | |
| 2887 | + | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", | |
| 2888 | + | "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", | |
| 2889 | + | "dev": true, | |
| 2890 | + | "license": "Apache-2.0", | |
| 2891 | + | "engines": { | |
| 2892 | + | "node": ">=8" | |
| 2893 | + | } | |
| 2894 | + | }, | |
| 2895 | + | "node_modules/locate-character": { | |
| 2896 | + | "version": "3.0.0", | |
| 2897 | + | "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", | |
| 2898 | + | "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", | |
| 2899 | + | "dev": true, | |
| 2900 | + | "license": "MIT" | |
| 2901 | + | }, | |
| 2902 | + | "node_modules/locate-path": { | |
| 2903 | + | "version": "6.0.0", | |
| 2904 | + | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", | |
| 2905 | + | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", | |
| 2906 | + | "dev": true, | |
| 2907 | + | "license": "MIT", | |
| 2908 | + | "dependencies": { | |
| 2909 | + | "p-locate": "^5.0.0" | |
| 2910 | + | }, | |
| 2911 | + | "engines": { | |
| 2912 | + | "node": ">=10" | |
| 2913 | + | }, | |
| 2914 | + | "funding": { | |
| 2915 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 2916 | + | } | |
| 2917 | + | }, | |
| 2918 | + | "node_modules/lodash.merge": { | |
| 2919 | + | "version": "4.6.2", | |
| 2920 | + | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", | |
| 2921 | + | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", | |
| 2922 | + | "dev": true, | |
| 2923 | + | "license": "MIT" | |
| 2924 | + | }, | |
| 2925 | + | "node_modules/magic-string": { | |
| 2926 | + | "version": "0.30.19", | |
| 2927 | + | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", | |
| 2928 | + | "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", | |
| 2929 | + | "dev": true, | |
| 2930 | + | "license": "MIT", | |
| 2931 | + | "dependencies": { | |
| 2932 | + | "@jridgewell/sourcemap-codec": "^1.5.5" | |
| 2933 | + | } | |
| 2934 | + | }, | |
| 2935 | + | "node_modules/merge2": { | |
| 2936 | + | "version": "1.4.1", | |
| 2937 | + | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", | |
| 2938 | + | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", | |
| 2939 | + | "dev": true, | |
| 2940 | + | "license": "MIT", | |
| 2941 | + | "engines": { | |
| 2942 | + | "node": ">= 8" | |
| 2943 | + | } | |
| 2944 | + | }, | |
| 2945 | + | "node_modules/micromatch": { | |
| 2946 | + | "version": "4.0.8", | |
| 2947 | + | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", | |
| 2948 | + | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", | |
| 2949 | + | "dev": true, | |
| 2950 | + | "license": "MIT", | |
| 2951 | + | "dependencies": { | |
| 2952 | + | "braces": "^3.0.3", | |
| 2953 | + | "picomatch": "^2.3.1" | |
| 2954 | + | }, | |
| 2955 | + | "engines": { | |
| 2956 | + | "node": ">=8.6" | |
| 2957 | + | } | |
| 2958 | + | }, | |
| 2959 | + | "node_modules/minimatch": { | |
| 2960 | + | "version": "9.0.5", | |
| 2961 | + | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", | |
| 2962 | + | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", | |
| 2963 | + | "dev": true, | |
| 2964 | + | "license": "ISC", | |
| 2965 | + | "dependencies": { | |
| 2966 | + | "brace-expansion": "^2.0.1" | |
| 2967 | + | }, | |
| 2968 | + | "engines": { | |
| 2969 | + | "node": ">=16 || 14 >=14.17" | |
| 2970 | + | }, | |
| 2971 | + | "funding": { | |
| 2972 | + | "url": "https://github.com/sponsors/isaacs" | |
| 2973 | + | } | |
| 2974 | + | }, | |
| 2975 | + | "node_modules/minipass": { | |
| 2976 | + | "version": "7.1.2", | |
| 2977 | + | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", | |
| 2978 | + | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", | |
| 2979 | + | "dev": true, | |
| 2980 | + | "license": "ISC", | |
| 2981 | + | "engines": { | |
| 2982 | + | "node": ">=16 || 14 >=14.17" | |
| 2983 | + | } | |
| 2984 | + | }, | |
| 2985 | + | "node_modules/minizlib": { | |
| 2986 | + | "version": "3.0.2", | |
| 2987 | + | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", | |
| 2988 | + | "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", | |
| 2989 | + | "dev": true, | |
| 2990 | + | "license": "MIT", | |
| 2991 | + | "dependencies": { | |
| 2992 | + | "minipass": "^7.1.2" | |
| 2993 | + | }, | |
| 2994 | + | "engines": { | |
| 2995 | + | "node": ">= 18" | |
| 2996 | + | } | |
| 2997 | + | }, | |
| 2998 | + | "node_modules/mkdirp": { | |
| 2999 | + | "version": "3.0.1", | |
| 3000 | + | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", | |
| 3001 | + | "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", | |
| 3002 | + | "dev": true, | |
| 3003 | + | "license": "MIT", | |
| 3004 | + | "bin": { | |
| 3005 | + | "mkdirp": "dist/cjs/src/bin.js" | |
| 3006 | + | }, | |
| 3007 | + | "engines": { | |
| 3008 | + | "node": ">=10" | |
| 3009 | + | }, | |
| 3010 | + | "funding": { | |
| 3011 | + | "url": "https://github.com/sponsors/isaacs" | |
| 3012 | + | } | |
| 3013 | + | }, | |
| 3014 | + | "node_modules/mri": { | |
| 3015 | + | "version": "1.2.0", | |
| 3016 | + | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", | |
| 3017 | + | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", | |
| 3018 | + | "dev": true, | |
| 3019 | + | "license": "MIT", | |
| 3020 | + | "engines": { | |
| 3021 | + | "node": ">=4" | |
| 3022 | + | } | |
| 3023 | + | }, | |
| 3024 | + | "node_modules/ms": { | |
| 3025 | + | "version": "2.1.3", | |
| 3026 | + | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | |
| 3027 | + | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | |
| 3028 | + | "dev": true, | |
| 3029 | + | "license": "MIT" | |
| 3030 | + | }, | |
| 3031 | + | "node_modules/nanoid": { | |
| 3032 | + | "version": "3.3.11", | |
| 3033 | + | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", | |
| 3034 | + | "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", | |
| 3035 | + | "dev": true, | |
| 3036 | + | "funding": [ | |
| 3037 | + | { | |
| 3038 | + | "type": "github", | |
| 3039 | + | "url": "https://github.com/sponsors/ai" | |
| 3040 | + | } | |
| 3041 | + | ], | |
| 3042 | + | "license": "MIT", | |
| 3043 | + | "bin": { | |
| 3044 | + | "nanoid": "bin/nanoid.cjs" | |
| 3045 | + | }, | |
| 3046 | + | "engines": { | |
| 3047 | + | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" | |
| 3048 | + | } | |
| 3049 | + | }, | |
| 3050 | + | "node_modules/natural-compare": { | |
| 3051 | + | "version": "1.4.0", | |
| 3052 | + | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", | |
| 3053 | + | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", | |
| 3054 | + | "dev": true, | |
| 3055 | + | "license": "MIT" | |
| 3056 | + | }, | |
| 3057 | + | "node_modules/node-addon-api": { | |
| 3058 | + | "version": "7.1.1", | |
| 3059 | + | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", | |
| 3060 | + | "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", | |
| 3061 | + | "dev": true, | |
| 3062 | + | "license": "MIT" | |
| 3063 | + | }, | |
| 3064 | + | "node_modules/node-releases": { | |
| 3065 | + | "version": "2.0.21", | |
| 3066 | + | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", | |
| 3067 | + | "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", | |
| 3068 | + | "dev": true, | |
| 3069 | + | "license": "MIT" | |
| 3070 | + | }, | |
| 3071 | + | "node_modules/normalize-range": { | |
| 3072 | + | "version": "0.1.2", | |
| 3073 | + | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", | |
| 3074 | + | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", | |
| 3075 | + | "dev": true, | |
| 3076 | + | "license": "MIT", | |
| 3077 | + | "engines": { | |
| 3078 | + | "node": ">=0.10.0" | |
| 3079 | + | } | |
| 3080 | + | }, | |
| 3081 | + | "node_modules/once": { | |
| 3082 | + | "version": "1.4.0", | |
| 3083 | + | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | |
| 3084 | + | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", | |
| 3085 | + | "dev": true, | |
| 3086 | + | "license": "ISC", | |
| 3087 | + | "dependencies": { | |
| 3088 | + | "wrappy": "1" | |
| 3089 | + | } | |
| 3090 | + | }, | |
| 3091 | + | "node_modules/optionator": { | |
| 3092 | + | "version": "0.9.4", | |
| 3093 | + | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", | |
| 3094 | + | "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", | |
| 3095 | + | "dev": true, | |
| 3096 | + | "license": "MIT", | |
| 3097 | + | "dependencies": { | |
| 3098 | + | "deep-is": "^0.1.3", | |
| 3099 | + | "fast-levenshtein": "^2.0.6", | |
| 3100 | + | "levn": "^0.4.1", | |
| 3101 | + | "prelude-ls": "^1.2.1", | |
| 3102 | + | "type-check": "^0.4.0", | |
| 3103 | + | "word-wrap": "^1.2.5" | |
| 3104 | + | }, | |
| 3105 | + | "engines": { | |
| 3106 | + | "node": ">= 0.8.0" | |
| 3107 | + | } | |
| 3108 | + | }, | |
| 3109 | + | "node_modules/p-limit": { | |
| 3110 | + | "version": "3.1.0", | |
| 3111 | + | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", | |
| 3112 | + | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", | |
| 3113 | + | "dev": true, | |
| 3114 | + | "license": "MIT", | |
| 3115 | + | "dependencies": { | |
| 3116 | + | "yocto-queue": "^0.1.0" | |
| 3117 | + | }, | |
| 3118 | + | "engines": { | |
| 3119 | + | "node": ">=10" | |
| 3120 | + | }, | |
| 3121 | + | "funding": { | |
| 3122 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 3123 | + | } | |
| 3124 | + | }, | |
| 3125 | + | "node_modules/p-locate": { | |
| 3126 | + | "version": "5.0.0", | |
| 3127 | + | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", | |
| 3128 | + | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", | |
| 3129 | + | "dev": true, | |
| 3130 | + | "license": "MIT", | |
| 3131 | + | "dependencies": { | |
| 3132 | + | "p-limit": "^3.0.2" | |
| 3133 | + | }, | |
| 3134 | + | "engines": { | |
| 3135 | + | "node": ">=10" | |
| 3136 | + | }, | |
| 3137 | + | "funding": { | |
| 3138 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 3139 | + | } | |
| 3140 | + | }, | |
| 3141 | + | "node_modules/parent-module": { | |
| 3142 | + | "version": "1.0.1", | |
| 3143 | + | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", | |
| 3144 | + | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", | |
| 3145 | + | "dev": true, | |
| 3146 | + | "license": "MIT", | |
| 3147 | + | "dependencies": { | |
| 3148 | + | "callsites": "^3.0.0" | |
| 3149 | + | }, | |
| 3150 | + | "engines": { | |
| 3151 | + | "node": ">=6" | |
| 3152 | + | } | |
| 3153 | + | }, | |
| 3154 | + | "node_modules/path-exists": { | |
| 3155 | + | "version": "4.0.0", | |
| 3156 | + | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", | |
| 3157 | + | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", | |
| 3158 | + | "dev": true, | |
| 3159 | + | "license": "MIT", | |
| 3160 | + | "engines": { | |
| 3161 | + | "node": ">=8" | |
| 3162 | + | } | |
| 3163 | + | }, | |
| 3164 | + | "node_modules/path-is-absolute": { | |
| 3165 | + | "version": "1.0.1", | |
| 3166 | + | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | |
| 3167 | + | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", | |
| 3168 | + | "dev": true, | |
| 3169 | + | "license": "MIT", | |
| 3170 | + | "engines": { | |
| 3171 | + | "node": ">=0.10.0" | |
| 3172 | + | } | |
| 3173 | + | }, | |
| 3174 | + | "node_modules/path-key": { | |
| 3175 | + | "version": "3.1.1", | |
| 3176 | + | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", | |
| 3177 | + | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", | |
| 3178 | + | "dev": true, | |
| 3179 | + | "license": "MIT", | |
| 3180 | + | "engines": { | |
| 3181 | + | "node": ">=8" | |
| 3182 | + | } | |
| 3183 | + | }, | |
| 3184 | + | "node_modules/path-type": { | |
| 3185 | + | "version": "4.0.0", | |
| 3186 | + | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", | |
| 3187 | + | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", | |
| 3188 | + | "dev": true, | |
| 3189 | + | "license": "MIT", | |
| 3190 | + | "engines": { | |
| 3191 | + | "node": ">=8" | |
| 3192 | + | } | |
| 3193 | + | }, | |
| 3194 | + | "node_modules/picocolors": { | |
| 3195 | + | "version": "1.1.1", | |
| 3196 | + | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", | |
| 3197 | + | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", | |
| 3198 | + | "dev": true, | |
| 3199 | + | "license": "ISC" | |
| 3200 | + | }, | |
| 3201 | + | "node_modules/picomatch": { | |
| 3202 | + | "version": "2.3.1", | |
| 3203 | + | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", | |
| 3204 | + | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", | |
| 3205 | + | "dev": true, | |
| 3206 | + | "license": "MIT", | |
| 3207 | + | "engines": { | |
| 3208 | + | "node": ">=8.6" | |
| 3209 | + | }, | |
| 3210 | + | "funding": { | |
| 3211 | + | "url": "https://github.com/sponsors/jonschlinkert" | |
| 3212 | + | } | |
| 3213 | + | }, | |
| 3214 | + | "node_modules/postcss": { | |
| 3215 | + | "version": "8.5.6", | |
| 3216 | + | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", | |
| 3217 | + | "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", | |
| 3218 | + | "dev": true, | |
| 3219 | + | "funding": [ | |
| 3220 | + | { | |
| 3221 | + | "type": "opencollective", | |
| 3222 | + | "url": "https://opencollective.com/postcss/" | |
| 3223 | + | }, | |
| 3224 | + | { | |
| 3225 | + | "type": "tidelift", | |
| 3226 | + | "url": "https://tidelift.com/funding/github/npm/postcss" | |
| 3227 | + | }, | |
| 3228 | + | { | |
| 3229 | + | "type": "github", | |
| 3230 | + | "url": "https://github.com/sponsors/ai" | |
| 3231 | + | } | |
| 3232 | + | ], | |
| 3233 | + | "license": "MIT", | |
| 3234 | + | "dependencies": { | |
| 3235 | + | "nanoid": "^3.3.11", | |
| 3236 | + | "picocolors": "^1.1.1", | |
| 3237 | + | "source-map-js": "^1.2.1" | |
| 3238 | + | }, | |
| 3239 | + | "engines": { | |
| 3240 | + | "node": "^10 || ^12 || >=14" | |
| 3241 | + | } | |
| 3242 | + | }, | |
| 3243 | + | "node_modules/postcss-value-parser": { | |
| 3244 | + | "version": "4.2.0", | |
| 3245 | + | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", | |
| 3246 | + | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", | |
| 3247 | + | "dev": true, | |
| 3248 | + | "license": "MIT" | |
| 3249 | + | }, | |
| 3250 | + | "node_modules/prelude-ls": { | |
| 3251 | + | "version": "1.2.1", | |
| 3252 | + | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", | |
| 3253 | + | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", | |
| 3254 | + | "dev": true, | |
| 3255 | + | "license": "MIT", | |
| 3256 | + | "engines": { | |
| 3257 | + | "node": ">= 0.8.0" | |
| 3258 | + | } | |
| 3259 | + | }, | |
| 3260 | + | "node_modules/punycode": { | |
| 3261 | + | "version": "2.3.1", | |
| 3262 | + | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", | |
| 3263 | + | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", | |
| 3264 | + | "dev": true, | |
| 3265 | + | "license": "MIT", | |
| 3266 | + | "engines": { | |
| 3267 | + | "node": ">=6" | |
| 3268 | + | } | |
| 3269 | + | }, | |
| 3270 | + | "node_modules/queue-microtask": { | |
| 3271 | + | "version": "1.2.3", | |
| 3272 | + | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", | |
| 3273 | + | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", | |
| 3274 | + | "dev": true, | |
| 3275 | + | "funding": [ | |
| 3276 | + | { | |
| 3277 | + | "type": "github", | |
| 3278 | + | "url": "https://github.com/sponsors/feross" | |
| 3279 | + | }, | |
| 3280 | + | { | |
| 3281 | + | "type": "patreon", | |
| 3282 | + | "url": "https://www.patreon.com/feross" | |
| 3283 | + | }, | |
| 3284 | + | { | |
| 3285 | + | "type": "consulting", | |
| 3286 | + | "url": "https://feross.org/support" | |
| 3287 | + | } | |
| 3288 | + | ], | |
| 3289 | + | "license": "MIT" | |
| 3290 | + | }, | |
| 3291 | + | "node_modules/readdirp": { | |
| 3292 | + | "version": "4.1.2", | |
| 3293 | + | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", | |
| 3294 | + | "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", | |
| 3295 | + | "dev": true, | |
| 3296 | + | "license": "MIT", | |
| 3297 | + | "engines": { | |
| 3298 | + | "node": ">= 14.18.0" | |
| 3299 | + | }, | |
| 3300 | + | "funding": { | |
| 3301 | + | "type": "individual", | |
| 3302 | + | "url": "https://paulmillr.com/funding/" | |
| 3303 | + | } | |
| 3304 | + | }, | |
| 3305 | + | "node_modules/resolve-from": { | |
| 3306 | + | "version": "4.0.0", | |
| 3307 | + | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | |
| 3308 | + | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", | |
| 3309 | + | "dev": true, | |
| 3310 | + | "license": "MIT", | |
| 3311 | + | "engines": { | |
| 3312 | + | "node": ">=4" | |
| 3313 | + | } | |
| 3314 | + | }, | |
| 3315 | + | "node_modules/reusify": { | |
| 3316 | + | "version": "1.1.0", | |
| 3317 | + | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", | |
| 3318 | + | "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", | |
| 3319 | + | "dev": true, | |
| 3320 | + | "license": "MIT", | |
| 3321 | + | "engines": { | |
| 3322 | + | "iojs": ">=1.0.0", | |
| 3323 | + | "node": ">=0.10.0" | |
| 3324 | + | } | |
| 3325 | + | }, | |
| 3326 | + | "node_modules/rimraf": { | |
| 3327 | + | "version": "3.0.2", | |
| 3328 | + | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", | |
| 3329 | + | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", | |
| 3330 | + | "deprecated": "Rimraf versions prior to v4 are no longer supported", | |
| 3331 | + | "dev": true, | |
| 3332 | + | "license": "ISC", | |
| 3333 | + | "dependencies": { | |
| 3334 | + | "glob": "^7.1.3" | |
| 3335 | + | }, | |
| 3336 | + | "bin": { | |
| 3337 | + | "rimraf": "bin.js" | |
| 3338 | + | }, | |
| 3339 | + | "funding": { | |
| 3340 | + | "url": "https://github.com/sponsors/isaacs" | |
| 3341 | + | } | |
| 3342 | + | }, | |
| 3343 | + | "node_modules/rollup": { | |
| 3344 | + | "version": "4.50.1", | |
| 3345 | + | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", | |
| 3346 | + | "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", | |
| 3347 | + | "dev": true, | |
| 3348 | + | "license": "MIT", | |
| 3349 | + | "dependencies": { | |
| 3350 | + | "@types/estree": "1.0.8" | |
| 3351 | + | }, | |
| 3352 | + | "bin": { | |
| 3353 | + | "rollup": "dist/bin/rollup" | |
| 3354 | + | }, | |
| 3355 | + | "engines": { | |
| 3356 | + | "node": ">=18.0.0", | |
| 3357 | + | "npm": ">=8.0.0" | |
| 3358 | + | }, | |
| 3359 | + | "optionalDependencies": { | |
| 3360 | + | "@rollup/rollup-android-arm-eabi": "4.50.1", | |
| 3361 | + | "@rollup/rollup-android-arm64": "4.50.1", | |
| 3362 | + | "@rollup/rollup-darwin-arm64": "4.50.1", | |
| 3363 | + | "@rollup/rollup-darwin-x64": "4.50.1", | |
| 3364 | + | "@rollup/rollup-freebsd-arm64": "4.50.1", | |
| 3365 | + | "@rollup/rollup-freebsd-x64": "4.50.1", | |
| 3366 | + | "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", | |
| 3367 | + | "@rollup/rollup-linux-arm-musleabihf": "4.50.1", | |
| 3368 | + | "@rollup/rollup-linux-arm64-gnu": "4.50.1", | |
| 3369 | + | "@rollup/rollup-linux-arm64-musl": "4.50.1", | |
| 3370 | + | "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", | |
| 3371 | + | "@rollup/rollup-linux-ppc64-gnu": "4.50.1", | |
| 3372 | + | "@rollup/rollup-linux-riscv64-gnu": "4.50.1", | |
| 3373 | + | "@rollup/rollup-linux-riscv64-musl": "4.50.1", | |
| 3374 | + | "@rollup/rollup-linux-s390x-gnu": "4.50.1", | |
| 3375 | + | "@rollup/rollup-linux-x64-gnu": "4.50.1", | |
| 3376 | + | "@rollup/rollup-linux-x64-musl": "4.50.1", | |
| 3377 | + | "@rollup/rollup-openharmony-arm64": "4.50.1", | |
| 3378 | + | "@rollup/rollup-win32-arm64-msvc": "4.50.1", | |
| 3379 | + | "@rollup/rollup-win32-ia32-msvc": "4.50.1", | |
| 3380 | + | "@rollup/rollup-win32-x64-msvc": "4.50.1", | |
| 3381 | + | "fsevents": "~2.3.2" | |
| 3382 | + | } | |
| 3383 | + | }, | |
| 3384 | + | "node_modules/run-parallel": { | |
| 3385 | + | "version": "1.2.0", | |
| 3386 | + | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", | |
| 3387 | + | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", | |
| 3388 | + | "dev": true, | |
| 3389 | + | "funding": [ | |
| 3390 | + | { | |
| 3391 | + | "type": "github", | |
| 3392 | + | "url": "https://github.com/sponsors/feross" | |
| 3393 | + | }, | |
| 3394 | + | { | |
| 3395 | + | "type": "patreon", | |
| 3396 | + | "url": "https://www.patreon.com/feross" | |
| 3397 | + | }, | |
| 3398 | + | { | |
| 3399 | + | "type": "consulting", | |
| 3400 | + | "url": "https://feross.org/support" | |
| 3401 | + | } | |
| 3402 | + | ], | |
| 3403 | + | "license": "MIT", | |
| 3404 | + | "dependencies": { | |
| 3405 | + | "queue-microtask": "^1.2.2" | |
| 3406 | + | } | |
| 3407 | + | }, | |
| 3408 | + | "node_modules/sade": { | |
| 3409 | + | "version": "1.8.1", | |
| 3410 | + | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", | |
| 3411 | + | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", | |
| 3412 | + | "dev": true, | |
| 3413 | + | "license": "MIT", | |
| 3414 | + | "dependencies": { | |
| 3415 | + | "mri": "^1.1.0" | |
| 3416 | + | }, | |
| 3417 | + | "engines": { | |
| 3418 | + | "node": ">=6" | |
| 3419 | + | } | |
| 3420 | + | }, | |
| 3421 | + | "node_modules/semver": { | |
| 3422 | + | "version": "7.7.2", | |
| 3423 | + | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", | |
| 3424 | + | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", | |
| 3425 | + | "dev": true, | |
| 3426 | + | "license": "ISC", | |
| 3427 | + | "bin": { | |
| 3428 | + | "semver": "bin/semver.js" | |
| 3429 | + | }, | |
| 3430 | + | "engines": { | |
| 3431 | + | "node": ">=10" | |
| 3432 | + | } | |
| 3433 | + | }, | |
| 3434 | + | "node_modules/shebang-command": { | |
| 3435 | + | "version": "2.0.0", | |
| 3436 | + | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", | |
| 3437 | + | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", | |
| 3438 | + | "dev": true, | |
| 3439 | + | "license": "MIT", | |
| 3440 | + | "dependencies": { | |
| 3441 | + | "shebang-regex": "^3.0.0" | |
| 3442 | + | }, | |
| 3443 | + | "engines": { | |
| 3444 | + | "node": ">=8" | |
| 3445 | + | } | |
| 3446 | + | }, | |
| 3447 | + | "node_modules/shebang-regex": { | |
| 3448 | + | "version": "3.0.0", | |
| 3449 | + | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", | |
| 3450 | + | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", | |
| 3451 | + | "dev": true, | |
| 3452 | + | "license": "MIT", | |
| 3453 | + | "engines": { | |
| 3454 | + | "node": ">=8" | |
| 3455 | + | } | |
| 3456 | + | }, | |
| 3457 | + | "node_modules/slash": { | |
| 3458 | + | "version": "3.0.0", | |
| 3459 | + | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", | |
| 3460 | + | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", | |
| 3461 | + | "dev": true, | |
| 3462 | + | "license": "MIT", | |
| 3463 | + | "engines": { | |
| 3464 | + | "node": ">=8" | |
| 3465 | + | } | |
| 3466 | + | }, | |
| 3467 | + | "node_modules/source-map-js": { | |
| 3468 | + | "version": "1.2.1", | |
| 3469 | + | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", | |
| 3470 | + | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", | |
| 3471 | + | "dev": true, | |
| 3472 | + | "license": "BSD-3-Clause", | |
| 3473 | + | "engines": { | |
| 3474 | + | "node": ">=0.10.0" | |
| 3475 | + | } | |
| 3476 | + | }, | |
| 3477 | + | "node_modules/strip-ansi": { | |
| 3478 | + | "version": "6.0.1", | |
| 3479 | + | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | |
| 3480 | + | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | |
| 3481 | + | "dev": true, | |
| 3482 | + | "license": "MIT", | |
| 3483 | + | "dependencies": { | |
| 3484 | + | "ansi-regex": "^5.0.1" | |
| 3485 | + | }, | |
| 3486 | + | "engines": { | |
| 3487 | + | "node": ">=8" | |
| 3488 | + | } | |
| 3489 | + | }, | |
| 3490 | + | "node_modules/strip-json-comments": { | |
| 3491 | + | "version": "3.1.1", | |
| 3492 | + | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", | |
| 3493 | + | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", | |
| 3494 | + | "dev": true, | |
| 3495 | + | "license": "MIT", | |
| 3496 | + | "engines": { | |
| 3497 | + | "node": ">=8" | |
| 3498 | + | }, | |
| 3499 | + | "funding": { | |
| 3500 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 3501 | + | } | |
| 3502 | + | }, | |
| 3503 | + | "node_modules/supports-color": { | |
| 3504 | + | "version": "7.2.0", | |
| 3505 | + | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | |
| 3506 | + | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", | |
| 3507 | + | "dev": true, | |
| 3508 | + | "license": "MIT", | |
| 3509 | + | "dependencies": { | |
| 3510 | + | "has-flag": "^4.0.0" | |
| 3511 | + | }, | |
| 3512 | + | "engines": { | |
| 3513 | + | "node": ">=8" | |
| 3514 | + | } | |
| 3515 | + | }, | |
| 3516 | + | "node_modules/svelte": { | |
| 3517 | + | "version": "5.38.10", | |
| 3518 | + | "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.38.10.tgz", | |
| 3519 | + | "integrity": "sha512-UY+OhrWK7WI22bCZ00P/M3HtyWgwJPi9IxSRkoAE2MeAy6kl7ZlZWJZ8RaB+X4KD/G+wjis+cGVnVYaoqbzBqg==", | |
| 3520 | + | "dev": true, | |
| 3521 | + | "license": "MIT", | |
| 3522 | + | "dependencies": { | |
| 3523 | + | "@jridgewell/remapping": "^2.3.4", | |
| 3524 | + | "@jridgewell/sourcemap-codec": "^1.5.0", | |
| 3525 | + | "@sveltejs/acorn-typescript": "^1.0.5", | |
| 3526 | + | "@types/estree": "^1.0.5", | |
| 3527 | + | "acorn": "^8.12.1", | |
| 3528 | + | "aria-query": "^5.3.1", | |
| 3529 | + | "axobject-query": "^4.1.0", | |
| 3530 | + | "clsx": "^2.1.1", | |
| 3531 | + | "esm-env": "^1.2.1", | |
| 3532 | + | "esrap": "^2.1.0", | |
| 3533 | + | "is-reference": "^3.0.3", | |
| 3534 | + | "locate-character": "^3.0.0", | |
| 3535 | + | "magic-string": "^0.30.11", | |
| 3536 | + | "zimmerframe": "^1.1.2" | |
| 3537 | + | }, | |
| 3538 | + | "engines": { | |
| 3539 | + | "node": ">=18" | |
| 3540 | + | } | |
| 3541 | + | }, | |
| 3542 | + | "node_modules/svelte-check": { | |
| 3543 | + | "version": "4.3.1", | |
| 3544 | + | "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.1.tgz", | |
| 3545 | + | "integrity": "sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg==", | |
| 3546 | + | "dev": true, | |
| 3547 | + | "license": "MIT", | |
| 3548 | + | "dependencies": { | |
| 3549 | + | "@jridgewell/trace-mapping": "^0.3.25", | |
| 3550 | + | "chokidar": "^4.0.1", | |
| 3551 | + | "fdir": "^6.2.0", | |
| 3552 | + | "picocolors": "^1.0.0", | |
| 3553 | + | "sade": "^1.7.4" | |
| 3554 | + | }, | |
| 3555 | + | "bin": { | |
| 3556 | + | "svelte-check": "bin/svelte-check" | |
| 3557 | + | }, | |
| 3558 | + | "engines": { | |
| 3559 | + | "node": ">= 18.0.0" | |
| 3560 | + | }, | |
| 3561 | + | "peerDependencies": { | |
| 3562 | + | "svelte": "^4.0.0 || ^5.0.0-next.0", | |
| 3563 | + | "typescript": ">=5.0.0" | |
| 3564 | + | } | |
| 3565 | + | }, | |
| 3566 | + | "node_modules/svelte-check/node_modules/fdir": { | |
| 3567 | + | "version": "6.5.0", | |
| 3568 | + | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", | |
| 3569 | + | "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", | |
| 3570 | + | "dev": true, | |
| 3571 | + | "license": "MIT", | |
| 3572 | + | "engines": { | |
| 3573 | + | "node": ">=12.0.0" | |
| 3574 | + | }, | |
| 3575 | + | "peerDependencies": { | |
| 3576 | + | "picomatch": "^3 || ^4" | |
| 3577 | + | }, | |
| 3578 | + | "peerDependenciesMeta": { | |
| 3579 | + | "picomatch": { | |
| 3580 | + | "optional": true | |
| 3581 | + | } | |
| 3582 | + | } | |
| 3583 | + | }, | |
| 3584 | + | "node_modules/svelte-check/node_modules/picomatch": { | |
| 3585 | + | "version": "4.0.3", | |
| 3586 | + | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", | |
| 3587 | + | "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", | |
| 3588 | + | "dev": true, | |
| 3589 | + | "license": "MIT", | |
| 3590 | + | "optional": true, | |
| 3591 | + | "peer": true, | |
| 3592 | + | "engines": { | |
| 3593 | + | "node": ">=12" | |
| 3594 | + | }, | |
| 3595 | + | "funding": { | |
| 3596 | + | "url": "https://github.com/sponsors/jonschlinkert" | |
| 3597 | + | } | |
| 3598 | + | }, | |
| 3599 | + | "node_modules/tailwindcss": { | |
| 3600 | + | "version": "4.1.13", | |
| 3601 | + | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz", | |
| 3602 | + | "integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==", | |
| 3603 | + | "dev": true, | |
| 3604 | + | "license": "MIT" | |
| 3605 | + | }, | |
| 3606 | + | "node_modules/tapable": { | |
| 3607 | + | "version": "2.2.3", | |
| 3608 | + | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", | |
| 3609 | + | "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", | |
| 3610 | + | "dev": true, | |
| 3611 | + | "license": "MIT", | |
| 3612 | + | "engines": { | |
| 3613 | + | "node": ">=6" | |
| 3614 | + | }, | |
| 3615 | + | "funding": { | |
| 3616 | + | "type": "opencollective", | |
| 3617 | + | "url": "https://opencollective.com/webpack" | |
| 3618 | + | } | |
| 3619 | + | }, | |
| 3620 | + | "node_modules/tar": { | |
| 3621 | + | "version": "7.4.3", | |
| 3622 | + | "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", | |
| 3623 | + | "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", | |
| 3624 | + | "dev": true, | |
| 3625 | + | "license": "ISC", | |
| 3626 | + | "dependencies": { | |
| 3627 | + | "@isaacs/fs-minipass": "^4.0.0", | |
| 3628 | + | "chownr": "^3.0.0", | |
| 3629 | + | "minipass": "^7.1.2", | |
| 3630 | + | "minizlib": "^3.0.1", | |
| 3631 | + | "mkdirp": "^3.0.1", | |
| 3632 | + | "yallist": "^5.0.0" | |
| 3633 | + | }, | |
| 3634 | + | "engines": { | |
| 3635 | + | "node": ">=18" | |
| 3636 | + | } | |
| 3637 | + | }, | |
| 3638 | + | "node_modules/text-table": { | |
| 3639 | + | "version": "0.2.0", | |
| 3640 | + | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", | |
| 3641 | + | "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", | |
| 3642 | + | "dev": true, | |
| 3643 | + | "license": "MIT" | |
| 3644 | + | }, | |
| 3645 | + | "node_modules/to-regex-range": { | |
| 3646 | + | "version": "5.0.1", | |
| 3647 | + | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", | |
| 3648 | + | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", | |
| 3649 | + | "dev": true, | |
| 3650 | + | "license": "MIT", | |
| 3651 | + | "dependencies": { | |
| 3652 | + | "is-number": "^7.0.0" | |
| 3653 | + | }, | |
| 3654 | + | "engines": { | |
| 3655 | + | "node": ">=8.0" | |
| 3656 | + | } | |
| 3657 | + | }, | |
| 3658 | + | "node_modules/ts-api-utils": { | |
| 3659 | + | "version": "1.4.3", | |
| 3660 | + | "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", | |
| 3661 | + | "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", | |
| 3662 | + | "dev": true, | |
| 3663 | + | "license": "MIT", | |
| 3664 | + | "engines": { | |
| 3665 | + | "node": ">=16" | |
| 3666 | + | }, | |
| 3667 | + | "peerDependencies": { | |
| 3668 | + | "typescript": ">=4.2.0" | |
| 3669 | + | } | |
| 3670 | + | }, | |
| 3671 | + | "node_modules/type-check": { | |
| 3672 | + | "version": "0.4.0", | |
| 3673 | + | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", | |
| 3674 | + | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", | |
| 3675 | + | "dev": true, | |
| 3676 | + | "license": "MIT", | |
| 3677 | + | "dependencies": { | |
| 3678 | + | "prelude-ls": "^1.2.1" | |
| 3679 | + | }, | |
| 3680 | + | "engines": { | |
| 3681 | + | "node": ">= 0.8.0" | |
| 3682 | + | } | |
| 3683 | + | }, | |
| 3684 | + | "node_modules/type-fest": { | |
| 3685 | + | "version": "0.20.2", | |
| 3686 | + | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", | |
| 3687 | + | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", | |
| 3688 | + | "dev": true, | |
| 3689 | + | "license": "(MIT OR CC0-1.0)", | |
| 3690 | + | "engines": { | |
| 3691 | + | "node": ">=10" | |
| 3692 | + | }, | |
| 3693 | + | "funding": { | |
| 3694 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 3695 | + | } | |
| 3696 | + | }, | |
| 3697 | + | "node_modules/typescript": { | |
| 3698 | + | "version": "5.9.2", | |
| 3699 | + | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", | |
| 3700 | + | "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", | |
| 3701 | + | "dev": true, | |
| 3702 | + | "license": "Apache-2.0", | |
| 3703 | + | "bin": { | |
| 3704 | + | "tsc": "bin/tsc", | |
| 3705 | + | "tsserver": "bin/tsserver" | |
| 3706 | + | }, | |
| 3707 | + | "engines": { | |
| 3708 | + | "node": ">=14.17" | |
| 3709 | + | } | |
| 3710 | + | }, | |
| 3711 | + | "node_modules/typescript-eslint": { | |
| 3712 | + | "version": "8.43.0", | |
| 3713 | + | "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.43.0.tgz", | |
| 3714 | + | "integrity": "sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==", | |
| 3715 | + | "dev": true, | |
| 3716 | + | "license": "MIT", | |
| 3717 | + | "dependencies": { | |
| 3718 | + | "@typescript-eslint/eslint-plugin": "8.43.0", | |
| 3719 | + | "@typescript-eslint/parser": "8.43.0", | |
| 3720 | + | "@typescript-eslint/typescript-estree": "8.43.0", | |
| 3721 | + | "@typescript-eslint/utils": "8.43.0" | |
| 3722 | + | }, | |
| 3723 | + | "engines": { | |
| 3724 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3725 | + | }, | |
| 3726 | + | "funding": { | |
| 3727 | + | "type": "opencollective", | |
| 3728 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3729 | + | }, | |
| 3730 | + | "peerDependencies": { | |
| 3731 | + | "eslint": "^8.57.0 || ^9.0.0", | |
| 3732 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3733 | + | } | |
| 3734 | + | }, | |
| 3735 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { | |
| 3736 | + | "version": "8.43.0", | |
| 3737 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz", | |
| 3738 | + | "integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==", | |
| 3739 | + | "dev": true, | |
| 3740 | + | "license": "MIT", | |
| 3741 | + | "dependencies": { | |
| 3742 | + | "@eslint-community/regexpp": "^4.10.0", | |
| 3743 | + | "@typescript-eslint/scope-manager": "8.43.0", | |
| 3744 | + | "@typescript-eslint/type-utils": "8.43.0", | |
| 3745 | + | "@typescript-eslint/utils": "8.43.0", | |
| 3746 | + | "@typescript-eslint/visitor-keys": "8.43.0", | |
| 3747 | + | "graphemer": "^1.4.0", | |
| 3748 | + | "ignore": "^7.0.0", | |
| 3749 | + | "natural-compare": "^1.4.0", | |
| 3750 | + | "ts-api-utils": "^2.1.0" | |
| 3751 | + | }, | |
| 3752 | + | "engines": { | |
| 3753 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3754 | + | }, | |
| 3755 | + | "funding": { | |
| 3756 | + | "type": "opencollective", | |
| 3757 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3758 | + | }, | |
| 3759 | + | "peerDependencies": { | |
| 3760 | + | "@typescript-eslint/parser": "^8.43.0", | |
| 3761 | + | "eslint": "^8.57.0 || ^9.0.0", | |
| 3762 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3763 | + | } | |
| 3764 | + | }, | |
| 3765 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { | |
| 3766 | + | "version": "8.43.0", | |
| 3767 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz", | |
| 3768 | + | "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", | |
| 3769 | + | "dev": true, | |
| 3770 | + | "license": "MIT", | |
| 3771 | + | "dependencies": { | |
| 3772 | + | "@typescript-eslint/scope-manager": "8.43.0", | |
| 3773 | + | "@typescript-eslint/types": "8.43.0", | |
| 3774 | + | "@typescript-eslint/typescript-estree": "8.43.0", | |
| 3775 | + | "@typescript-eslint/visitor-keys": "8.43.0", | |
| 3776 | + | "debug": "^4.3.4" | |
| 3777 | + | }, | |
| 3778 | + | "engines": { | |
| 3779 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3780 | + | }, | |
| 3781 | + | "funding": { | |
| 3782 | + | "type": "opencollective", | |
| 3783 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3784 | + | }, | |
| 3785 | + | "peerDependencies": { | |
| 3786 | + | "eslint": "^8.57.0 || ^9.0.0", | |
| 3787 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3788 | + | } | |
| 3789 | + | }, | |
| 3790 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { | |
| 3791 | + | "version": "8.43.0", | |
| 3792 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz", | |
| 3793 | + | "integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==", | |
| 3794 | + | "dev": true, | |
| 3795 | + | "license": "MIT", | |
| 3796 | + | "dependencies": { | |
| 3797 | + | "@typescript-eslint/types": "8.43.0", | |
| 3798 | + | "@typescript-eslint/visitor-keys": "8.43.0" | |
| 3799 | + | }, | |
| 3800 | + | "engines": { | |
| 3801 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3802 | + | }, | |
| 3803 | + | "funding": { | |
| 3804 | + | "type": "opencollective", | |
| 3805 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3806 | + | } | |
| 3807 | + | }, | |
| 3808 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { | |
| 3809 | + | "version": "8.43.0", | |
| 3810 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz", | |
| 3811 | + | "integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==", | |
| 3812 | + | "dev": true, | |
| 3813 | + | "license": "MIT", | |
| 3814 | + | "dependencies": { | |
| 3815 | + | "@typescript-eslint/types": "8.43.0", | |
| 3816 | + | "@typescript-eslint/typescript-estree": "8.43.0", | |
| 3817 | + | "@typescript-eslint/utils": "8.43.0", | |
| 3818 | + | "debug": "^4.3.4", | |
| 3819 | + | "ts-api-utils": "^2.1.0" | |
| 3820 | + | }, | |
| 3821 | + | "engines": { | |
| 3822 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3823 | + | }, | |
| 3824 | + | "funding": { | |
| 3825 | + | "type": "opencollective", | |
| 3826 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3827 | + | }, | |
| 3828 | + | "peerDependencies": { | |
| 3829 | + | "eslint": "^8.57.0 || ^9.0.0", | |
| 3830 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3831 | + | } | |
| 3832 | + | }, | |
| 3833 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { | |
| 3834 | + | "version": "8.43.0", | |
| 3835 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", | |
| 3836 | + | "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", | |
| 3837 | + | "dev": true, | |
| 3838 | + | "license": "MIT", | |
| 3839 | + | "engines": { | |
| 3840 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3841 | + | }, | |
| 3842 | + | "funding": { | |
| 3843 | + | "type": "opencollective", | |
| 3844 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3845 | + | } | |
| 3846 | + | }, | |
| 3847 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { | |
| 3848 | + | "version": "8.43.0", | |
| 3849 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz", | |
| 3850 | + | "integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==", | |
| 3851 | + | "dev": true, | |
| 3852 | + | "license": "MIT", | |
| 3853 | + | "dependencies": { | |
| 3854 | + | "@typescript-eslint/project-service": "8.43.0", | |
| 3855 | + | "@typescript-eslint/tsconfig-utils": "8.43.0", | |
| 3856 | + | "@typescript-eslint/types": "8.43.0", | |
| 3857 | + | "@typescript-eslint/visitor-keys": "8.43.0", | |
| 3858 | + | "debug": "^4.3.4", | |
| 3859 | + | "fast-glob": "^3.3.2", | |
| 3860 | + | "is-glob": "^4.0.3", | |
| 3861 | + | "minimatch": "^9.0.4", | |
| 3862 | + | "semver": "^7.6.0", | |
| 3863 | + | "ts-api-utils": "^2.1.0" | |
| 3864 | + | }, | |
| 3865 | + | "engines": { | |
| 3866 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3867 | + | }, | |
| 3868 | + | "funding": { | |
| 3869 | + | "type": "opencollective", | |
| 3870 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3871 | + | }, | |
| 3872 | + | "peerDependencies": { | |
| 3873 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3874 | + | } | |
| 3875 | + | }, | |
| 3876 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { | |
| 3877 | + | "version": "8.43.0", | |
| 3878 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz", | |
| 3879 | + | "integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==", | |
| 3880 | + | "dev": true, | |
| 3881 | + | "license": "MIT", | |
| 3882 | + | "dependencies": { | |
| 3883 | + | "@eslint-community/eslint-utils": "^4.7.0", | |
| 3884 | + | "@typescript-eslint/scope-manager": "8.43.0", | |
| 3885 | + | "@typescript-eslint/types": "8.43.0", | |
| 3886 | + | "@typescript-eslint/typescript-estree": "8.43.0" | |
| 3887 | + | }, | |
| 3888 | + | "engines": { | |
| 3889 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3890 | + | }, | |
| 3891 | + | "funding": { | |
| 3892 | + | "type": "opencollective", | |
| 3893 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3894 | + | }, | |
| 3895 | + | "peerDependencies": { | |
| 3896 | + | "eslint": "^8.57.0 || ^9.0.0", | |
| 3897 | + | "typescript": ">=4.8.4 <6.0.0" | |
| 3898 | + | } | |
| 3899 | + | }, | |
| 3900 | + | "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { | |
| 3901 | + | "version": "8.43.0", | |
| 3902 | + | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz", | |
| 3903 | + | "integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==", | |
| 3904 | + | "dev": true, | |
| 3905 | + | "license": "MIT", | |
| 3906 | + | "dependencies": { | |
| 3907 | + | "@typescript-eslint/types": "8.43.0", | |
| 3908 | + | "eslint-visitor-keys": "^4.2.1" | |
| 3909 | + | }, | |
| 3910 | + | "engines": { | |
| 3911 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3912 | + | }, | |
| 3913 | + | "funding": { | |
| 3914 | + | "type": "opencollective", | |
| 3915 | + | "url": "https://opencollective.com/typescript-eslint" | |
| 3916 | + | } | |
| 3917 | + | }, | |
| 3918 | + | "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { | |
| 3919 | + | "version": "4.2.1", | |
| 3920 | + | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", | |
| 3921 | + | "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", | |
| 3922 | + | "dev": true, | |
| 3923 | + | "license": "Apache-2.0", | |
| 3924 | + | "engines": { | |
| 3925 | + | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| 3926 | + | }, | |
| 3927 | + | "funding": { | |
| 3928 | + | "url": "https://opencollective.com/eslint" | |
| 3929 | + | } | |
| 3930 | + | }, | |
| 3931 | + | "node_modules/typescript-eslint/node_modules/ignore": { | |
| 3932 | + | "version": "7.0.5", | |
| 3933 | + | "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", | |
| 3934 | + | "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", | |
| 3935 | + | "dev": true, | |
| 3936 | + | "license": "MIT", | |
| 3937 | + | "engines": { | |
| 3938 | + | "node": ">= 4" | |
| 3939 | + | } | |
| 3940 | + | }, | |
| 3941 | + | "node_modules/typescript-eslint/node_modules/ts-api-utils": { | |
| 3942 | + | "version": "2.1.0", | |
| 3943 | + | "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", | |
| 3944 | + | "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", | |
| 3945 | + | "dev": true, | |
| 3946 | + | "license": "MIT", | |
| 3947 | + | "engines": { | |
| 3948 | + | "node": ">=18.12" | |
| 3949 | + | }, | |
| 3950 | + | "peerDependencies": { | |
| 3951 | + | "typescript": ">=4.8.4" | |
| 3952 | + | } | |
| 3953 | + | }, | |
| 3954 | + | "node_modules/undici-types": { | |
| 3955 | + | "version": "6.21.0", | |
| 3956 | + | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", | |
| 3957 | + | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", | |
| 3958 | + | "dev": true, | |
| 3959 | + | "license": "MIT" | |
| 3960 | + | }, | |
| 3961 | + | "node_modules/update-browserslist-db": { | |
| 3962 | + | "version": "1.1.3", | |
| 3963 | + | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", | |
| 3964 | + | "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", | |
| 3965 | + | "dev": true, | |
| 3966 | + | "funding": [ | |
| 3967 | + | { | |
| 3968 | + | "type": "opencollective", | |
| 3969 | + | "url": "https://opencollective.com/browserslist" | |
| 3970 | + | }, | |
| 3971 | + | { | |
| 3972 | + | "type": "tidelift", | |
| 3973 | + | "url": "https://tidelift.com/funding/github/npm/browserslist" | |
| 3974 | + | }, | |
| 3975 | + | { | |
| 3976 | + | "type": "github", | |
| 3977 | + | "url": "https://github.com/sponsors/ai" | |
| 3978 | + | } | |
| 3979 | + | ], | |
| 3980 | + | "license": "MIT", | |
| 3981 | + | "dependencies": { | |
| 3982 | + | "escalade": "^3.2.0", | |
| 3983 | + | "picocolors": "^1.1.1" | |
| 3984 | + | }, | |
| 3985 | + | "bin": { | |
| 3986 | + | "update-browserslist-db": "cli.js" | |
| 3987 | + | }, | |
| 3988 | + | "peerDependencies": { | |
| 3989 | + | "browserslist": ">= 4.21.0" | |
| 3990 | + | } | |
| 3991 | + | }, | |
| 3992 | + | "node_modules/uri-js": { | |
| 3993 | + | "version": "4.4.1", | |
| 3994 | + | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", | |
| 3995 | + | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", | |
| 3996 | + | "dev": true, | |
| 3997 | + | "license": "BSD-2-Clause", | |
| 3998 | + | "dependencies": { | |
| 3999 | + | "punycode": "^2.1.0" | |
| 4000 | + | } | |
| 4001 | + | }, | |
| 4002 | + | "node_modules/vite": { | |
| 4003 | + | "version": "5.4.20", | |
| 4004 | + | "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", | |
| 4005 | + | "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", | |
| 4006 | + | "dev": true, | |
| 4007 | + | "license": "MIT", | |
| 4008 | + | "dependencies": { | |
| 4009 | + | "esbuild": "^0.21.3", | |
| 4010 | + | "postcss": "^8.4.43", | |
| 4011 | + | "rollup": "^4.20.0" | |
| 4012 | + | }, | |
| 4013 | + | "bin": { | |
| 4014 | + | "vite": "bin/vite.js" | |
| 4015 | + | }, | |
| 4016 | + | "engines": { | |
| 4017 | + | "node": "^18.0.0 || >=20.0.0" | |
| 4018 | + | }, | |
| 4019 | + | "funding": { | |
| 4020 | + | "url": "https://github.com/vitejs/vite?sponsor=1" | |
| 4021 | + | }, | |
| 4022 | + | "optionalDependencies": { | |
| 4023 | + | "fsevents": "~2.3.3" | |
| 4024 | + | }, | |
| 4025 | + | "peerDependencies": { | |
| 4026 | + | "@types/node": "^18.0.0 || >=20.0.0", | |
| 4027 | + | "less": "*", | |
| 4028 | + | "lightningcss": "^1.21.0", | |
| 4029 | + | "sass": "*", | |
| 4030 | + | "sass-embedded": "*", | |
| 4031 | + | "stylus": "*", | |
| 4032 | + | "sugarss": "*", | |
| 4033 | + | "terser": "^5.4.0" | |
| 4034 | + | }, | |
| 4035 | + | "peerDependenciesMeta": { | |
| 4036 | + | "@types/node": { | |
| 4037 | + | "optional": true | |
| 4038 | + | }, | |
| 4039 | + | "less": { | |
| 4040 | + | "optional": true | |
| 4041 | + | }, | |
| 4042 | + | "lightningcss": { | |
| 4043 | + | "optional": true | |
| 4044 | + | }, | |
| 4045 | + | "sass": { | |
| 4046 | + | "optional": true | |
| 4047 | + | }, | |
| 4048 | + | "sass-embedded": { | |
| 4049 | + | "optional": true | |
| 4050 | + | }, | |
| 4051 | + | "stylus": { | |
| 4052 | + | "optional": true | |
| 4053 | + | }, | |
| 4054 | + | "sugarss": { | |
| 4055 | + | "optional": true | |
| 4056 | + | }, | |
| 4057 | + | "terser": { | |
| 4058 | + | "optional": true | |
| 4059 | + | } | |
| 4060 | + | } | |
| 4061 | + | }, | |
| 4062 | + | "node_modules/vite/node_modules/@esbuild/aix-ppc64": { | |
| 4063 | + | "version": "0.21.5", | |
| 4064 | + | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", | |
| 4065 | + | "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", | |
| 4066 | + | "cpu": [ | |
| 4067 | + | "ppc64" | |
| 4068 | + | ], | |
| 4069 | + | "dev": true, | |
| 4070 | + | "license": "MIT", | |
| 4071 | + | "optional": true, | |
| 4072 | + | "os": [ | |
| 4073 | + | "aix" | |
| 4074 | + | ], | |
| 4075 | + | "engines": { | |
| 4076 | + | "node": ">=12" | |
| 4077 | + | } | |
| 4078 | + | }, | |
| 4079 | + | "node_modules/vite/node_modules/@esbuild/android-arm": { | |
| 4080 | + | "version": "0.21.5", | |
| 4081 | + | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", | |
| 4082 | + | "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", | |
| 4083 | + | "cpu": [ | |
| 4084 | + | "arm" | |
| 4085 | + | ], | |
| 4086 | + | "dev": true, | |
| 4087 | + | "license": "MIT", | |
| 4088 | + | "optional": true, | |
| 4089 | + | "os": [ | |
| 4090 | + | "android" | |
| 4091 | + | ], | |
| 4092 | + | "engines": { | |
| 4093 | + | "node": ">=12" | |
| 4094 | + | } | |
| 4095 | + | }, | |
| 4096 | + | "node_modules/vite/node_modules/@esbuild/android-arm64": { | |
| 4097 | + | "version": "0.21.5", | |
| 4098 | + | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", | |
| 4099 | + | "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", | |
| 4100 | + | "cpu": [ | |
| 4101 | + | "arm64" | |
| 4102 | + | ], | |
| 4103 | + | "dev": true, | |
| 4104 | + | "license": "MIT", | |
| 4105 | + | "optional": true, | |
| 4106 | + | "os": [ | |
| 4107 | + | "android" | |
| 4108 | + | ], | |
| 4109 | + | "engines": { | |
| 4110 | + | "node": ">=12" | |
| 4111 | + | } | |
| 4112 | + | }, | |
| 4113 | + | "node_modules/vite/node_modules/@esbuild/android-x64": { | |
| 4114 | + | "version": "0.21.5", | |
| 4115 | + | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", | |
| 4116 | + | "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", | |
| 4117 | + | "cpu": [ | |
| 4118 | + | "x64" | |
| 4119 | + | ], | |
| 4120 | + | "dev": true, | |
| 4121 | + | "license": "MIT", | |
| 4122 | + | "optional": true, | |
| 4123 | + | "os": [ | |
| 4124 | + | "android" | |
| 4125 | + | ], | |
| 4126 | + | "engines": { | |
| 4127 | + | "node": ">=12" | |
| 4128 | + | } | |
| 4129 | + | }, | |
| 4130 | + | "node_modules/vite/node_modules/@esbuild/darwin-arm64": { | |
| 4131 | + | "version": "0.21.5", | |
| 4132 | + | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", | |
| 4133 | + | "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", | |
| 4134 | + | "cpu": [ | |
| 4135 | + | "arm64" | |
| 4136 | + | ], | |
| 4137 | + | "dev": true, | |
| 4138 | + | "license": "MIT", | |
| 4139 | + | "optional": true, | |
| 4140 | + | "os": [ | |
| 4141 | + | "darwin" | |
| 4142 | + | ], | |
| 4143 | + | "engines": { | |
| 4144 | + | "node": ">=12" | |
| 4145 | + | } | |
| 4146 | + | }, | |
| 4147 | + | "node_modules/vite/node_modules/@esbuild/darwin-x64": { | |
| 4148 | + | "version": "0.21.5", | |
| 4149 | + | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", | |
| 4150 | + | "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", | |
| 4151 | + | "cpu": [ | |
| 4152 | + | "x64" | |
| 4153 | + | ], | |
| 4154 | + | "dev": true, | |
| 4155 | + | "license": "MIT", | |
| 4156 | + | "optional": true, | |
| 4157 | + | "os": [ | |
| 4158 | + | "darwin" | |
| 4159 | + | ], | |
| 4160 | + | "engines": { | |
| 4161 | + | "node": ">=12" | |
| 4162 | + | } | |
| 4163 | + | }, | |
| 4164 | + | "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { | |
| 4165 | + | "version": "0.21.5", | |
| 4166 | + | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", | |
| 4167 | + | "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", | |
| 4168 | + | "cpu": [ | |
| 4169 | + | "arm64" | |
| 4170 | + | ], | |
| 4171 | + | "dev": true, | |
| 4172 | + | "license": "MIT", | |
| 4173 | + | "optional": true, | |
| 4174 | + | "os": [ | |
| 4175 | + | "freebsd" | |
| 4176 | + | ], | |
| 4177 | + | "engines": { | |
| 4178 | + | "node": ">=12" | |
| 4179 | + | } | |
| 4180 | + | }, | |
| 4181 | + | "node_modules/vite/node_modules/@esbuild/freebsd-x64": { | |
| 4182 | + | "version": "0.21.5", | |
| 4183 | + | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", | |
| 4184 | + | "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", | |
| 4185 | + | "cpu": [ | |
| 4186 | + | "x64" | |
| 4187 | + | ], | |
| 4188 | + | "dev": true, | |
| 4189 | + | "license": "MIT", | |
| 4190 | + | "optional": true, | |
| 4191 | + | "os": [ | |
| 4192 | + | "freebsd" | |
| 4193 | + | ], | |
| 4194 | + | "engines": { | |
| 4195 | + | "node": ">=12" | |
| 4196 | + | } | |
| 4197 | + | }, | |
| 4198 | + | "node_modules/vite/node_modules/@esbuild/linux-arm": { | |
| 4199 | + | "version": "0.21.5", | |
| 4200 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", | |
| 4201 | + | "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", | |
| 4202 | + | "cpu": [ | |
| 4203 | + | "arm" | |
| 4204 | + | ], | |
| 4205 | + | "dev": true, | |
| 4206 | + | "license": "MIT", | |
| 4207 | + | "optional": true, | |
| 4208 | + | "os": [ | |
| 4209 | + | "linux" | |
| 4210 | + | ], | |
| 4211 | + | "engines": { | |
| 4212 | + | "node": ">=12" | |
| 4213 | + | } | |
| 4214 | + | }, | |
| 4215 | + | "node_modules/vite/node_modules/@esbuild/linux-arm64": { | |
| 4216 | + | "version": "0.21.5", | |
| 4217 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", | |
| 4218 | + | "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", | |
| 4219 | + | "cpu": [ | |
| 4220 | + | "arm64" | |
| 4221 | + | ], | |
| 4222 | + | "dev": true, | |
| 4223 | + | "license": "MIT", | |
| 4224 | + | "optional": true, | |
| 4225 | + | "os": [ | |
| 4226 | + | "linux" | |
| 4227 | + | ], | |
| 4228 | + | "engines": { | |
| 4229 | + | "node": ">=12" | |
| 4230 | + | } | |
| 4231 | + | }, | |
| 4232 | + | "node_modules/vite/node_modules/@esbuild/linux-ia32": { | |
| 4233 | + | "version": "0.21.5", | |
| 4234 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", | |
| 4235 | + | "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", | |
| 4236 | + | "cpu": [ | |
| 4237 | + | "ia32" | |
| 4238 | + | ], | |
| 4239 | + | "dev": true, | |
| 4240 | + | "license": "MIT", | |
| 4241 | + | "optional": true, | |
| 4242 | + | "os": [ | |
| 4243 | + | "linux" | |
| 4244 | + | ], | |
| 4245 | + | "engines": { | |
| 4246 | + | "node": ">=12" | |
| 4247 | + | } | |
| 4248 | + | }, | |
| 4249 | + | "node_modules/vite/node_modules/@esbuild/linux-loong64": { | |
| 4250 | + | "version": "0.21.5", | |
| 4251 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", | |
| 4252 | + | "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", | |
| 4253 | + | "cpu": [ | |
| 4254 | + | "loong64" | |
| 4255 | + | ], | |
| 4256 | + | "dev": true, | |
| 4257 | + | "license": "MIT", | |
| 4258 | + | "optional": true, | |
| 4259 | + | "os": [ | |
| 4260 | + | "linux" | |
| 4261 | + | ], | |
| 4262 | + | "engines": { | |
| 4263 | + | "node": ">=12" | |
| 4264 | + | } | |
| 4265 | + | }, | |
| 4266 | + | "node_modules/vite/node_modules/@esbuild/linux-mips64el": { | |
| 4267 | + | "version": "0.21.5", | |
| 4268 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", | |
| 4269 | + | "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", | |
| 4270 | + | "cpu": [ | |
| 4271 | + | "mips64el" | |
| 4272 | + | ], | |
| 4273 | + | "dev": true, | |
| 4274 | + | "license": "MIT", | |
| 4275 | + | "optional": true, | |
| 4276 | + | "os": [ | |
| 4277 | + | "linux" | |
| 4278 | + | ], | |
| 4279 | + | "engines": { | |
| 4280 | + | "node": ">=12" | |
| 4281 | + | } | |
| 4282 | + | }, | |
| 4283 | + | "node_modules/vite/node_modules/@esbuild/linux-ppc64": { | |
| 4284 | + | "version": "0.21.5", | |
| 4285 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", | |
| 4286 | + | "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", | |
| 4287 | + | "cpu": [ | |
| 4288 | + | "ppc64" | |
| 4289 | + | ], | |
| 4290 | + | "dev": true, | |
| 4291 | + | "license": "MIT", | |
| 4292 | + | "optional": true, | |
| 4293 | + | "os": [ | |
| 4294 | + | "linux" | |
| 4295 | + | ], | |
| 4296 | + | "engines": { | |
| 4297 | + | "node": ">=12" | |
| 4298 | + | } | |
| 4299 | + | }, | |
| 4300 | + | "node_modules/vite/node_modules/@esbuild/linux-riscv64": { | |
| 4301 | + | "version": "0.21.5", | |
| 4302 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", | |
| 4303 | + | "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", | |
| 4304 | + | "cpu": [ | |
| 4305 | + | "riscv64" | |
| 4306 | + | ], | |
| 4307 | + | "dev": true, | |
| 4308 | + | "license": "MIT", | |
| 4309 | + | "optional": true, | |
| 4310 | + | "os": [ | |
| 4311 | + | "linux" | |
| 4312 | + | ], | |
| 4313 | + | "engines": { | |
| 4314 | + | "node": ">=12" | |
| 4315 | + | } | |
| 4316 | + | }, | |
| 4317 | + | "node_modules/vite/node_modules/@esbuild/linux-s390x": { | |
| 4318 | + | "version": "0.21.5", | |
| 4319 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", | |
| 4320 | + | "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", | |
| 4321 | + | "cpu": [ | |
| 4322 | + | "s390x" | |
| 4323 | + | ], | |
| 4324 | + | "dev": true, | |
| 4325 | + | "license": "MIT", | |
| 4326 | + | "optional": true, | |
| 4327 | + | "os": [ | |
| 4328 | + | "linux" | |
| 4329 | + | ], | |
| 4330 | + | "engines": { | |
| 4331 | + | "node": ">=12" | |
| 4332 | + | } | |
| 4333 | + | }, | |
| 4334 | + | "node_modules/vite/node_modules/@esbuild/linux-x64": { | |
| 4335 | + | "version": "0.21.5", | |
| 4336 | + | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", | |
| 4337 | + | "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", | |
| 4338 | + | "cpu": [ | |
| 4339 | + | "x64" | |
| 4340 | + | ], | |
| 4341 | + | "dev": true, | |
| 4342 | + | "license": "MIT", | |
| 4343 | + | "optional": true, | |
| 4344 | + | "os": [ | |
| 4345 | + | "linux" | |
| 4346 | + | ], | |
| 4347 | + | "engines": { | |
| 4348 | + | "node": ">=12" | |
| 4349 | + | } | |
| 4350 | + | }, | |
| 4351 | + | "node_modules/vite/node_modules/@esbuild/netbsd-x64": { | |
| 4352 | + | "version": "0.21.5", | |
| 4353 | + | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", | |
| 4354 | + | "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", | |
| 4355 | + | "cpu": [ | |
| 4356 | + | "x64" | |
| 4357 | + | ], | |
| 4358 | + | "dev": true, | |
| 4359 | + | "license": "MIT", | |
| 4360 | + | "optional": true, | |
| 4361 | + | "os": [ | |
| 4362 | + | "netbsd" | |
| 4363 | + | ], | |
| 4364 | + | "engines": { | |
| 4365 | + | "node": ">=12" | |
| 4366 | + | } | |
| 4367 | + | }, | |
| 4368 | + | "node_modules/vite/node_modules/@esbuild/openbsd-x64": { | |
| 4369 | + | "version": "0.21.5", | |
| 4370 | + | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", | |
| 4371 | + | "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", | |
| 4372 | + | "cpu": [ | |
| 4373 | + | "x64" | |
| 4374 | + | ], | |
| 4375 | + | "dev": true, | |
| 4376 | + | "license": "MIT", | |
| 4377 | + | "optional": true, | |
| 4378 | + | "os": [ | |
| 4379 | + | "openbsd" | |
| 4380 | + | ], | |
| 4381 | + | "engines": { | |
| 4382 | + | "node": ">=12" | |
| 4383 | + | } | |
| 4384 | + | }, | |
| 4385 | + | "node_modules/vite/node_modules/@esbuild/sunos-x64": { | |
| 4386 | + | "version": "0.21.5", | |
| 4387 | + | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", | |
| 4388 | + | "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", | |
| 4389 | + | "cpu": [ | |
| 4390 | + | "x64" | |
| 4391 | + | ], | |
| 4392 | + | "dev": true, | |
| 4393 | + | "license": "MIT", | |
| 4394 | + | "optional": true, | |
| 4395 | + | "os": [ | |
| 4396 | + | "sunos" | |
| 4397 | + | ], | |
| 4398 | + | "engines": { | |
| 4399 | + | "node": ">=12" | |
| 4400 | + | } | |
| 4401 | + | }, | |
| 4402 | + | "node_modules/vite/node_modules/@esbuild/win32-arm64": { | |
| 4403 | + | "version": "0.21.5", | |
| 4404 | + | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", | |
| 4405 | + | "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", | |
| 4406 | + | "cpu": [ | |
| 4407 | + | "arm64" | |
| 4408 | + | ], | |
| 4409 | + | "dev": true, | |
| 4410 | + | "license": "MIT", | |
| 4411 | + | "optional": true, | |
| 4412 | + | "os": [ | |
| 4413 | + | "win32" | |
| 4414 | + | ], | |
| 4415 | + | "engines": { | |
| 4416 | + | "node": ">=12" | |
| 4417 | + | } | |
| 4418 | + | }, | |
| 4419 | + | "node_modules/vite/node_modules/@esbuild/win32-ia32": { | |
| 4420 | + | "version": "0.21.5", | |
| 4421 | + | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", | |
| 4422 | + | "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", | |
| 4423 | + | "cpu": [ | |
| 4424 | + | "ia32" | |
| 4425 | + | ], | |
| 4426 | + | "dev": true, | |
| 4427 | + | "license": "MIT", | |
| 4428 | + | "optional": true, | |
| 4429 | + | "os": [ | |
| 4430 | + | "win32" | |
| 4431 | + | ], | |
| 4432 | + | "engines": { | |
| 4433 | + | "node": ">=12" | |
| 4434 | + | } | |
| 4435 | + | }, | |
| 4436 | + | "node_modules/vite/node_modules/@esbuild/win32-x64": { | |
| 4437 | + | "version": "0.21.5", | |
| 4438 | + | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", | |
| 4439 | + | "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", | |
| 4440 | + | "cpu": [ | |
| 4441 | + | "x64" | |
| 4442 | + | ], | |
| 4443 | + | "dev": true, | |
| 4444 | + | "license": "MIT", | |
| 4445 | + | "optional": true, | |
| 4446 | + | "os": [ | |
| 4447 | + | "win32" | |
| 4448 | + | ], | |
| 4449 | + | "engines": { | |
| 4450 | + | "node": ">=12" | |
| 4451 | + | } | |
| 4452 | + | }, | |
| 4453 | + | "node_modules/vite/node_modules/esbuild": { | |
| 4454 | + | "version": "0.21.5", | |
| 4455 | + | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", | |
| 4456 | + | "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", | |
| 4457 | + | "dev": true, | |
| 4458 | + | "hasInstallScript": true, | |
| 4459 | + | "license": "MIT", | |
| 4460 | + | "bin": { | |
| 4461 | + | "esbuild": "bin/esbuild" | |
| 4462 | + | }, | |
| 4463 | + | "engines": { | |
| 4464 | + | "node": ">=12" | |
| 4465 | + | }, | |
| 4466 | + | "optionalDependencies": { | |
| 4467 | + | "@esbuild/aix-ppc64": "0.21.5", | |
| 4468 | + | "@esbuild/android-arm": "0.21.5", | |
| 4469 | + | "@esbuild/android-arm64": "0.21.5", | |
| 4470 | + | "@esbuild/android-x64": "0.21.5", | |
| 4471 | + | "@esbuild/darwin-arm64": "0.21.5", | |
| 4472 | + | "@esbuild/darwin-x64": "0.21.5", | |
| 4473 | + | "@esbuild/freebsd-arm64": "0.21.5", | |
| 4474 | + | "@esbuild/freebsd-x64": "0.21.5", | |
| 4475 | + | "@esbuild/linux-arm": "0.21.5", | |
| 4476 | + | "@esbuild/linux-arm64": "0.21.5", | |
| 4477 | + | "@esbuild/linux-ia32": "0.21.5", | |
| 4478 | + | "@esbuild/linux-loong64": "0.21.5", | |
| 4479 | + | "@esbuild/linux-mips64el": "0.21.5", | |
| 4480 | + | "@esbuild/linux-ppc64": "0.21.5", | |
| 4481 | + | "@esbuild/linux-riscv64": "0.21.5", | |
| 4482 | + | "@esbuild/linux-s390x": "0.21.5", | |
| 4483 | + | "@esbuild/linux-x64": "0.21.5", | |
| 4484 | + | "@esbuild/netbsd-x64": "0.21.5", | |
| 4485 | + | "@esbuild/openbsd-x64": "0.21.5", | |
| 4486 | + | "@esbuild/sunos-x64": "0.21.5", | |
| 4487 | + | "@esbuild/win32-arm64": "0.21.5", | |
| 4488 | + | "@esbuild/win32-ia32": "0.21.5", | |
| 4489 | + | "@esbuild/win32-x64": "0.21.5" | |
| 4490 | + | } | |
| 4491 | + | }, | |
| 4492 | + | "node_modules/vitefu": { | |
| 4493 | + | "version": "1.1.1", | |
| 4494 | + | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", | |
| 4495 | + | "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", | |
| 4496 | + | "dev": true, | |
| 4497 | + | "license": "MIT", | |
| 4498 | + | "workspaces": [ | |
| 4499 | + | "tests/deps/*", | |
| 4500 | + | "tests/projects/*", | |
| 4501 | + | "tests/projects/workspace/packages/*" | |
| 4502 | + | ], | |
| 4503 | + | "peerDependencies": { | |
| 4504 | + | "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" | |
| 4505 | + | }, | |
| 4506 | + | "peerDependenciesMeta": { | |
| 4507 | + | "vite": { | |
| 4508 | + | "optional": true | |
| 4509 | + | } | |
| 4510 | + | } | |
| 4511 | + | }, | |
| 4512 | + | "node_modules/which": { | |
| 4513 | + | "version": "2.0.2", | |
| 4514 | + | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", | |
| 4515 | + | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", | |
| 4516 | + | "dev": true, | |
| 4517 | + | "license": "ISC", | |
| 4518 | + | "dependencies": { | |
| 4519 | + | "isexe": "^2.0.0" | |
| 4520 | + | }, | |
| 4521 | + | "bin": { | |
| 4522 | + | "node-which": "bin/node-which" | |
| 4523 | + | }, | |
| 4524 | + | "engines": { | |
| 4525 | + | "node": ">= 8" | |
| 4526 | + | } | |
| 4527 | + | }, | |
| 4528 | + | "node_modules/word-wrap": { | |
| 4529 | + | "version": "1.2.5", | |
| 4530 | + | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", | |
| 4531 | + | "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", | |
| 4532 | + | "dev": true, | |
| 4533 | + | "license": "MIT", | |
| 4534 | + | "engines": { | |
| 4535 | + | "node": ">=0.10.0" | |
| 4536 | + | } | |
| 4537 | + | }, | |
| 4538 | + | "node_modules/wrappy": { | |
| 4539 | + | "version": "1.0.2", | |
| 4540 | + | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | |
| 4541 | + | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", | |
| 4542 | + | "dev": true, | |
| 4543 | + | "license": "ISC" | |
| 4544 | + | }, | |
| 4545 | + | "node_modules/yallist": { | |
| 4546 | + | "version": "5.0.0", | |
| 4547 | + | "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", | |
| 4548 | + | "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", | |
| 4549 | + | "dev": true, | |
| 4550 | + | "license": "BlueOak-1.0.0", | |
| 4551 | + | "engines": { | |
| 4552 | + | "node": ">=18" | |
| 4553 | + | } | |
| 4554 | + | }, | |
| 4555 | + | "node_modules/yocto-queue": { | |
| 4556 | + | "version": "0.1.0", | |
| 4557 | + | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", | |
| 4558 | + | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", | |
| 4559 | + | "dev": true, | |
| 4560 | + | "license": "MIT", | |
| 4561 | + | "engines": { | |
| 4562 | + | "node": ">=10" | |
| 4563 | + | }, | |
| 4564 | + | "funding": { | |
| 4565 | + | "url": "https://github.com/sponsors/sindresorhus" | |
| 4566 | + | } | |
| 4567 | + | }, | |
| 4568 | + | "node_modules/zimmerframe": { | |
| 4569 | + | "version": "1.1.4", | |
| 4570 | + | "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", | |
| 4571 | + | "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", | |
| 4572 | + | "dev": true, | |
| 4573 | + | "license": "MIT" | |
| 4574 | + | } | |
| 4575 | + | } | |
| 4576 | + | } | |
A gui/package.json +33 -0
| @@ -0,0 +1,33 @@ | |||
| 1 | + | { | |
| 2 | + | "name": "@dumber/gui", | |
| 3 | + | "version": "0.1.0", | |
| 4 | + | "private": true, | |
| 5 | + | "type": "module", | |
| 6 | + | "scripts": { | |
| 7 | + | "build": "npm run build:gui && npm run build:homepage", | |
| 8 | + | "build:gui": "vite build --config vite.config.gui.ts", | |
| 9 | + | "build:homepage": "vite build --config vite.config.homepage.ts", | |
| 10 | + | "dev": "npm run build:gui -- --watch", | |
| 11 | + | "dev:homepage": "npm run build:homepage -- --watch", | |
| 12 | + | "check": "svelte-check", | |
| 13 | + | "lint": "eslint src --fix", | |
| 14 | + | "generate:types": "node ../scripts/generate-types.js" | |
| 15 | + | }, | |
| 16 | + | "devDependencies": { | |
| 17 | + | "@sveltejs/vite-plugin-svelte": "^4.0.0", | |
| 18 | + | "@tailwindcss/cli": "^4.0.0", | |
| 19 | + | "@tailwindcss/postcss": "^4.1.13", | |
| 20 | + | "@types/node": "^20.0.0", | |
| 21 | + | "@typescript-eslint/eslint-plugin": "^7.0.0", | |
| 22 | + | "@typescript-eslint/parser": "^7.0.0", | |
| 23 | + | "autoprefixer": "^10.4.20", | |
| 24 | + | "eslint": "^8.57.0", | |
| 25 | + | "postcss": "^8.4.47", | |
| 26 | + | "svelte": "^5.0.0", | |
| 27 | + | "svelte-check": "^4.0.0", | |
| 28 | + | "tailwindcss": "^4.0.0", | |
| 29 | + | "typescript": "^5.3.0", | |
| 30 | + | "typescript-eslint": "^8.43.0", | |
| 31 | + | "vite": "^5.0.0" | |
| 32 | + | } | |
| 33 | + | } | |
A gui/postcss.config.js +6 -0
| @@ -0,0 +1,6 @@ | |||
| 1 | + | export default { | |
| 2 | + | plugins: { | |
| 3 | + | '@tailwindcss/postcss': {}, | |
| 4 | + | autoprefixer: {}, | |
| 5 | + | }, | |
| 6 | + | };⏎̸ | |
A gui/src/build-html.ts +24 -0
| @@ -0,0 +1,24 @@ | |||
| 1 | + | import { writeFileSync } from 'fs'; | |
| 2 | + | import { join } from 'path'; | |
| 3 | + | import { HTMLBuilder } from './utils/html-builder.js'; | |
| 4 | + | ||
| 5 | + | // Generate the HTML file | |
| 6 | + | function buildHTML() { | |
| 7 | + | try { | |
| 8 | + | const html = HTMLBuilder.createBaseHTML(); | |
| 9 | + | const outputPath = join(process.cwd(), 'dist', 'index.html'); | |
| 10 | + | writeFileSync(outputPath, html); | |
| 11 | + | // Also emit favicon.svg as a file for dumb:// scheme lookups | |
| 12 | + | const favPath = join(process.cwd(), 'dist', 'favicon.svg'); | |
| 13 | + | writeFileSync(favPath, HTMLBuilder.getFaviconSVG()); | |
| 14 | + | console.log('✓ Generated index.html'); | |
| 15 | + | } catch (error) { | |
| 16 | + | console.error('✗ Failed to generate HTML:', error); | |
| 17 | + | process.exit(1); | |
| 18 | + | } | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | // Only run when called directly (not imported) | |
| 22 | + | if (import.meta.url === `file://${process.argv[1]}`) { | |
| 23 | + | buildHTML(); | |
| 24 | + | } | |
A gui/src/components/omnibox/Omnibox.svelte +209 -0
| @@ -0,0 +1,209 @@ | |||
| 1 | + | <!-- | |
| 2 | + | Omnibox Component | |
| 3 | + | ||
| 4 | + | Main container for omnibox/find functionality using Svelte 5 runes | |
| 5 | + | --> | |
| 6 | + | <script lang="ts"> | |
| 7 | + | import { onMount, onDestroy } from 'svelte'; | |
| 8 | + | import OmniboxInput from './OmniboxInput.svelte'; | |
| 9 | + | import OmniboxSuggestions from './OmniboxSuggestions.svelte'; | |
| 10 | + | import OmniboxFind from './OmniboxFind.svelte'; | |
| 11 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 12 | + | import { omniboxBridge } from './messaging'; | |
| 13 | + | ||
| 14 | + | // Reactive state from store | |
| 15 | + | let visible = $derived(omniboxStore.visible); | |
| 16 | + | let mode = $derived(omniboxStore.mode); | |
| 17 | + | let faded = $derived(omniboxStore.faded); | |
| 18 | + | ||
| 19 | + | // Component refs | |
| 20 | + | let boxElement: HTMLDivElement; | |
| 21 | + | let inputElement = $state<HTMLInputElement>(); | |
| 22 | + | ||
| 23 | + | // Handle click outside to close | |
| 24 | + | function handleOverlayClick(event: MouseEvent) { | |
| 25 | + | const target = event.target as HTMLElement; | |
| 26 | + | if (target && boxElement && !boxElement.contains(target)) { | |
| 27 | + | event.preventDefault(); | |
| 28 | + | event.stopPropagation(); | |
| 29 | + | omniboxStore.close(); | |
| 30 | + | } | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | // Handle box click to prevent propagation | |
| 34 | + | function handleBoxClick(event: MouseEvent) { | |
| 35 | + | event.stopPropagation(); | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // Handle mouse enter to focus input and clear fade | |
| 39 | + | function handleMouseEnter() { | |
| 40 | + | if (visible && inputElement) { | |
| 41 | + | try { | |
| 42 | + | inputElement.focus({ preventScroll: true }); | |
| 43 | + | } catch { | |
| 44 | + | inputElement.focus(); | |
| 45 | + | } | |
| 46 | + | omniboxStore.setFaded(false); | |
| 47 | + | } | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Focus input when component becomes visible | |
| 51 | + | $effect(() => { | |
| 52 | + | if (visible && inputElement) { | |
| 53 | + | inputElement.focus(); | |
| 54 | + | } | |
| 55 | + | }); | |
| 56 | + | ||
| 57 | + | ||
| 58 | + | // Apply faded styling effect (matching original JS implementation) | |
| 59 | + | $effect(() => { | |
| 60 | + | if (!boxElement || !inputElement) return; | |
| 61 | + | ||
| 62 | + | if (faded) { | |
| 63 | + | // Faded state - semi-transparent with backdrop blur | |
| 64 | + | boxElement.style.background = 'rgba(27,27,27,0.25)'; | |
| 65 | + | boxElement.style.backdropFilter = 'blur(2px) saturate(110%)'; | |
| 66 | + | (boxElement.style as any).webkitBackdropFilter = 'blur(2px) saturate(110%)'; | |
| 67 | + | inputElement.style.background = 'rgba(18,18,18,0.35)'; | |
| 68 | + | inputElement.style.color = '#eee'; | |
| 69 | + | } else { | |
| 70 | + | // Normal state - solid background | |
| 71 | + | boxElement.style.background = '#1b1b1b'; | |
| 72 | + | boxElement.style.backdropFilter = ''; | |
| 73 | + | (boxElement.style as any).webkitBackdropFilter = ''; | |
| 74 | + | inputElement.style.background = '#121212'; | |
| 75 | + | inputElement.style.color = '#eee'; | |
| 76 | + | } | |
| 77 | + | }); | |
| 78 | + | ||
| 79 | + | // Global click handler to close omnibox when clicking anywhere outside | |
| 80 | + | function handleGlobalClick(event: MouseEvent) { | |
| 81 | + | if (!visible) return; | |
| 82 | + | ||
| 83 | + | const target = event.target as HTMLElement; | |
| 84 | + | const omniboxContainer = document.getElementById('dumber-omnibox-root'); | |
| 85 | + | ||
| 86 | + | // Close if clicking outside the omnibox container | |
| 87 | + | if (omniboxContainer && !omniboxContainer.contains(target)) { | |
| 88 | + | omniboxStore.close(); | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | onMount(() => { | |
| 93 | + | console.log('🔧 Omnibox component mounted'); | |
| 94 | + | ||
| 95 | + | // Add global click listener | |
| 96 | + | document.addEventListener('click', handleGlobalClick, true); | |
| 97 | + | ||
| 98 | + | try { | |
| 99 | + | // Set up global API for Go bridge | |
| 100 | + | window.__dumber_omnibox = { | |
| 101 | + | setSuggestions: (suggestions) => { | |
| 102 | + | try { | |
| 103 | + | console.log('📋 setSuggestions called with:', suggestions?.length || 0, 'items'); | |
| 104 | + | omniboxBridge.setSuggestions(suggestions); | |
| 105 | + | } catch (error) { | |
| 106 | + | console.error('Error in setSuggestions:', error); | |
| 107 | + | } | |
| 108 | + | }, | |
| 109 | + | toggle: () => { | |
| 110 | + | try { | |
| 111 | + | console.log('🔄 Omnibox toggle called, current visible:', omniboxStore.visible); | |
| 112 | + | omniboxStore.toggle(); | |
| 113 | + | console.log('🔄 After toggle, visible:', omniboxStore.visible); | |
| 114 | + | } catch (error) { | |
| 115 | + | console.error('Error in toggle:', error); | |
| 116 | + | } | |
| 117 | + | }, | |
| 118 | + | open: (mode, query) => { | |
| 119 | + | try { | |
| 120 | + | console.log('🚪 Omnibox open called with mode:', mode, 'query:', query); | |
| 121 | + | omniboxStore.open(mode as any, query); | |
| 122 | + | console.log('🚪 After open, visible:', omniboxStore.visible, 'mode:', omniboxStore.mode); | |
| 123 | + | } catch (error) { | |
| 124 | + | console.error('Error in open:', error); | |
| 125 | + | } | |
| 126 | + | }, | |
| 127 | + | close: () => { | |
| 128 | + | try { | |
| 129 | + | console.log('🚪 Omnibox close called'); | |
| 130 | + | omniboxStore.close(); | |
| 131 | + | } catch (error) { | |
| 132 | + | console.error('Error in close:', error); | |
| 133 | + | } | |
| 134 | + | }, | |
| 135 | + | findQuery: (query) => { | |
| 136 | + | try { | |
| 137 | + | console.log('🔍 Find query called with:', query); | |
| 138 | + | if (omniboxStore.mode !== 'find') { | |
| 139 | + | omniboxStore.setMode('find'); | |
| 140 | + | } | |
| 141 | + | if (!omniboxStore.visible) { | |
| 142 | + | omniboxStore.setVisible(true); | |
| 143 | + | } | |
| 144 | + | omniboxStore.setInputValue(query || ''); | |
| 145 | + | // Find will be triggered by input value change | |
| 146 | + | } catch (error) { | |
| 147 | + | console.error('Error in findQuery:', error); | |
| 148 | + | } | |
| 149 | + | } | |
| 150 | + | }; | |
| 151 | + | ||
| 152 | + | console.log('✅ Omnibox API exposed:', Object.keys(window.__dumber_omnibox)); | |
| 153 | + | } catch (error) { | |
| 154 | + | console.error('❌ Failed to set up omnibox global API:', error); | |
| 155 | + | } | |
| 156 | + | }); | |
| 157 | + | ||
| 158 | + | onDestroy(() => { | |
| 159 | + | // Cleanup global click listener | |
| 160 | + | document.removeEventListener('click', handleGlobalClick, true); | |
| 161 | + | ||
| 162 | + | // Reset omnibox state completely | |
| 163 | + | omniboxStore.reset(); | |
| 164 | + | ||
| 165 | + | // Cleanup global API | |
| 166 | + | if (window.__dumber_omnibox) { | |
| 167 | + | delete window.__dumber_omnibox; | |
| 168 | + | } | |
| 169 | + | }); | |
| 170 | + | </script> | |
| 171 | + | ||
| 172 | + | <!-- Overlay container --> | |
| 173 | + | <div | |
| 174 | + | class="fixed inset-0 z-[2147483647]" | |
| 175 | + | style="display: {visible ? 'block' : 'none'}" | |
| 176 | + | onmousedown={handleOverlayClick} | |
| 177 | + | role="presentation" | |
| 178 | + | > | |
| 179 | + | <!-- Main omnibox container --> | |
| 180 | + | <div | |
| 181 | + | bind:this={boxElement} | |
| 182 | + | class="w-[min(90vw,720px)] mx-auto mt-[8vh] p-3 | |
| 183 | + | bg-[#1b1b1b] border border-[#444] rounded-lg shadow-[0_10px_30px_rgba(0,0,0,0.6)] | |
| 184 | + | text-[#eee] | |
| 185 | + | sm:w-[95vw] sm:p-2 | |
| 186 | + | xl:w-[min(90vw,840px)]" | |
| 187 | + | style="font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', Arial, sans-serif" | |
| 188 | + | onmousedown={handleBoxClick} | |
| 189 | + | onmouseenter={handleMouseEnter} | |
| 190 | + | role="dialog" | |
| 191 | + | tabindex="-1" | |
| 192 | + | aria-modal="true" | |
| 193 | + | aria-label={mode === 'find' ? 'Find in page' : 'Omnibox search'} | |
| 194 | + | > | |
| 195 | + | <!-- Input component --> | |
| 196 | + | <OmniboxInput bind:inputElement /> | |
| 197 | + | ||
| 198 | + | <!-- Content based on mode --> | |
| 199 | + | {#if mode === 'omnibox'} | |
| 200 | + | <OmniboxSuggestions /> | |
| 201 | + | {:else if mode === 'find'} | |
| 202 | + | <OmniboxFind /> | |
| 203 | + | {/if} | |
| 204 | + | </div> | |
| 205 | + | </div> | |
| 206 | + | ||
| 207 | + | <style> | |
| 208 | + | /* Additional custom styles if needed */ | |
| 209 | + | </style>⏎̸ | |
A gui/src/components/omnibox/OmniboxFind.svelte +102 -0
| @@ -0,0 +1,102 @@ | |||
| 1 | + | <!-- | |
| 2 | + | Omnibox Find Component | |
| 3 | + | ||
| 4 | + | Displays find results and match navigation | |
| 5 | + | --> | |
| 6 | + | <script lang="ts"> | |
| 7 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 8 | + | import { revealMatch } from './find'; | |
| 9 | + | ||
| 10 | + | // Reactive state | |
| 11 | + | let matches = $derived(omniboxStore.matches); | |
| 12 | + | let selectedIndex = $derived(omniboxStore.selectedIndex); | |
| 13 | + | let hasContent = $state(false); | |
| 14 | + | ||
| 15 | + | // Update hasContent when matches change | |
| 16 | + | $effect(() => { | |
| 17 | + | hasContent = omniboxStore.mode === 'find' && matches.length > 0; | |
| 18 | + | }); | |
| 19 | + | ||
| 20 | + | // Computed total count | |
| 21 | + | let totalMatches = $derived(matches.length); | |
| 22 | + | ||
| 23 | + | // Handle match item mouse enter | |
| 24 | + | function handleItemMouseEnter(index: number) { | |
| 25 | + | omniboxStore.setSelectedIndex(index); | |
| 26 | + | omniboxStore.setFaded(true); | |
| 27 | + | scrollToSelection(); | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | // Handle match item click | |
| 31 | + | function handleItemClick(index: number) { | |
| 32 | + | omniboxStore.setSelectedIndex(index); | |
| 33 | + | revealMatch(index); | |
| 34 | + | omniboxStore.close(); | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | // Scroll list to show selected item | |
| 38 | + | function scrollToSelection() { | |
| 39 | + | const selectedItem = document.getElementById(`find-item-${selectedIndex}`); | |
| 40 | + | if (selectedItem && selectedItem.scrollIntoView) { | |
| 41 | + | try { | |
| 42 | + | selectedItem.scrollIntoView({ block: 'nearest' }); | |
| 43 | + | } catch { | |
| 44 | + | selectedItem.scrollIntoView(); | |
| 45 | + | } | |
| 46 | + | } | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // Watch for selection changes to scroll | |
| 50 | + | $effect(() => { | |
| 51 | + | if (selectedIndex >= 0) { | |
| 52 | + | scrollToSelection(); | |
| 53 | + | } | |
| 54 | + | }); | |
| 55 | + | </script> | |
| 56 | + | ||
| 57 | + | <div | |
| 58 | + | id="find-list" | |
| 59 | + | class="mt-2 max-h-[50vh] overflow-auto border-t border-[#333]" | |
| 60 | + | role="listbox" | |
| 61 | + | aria-label="Find results" | |
| 62 | + | > | |
| 63 | + | <!-- Header with match count --> | |
| 64 | + | <div | |
| 65 | + | class="px-2.5 py-1.5 text-xs text-[#bbb] | |
| 66 | + | border-b border-[#2a2a2a]" | |
| 67 | + | > | |
| 68 | + | {#if totalMatches > 0} | |
| 69 | + | {totalMatches} match{totalMatches === 1 ? '' : 'es'} | |
| 70 | + | {:else} | |
| 71 | + | No matches | |
| 72 | + | {/if} | |
| 73 | + | </div> | |
| 74 | + | ||
| 75 | + | <!-- Match results --> | |
| 76 | + | {#if hasContent} | |
| 77 | + | {#each matches as match, index (index)} | |
| 78 | + | {@const isSelected = index === selectedIndex} | |
| 79 | + | ||
| 80 | + | <div | |
| 81 | + | id="find-item-{index}" | |
| 82 | + | class="px-2.5 py-2 cursor-pointer | |
| 83 | + | border-b border-[#2a2a2a] last:border-b-0 | |
| 84 | + | {isSelected ? 'bg-[#0a0a0a]' : ''}" | |
| 85 | + | role="option" | |
| 86 | + | tabindex="-1" | |
| 87 | + | aria-selected={isSelected} | |
| 88 | + | onmouseenter={() => handleItemMouseEnter(index)} | |
| 89 | + | onclick={() => handleItemClick(index)} | |
| 90 | + | > | |
| 91 | + | <!-- Match context --> | |
| 92 | + | <div | |
| 93 | + | class="text-[#ddd] text-sm | |
| 94 | + | whitespace-nowrap overflow-hidden text-ellipsis" | |
| 95 | + | > | |
| 96 | + | {match.context || ''} | |
| 97 | + | </div> | |
| 98 | + | </div> | |
| 99 | + | {/each} | |
| 100 | + | {/if} | |
| 101 | + | </div> | |
| 102 | + | ||
A gui/src/components/omnibox/OmniboxInput.svelte +209 -0
| @@ -0,0 +1,209 @@ | |||
| 1 | + | <!-- | |
| 2 | + | Omnibox Input Component | |
| 3 | + | ||
| 4 | + | Input field with keyboard handling and debounced search | |
| 5 | + | --> | |
| 6 | + | <script lang="ts"> | |
| 7 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 8 | + | import { debouncedQuery, omniboxBridge } from './messaging'; | |
| 9 | + | import { findInPage } from './find'; | |
| 10 | + | ||
| 11 | + | // Reactive state | |
| 12 | + | let mode = $derived(omniboxStore.mode); | |
| 13 | + | let inputValue = $derived(omniboxStore.inputValue); | |
| 14 | + | let selectedIndex = $derived(omniboxStore.selectedIndex); | |
| 15 | + | let suggestions = $derived(omniboxStore.suggestions); | |
| 16 | + | let matches = $derived(omniboxStore.matches); | |
| 17 | + | ||
| 18 | + | // Input element ref (props for parent to bind) | |
| 19 | + | interface Props { | |
| 20 | + | inputElement?: HTMLInputElement; | |
| 21 | + | } | |
| 22 | + | ||
| 23 | + | let { inputElement = $bindable() }: Props = $props(); | |
| 24 | + | ||
| 25 | + | // Computed placeholder | |
| 26 | + | let placeholder = $derived( | |
| 27 | + | mode === 'find' ? 'Find in page…' : 'Type URL or search…' | |
| 28 | + | ); | |
| 29 | + | ||
| 30 | + | // Handle input changes | |
| 31 | + | function handleInput(event: Event) { | |
| 32 | + | const target = event.target as HTMLInputElement; | |
| 33 | + | const value = target.value || ''; | |
| 34 | + | ||
| 35 | + | omniboxStore.setInputValue(value); | |
| 36 | + | omniboxStore.setFaded(false); | |
| 37 | + | ||
| 38 | + | if (mode === 'omnibox') { | |
| 39 | + | // Debounced search for omnibox | |
| 40 | + | debouncedQuery(value); | |
| 41 | + | } else if (mode === 'find') { | |
| 42 | + | // Immediate find for search | |
| 43 | + | findInPage(value); | |
| 44 | + | } | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | // Handle key events | |
| 48 | + | function handleKeyDown(event: KeyboardEvent) { | |
| 49 | + | switch (event.key) { | |
| 50 | + | case 'Escape': | |
| 51 | + | omniboxStore.close(); | |
| 52 | + | break; | |
| 53 | + | ||
| 54 | + | case 'Enter': | |
| 55 | + | event.preventDefault(); | |
| 56 | + | handleEnterKey(event); | |
| 57 | + | break; | |
| 58 | + | ||
| 59 | + | case 'ArrowDown': | |
| 60 | + | case 'ArrowUp': | |
| 61 | + | event.preventDefault(); | |
| 62 | + | event.stopPropagation(); | |
| 63 | + | handleArrowKeys(event.key); | |
| 64 | + | break; | |
| 65 | + | ||
| 66 | + | default: | |
| 67 | + | // Any other key should restore full opacity | |
| 68 | + | omniboxStore.setFaded(false); | |
| 69 | + | break; | |
| 70 | + | } | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | // Handle Enter key based on mode | |
| 74 | + | function handleEnterKey(event: KeyboardEvent) { | |
| 75 | + | if (mode === 'omnibox') { | |
| 76 | + | const selectedSuggestion = selectedIndex >= 0 ? suggestions[selectedIndex] : null; | |
| 77 | + | const url = selectedSuggestion?.url || inputValue || ''; | |
| 78 | + | ||
| 79 | + | if (url) { | |
| 80 | + | omniboxBridge.navigate(url); | |
| 81 | + | omniboxStore.close(); | |
| 82 | + | } | |
| 83 | + | } else if (mode === 'find') { | |
| 84 | + | if (event.shiftKey) { | |
| 85 | + | // Shift+Enter: jump to previous match | |
| 86 | + | jumpToMatch(-1); | |
| 87 | + | } else if (event.altKey) { | |
| 88 | + | // Alt+Enter: center on current match but keep overlay open | |
| 89 | + | revealCurrentMatch(); | |
| 90 | + | } else { | |
| 91 | + | // Enter: center and close | |
| 92 | + | revealCurrentMatch(); | |
| 93 | + | omniboxStore.close(); | |
| 94 | + | } | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | // Handle arrow key navigation | |
| 99 | + | function handleArrowKeys(key: string) { | |
| 100 | + | const totalItems = mode === 'omnibox' ? suggestions.length : matches.length; | |
| 101 | + | ||
| 102 | + | if (totalItems > 0) { | |
| 103 | + | if (key === 'ArrowDown') { | |
| 104 | + | omniboxStore.selectNext(); | |
| 105 | + | } else { | |
| 106 | + | omniboxStore.selectPrevious(); | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // Fade overlay while navigating results | |
| 110 | + | omniboxStore.setFaded(true); | |
| 111 | + | ||
| 112 | + | // For find mode, reveal the current match | |
| 113 | + | if (mode === 'find') { | |
| 114 | + | revealCurrentMatch(); | |
| 115 | + | } | |
| 116 | + | } | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Jump to match (for find mode) | |
| 120 | + | function jumpToMatch(delta: number) { | |
| 121 | + | if (mode !== 'find' || matches.length === 0) return; | |
| 122 | + | ||
| 123 | + | const currentIndex = selectedIndex || 0; | |
| 124 | + | const newIndex = ((currentIndex + delta) % matches.length + matches.length) % matches.length; | |
| 125 | + | ||
| 126 | + | omniboxStore.setSelectedIndex(newIndex); | |
| 127 | + | revealCurrentMatch(); | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | // Reveal current match (for find mode) | |
| 131 | + | function revealCurrentMatch() { | |
| 132 | + | if (mode !== 'find' || selectedIndex < 0 || !matches[selectedIndex]) return; | |
| 133 | + | ||
| 134 | + | // Remove previous active class | |
| 135 | + | const prevMatch = matches[omniboxStore.activeIndex]; | |
| 136 | + | if (prevMatch?.element?.classList) { | |
| 137 | + | prevMatch.element.classList.remove('find-active'); | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // Add active class to current match | |
| 141 | + | const currentMatch = matches[selectedIndex]; | |
| 142 | + | if (currentMatch?.element?.classList) { | |
| 143 | + | currentMatch.element.classList.add('find-active'); | |
| 144 | + | omniboxStore.setActiveIndex(selectedIndex); | |
| 145 | + | ||
| 146 | + | // Scroll into view | |
| 147 | + | try { | |
| 148 | + | currentMatch.element.scrollIntoView({ | |
| 149 | + | block: 'center', | |
| 150 | + | inline: 'nearest' | |
| 151 | + | }); | |
| 152 | + | } catch { | |
| 153 | + | currentMatch.element.scrollIntoView(); | |
| 154 | + | } | |
| 155 | + | } | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // Handle mouse events | |
| 159 | + | function handleMouseDown() { | |
| 160 | + | omniboxStore.setFaded(false); | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | function handleClick() { | |
| 164 | + | omniboxStore.setFaded(false); | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | function handleFocus() { | |
| 168 | + | omniboxStore.setFaded(false); | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | function handleMouseEnter() { | |
| 172 | + | if (omniboxStore.visible && inputElement) { | |
| 173 | + | try { | |
| 174 | + | inputElement.focus({ preventScroll: true }); | |
| 175 | + | inputElement.select(); | |
| 176 | + | } catch { | |
| 177 | + | inputElement.focus(); | |
| 178 | + | } | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | </script> | |
| 182 | + | ||
| 183 | + | <input | |
| 184 | + | bind:this={inputElement} | |
| 185 | + | type="text" | |
| 186 | + | {placeholder} | |
| 187 | + | value={inputValue} | |
| 188 | + | class="w-full box-border px-3 py-2.5 | |
| 189 | + | bg-[#121212] text-[#eee] | |
| 190 | + | border border-[#555] rounded-md | |
| 191 | + | focus:outline-none | |
| 192 | + | text-base | |
| 193 | + | sm:px-2.5 sm:py-2 sm:text-sm | |
| 194 | + | xl:text-lg xl:px-3 xl:py-3" | |
| 195 | + | oninput={handleInput} | |
| 196 | + | onkeydown={handleKeyDown} | |
| 197 | + | onmousedown={handleMouseDown} | |
| 198 | + | onclick={handleClick} | |
| 199 | + | onfocus={handleFocus} | |
| 200 | + | onmouseenter={handleMouseEnter} | |
| 201 | + | autocomplete="off" | |
| 202 | + | spellcheck="false" | |
| 203 | + | role="combobox" | |
| 204 | + | aria-expanded={omniboxStore.hasContent} | |
| 205 | + | aria-controls="omnibox-list" | |
| 206 | + | aria-haspopup="listbox" | |
| 207 | + | aria-owns="omnibox-list" | |
| 208 | + | aria-activedescendant={selectedIndex >= 0 ? `omnibox-item-${selectedIndex}` : undefined} | |
| 209 | + | />⏎̸ | |
A gui/src/components/omnibox/OmniboxSuggestions.svelte +144 -0
| @@ -0,0 +1,144 @@ | |||
| 1 | + | <!-- | |
| 2 | + | Omnibox Suggestions Component | |
| 3 | + | ||
| 4 | + | Displays search suggestions with favicons and URL highlighting | |
| 5 | + | --> | |
| 6 | + | <script lang="ts"> | |
| 7 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 8 | + | import { omniboxBridge } from './messaging'; | |
| 9 | + | ||
| 10 | + | // Reactive state | |
| 11 | + | let suggestions = $derived(omniboxStore.suggestions); | |
| 12 | + | let selectedIndex = $derived(omniboxStore.selectedIndex); | |
| 13 | + | let hasContent = $state(false); | |
| 14 | + | ||
| 15 | + | // Update hasContent when suggestions change | |
| 16 | + | $effect(() => { | |
| 17 | + | hasContent = omniboxStore.mode === 'omnibox' && suggestions.length > 0; | |
| 18 | + | }); | |
| 19 | + | ||
| 20 | + | // Handle suggestion item mouse enter | |
| 21 | + | function handleItemMouseEnter(index: number) { | |
| 22 | + | omniboxStore.setSelectedIndex(index); | |
| 23 | + | omniboxStore.setFaded(true); | |
| 24 | + | scrollToSelection(); | |
| 25 | + | } | |
| 26 | + | ||
| 27 | + | // Handle suggestion item click | |
| 28 | + | function handleItemClick(suggestion: any) { | |
| 29 | + | omniboxBridge.navigate(suggestion.url); | |
| 30 | + | omniboxStore.close(); | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | // Scroll list to show selected item | |
| 34 | + | function scrollToSelection() { | |
| 35 | + | const selectedItem = document.getElementById(`omnibox-item-${selectedIndex}`); | |
| 36 | + | if (selectedItem && selectedItem.scrollIntoView) { | |
| 37 | + | try { | |
| 38 | + | selectedItem.scrollIntoView({ block: 'nearest' }); | |
| 39 | + | } catch { | |
| 40 | + | selectedItem.scrollIntoView(); | |
| 41 | + | } | |
| 42 | + | } | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // Parse URL for display | |
| 46 | + | function parseUrl(url: string) { | |
| 47 | + | try { | |
| 48 | + | const urlObj = new URL(url, window.location.href); | |
| 49 | + | return { | |
| 50 | + | domain: urlObj.hostname, | |
| 51 | + | path: (urlObj.pathname || '') + (urlObj.search || '') + (urlObj.hash || '') | |
| 52 | + | }; | |
| 53 | + | } catch { | |
| 54 | + | return { | |
| 55 | + | domain: url || '', | |
| 56 | + | path: '' | |
| 57 | + | }; | |
| 58 | + | } | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Handle favicon error | |
| 62 | + | function handleFaviconError(event: Event) { | |
| 63 | + | const target = event.target as HTMLImageElement; | |
| 64 | + | const chip = target.parentElement; | |
| 65 | + | if (chip) { | |
| 66 | + | chip.style.display = 'none'; | |
| 67 | + | } | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // Watch for selection changes to scroll | |
| 71 | + | $effect(() => { | |
| 72 | + | if (selectedIndex >= 0) { | |
| 73 | + | scrollToSelection(); | |
| 74 | + | } | |
| 75 | + | }); | |
| 76 | + | </script> | |
| 77 | + | ||
| 78 | + | {#if hasContent} | |
| 79 | + | <div | |
| 80 | + | id="omnibox-list" | |
| 81 | + | class="mt-2 max-h-[50vh] overflow-auto border-t border-[#333]" | |
| 82 | + | role="listbox" | |
| 83 | + | aria-label="Search suggestions" | |
| 84 | + | > | |
| 85 | + | {#each suggestions as suggestion, index (suggestion.url)} | |
| 86 | + | {@const { domain, path } = parseUrl(suggestion.url)} | |
| 87 | + | {@const isSelected = index === selectedIndex} | |
| 88 | + | ||
| 89 | + | <div | |
| 90 | + | id="omnibox-item-{index}" | |
| 91 | + | class="px-2.5 py-2 flex gap-2.5 items-center cursor-pointer | |
| 92 | + | border-b border-[#2a2a2a] last:border-b-0 | |
| 93 | + | {isSelected ? 'bg-[#0a0a0a]' : ''}" | |
| 94 | + | role="option" | |
| 95 | + | tabindex="-1" | |
| 96 | + | aria-selected={isSelected} | |
| 97 | + | onmouseenter={() => handleItemMouseEnter(index)} | |
| 98 | + | onclick={() => handleItemClick(suggestion)} | |
| 99 | + | > | |
| 100 | + | <!-- Favicon chip --> | |
| 101 | + | {#if suggestion.favicon} | |
| 102 | + | <div | |
| 103 | + | class="flex-shrink-0 w-5 h-5 rounded-full | |
| 104 | + | bg-[#ccc] border border-black/12 | |
| 105 | + | shadow-sm flex items-center justify-center" | |
| 106 | + | > | |
| 107 | + | <img | |
| 108 | + | src={suggestion.favicon} | |
| 109 | + | alt="" | |
| 110 | + | class="w-4 h-4 filter brightness-105 contrast-103" | |
| 111 | + | loading="lazy" | |
| 112 | + | onerror={handleFaviconError} | |
| 113 | + | style="image-rendering: -webkit-optimize-contrast;" | |
| 114 | + | /> | |
| 115 | + | </div> | |
| 116 | + | {/if} | |
| 117 | + | ||
| 118 | + | <!-- URL text with gradient fade --> | |
| 119 | + | <div | |
| 120 | + | class="flex-1 min-w-0 flex gap-2 items-center | |
| 121 | + | whitespace-nowrap overflow-hidden | |
| 122 | + | [mask-image:linear-gradient(90deg,black_85%,transparent_100%)] | |
| 123 | + | [-webkit-mask-image:linear-gradient(90deg,black_85%,transparent_100%)]" | |
| 124 | + | > | |
| 125 | + | <!-- Domain --> | |
| 126 | + | <span class="text-[#e6e6e6] opacity-95"> | |
| 127 | + | {domain} | |
| 128 | + | </span> | |
| 129 | + | ||
| 130 | + | <!-- Separator --> | |
| 131 | + | <span class="text-[#777]"> | |
| 132 | + | {' | '} | |
| 133 | + | </span> | |
| 134 | + | ||
| 135 | + | <!-- Path --> | |
| 136 | + | <span class="text-[#99aadd]"> | |
| 137 | + | {path || '/'} | |
| 138 | + | </span> | |
| 139 | + | </div> | |
| 140 | + | </div> | |
| 141 | + | {/each} | |
| 142 | + | </div> | |
| 143 | + | {/if} | |
| 144 | + | ||
A gui/src/components/omnibox/find.ts +202 -0
| @@ -0,0 +1,202 @@ | |||
| 1 | + | /** | |
| 2 | + | * Find in Page Functionality | |
| 3 | + | * | |
| 4 | + | * Text search and highlighting implementation | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | import type { FindMatch, HighlightNode } from './types'; | |
| 8 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 9 | + | ||
| 10 | + | /** | |
| 11 | + | * Find text in the current page and highlight matches | |
| 12 | + | */ | |
| 13 | + | export function findInPage(query: string): void { | |
| 14 | + | // Clear previous highlights | |
| 15 | + | omniboxStore.clearHighlights(); | |
| 16 | + | ||
| 17 | + | const trimmedQuery = (query || '').trim(); | |
| 18 | + | if (!trimmedQuery) { | |
| 19 | + | return; | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | const body = document.body; | |
| 23 | + | if (!body) { | |
| 24 | + | return; | |
| 25 | + | } | |
| 26 | + | ||
| 27 | + | // Get omnibox root to exclude from search | |
| 28 | + | const omniboxRoot = document.getElementById('dumber-omnibox-root'); | |
| 29 | + | const matches: FindMatch[] = []; | |
| 30 | + | const maxMatches = omniboxStore.config.maxMatches; | |
| 31 | + | ||
| 32 | + | // Create tree walker to find text nodes | |
| 33 | + | const walker = document.createTreeWalker( | |
| 34 | + | body, | |
| 35 | + | NodeFilter.SHOW_TEXT, | |
| 36 | + | { | |
| 37 | + | acceptNode(node: Text): number { | |
| 38 | + | // Skip empty or whitespace-only nodes | |
| 39 | + | if (!node.nodeValue || !node.nodeValue.trim()) { | |
| 40 | + | return NodeFilter.FILTER_REJECT; | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | const parentElement = node.parentElement; | |
| 44 | + | if (!parentElement) { | |
| 45 | + | return NodeFilter.FILTER_REJECT; | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // Skip omnibox content | |
| 49 | + | if (omniboxRoot && omniboxRoot.contains(parentElement)) { | |
| 50 | + | return NodeFilter.FILTER_REJECT; | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Skip script, style, and noscript tags | |
| 54 | + | const tagName = parentElement.tagName; | |
| 55 | + | if (tagName === 'SCRIPT' || tagName === 'STYLE' || tagName === 'NOSCRIPT') { | |
| 56 | + | return NodeFilter.FILTER_REJECT; | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | // Skip hidden elements | |
| 60 | + | const computedStyle = getComputedStyle(parentElement); | |
| 61 | + | if (computedStyle.visibility === 'hidden' || computedStyle.display === 'none') { | |
| 62 | + | return NodeFilter.FILTER_REJECT; | |
| 63 | + | } | |
| 64 | + | ||
| 65 | + | return NodeFilter.FILTER_ACCEPT; | |
| 66 | + | } | |
| 67 | + | } | |
| 68 | + | ); | |
| 69 | + | ||
| 70 | + | const queryLowerCase = trimmedQuery.toLowerCase(); | |
| 71 | + | ||
| 72 | + | // Process each text node | |
| 73 | + | while (walker.nextNode() && matches.length < maxMatches) { | |
| 74 | + | const textNode = walker.currentNode as Text; | |
| 75 | + | let nodeValue = textNode.nodeValue || ''; | |
| 76 | + | let searchIndex = 0; | |
| 77 | + | ||
| 78 | + | // Find all matches in this text node | |
| 79 | + | while (nodeValue && matches.length < maxMatches) { | |
| 80 | + | const matchIndex = nodeValue.toLowerCase().indexOf(queryLowerCase, searchIndex); | |
| 81 | + | if (matchIndex === -1) { | |
| 82 | + | break; | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // Create text nodes for before, match, and after | |
| 86 | + | const beforeText = nodeValue.slice(0, matchIndex); | |
| 87 | + | const matchText = nodeValue.slice(matchIndex, matchIndex + trimmedQuery.length); | |
| 88 | + | const afterText = nodeValue.slice(matchIndex + trimmedQuery.length); | |
| 89 | + | ||
| 90 | + | // Create elements | |
| 91 | + | const beforeNode = document.createTextNode(beforeText); | |
| 92 | + | const matchTextNode = document.createTextNode(matchText); | |
| 93 | + | const highlightSpan = document.createElement('span'); | |
| 94 | + | ||
| 95 | + | // Style the highlight span | |
| 96 | + | highlightSpan.className = 'find-highlight'; | |
| 97 | + | highlightSpan.appendChild(matchTextNode); | |
| 98 | + | ||
| 99 | + | // Insert into DOM | |
| 100 | + | const parent = textNode.parentNode; | |
| 101 | + | if (!parent) { | |
| 102 | + | break; | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | parent.insertBefore(beforeNode, textNode); | |
| 106 | + | parent.insertBefore(highlightSpan, textNode); | |
| 107 | + | textNode.nodeValue = afterText; | |
| 108 | + | ||
| 109 | + | // Track highlight node for cleanup | |
| 110 | + | const highlightNode: HighlightNode = { | |
| 111 | + | span: highlightSpan, | |
| 112 | + | text: matchTextNode | |
| 113 | + | }; | |
| 114 | + | omniboxStore.addHighlightNode(highlightNode); | |
| 115 | + | ||
| 116 | + | // Create match context | |
| 117 | + | const leftContext = beforeText.slice(-30); | |
| 118 | + | let rightContext = afterText.slice(0, 30); | |
| 119 | + | ||
| 120 | + | // Try to break at word boundaries | |
| 121 | + | const boundaryMatch = rightContext.match(/[.,;:-]/); | |
| 122 | + | if (boundaryMatch && boundaryMatch.index !== undefined) { | |
| 123 | + | rightContext = rightContext.slice(0, boundaryMatch.index + 1); | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | const context = (leftContext + matchText + rightContext) | |
| 127 | + | .replace(/\s+/g, ' ') | |
| 128 | + | .trim(); | |
| 129 | + | ||
| 130 | + | // Add to matches | |
| 131 | + | const findMatch: FindMatch = { | |
| 132 | + | element: highlightSpan, | |
| 133 | + | context | |
| 134 | + | }; | |
| 135 | + | matches.push(findMatch); | |
| 136 | + | ||
| 137 | + | // Continue searching in the remaining text | |
| 138 | + | nodeValue = afterText; | |
| 139 | + | searchIndex = 0; | |
| 140 | + | } | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | // Update store with matches | |
| 144 | + | omniboxStore.updateMatches(matches); | |
| 145 | + | ||
| 146 | + | // Reveal first match if any | |
| 147 | + | if (matches.length > 0) { | |
| 148 | + | revealMatch(0); | |
| 149 | + | } | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | /** | |
| 153 | + | * Reveal a specific match by index | |
| 154 | + | */ | |
| 155 | + | export function revealMatch(index: number): void { | |
| 156 | + | const matches = omniboxStore.matches; | |
| 157 | + | if (index < 0 || index >= matches.length) { | |
| 158 | + | return; | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | // Remove previous active class | |
| 162 | + | const prevActiveIndex = omniboxStore.activeIndex; | |
| 163 | + | if (prevActiveIndex >= 0 && matches[prevActiveIndex]) { | |
| 164 | + | const prevElement = matches[prevActiveIndex].element; | |
| 165 | + | if (prevElement.classList) { | |
| 166 | + | prevElement.classList.remove('find-active'); | |
| 167 | + | } | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // Add active class to current match | |
| 171 | + | const currentMatch = matches[index]; | |
| 172 | + | if (currentMatch && currentMatch.element.classList) { | |
| 173 | + | currentMatch.element.classList.add('find-active'); | |
| 174 | + | omniboxStore.setActiveIndex(index); | |
| 175 | + | ||
| 176 | + | // Scroll into view | |
| 177 | + | try { | |
| 178 | + | currentMatch.element.scrollIntoView({ | |
| 179 | + | block: 'center', | |
| 180 | + | inline: 'nearest' | |
| 181 | + | }); | |
| 182 | + | } catch { | |
| 183 | + | currentMatch.element.scrollIntoView(); | |
| 184 | + | } | |
| 185 | + | } | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | /** | |
| 189 | + | * Jump to next/previous match | |
| 190 | + | */ | |
| 191 | + | export function jumpToMatch(delta: number): void { | |
| 192 | + | const matches = omniboxStore.matches; | |
| 193 | + | if (matches.length === 0) { | |
| 194 | + | return; | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | const currentIndex = omniboxStore.selectedIndex || 0; | |
| 198 | + | const newIndex = ((currentIndex + delta) % matches.length + matches.length) % matches.length; | |
| 199 | + | ||
| 200 | + | omniboxStore.setSelectedIndex(newIndex); | |
| 201 | + | revealMatch(newIndex); | |
| 202 | + | }⏎̸ | |
A gui/src/components/omnibox/index.ts +16 -0
| @@ -0,0 +1,16 @@ | |||
| 1 | + | /** | |
| 2 | + | * Omnibox Component Exports | |
| 3 | + | * | |
| 4 | + | * Main entry point for omnibox functionality | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | export { default as Omnibox } from './Omnibox.svelte'; | |
| 8 | + | export { default as OmniboxInput } from './OmniboxInput.svelte'; | |
| 9 | + | export { default as OmniboxSuggestions } from './OmniboxSuggestions.svelte'; | |
| 10 | + | export { default as OmniboxFind } from './OmniboxFind.svelte'; | |
| 11 | + | ||
| 12 | + | export { omniboxStore } from './stores.svelte.ts'; | |
| 13 | + | export { omniboxBridge } from './messaging'; | |
| 14 | + | export { findInPage, revealMatch, jumpToMatch } from './find'; | |
| 15 | + | ||
| 16 | + | export type * from './types';⏎̸ | |
A gui/src/components/omnibox/messaging.ts +95 -0
| @@ -0,0 +1,95 @@ | |||
| 1 | + | /** | |
| 2 | + | * Omnibox Message Bridge | |
| 3 | + | * | |
| 4 | + | * TypeScript interface for Go-JavaScript communication | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | import type { OmniboxMessage, OmniboxMessageBridge, Suggestion } from './types'; | |
| 8 | + | import { omniboxStore } from './stores.svelte.ts'; | |
| 9 | + | ||
| 10 | + | export class OmniboxBridge implements OmniboxMessageBridge { | |
| 11 | + | /** | |
| 12 | + | * Send message to Go backend via WebKit message handler | |
| 13 | + | */ | |
| 14 | + | postMessage(msg: OmniboxMessage): void { | |
| 15 | + | try { | |
| 16 | + | console.log('📨 Sending message to Go backend:', msg); | |
| 17 | + | const messageHandler = window.webkit?.messageHandlers?.dumber; | |
| 18 | + | if (messageHandler && messageHandler.postMessage) { | |
| 19 | + | const jsonMsg = JSON.stringify(msg); | |
| 20 | + | console.log('📨 JSON message:', jsonMsg); | |
| 21 | + | messageHandler.postMessage(jsonMsg); | |
| 22 | + | } else { | |
| 23 | + | console.warn('WebKit message handler not available'); | |
| 24 | + | } | |
| 25 | + | } catch (error) { | |
| 26 | + | console.error('Failed to send message to Go backend:', error); | |
| 27 | + | } | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | /** | |
| 31 | + | * Update suggestions from Go backend | |
| 32 | + | */ | |
| 33 | + | setSuggestions(suggestions: Suggestion[]): void { | |
| 34 | + | omniboxStore.updateSuggestions(suggestions); | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | /** | |
| 38 | + | * Handle navigation request | |
| 39 | + | */ | |
| 40 | + | navigate(url: string): void { | |
| 41 | + | console.log('🚀 Omnibox navigate called with:', url); | |
| 42 | + | this.postMessage({ | |
| 43 | + | type: 'navigate', | |
| 44 | + | url | |
| 45 | + | }); | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | /** | |
| 49 | + | * Handle search query | |
| 50 | + | */ | |
| 51 | + | query(searchTerm: string, limit?: number): void { | |
| 52 | + | this.postMessage({ | |
| 53 | + | type: 'query', | |
| 54 | + | q: searchTerm, | |
| 55 | + | limit: limit || omniboxStore.config.defaultLimit | |
| 56 | + | }); | |
| 57 | + | } | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // Singleton instance | |
| 61 | + | export const omniboxBridge = new OmniboxBridge(); | |
| 62 | + | ||
| 63 | + | /** | |
| 64 | + | * Debounced query function for search input | |
| 65 | + | */ | |
| 66 | + | export function debouncedQuery(searchTerm: string): void { | |
| 67 | + | omniboxStore.clearDebounceTimer(); | |
| 68 | + | ||
| 69 | + | const timerId = window.setTimeout(() => { | |
| 70 | + | omniboxBridge.query(searchTerm); | |
| 71 | + | }, omniboxStore.config.debounceDelay); | |
| 72 | + | ||
| 73 | + | omniboxStore.setDebounceTimer(timerId); | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // Extend global window interface for Go bridge compatibility | |
| 77 | + | declare global { | |
| 78 | + | interface Window { | |
| 79 | + | webkit?: { | |
| 80 | + | messageHandlers?: { | |
| 81 | + | dumber?: { | |
| 82 | + | postMessage: (message: string) => void; | |
| 83 | + | }; | |
| 84 | + | }; | |
| 85 | + | }; | |
| 86 | + | // Omnibox API for Go bridge | |
| 87 | + | __dumber_omnibox?: { | |
| 88 | + | setSuggestions: (suggestions: Suggestion[]) => void; | |
| 89 | + | toggle: () => void; | |
| 90 | + | open: (mode?: string, query?: string) => void; | |
| 91 | + | close: () => void; | |
| 92 | + | findQuery: (query: string) => void; | |
| 93 | + | }; | |
| 94 | + | } | |
| 95 | + | }⏎̸ | |
A gui/src/components/omnibox/stores.svelte.ts +215 -0
| @@ -0,0 +1,215 @@ | |||
| 1 | + | /** | |
| 2 | + | * Omnibox State Management | |
| 3 | + | * | |
| 4 | + | * Svelte 5 rune-based state management for omnibox functionality | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | import type { | |
| 8 | + | OmniboxMode, | |
| 9 | + | Suggestion, | |
| 10 | + | FindMatch, | |
| 11 | + | HighlightNode, | |
| 12 | + | OmniboxConfig | |
| 13 | + | } from './types'; | |
| 14 | + | ||
| 15 | + | // Default configuration | |
| 16 | + | const DEFAULT_CONFIG: Required<OmniboxConfig> = { | |
| 17 | + | maxMatches: 2000, | |
| 18 | + | debounceDelay: 120, | |
| 19 | + | defaultLimit: 10 | |
| 20 | + | }; | |
| 21 | + | ||
| 22 | + | // Global state using Svelte 5 runes | |
| 23 | + | let visible = $state(false); | |
| 24 | + | let mode = $state<OmniboxMode>('omnibox'); | |
| 25 | + | let suggestions = $state<Suggestion[]>([]); | |
| 26 | + | let matches = $state<FindMatch[]>([]); | |
| 27 | + | let selectedIndex = $state(-1); | |
| 28 | + | let activeIndex = $state(-1); | |
| 29 | + | let faded = $state(false); | |
| 30 | + | let inputValue = $state(''); | |
| 31 | + | let highlightNodes = $state<HighlightNode[]>([]); | |
| 32 | + | let prevOverflow = $state(''); | |
| 33 | + | let debounceTimer = $state(0); | |
| 34 | + | ||
| 35 | + | // Configuration | |
| 36 | + | let config = $state<Required<OmniboxConfig>>(DEFAULT_CONFIG); | |
| 37 | + | ||
| 38 | + | export const omniboxStore = { | |
| 39 | + | // State getters | |
| 40 | + | get visible() { return visible; }, | |
| 41 | + | get mode() { return mode; }, | |
| 42 | + | get suggestions() { return suggestions; }, | |
| 43 | + | get matches() { return matches; }, | |
| 44 | + | get selectedIndex() { return selectedIndex; }, | |
| 45 | + | get activeIndex() { return activeIndex; }, | |
| 46 | + | get faded() { return faded; }, | |
| 47 | + | get inputValue() { return inputValue; }, | |
| 48 | + | get highlightNodes() { return highlightNodes; }, | |
| 49 | + | get prevOverflow() { return prevOverflow; }, | |
| 50 | + | get config() { return config; }, | |
| 51 | + | ||
| 52 | + | // Computed getters | |
| 53 | + | get hasContent() { | |
| 54 | + | return (mode === 'omnibox' && suggestions.length > 0) || | |
| 55 | + | (mode === 'find' && matches.length > 0); | |
| 56 | + | }, | |
| 57 | + | get totalItems() { | |
| 58 | + | return mode === 'omnibox' ? suggestions.length : matches.length; | |
| 59 | + | }, | |
| 60 | + | get selectedItem() { | |
| 61 | + | if (selectedIndex < 0) return null; | |
| 62 | + | return mode === 'omnibox' ? suggestions[selectedIndex] : matches[selectedIndex]; | |
| 63 | + | }, | |
| 64 | + | ||
| 65 | + | // Actions | |
| 66 | + | setVisible(value: boolean) { | |
| 67 | + | if (value && !visible) { | |
| 68 | + | // Store scroll state when opening | |
| 69 | + | prevOverflow = document.documentElement.style.overflow; | |
| 70 | + | document.documentElement.style.overflow = 'hidden'; | |
| 71 | + | } else if (!value && visible) { | |
| 72 | + | // Restore scroll state when closing | |
| 73 | + | document.documentElement.style.overflow = prevOverflow || ''; | |
| 74 | + | prevOverflow = ''; | |
| 75 | + | ||
| 76 | + | // Clear find highlights when closing | |
| 77 | + | if (mode === 'find') { | |
| 78 | + | this.clearHighlights(); | |
| 79 | + | } | |
| 80 | + | } | |
| 81 | + | visible = value; | |
| 82 | + | }, | |
| 83 | + | ||
| 84 | + | setMode(newMode: OmniboxMode) { | |
| 85 | + | // Clear previous mode's state | |
| 86 | + | if (newMode === 'omnibox') { | |
| 87 | + | // Switching to omnibox mode - clear find state | |
| 88 | + | this.clearHighlights(); | |
| 89 | + | } else if (newMode === 'find') { | |
| 90 | + | // Switching to find mode - clear suggestions | |
| 91 | + | this.updateSuggestions([]); | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | mode = newMode; | |
| 95 | + | selectedIndex = -1; | |
| 96 | + | faded = false; | |
| 97 | + | inputValue = ''; // Clear input for fresh start | |
| 98 | + | }, | |
| 99 | + | ||
| 100 | + | setInputValue(value: string) { | |
| 101 | + | inputValue = value; | |
| 102 | + | }, | |
| 103 | + | ||
| 104 | + | setFaded(value: boolean) { | |
| 105 | + | faded = value; | |
| 106 | + | }, | |
| 107 | + | ||
| 108 | + | setSelectedIndex(index: number) { | |
| 109 | + | const maxIndex = this.totalItems - 1; | |
| 110 | + | if (maxIndex < 0) { | |
| 111 | + | selectedIndex = -1; | |
| 112 | + | } else { | |
| 113 | + | selectedIndex = Math.max(0, Math.min(index, maxIndex)); | |
| 114 | + | } | |
| 115 | + | }, | |
| 116 | + | ||
| 117 | + | selectNext() { | |
| 118 | + | if (this.totalItems === 0) return; | |
| 119 | + | const newIndex = selectedIndex < 0 ? 0 : (selectedIndex + 1) % this.totalItems; | |
| 120 | + | this.setSelectedIndex(newIndex); | |
| 121 | + | faded = true; | |
| 122 | + | }, | |
| 123 | + | ||
| 124 | + | selectPrevious() { | |
| 125 | + | if (this.totalItems === 0) return; | |
| 126 | + | const newIndex = selectedIndex <= 0 ? this.totalItems - 1 : selectedIndex - 1; | |
| 127 | + | this.setSelectedIndex(newIndex); | |
| 128 | + | faded = true; | |
| 129 | + | }, | |
| 130 | + | ||
| 131 | + | open(newMode: OmniboxMode = 'omnibox', initialQuery?: string) { | |
| 132 | + | this.setMode(newMode); | |
| 133 | + | this.setVisible(true); | |
| 134 | + | if (typeof initialQuery === 'string') { | |
| 135 | + | inputValue = initialQuery; | |
| 136 | + | } | |
| 137 | + | }, | |
| 138 | + | ||
| 139 | + | close() { | |
| 140 | + | this.setVisible(false); | |
| 141 | + | faded = false; | |
| 142 | + | }, | |
| 143 | + | ||
| 144 | + | toggle() { | |
| 145 | + | this.setVisible(!visible); | |
| 146 | + | }, | |
| 147 | + | ||
| 148 | + | updateSuggestions(newSuggestions: Suggestion[]) { | |
| 149 | + | suggestions = Array.isArray(newSuggestions) ? newSuggestions : []; | |
| 150 | + | selectedIndex = -1; | |
| 151 | + | }, | |
| 152 | + | ||
| 153 | + | updateMatches(newMatches: FindMatch[]) { | |
| 154 | + | matches = Array.isArray(newMatches) ? newMatches : []; | |
| 155 | + | selectedIndex = newMatches.length > 0 ? 0 : -1; | |
| 156 | + | }, | |
| 157 | + | ||
| 158 | + | clearHighlights() { | |
| 159 | + | try { | |
| 160 | + | highlightNodes.forEach(({ span, text }) => { | |
| 161 | + | const parent = span.parentNode; | |
| 162 | + | if (parent) { | |
| 163 | + | parent.replaceChild(text, span); | |
| 164 | + | parent.normalize(); | |
| 165 | + | } | |
| 166 | + | }); | |
| 167 | + | } catch (error) { | |
| 168 | + | console.warn('Error clearing highlights:', error); | |
| 169 | + | } | |
| 170 | + | highlightNodes = []; | |
| 171 | + | matches = []; | |
| 172 | + | selectedIndex = -1; | |
| 173 | + | activeIndex = -1; | |
| 174 | + | }, | |
| 175 | + | ||
| 176 | + | addHighlightNode(node: HighlightNode) { | |
| 177 | + | highlightNodes = [...highlightNodes, node]; | |
| 178 | + | }, | |
| 179 | + | ||
| 180 | + | setActiveIndex(index: number) { | |
| 181 | + | activeIndex = index; | |
| 182 | + | }, | |
| 183 | + | ||
| 184 | + | setDebounceTimer(timerId: number) { | |
| 185 | + | if (debounceTimer) { | |
| 186 | + | clearTimeout(debounceTimer); | |
| 187 | + | } | |
| 188 | + | debounceTimer = timerId; | |
| 189 | + | }, | |
| 190 | + | ||
| 191 | + | clearDebounceTimer() { | |
| 192 | + | if (debounceTimer) { | |
| 193 | + | clearTimeout(debounceTimer); | |
| 194 | + | debounceTimer = 0; | |
| 195 | + | } | |
| 196 | + | }, | |
| 197 | + | ||
| 198 | + | updateConfig(newConfig: Partial<OmniboxConfig>) { | |
| 199 | + | config = { ...config, ...newConfig }; | |
| 200 | + | }, | |
| 201 | + | ||
| 202 | + | reset() { | |
| 203 | + | visible = false; | |
| 204 | + | mode = 'omnibox'; | |
| 205 | + | suggestions = []; | |
| 206 | + | matches = []; | |
| 207 | + | selectedIndex = -1; | |
| 208 | + | activeIndex = -1; | |
| 209 | + | faded = false; | |
| 210 | + | inputValue = ''; | |
| 211 | + | prevOverflow = ''; | |
| 212 | + | this.clearHighlights(); | |
| 213 | + | this.clearDebounceTimer(); | |
| 214 | + | } | |
| 215 | + | };⏎̸ | |
A gui/src/components/omnibox/types.ts +63 -0
| @@ -0,0 +1,63 @@ | |||
| 1 | + | /** | |
| 2 | + | * Omnibox Component Types | |
| 3 | + | * | |
| 4 | + | * TypeScript interfaces for omnibox/find functionality that match Go structs | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | export interface Suggestion { | |
| 8 | + | url: string; | |
| 9 | + | favicon?: string; | |
| 10 | + | } | |
| 11 | + | ||
| 12 | + | export interface OmniboxMessage { | |
| 13 | + | type: 'navigate' | 'query'; | |
| 14 | + | url?: string; | |
| 15 | + | q?: string; | |
| 16 | + | limit?: number; | |
| 17 | + | } | |
| 18 | + | ||
| 19 | + | export interface FindMatch { | |
| 20 | + | element: HTMLElement; | |
| 21 | + | context: string; | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | export interface HighlightNode { | |
| 25 | + | span: HTMLElement; | |
| 26 | + | text: Text; | |
| 27 | + | } | |
| 28 | + | ||
| 29 | + | export type OmniboxMode = 'omnibox' | 'find'; | |
| 30 | + | ||
| 31 | + | export interface OmniboxConfig { | |
| 32 | + | maxMatches?: number; | |
| 33 | + | debounceDelay?: number; | |
| 34 | + | defaultLimit?: number; | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | export interface OmniboxState { | |
| 38 | + | visible: boolean; | |
| 39 | + | mode: OmniboxMode; | |
| 40 | + | suggestions: Suggestion[]; | |
| 41 | + | matches: FindMatch[]; | |
| 42 | + | selectedIndex: number; | |
| 43 | + | activeIndex: number; | |
| 44 | + | faded: boolean; | |
| 45 | + | inputValue: string; | |
| 46 | + | highlightNodes: HighlightNode[]; | |
| 47 | + | prevOverflow: string; | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Message bridge interface for Go communication | |
| 51 | + | export interface OmniboxMessageBridge { | |
| 52 | + | postMessage(msg: OmniboxMessage): void; | |
| 53 | + | setSuggestions(suggestions: Suggestion[]): void; | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Global API for Go bridge | |
| 57 | + | export interface OmniboxAPI { | |
| 58 | + | setSuggestions: (suggestions: Suggestion[]) => void; | |
| 59 | + | toggle: () => void; | |
| 60 | + | open: (mode?: OmniboxMode, query?: string) => void; | |
| 61 | + | close: () => void; | |
| 62 | + | findQuery: (query: string) => void; | |
| 63 | + | }⏎̸ | |
A gui/src/components/toast/Toast.svelte +121 -0
| @@ -0,0 +1,121 @@ | |||
| 1 | + | <script lang="ts"> | |
| 2 | + | import { onMount, onDestroy } from 'svelte'; | |
| 3 | + | ||
| 4 | + | interface ToastProps { | |
| 5 | + | id: number; | |
| 6 | + | message: string; | |
| 7 | + | duration?: number; | |
| 8 | + | type?: 'info' | 'success' | 'error'; | |
| 9 | + | onDismiss: (id: number) => void; | |
| 10 | + | } | |
| 11 | + | ||
| 12 | + | let { id, message, duration = 2500, type = 'info', onDismiss }: ToastProps = $props(); | |
| 13 | + | ||
| 14 | + | let isExiting = $state(false); | |
| 15 | + | let timeoutId: number | undefined; | |
| 16 | + | ||
| 17 | + | onMount(() => { | |
| 18 | + | timeoutId = window.setTimeout(() => { | |
| 19 | + | dismiss(); | |
| 20 | + | }, duration); | |
| 21 | + | }); | |
| 22 | + | ||
| 23 | + | onDestroy(() => { | |
| 24 | + | if (timeoutId) { | |
| 25 | + | window.clearTimeout(timeoutId); | |
| 26 | + | timeoutId = undefined; | |
| 27 | + | } | |
| 28 | + | }); | |
| 29 | + | ||
| 30 | + | function dismiss() { | |
| 31 | + | if (timeoutId) { | |
| 32 | + | window.clearTimeout(timeoutId); | |
| 33 | + | timeoutId = undefined; | |
| 34 | + | } | |
| 35 | + | isExiting = true; | |
| 36 | + | // Allow time for exit animation before removing from parent | |
| 37 | + | setTimeout(() => { | |
| 38 | + | onDismiss(id); | |
| 39 | + | }, 250); | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | function handleClick() { | |
| 43 | + | dismiss(); | |
| 44 | + | } | |
| 45 | + | </script> | |
| 46 | + | ||
| 47 | + | <button | |
| 48 | + | class="toast-base {type === 'success' ? 'toast-success' : type === 'error' ? 'toast-error' : 'toast-info'} {isExiting ? 'exiting' : ''}" | |
| 49 | + | onclick={handleClick} | |
| 50 | + | data-toast-id={id} | |
| 51 | + | type="button" | |
| 52 | + | aria-label="Dismiss notification" | |
| 53 | + | title="Click to dismiss" | |
| 54 | + | > | |
| 55 | + | <div class="w-full min-w-36 px-5 py-4 text-center text-white font-semibold text-sm rounded-xl shadow-2xl backdrop-blur-md border transition-all duration-250 {type === 'success' ? 'bg-gradient-to-br from-green-500/90 to-green-700/90 border-green-300/30' : type === 'error' ? 'bg-gradient-to-br from-red-500/90 to-red-700/90 border-red-300/30' : 'bg-gradient-to-br from-blue-500/90 to-blue-700/90 border-blue-300/30'}"> | |
| 56 | + | {message || 'Notification'} | |
| 57 | + | </div> | |
| 58 | + | </button> | |
| 59 | + | ||
| 60 | + | <style> | |
| 61 | + | .toast-base { | |
| 62 | + | /* Reset button styles */ | |
| 63 | + | border: none; | |
| 64 | + | background: none; | |
| 65 | + | padding: 0; | |
| 66 | + | font: inherit; | |
| 67 | + | text-align: left; | |
| 68 | + | ||
| 69 | + | /* Toast functionality */ | |
| 70 | + | cursor: pointer; | |
| 71 | + | user-select: none; | |
| 72 | + | position: relative; | |
| 73 | + | overflow: visible; | |
| 74 | + | ||
| 75 | + | /* Layout */ | |
| 76 | + | display: block; | |
| 77 | + | visibility: visible; | |
| 78 | + | z-index: 2147483647; | |
| 79 | + | pointer-events: auto; | |
| 80 | + | ||
| 81 | + | /* Animations */ | |
| 82 | + | animation: slideIn 0.3s ease-out forwards; | |
| 83 | + | transition: transform 0.2s ease, filter 0.2s ease; | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | .toast-base.exiting { | |
| 87 | + | animation: slideOut 0.25s ease-in forwards; | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | @keyframes slideIn { | |
| 91 | + | from { | |
| 92 | + | transform: translateX(-100%); | |
| 93 | + | opacity: 0; | |
| 94 | + | } | |
| 95 | + | to { | |
| 96 | + | transform: translateX(0); | |
| 97 | + | opacity: 1; | |
| 98 | + | } | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | @keyframes slideOut { | |
| 102 | + | from { | |
| 103 | + | transform: translateX(0); | |
| 104 | + | opacity: 1; | |
| 105 | + | } | |
| 106 | + | to { | |
| 107 | + | transform: translateX(-100%); | |
| 108 | + | opacity: 0; | |
| 109 | + | } | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | .toast-base:hover { | |
| 113 | + | filter: brightness(1.1); | |
| 114 | + | transform: scale(1.02); | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | .toast-base:active { | |
| 118 | + | transform: scale(0.98); | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | </style>⏎̸ | |
A gui/src/components/toast/ToastContainer.svelte +144 -0
| @@ -0,0 +1,144 @@ | |||
| 1 | + | <script lang="ts"> | |
| 2 | + | import Toast from './Toast.svelte'; | |
| 3 | + | ||
| 4 | + | interface ToastData { | |
| 5 | + | id: number; | |
| 6 | + | message: string; | |
| 7 | + | duration?: number; | |
| 8 | + | type?: 'info' | 'success' | 'error'; | |
| 9 | + | } | |
| 10 | + | ||
| 11 | + | // Svelte 5 rune for reactive state | |
| 12 | + | let toasts = $state<ToastData[]>([]); | |
| 13 | + | let counter = $state(0); | |
| 14 | + | let zoomToastId = $state<number | null>(null); | |
| 15 | + | let zoomDebounceTimer: number | undefined = undefined; | |
| 16 | + | ||
| 17 | + | function addToast(message: string, duration = 2500, type: 'info' | 'success' | 'error' = 'info'): number { | |
| 18 | + | const id = ++counter; | |
| 19 | + | const toast: ToastData = { id, message, duration, type }; | |
| 20 | + | ||
| 21 | + | toasts.push(toast); | |
| 22 | + | console.log('📋 Toast:', message); | |
| 23 | + | return id; | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | function dismissToast(id: number) { | |
| 27 | + | console.log(`[ToastContainer] Dismissing toast with id: ${id}`); | |
| 28 | + | const index = toasts.findIndex(t => t.id === id); | |
| 29 | + | if (index === -1) { | |
| 30 | + | console.log(`[ToastContainer] Toast with id ${id} not found in array`); | |
| 31 | + | return; | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | // Clear zoom toast tracking if this is the zoom toast | |
| 35 | + | if (zoomToastId === id) { | |
| 36 | + | console.log(`[ToastContainer] Clearing zoom toast tracking for id: ${id}`); | |
| 37 | + | zoomToastId = null; | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | console.log(`[ToastContainer] Removing toast at index ${index}, remaining: ${toasts.length - 1}`); | |
| 41 | + | toasts.splice(index, 1); | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | function clearAllToasts() { | |
| 45 | + | toasts = []; | |
| 46 | + | zoomToastId = null; | |
| 47 | + | if (zoomDebounceTimer) { | |
| 48 | + | window.clearTimeout(zoomDebounceTimer); | |
| 49 | + | zoomDebounceTimer = undefined; | |
| 50 | + | } | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | function showZoomToast(zoomLevel: number) { | |
| 54 | + | console.log('[dumber] showZoomToast called with level:', zoomLevel); | |
| 55 | + | ||
| 56 | + | // Debug: Check if toast container exists in DOM | |
| 57 | + | const container = document.querySelector('.toast-container'); | |
| 58 | + | const browserRoot = document.querySelector('.browser-component-root'); | |
| 59 | + | console.log('[dumber] DOM check - container exists:', !!container, 'browser-root exists:', !!browserRoot, 'toasts array length:', toasts.length); | |
| 60 | + | ||
| 61 | + | // Clear existing debounce timer | |
| 62 | + | if (zoomDebounceTimer) { | |
| 63 | + | window.clearTimeout(zoomDebounceTimer); | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // Remove existing zoom toasts immediately (no animation needed for replacement) | |
| 67 | + | toasts = toasts.filter(toast => { | |
| 68 | + | const isZoomToast = toast.message.includes('Zoom level:') || toast.id === zoomToastId; | |
| 69 | + | return !isZoomToast; | |
| 70 | + | }); | |
| 71 | + | ||
| 72 | + | // Show new zoom toast | |
| 73 | + | const percentage = Math.round(zoomLevel * 100); | |
| 74 | + | const message = `Zoom level: ${percentage}%`; | |
| 75 | + | const id = addToast(message, 1500, 'info'); | |
| 76 | + | zoomToastId = id; | |
| 77 | + | ||
| 78 | + | console.log('[dumber] Added zoom toast - id:', id, 'current toasts count:', toasts.length); | |
| 79 | + | ||
| 80 | + | // Debounced cleanup for rapid zoom changes | |
| 81 | + | zoomDebounceTimer = window.setTimeout(() => { | |
| 82 | + | zoomToastId = null; | |
| 83 | + | zoomDebounceTimer = undefined; | |
| 84 | + | }, 1500); | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // Expose API to global window for Go integration immediately | |
| 88 | + | // This must happen outside onMount to ensure functions are available immediately | |
| 89 | + | if (typeof window !== 'undefined') { | |
| 90 | + | window.__dumber_showToast = addToast; | |
| 91 | + | window.__dumber_dismissToast = dismissToast; | |
| 92 | + | window.__dumber_clearToasts = clearAllToasts; | |
| 93 | + | window.__dumber_showZoomToast = showZoomToast; | |
| 94 | + | console.log('✅ Toast functions exposed to window:', { | |
| 95 | + | showToast: typeof window.__dumber_showToast, | |
| 96 | + | dismissToast: typeof window.__dumber_dismissToast, | |
| 97 | + | clearToasts: typeof window.__dumber_clearToasts, | |
| 98 | + | showZoomToast: typeof window.__dumber_showZoomToast | |
| 99 | + | }); | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // Effect that runs when toasts array changes | |
| 103 | + | $effect(() => { | |
| 104 | + | const container = document.querySelector('.toast-container'); | |
| 105 | + | const browserRoot = document.querySelector('.browser-component-root'); | |
| 106 | + | console.log('[dumber] Toast state changed - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length, 'toasts:', toasts.map(t => t.message)); | |
| 107 | + | }); | |
| 108 | + | ||
| 109 | + | // One-time setup effect | |
| 110 | + | $effect(() => { | |
| 111 | + | console.log('🔄 ToastContainer initialized, functions exposed'); | |
| 112 | + | ||
| 113 | + | // Monitor container periodically for debugging | |
| 114 | + | const monitorInterval = setInterval(() => { | |
| 115 | + | const container = document.querySelector('.toast-container'); | |
| 116 | + | const browserRoot = document.querySelector('.browser-component-root'); | |
| 117 | + | console.log('[dumber] Periodic check - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length); | |
| 118 | + | }, 5000); | |
| 119 | + | ||
| 120 | + | return () => { | |
| 121 | + | clearInterval(monitorInterval); | |
| 122 | + | console.log('🗑️ ToastContainer cleanup'); | |
| 123 | + | }; | |
| 124 | + | }); | |
| 125 | + | </script> | |
| 126 | + | ||
| 127 | + | <div class="fixed top-5 left-5 z-[2147483647] pointer-events-none flex flex-col gap-2 max-w-80 visible opacity-100 backdrop-blur-sm"> | |
| 128 | + | {#each toasts as toast (toast.id)} | |
| 129 | + | <Toast | |
| 130 | + | id={toast.id} | |
| 131 | + | message={toast.message} | |
| 132 | + | duration={toast.duration} | |
| 133 | + | type={toast.type} | |
| 134 | + | onDismiss={dismissToast} | |
| 135 | + | /> | |
| 136 | + | {/each} | |
| 137 | + | </div> | |
| 138 | + | ||
| 139 | + | <style> | |
| 140 | + | :global(.toast-base) { | |
| 141 | + | pointer-events: auto; | |
| 142 | + | will-change: transform, opacity; | |
| 143 | + | } | |
| 144 | + | </style>⏎̸ | |
A gui/src/injected/gui.ts +223 -0
| @@ -0,0 +1,223 @@ | |||
| 1 | + | /** | |
| 2 | + | * Unified GUI Bundle Entry Point | |
| 3 | + | * | |
| 4 | + | * Single entry point for all WebKit GUI functionality. | |
| 5 | + | * Loads immediately and provides modular initialization system. | |
| 6 | + | */ | |
| 7 | + | ||
| 8 | + | // Import all GUI modules | |
| 9 | + | import { initializeToast, type ToastConfig } from './modules/toast'; | |
| 10 | + | import { initializeOmnibox, type OmniboxInitConfig } from './modules/omnibox'; | |
| 11 | + | import { keyboardService, type KeyboardService } from '../lib/keyboard'; | |
| 12 | + | ||
| 13 | + | // Global interface for the unified GUI system | |
| 14 | + | interface DumberGUI { | |
| 15 | + | initializeToast: (config?: ToastConfig) => Promise<void>; | |
| 16 | + | initializeOmnibox: (config?: OmniboxInitConfig) => Promise<void>; | |
| 17 | + | keyboard: KeyboardService; | |
| 18 | + | isReady: boolean; | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | // DOM readiness utility - handles all document ready states | |
| 22 | + | function whenDOMReady(callback: () => void) { | |
| 23 | + | if (document.readyState === 'loading') { | |
| 24 | + | document.addEventListener('DOMContentLoaded', callback, { once: true }); | |
| 25 | + | } else if (document.readyState === 'interactive' && !document.body) { | |
| 26 | + | // Interactive but no body yet, wait a bit more | |
| 27 | + | setTimeout(() => whenDOMReady(callback), 10); | |
| 28 | + | } else { | |
| 29 | + | // DOM ready and body exists | |
| 30 | + | callback(); | |
| 31 | + | } | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | // Create global namespace | |
| 35 | + | declare global { | |
| 36 | + | interface Window { | |
| 37 | + | __dumber_gui?: DumberGUI; | |
| 38 | + | __dumber_gui_ready?: boolean; | |
| 39 | + | __dumber_showToast?: (message: string, duration?: number, type?: 'info' | 'success' | 'error') => number | void; | |
| 40 | + | __dumber_showZoomToast?: (level: number) => void; | |
| 41 | + | __dumber_keyboard?: KeyboardService; | |
| 42 | + | // Legacy compatibility functions for Go bridge | |
| 43 | + | __dumber_toggle?: () => void; | |
| 44 | + | __dumber_find_open?: (query?: string) => void; | |
| 45 | + | __dumber_find_close?: () => void; | |
| 46 | + | __dumber_setSuggestions?: (suggestions: any[]) => void; | |
| 47 | + | __dumber_find_query?: (query: string) => void; | |
| 48 | + | } | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // Prevent multiple initialization with enhanced logging | |
| 52 | + | if (!window.__dumber_gui_ready) { | |
| 53 | + | // Skip initialization in iframes - GUI only needed in main frame | |
| 54 | + | if (window.self !== window.top) { | |
| 55 | + | console.log('🚫 Dumber GUI skipped in iframe'); | |
| 56 | + | } else { | |
| 57 | + | window.__dumber_gui_ready = true; | |
| 58 | + | ||
| 59 | + | // Initialize Svelte GUI systems immediately | |
| 60 | + | whenDOMReady(async () => { | |
| 61 | + | try { | |
| 62 | + | // Initialize toast system first | |
| 63 | + | await initializeToast(); | |
| 64 | + | ||
| 65 | + | // Verify toast functions are available | |
| 66 | + | if (typeof window.__dumber_showToast !== 'function') { | |
| 67 | + | throw new Error('Toast functions not exposed after initialization'); | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // Initialize omnibox system | |
| 71 | + | await initializeOmnibox(); | |
| 72 | + | ||
| 73 | + | console.log('✅ All GUI systems initialized successfully'); | |
| 74 | + | } catch (e) { | |
| 75 | + | console.error('❌ Failed to initialize Svelte toast system:', e); | |
| 76 | + | ||
| 77 | + | // Enhanced fallback with better error recovery | |
| 78 | + | window.__dumber_showToast = (message: string, duration: number = 2500) => { | |
| 79 | + | // Remove existing toasts to prevent overlap | |
| 80 | + | document.querySelectorAll('.dumber-fallback-toast').forEach(el => el.remove()); | |
| 81 | + | ||
| 82 | + | const toast = document.createElement('div'); | |
| 83 | + | toast.className = 'dumber-fallback-toast'; | |
| 84 | + | toast.textContent = message; | |
| 85 | + | toast.style.cssText = ` | |
| 86 | + | position: fixed; | |
| 87 | + | bottom: 20px; | |
| 88 | + | right: 20px; | |
| 89 | + | background: rgba(0,0,0,0.9); | |
| 90 | + | color: white; | |
| 91 | + | padding: 12px 16px; | |
| 92 | + | border-radius: 6px; | |
| 93 | + | z-index: 2147483647; | |
| 94 | + | font-family: system-ui, -apple-system, sans-serif; | |
| 95 | + | font-size: 14px; | |
| 96 | + | opacity: 0; | |
| 97 | + | transform: translateX(100%); | |
| 98 | + | transition: all 0.3s ease; | |
| 99 | + | max-width: 300px; | |
| 100 | + | word-wrap: break-word; | |
| 101 | + | `; | |
| 102 | + | ||
| 103 | + | if (document.body) { | |
| 104 | + | document.body.appendChild(toast); | |
| 105 | + | ||
| 106 | + | // Animate in | |
| 107 | + | requestAnimationFrame(() => { | |
| 108 | + | toast.style.opacity = '1'; | |
| 109 | + | toast.style.transform = 'translateX(0)'; | |
| 110 | + | }); | |
| 111 | + | ||
| 112 | + | // Animate out and remove | |
| 113 | + | setTimeout(() => { | |
| 114 | + | toast.style.opacity = '0'; | |
| 115 | + | toast.style.transform = 'translateX(100%)'; | |
| 116 | + | setTimeout(() => toast.remove(), 300); | |
| 117 | + | }, duration); | |
| 118 | + | ||
| 119 | + | } | |
| 120 | + | }; | |
| 121 | + | ||
| 122 | + | window.__dumber_showZoomToast = (level: number) => { | |
| 123 | + | const percentage = Math.round(level * 100); | |
| 124 | + | window.__dumber_showToast!(`Zoom: ${percentage}%`, 1500); | |
| 125 | + | }; | |
| 126 | + | ||
| 127 | + | // Expose other required functions | |
| 128 | + | window.__dumber_dismissToast = () => { | |
| 129 | + | document.querySelectorAll('.dumber-fallback-toast').forEach(el => el.remove()); | |
| 130 | + | }; | |
| 131 | + | ||
| 132 | + | window.__dumber_clearToasts = () => { | |
| 133 | + | document.querySelectorAll('.dumber-fallback-toast').forEach(el => el.remove()); | |
| 134 | + | }; | |
| 135 | + | } | |
| 136 | + | }); | |
| 137 | + | ||
| 138 | + | // Expose keyboard service globally for Go bridge | |
| 139 | + | window.__dumber_keyboard = keyboardService; | |
| 140 | + | ||
| 141 | + | // Initialize global keyboard and mouse event listeners for the keyboard service | |
| 142 | + | whenDOMReady(() => { | |
| 143 | + | // Global keyboard event listener (capture phase for high priority) | |
| 144 | + | document.addEventListener('keydown', (event) => { | |
| 145 | + | keyboardService.handleKeyboardEvent(event); | |
| 146 | + | }, true); | |
| 147 | + | ||
| 148 | + | // Global mouse event listener for navigation buttons | |
| 149 | + | document.addEventListener('mousedown', (event) => { | |
| 150 | + | keyboardService.handleMouseEvent(event); | |
| 151 | + | }, true); | |
| 152 | + | ||
| 153 | + | console.log('✅ KeyboardService initialized with global listeners'); | |
| 154 | + | }); | |
| 155 | + | ||
| 156 | + | // Legacy compatibility functions for existing Go code | |
| 157 | + | window.__dumber_toggle = () => { | |
| 158 | + | try { | |
| 159 | + | console.log('🎯 __dumber_toggle called'); | |
| 160 | + | console.log('🔧 Omnibox API available:', !!window.__dumber_omnibox); | |
| 161 | + | if (window.__dumber_omnibox?.toggle) { | |
| 162 | + | console.log('✅ Using Svelte omnibox toggle'); | |
| 163 | + | window.__dumber_omnibox.toggle(); | |
| 164 | + | } else { | |
| 165 | + | console.log('⚠️ Falling back to keyboard service'); | |
| 166 | + | keyboardService.handleNativeShortcut('cmdorctrl+l'); | |
| 167 | + | } | |
| 168 | + | } catch (error) { | |
| 169 | + | console.error('❌ Error in __dumber_toggle:', error); | |
| 170 | + | } | |
| 171 | + | }; | |
| 172 | + | ||
| 173 | + | window.__dumber_find_open = (query?: string) => { | |
| 174 | + | try { | |
| 175 | + | if (window.__dumber_omnibox?.open) { | |
| 176 | + | window.__dumber_omnibox.open('find', query); | |
| 177 | + | } else { | |
| 178 | + | keyboardService.handleNativeShortcut('cmdorctrl+f'); | |
| 179 | + | } | |
| 180 | + | } catch (error) { | |
| 181 | + | console.error('❌ Error in __dumber_find_open:', error); | |
| 182 | + | } | |
| 183 | + | }; | |
| 184 | + | ||
| 185 | + | window.__dumber_find_close = () => { | |
| 186 | + | if (window.__dumber_omnibox?.close) { | |
| 187 | + | window.__dumber_omnibox.close(); | |
| 188 | + | } else { | |
| 189 | + | keyboardService.handleNativeShortcut('escape'); | |
| 190 | + | } | |
| 191 | + | }; | |
| 192 | + | ||
| 193 | + | // Key function that Go uses to send search suggestions | |
| 194 | + | window.__dumber_setSuggestions = (suggestions: any[]) => { | |
| 195 | + | if (window.__dumber_omnibox?.setSuggestions) { | |
| 196 | + | window.__dumber_omnibox.setSuggestions(suggestions); | |
| 197 | + | } | |
| 198 | + | }; | |
| 199 | + | ||
| 200 | + | // Find query function that Go uses to set find query | |
| 201 | + | window.__dumber_find_query = (query: string) => { | |
| 202 | + | if (window.__dumber_omnibox?.findQuery) { | |
| 203 | + | window.__dumber_omnibox.findQuery(query); | |
| 204 | + | } | |
| 205 | + | }; | |
| 206 | + | ||
| 207 | + | // Create the global GUI object | |
| 208 | + | window.__dumber_gui = { | |
| 209 | + | initializeToast: async (config?: ToastConfig) => { | |
| 210 | + | return await initializeToast(config); | |
| 211 | + | }, | |
| 212 | + | ||
| 213 | + | initializeOmnibox: async (config?: OmniboxInitConfig) => { | |
| 214 | + | return await initializeOmnibox(config); | |
| 215 | + | }, | |
| 216 | + | ||
| 217 | + | keyboard: keyboardService, | |
| 218 | + | ||
| 219 | + | isReady: true | |
| 220 | + | }; | |
| 221 | + | ||
| 222 | + | } | |
| 223 | + | }⏎̸ | |
A gui/src/injected/modules/controls.ts +109 -0
| @@ -0,0 +1,109 @@ | |||
| 1 | + | /** | |
| 2 | + | * Browser Controls Module | |
| 3 | + | * | |
| 4 | + | * Provides global keyboard and mouse controls that work on all domains. | |
| 5 | + | * Only includes essential controls that can work cross-origin: | |
| 6 | + | * - Navigation (back/forward) | |
| 7 | + | * - Mouse navigation buttons | |
| 8 | + | * | |
| 9 | + | * Zoom controls are handled natively by the GTK backend | |
| 10 | + | */ | |
| 11 | + | ||
| 12 | + | export interface ControlsConfig { | |
| 13 | + | // Future configuration options can be added here | |
| 14 | + | _placeholder?: never; // Prevent empty interface warning | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | let controlsInitialized = false; | |
| 18 | + | ||
| 19 | + | export function initializeControls(_config?: ControlsConfig): void { | |
| 20 | + | if (controlsInitialized) { | |
| 21 | + | console.log('🔄 Browser controls already initialized, skipping'); | |
| 22 | + | return; | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | console.log('🚀 Initializing browser controls on:', window.location.href); | |
| 26 | + | ||
| 27 | + | // Keyboard event handler for global controls | |
| 28 | + | function handleKeyboardEvent(event: KeyboardEvent): void { | |
| 29 | + | const { altKey, key } = event; | |
| 30 | + | // Note: ctrlKey, metaKey reserved for future use | |
| 31 | + | ||
| 32 | + | try { | |
| 33 | + | // Navigation: Alt + Left Arrow (Back) | |
| 34 | + | if (altKey && key === 'ArrowLeft') { | |
| 35 | + | event.preventDefault(); | |
| 36 | + | event.stopPropagation(); | |
| 37 | + | ||
| 38 | + | if (window.history.length > 1) { | |
| 39 | + | console.log('⬅️ Navigating back'); | |
| 40 | + | window.history.back(); | |
| 41 | + | } | |
| 42 | + | return; | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // Navigation: Alt + Right Arrow (Forward) | |
| 46 | + | if (altKey && key === 'ArrowRight') { | |
| 47 | + | event.preventDefault(); | |
| 48 | + | event.stopPropagation(); | |
| 49 | + | ||
| 50 | + | console.log('➡️ Navigating forward'); | |
| 51 | + | window.history.forward(); | |
| 52 | + | return; | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | } catch (error) { | |
| 56 | + | console.error('❌ Error in keyboard handler:', error); | |
| 57 | + | } | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // Mouse event handler for navigation buttons | |
| 61 | + | function handleMouseEvent(event: MouseEvent): void { | |
| 62 | + | try { | |
| 63 | + | // Mouse button 3 (back button) | |
| 64 | + | if (event.button === 3) { | |
| 65 | + | event.preventDefault(); | |
| 66 | + | event.stopPropagation(); | |
| 67 | + | ||
| 68 | + | if (window.history.length > 1) { | |
| 69 | + | console.log('⬅️ Mouse back button pressed'); | |
| 70 | + | window.history.back(); | |
| 71 | + | } | |
| 72 | + | return; | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Mouse button 4 (forward button) | |
| 76 | + | if (event.button === 4) { | |
| 77 | + | event.preventDefault(); | |
| 78 | + | event.stopPropagation(); | |
| 79 | + | ||
| 80 | + | console.log('➡️ Mouse forward button pressed'); | |
| 81 | + | window.history.forward(); | |
| 82 | + | return; | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | } catch (error) { | |
| 86 | + | console.error('❌ Error in mouse handler:', error); | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // Add event listeners with high priority (capture phase) | |
| 91 | + | try { | |
| 92 | + | document.addEventListener('keydown', handleKeyboardEvent, true); | |
| 93 | + | document.addEventListener('mousedown', handleMouseEvent, true); | |
| 94 | + | ||
| 95 | + | controlsInitialized = true; | |
| 96 | + | console.log('✅ Browser controls initialized'); | |
| 97 | + | ||
| 98 | + | // Cleanup function for when page is unloaded | |
| 99 | + | window.addEventListener('beforeunload', () => { | |
| 100 | + | document.removeEventListener('keydown', handleKeyboardEvent, true); | |
| 101 | + | document.removeEventListener('mousedown', handleMouseEvent, true); | |
| 102 | + | controlsInitialized = false; | |
| 103 | + | console.log('🧹 Browser controls cleaned up'); | |
| 104 | + | }); | |
| 105 | + | ||
| 106 | + | } catch (error) { | |
| 107 | + | console.error('❌ Failed to initialize browser controls:', error); | |
| 108 | + | } | |
| 109 | + | }⏎̸ | |
A gui/src/injected/modules/omnibox.ts +105 -0
| @@ -0,0 +1,105 @@ | |||
| 1 | + | /** | |
| 2 | + | * Omnibox Module Initialization | |
| 3 | + | * | |
| 4 | + | * Initializes the Svelte 5 omnibox component system | |
| 5 | + | */ | |
| 6 | + | ||
| 7 | + | import { mount } from 'svelte'; | |
| 8 | + | import { Omnibox } from '../../components/omnibox'; | |
| 9 | + | import type { OmniboxConfig } from '../../components/omnibox/types'; | |
| 10 | + | ||
| 11 | + | let omniboxComponent: ReturnType<typeof mount> | null = null; | |
| 12 | + | let isInitialized = false; | |
| 13 | + | ||
| 14 | + | export interface OmniboxInitConfig extends OmniboxConfig { | |
| 15 | + | // Additional initialization options if needed | |
| 16 | + | containerId?: string; | |
| 17 | + | } | |
| 18 | + | ||
| 19 | + | /** | |
| 20 | + | * Initialize the omnibox component system | |
| 21 | + | */ | |
| 22 | + | export async function initializeOmnibox(config: OmniboxInitConfig = {}): Promise<void> { | |
| 23 | + | if (isInitialized) { | |
| 24 | + | console.warn('Omnibox already initialized'); | |
| 25 | + | return; | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | try { | |
| 29 | + | // Ensure we're in the main frame (not an iframe) | |
| 30 | + | if (window.self !== window.top) { | |
| 31 | + | console.log('🚫 Omnibox skipped in iframe'); | |
| 32 | + | return; | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | // Check if DOM is ready | |
| 36 | + | if (!document.body) { | |
| 37 | + | console.warn('DOM body not ready for omnibox initialization'); | |
| 38 | + | return; | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | // Create container element | |
| 42 | + | const containerId = config.containerId || 'dumber-omnibox-root'; | |
| 43 | + | let container = document.getElementById(containerId); | |
| 44 | + | ||
| 45 | + | if (!container) { | |
| 46 | + | container = document.createElement('div'); | |
| 47 | + | container.id = containerId; | |
| 48 | + | container.style.cssText = 'position:fixed;inset:0;z-index:2147483647;pointer-events:none;'; | |
| 49 | + | document.documentElement.appendChild(container); | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Mount the Svelte component | |
| 53 | + | omniboxComponent = mount(Omnibox, { | |
| 54 | + | target: container | |
| 55 | + | }); | |
| 56 | + | ||
| 57 | + | // Wait for the component to mount and set up the global API | |
| 58 | + | await new Promise<void>((resolve) => { | |
| 59 | + | const checkAPI = () => { | |
| 60 | + | if (window.__dumber_omnibox && typeof window.__dumber_omnibox === 'object') { | |
| 61 | + | console.log('✅ Omnibox component system initialized'); | |
| 62 | + | console.log('🔧 Global API is available:', Object.keys(window.__dumber_omnibox)); | |
| 63 | + | isInitialized = true; | |
| 64 | + | resolve(); | |
| 65 | + | } else { | |
| 66 | + | setTimeout(checkAPI, 10); // Check again in 10ms | |
| 67 | + | } | |
| 68 | + | }; | |
| 69 | + | checkAPI(); | |
| 70 | + | }); | |
| 71 | + | ||
| 72 | + | } catch (error) { | |
| 73 | + | console.error('❌ Failed to initialize omnibox component:', error); | |
| 74 | + | throw error; | |
| 75 | + | } | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | /** | |
| 79 | + | * Get the current initialization status | |
| 80 | + | */ | |
| 81 | + | export function isOmniboxInitialized(): boolean { | |
| 82 | + | return isInitialized; | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | /** | |
| 86 | + | * Cleanup omnibox component (useful for hot reload during development) | |
| 87 | + | */ | |
| 88 | + | export function cleanupOmnibox(): void { | |
| 89 | + | if (omniboxComponent) { | |
| 90 | + | try { | |
| 91 | + | omniboxComponent.$destroy?.(); | |
| 92 | + | } catch (error) { | |
| 93 | + | console.warn('Error destroying omnibox component:', error); | |
| 94 | + | } | |
| 95 | + | omniboxComponent = null; | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | const container = document.getElementById('dumber-omnibox-root'); | |
| 99 | + | if (container) { | |
| 100 | + | container.remove(); | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | isInitialized = false; | |
| 104 | + | console.log('🧹 Omnibox component cleaned up'); | |
| 105 | + | }⏎̸ | |
A gui/src/injected/modules/toast.ts +147 -0
| @@ -0,0 +1,147 @@ | |||
| 1 | + | /** | |
| 2 | + | * Toast System Module | |
| 3 | + | * | |
| 4 | + | * Provides toast notification functionality using Svelte 5 components | |
| 5 | + | * with proper DOM ready checking and theme support. | |
| 6 | + | */ | |
| 7 | + | ||
| 8 | + | import { mount, flushSync } from 'svelte'; | |
| 9 | + | import ToastContainer from '$components/toast/ToastContainer.svelte'; | |
| 10 | + | import '$lib/styles.css'; | |
| 11 | + | ||
| 12 | + | export interface ToastConfig { | |
| 13 | + | theme?: 'light' | 'dark'; | |
| 14 | + | } | |
| 15 | + | ||
| 16 | + | // Type definitions for window globals | |
| 17 | + | declare global { | |
| 18 | + | interface Window { | |
| 19 | + | __dumber_toast_loaded?: boolean; | |
| 20 | + | __dumber_initial_theme?: string; | |
| 21 | + | } | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | let toastInitialized = false; | |
| 25 | + | ||
| 26 | + | // Apply theme based on current system/GTK preference | |
| 27 | + | function updateTheme(isDark: boolean): void { | |
| 28 | + | if (isDark) { | |
| 29 | + | document.documentElement.classList.add('dark'); | |
| 30 | + | } else { | |
| 31 | + | document.documentElement.classList.remove('dark'); | |
| 32 | + | } | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | export async function initializeToast(config?: ToastConfig): Promise<void> { | |
| 36 | + | if (toastInitialized || window.__dumber_toast_loaded) { | |
| 37 | + | // Verify functions still exist - if not, reinitialize | |
| 38 | + | if (typeof window.__dumber_showToast === 'function' && | |
| 39 | + | typeof window.__dumber_showZoomToast === 'function') { | |
| 40 | + | console.log('✅ Toast system already initialized and functional'); | |
| 41 | + | return; | |
| 42 | + | } | |
| 43 | + | // If functions are missing, reinitialize | |
| 44 | + | console.log('⚠️ Toast functions missing, reinitializing...'); | |
| 45 | + | toastInitialized = false; | |
| 46 | + | window.__dumber_toast_loaded = false; | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | console.log('🚀 Initializing Svelte toast system at:', document.readyState); | |
| 50 | + | console.log('📊 DOM state check - head:', !!document.head, 'body:', !!document.body); | |
| 51 | + | window.__dumber_toast_loaded = true; | |
| 52 | + | ||
| 53 | + | // Ensure DOM is ready | |
| 54 | + | if (document.readyState === 'loading') { | |
| 55 | + | return new Promise((resolve) => { | |
| 56 | + | document.addEventListener('DOMContentLoaded', async () => { | |
| 57 | + | await initializeToast(config); | |
| 58 | + | resolve(); | |
| 59 | + | }); | |
| 60 | + | }); | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | if (!document.head || !document.body) { | |
| 64 | + | console.warn('❌ DOM structure not ready, deferring toast initialization. Retrying...'); | |
| 65 | + | window.__dumber_toast_loaded = false; // Reset the flag so we can try again | |
| 66 | + | return new Promise((resolve) => { | |
| 67 | + | const checkDOM = () => { | |
| 68 | + | if (document.head && document.body) { | |
| 69 | + | console.log('✅ DOM structure now ready, initializing toast system'); | |
| 70 | + | initializeToast(config).then(() => resolve()); | |
| 71 | + | } else { | |
| 72 | + | console.log('⏳ DOM still not ready, retrying in 50ms...'); | |
| 73 | + | setTimeout(checkDOM, 50); | |
| 74 | + | } | |
| 75 | + | }; | |
| 76 | + | setTimeout(checkDOM, 100); | |
| 77 | + | }); | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | try { | |
| 81 | + | // Find or create browser component root | |
| 82 | + | let rootElement = document.querySelector('.browser-component-root') as HTMLDivElement; | |
| 83 | + | if (!rootElement) { | |
| 84 | + | console.log('🔧 Creating browser-component-root'); | |
| 85 | + | rootElement = document.createElement('div'); | |
| 86 | + | rootElement.className = 'browser-component-root'; | |
| 87 | + | rootElement.style.cssText = 'position: fixed; top: 0; left: 0; pointer-events: none; z-index: 2147483647;'; | |
| 88 | + | document.documentElement.appendChild(rootElement); | |
| 89 | + | } else { | |
| 90 | + | console.log('✅ Found existing browser-component-root'); | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // Initialize theme | |
| 94 | + | const initialTheme = config?.theme || window.__dumber_initial_theme; | |
| 95 | + | if (initialTheme !== undefined) { | |
| 96 | + | updateTheme(initialTheme === 'dark'); | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // Mount the Svelte toast container (Svelte 5 syntax) | |
| 100 | + | mount(ToastContainer, { | |
| 101 | + | target: rootElement | |
| 102 | + | }); | |
| 103 | + | ||
| 104 | + | // Force immediate effect execution to ensure onMount callbacks run | |
| 105 | + | flushSync(); | |
| 106 | + | ||
| 107 | + | // Toast functions are now exposed by the component itself | |
| 108 | + | console.log('✅ Toast functions exposed via component instantiation'); | |
| 109 | + | ||
| 110 | + | toastInitialized = true; | |
| 111 | + | console.log('✅ Toast system initialized with Svelte 5'); | |
| 112 | + | ||
| 113 | + | } catch (error) { | |
| 114 | + | console.error('❌ Failed to initialize toast system:', error); | |
| 115 | + | ||
| 116 | + | // Fallback to basic toast system if Svelte fails | |
| 117 | + | initializeFallbackToast(); | |
| 118 | + | } | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | function exposeToastFunctions(): void { | |
| 122 | + | // The Svelte ToastContainer component already exposes these functions | |
| 123 | + | // We just need to make sure they exist, they're handled by the component | |
| 124 | + | console.log('✅ Toast functions will be exposed by ToastContainer component'); | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | function initializeFallbackToast(): void { | |
| 128 | + | console.warn('🔄 Falling back to basic toast system'); | |
| 129 | + | ||
| 130 | + | // Create basic toast container for fallback | |
| 131 | + | const fallbackContainer = document.createElement('div'); | |
| 132 | + | fallbackContainer.id = 'dumber-fallback-toast'; | |
| 133 | + | fallbackContainer.style.cssText = ` | |
| 134 | + | position: fixed; | |
| 135 | + | top: 20px; | |
| 136 | + | right: 20px; | |
| 137 | + | z-index: 10000; | |
| 138 | + | pointer-events: none; | |
| 139 | + | `; | |
| 140 | + | document.documentElement.appendChild(fallbackContainer); | |
| 141 | + | ||
| 142 | + | // Expose toast functions for fallback too | |
| 143 | + | exposeToastFunctions(); | |
| 144 | + | ||
| 145 | + | toastInitialized = true; | |
| 146 | + | console.log('✅ Fallback toast system ready'); | |
| 147 | + | }⏎̸ | |
A gui/src/lib/keyboard/KeyboardService.ts +446 -0
| @@ -0,0 +1,446 @@ | |||
| 1 | + | /** | |
| 2 | + | * Keyboard Service | |
| 3 | + | * | |
| 4 | + | * Centralized keyboard shortcut management for the Dumber Browser GUI. | |
| 5 | + | * Bridges between native GTK keyboard events and Svelte component handlers. | |
| 6 | + | */ | |
| 7 | + | ||
| 8 | + | import type { | |
| 9 | + | ShortcutConfig, | |
| 10 | + | ComponentShortcuts, | |
| 11 | + | KeyboardServiceConfig, | |
| 12 | + | KeyboardEventDetail, | |
| 13 | + | KeyboardEvent, | |
| 14 | + | KeyboardEventType | |
| 15 | + | } from './types'; | |
| 16 | + | import { COMMON_SHORTCUTS } from './types'; | |
| 17 | + | ||
| 18 | + | export class KeyboardService { | |
| 19 | + | private components = new Map<string, ComponentShortcuts>(); | |
| 20 | + | private activeComponent: string | null = null; | |
| 21 | + | private globalShortcuts: ShortcutConfig[] = []; | |
| 22 | + | private eventListeners = new Map<KeyboardEventType, Set<(event: KeyboardEvent) => void>>(); | |
| 23 | + | private debug: boolean = false; | |
| 24 | + | ||
| 25 | + | constructor(config: KeyboardServiceConfig = {}) { | |
| 26 | + | this.debug = config.debug ?? false; | |
| 27 | + | this.globalShortcuts = config.globalShortcuts ?? []; | |
| 28 | + | ||
| 29 | + | this.log('info', 'KeyboardService initialized', { config }); | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | /** | |
| 33 | + | * Register shortcuts for a component | |
| 34 | + | */ | |
| 35 | + | registerShortcuts(componentId: string, shortcuts: ShortcutConfig[]): void { | |
| 36 | + | if (this.components.has(componentId)) { | |
| 37 | + | this.log('warn', `Component ${componentId} already registered, overwriting shortcuts`); | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | const componentShortcuts: ComponentShortcuts = { | |
| 41 | + | componentId, | |
| 42 | + | shortcuts: shortcuts.map(shortcut => ({ | |
| 43 | + | ...shortcut, | |
| 44 | + | preventDefault: shortcut.preventDefault ?? true, | |
| 45 | + | stopPropagation: shortcut.stopPropagation ?? true, | |
| 46 | + | whenFocused: shortcut.whenFocused ?? false | |
| 47 | + | })), | |
| 48 | + | focused: false | |
| 49 | + | }; | |
| 50 | + | ||
| 51 | + | this.components.set(componentId, componentShortcuts); | |
| 52 | + | ||
| 53 | + | this.log('info', 'Shortcuts registered', { componentId, shortcuts: shortcuts.length }); | |
| 54 | + | this.emit('shortcut-registered', { | |
| 55 | + | shortcut: componentId, | |
| 56 | + | timestamp: Date.now(), | |
| 57 | + | targetComponent: componentId | |
| 58 | + | }); | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | /** | |
| 62 | + | * Unregister shortcuts for a component | |
| 63 | + | */ | |
| 64 | + | unregisterShortcuts(componentId: string): void { | |
| 65 | + | const component = this.components.get(componentId); | |
| 66 | + | if (!component) { | |
| 67 | + | this.log('warn', `Component ${componentId} not found for unregistration`); | |
| 68 | + | return; | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // Call cleanup function if provided | |
| 72 | + | if (component.cleanup) { | |
| 73 | + | component.cleanup(); | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | this.components.delete(componentId); | |
| 77 | + | ||
| 78 | + | // Clear active component if it was this one | |
| 79 | + | if (this.activeComponent === componentId) { | |
| 80 | + | this.activeComponent = null; | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | this.log('info', 'Shortcuts unregistered', { componentId }); | |
| 84 | + | this.emit('shortcut-unregistered', { | |
| 85 | + | shortcut: componentId, | |
| 86 | + | timestamp: Date.now(), | |
| 87 | + | targetComponent: componentId | |
| 88 | + | }); | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | /** | |
| 92 | + | * Set which component is currently focused | |
| 93 | + | */ | |
| 94 | + | setActiveComponent(componentId: string | null): void { | |
| 95 | + | // Blur previous component | |
| 96 | + | if (this.activeComponent && this.components.has(this.activeComponent)) { | |
| 97 | + | const prevComponent = this.components.get(this.activeComponent)!; | |
| 98 | + | prevComponent.focused = false; | |
| 99 | + | this.emit('component-blurred', { | |
| 100 | + | shortcut: this.activeComponent, | |
| 101 | + | timestamp: Date.now(), | |
| 102 | + | targetComponent: this.activeComponent | |
| 103 | + | }); | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | this.activeComponent = componentId; | |
| 107 | + | ||
| 108 | + | // Focus new component | |
| 109 | + | if (componentId && this.components.has(componentId)) { | |
| 110 | + | const newComponent = this.components.get(componentId)!; | |
| 111 | + | newComponent.focused = true; | |
| 112 | + | this.emit('component-focused', { | |
| 113 | + | shortcut: componentId, | |
| 114 | + | timestamp: Date.now(), | |
| 115 | + | targetComponent: componentId | |
| 116 | + | }); | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | this.log('info', 'Active component changed', { from: this.activeComponent, to: componentId }); | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | /** | |
| 123 | + | * Handle a keyboard shortcut from native GTK layer | |
| 124 | + | */ | |
| 125 | + | handleNativeShortcut(shortcut: string): boolean { | |
| 126 | + | this.log('info', 'Native shortcut received', { shortcut }); | |
| 127 | + | ||
| 128 | + | // Normalize shortcut string | |
| 129 | + | const normalizedShortcut = this.normalizeShortcut(shortcut); | |
| 130 | + | ||
| 131 | + | // Try to handle with focused component first | |
| 132 | + | if (this.activeComponent) { | |
| 133 | + | const handled = this.handleComponentShortcut(this.activeComponent, normalizedShortcut, true); | |
| 134 | + | if (handled) { | |
| 135 | + | return true; | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // Try global shortcuts | |
| 140 | + | const globalHandled = this.handleGlobalShortcuts(normalizedShortcut); | |
| 141 | + | if (globalHandled) { | |
| 142 | + | return true; | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // Try all components (for non-focused shortcuts) | |
| 146 | + | for (const [componentId] of this.components) { | |
| 147 | + | if (componentId === this.activeComponent) continue; // Already tried above | |
| 148 | + | ||
| 149 | + | const handled = this.handleComponentShortcut(componentId, normalizedShortcut, false); | |
| 150 | + | if (handled) { | |
| 151 | + | return true; | |
| 152 | + | } | |
| 153 | + | } | |
| 154 | + | ||
| 155 | + | this.log('info', 'Shortcut not handled', { shortcut: normalizedShortcut }); | |
| 156 | + | return false; | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | /** | |
| 160 | + | * Handle JavaScript keyboard events (for web page events) | |
| 161 | + | */ | |
| 162 | + | handleKeyboardEvent(event: globalThis.KeyboardEvent): boolean { | |
| 163 | + | const shortcut = this.eventToShortcut(event); | |
| 164 | + | if (!shortcut) return false; | |
| 165 | + | ||
| 166 | + | this.log('info', 'Keyboard event received', { shortcut }); | |
| 167 | + | return this.handleNativeShortcut(shortcut); | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | /** | |
| 171 | + | * Handle JavaScript mouse events (for navigation buttons) | |
| 172 | + | */ | |
| 173 | + | handleMouseEvent(event: globalThis.MouseEvent): boolean { | |
| 174 | + | try { | |
| 175 | + | // Mouse button 3 (back button) | |
| 176 | + | if (event.button === 3) { | |
| 177 | + | event.preventDefault(); | |
| 178 | + | event.stopPropagation(); | |
| 179 | + | ||
| 180 | + | if (window.history.length > 1) { | |
| 181 | + | console.log('⬅️ Mouse back button pressed'); | |
| 182 | + | window.history.back(); | |
| 183 | + | } | |
| 184 | + | return true; | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | // Mouse button 4 (forward button) | |
| 188 | + | if (event.button === 4) { | |
| 189 | + | event.preventDefault(); | |
| 190 | + | event.stopPropagation(); | |
| 191 | + | ||
| 192 | + | console.log('➡️ Mouse forward button pressed'); | |
| 193 | + | window.history.forward(); | |
| 194 | + | return true; | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | } catch (error) { | |
| 198 | + | this.log('error', 'Mouse handler error', { error }); | |
| 199 | + | } | |
| 200 | + | ||
| 201 | + | return false; | |
| 202 | + | } | |
| 203 | + | ||
| 204 | + | /** | |
| 205 | + | * Add event listener for keyboard service events | |
| 206 | + | */ | |
| 207 | + | addEventListener(type: KeyboardEventType, listener: (event: KeyboardEvent) => void): void { | |
| 208 | + | if (!this.eventListeners.has(type)) { | |
| 209 | + | this.eventListeners.set(type, new Set()); | |
| 210 | + | } | |
| 211 | + | this.eventListeners.get(type)!.add(listener); | |
| 212 | + | } | |
| 213 | + | ||
| 214 | + | /** | |
| 215 | + | * Remove event listener | |
| 216 | + | */ | |
| 217 | + | removeEventListener(type: KeyboardEventType, listener: (event: KeyboardEvent) => void): void { | |
| 218 | + | const listeners = this.eventListeners.get(type); | |
| 219 | + | if (listeners) { | |
| 220 | + | listeners.delete(listener); | |
| 221 | + | } | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | /** | |
| 225 | + | * Get all registered shortcuts for debugging | |
| 226 | + | */ | |
| 227 | + | getDebugInfo(): object { | |
| 228 | + | return { | |
| 229 | + | components: Array.from(this.components.entries()).map(([id, comp]) => ({ | |
| 230 | + | id, | |
| 231 | + | shortcuts: comp.shortcuts.length, | |
| 232 | + | focused: comp.focused | |
| 233 | + | })), | |
| 234 | + | activeComponent: this.activeComponent, | |
| 235 | + | globalShortcuts: this.globalShortcuts.length | |
| 236 | + | }; | |
| 237 | + | } | |
| 238 | + | ||
| 239 | + | // Private methods | |
| 240 | + | ||
| 241 | + | private handleComponentShortcut(componentId: string, shortcut: string, respectFocus: boolean): boolean { | |
| 242 | + | const component = this.components.get(componentId); | |
| 243 | + | if (!component) return false; | |
| 244 | + | ||
| 245 | + | for (const shortcutConfig of component.shortcuts) { | |
| 246 | + | if (this.normalizeShortcut(shortcutConfig.key) === shortcut) { | |
| 247 | + | // Check focus requirement | |
| 248 | + | if (respectFocus && shortcutConfig.whenFocused && !component.focused) { | |
| 249 | + | continue; | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | try { | |
| 253 | + | shortcutConfig.handler(); | |
| 254 | + | this.log('info', 'Shortcut handled', { | |
| 255 | + | shortcut, | |
| 256 | + | componentId, | |
| 257 | + | focused: component.focused, | |
| 258 | + | description: shortcutConfig.description | |
| 259 | + | }); | |
| 260 | + | ||
| 261 | + | this.emit('shortcut-triggered', { | |
| 262 | + | shortcut, | |
| 263 | + | timestamp: Date.now(), | |
| 264 | + | targetComponent: componentId | |
| 265 | + | }); | |
| 266 | + | ||
| 267 | + | return true; | |
| 268 | + | } catch (error) { | |
| 269 | + | this.log('error', 'Shortcut handler error', { shortcut, componentId, error }); | |
| 270 | + | } | |
| 271 | + | } | |
| 272 | + | } | |
| 273 | + | ||
| 274 | + | return false; | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | private handleGlobalShortcuts(shortcut: string): boolean { | |
| 278 | + | for (const shortcutConfig of this.globalShortcuts) { | |
| 279 | + | if (this.normalizeShortcut(shortcutConfig.key) === shortcut) { | |
| 280 | + | try { | |
| 281 | + | shortcutConfig.handler(); | |
| 282 | + | this.log('info', 'Global shortcut handled', { shortcut, description: shortcutConfig.description }); | |
| 283 | + | ||
| 284 | + | this.emit('shortcut-triggered', { | |
| 285 | + | shortcut, | |
| 286 | + | timestamp: Date.now() | |
| 287 | + | }); | |
| 288 | + | ||
| 289 | + | return true; | |
| 290 | + | } catch (error) { | |
| 291 | + | this.log('error', 'Global shortcut handler error', { shortcut, error }); | |
| 292 | + | } | |
| 293 | + | } | |
| 294 | + | } | |
| 295 | + | return false; | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | private normalizeShortcut(shortcut: string): string { | |
| 299 | + | return shortcut.toLowerCase().replace(/\s+/g, ''); | |
| 300 | + | } | |
| 301 | + | ||
| 302 | + | private eventToShortcut(event: globalThis.KeyboardEvent): string | null { | |
| 303 | + | const parts: string[] = []; | |
| 304 | + | ||
| 305 | + | // Add modifiers using MODIFIER_KEYS mapping | |
| 306 | + | if (event.ctrlKey && event.metaKey) { | |
| 307 | + | // Both ctrl and meta pressed - use cmdorctrl | |
| 308 | + | parts.push('cmdorctrl'); | |
| 309 | + | } else if (event.ctrlKey) { | |
| 310 | + | parts.push('ctrl'); | |
| 311 | + | } else if (event.metaKey) { | |
| 312 | + | parts.push('cmd'); | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | if (event.altKey) parts.push('alt'); | |
| 316 | + | if (event.shiftKey) parts.push('shift'); | |
| 317 | + | ||
| 318 | + | // Add key | |
| 319 | + | if (event.key) { | |
| 320 | + | parts.push(event.key.toLowerCase()); | |
| 321 | + | } | |
| 322 | + | ||
| 323 | + | return parts.length > 0 ? parts.join('+') : null; | |
| 324 | + | } | |
| 325 | + | ||
| 326 | + | private emit(type: KeyboardEventType, detail: KeyboardEventDetail): void { | |
| 327 | + | const listeners = this.eventListeners.get(type); | |
| 328 | + | if (listeners) { | |
| 329 | + | const keyboardEvent: KeyboardEvent = { type, detail }; | |
| 330 | + | listeners.forEach(listener => { | |
| 331 | + | try { | |
| 332 | + | listener(keyboardEvent); | |
| 333 | + | } catch (error) { | |
| 334 | + | this.log('error', 'Event listener error', { type, error }); | |
| 335 | + | } | |
| 336 | + | }); | |
| 337 | + | } | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | private log(level: 'info' | 'warn' | 'error' | string, message?: string, data?: unknown): void { | |
| 341 | + | if (!this.debug && level !== 'error') return; | |
| 342 | + | ||
| 343 | + | const logMessage = message ? `[KeyboardService] ${message}` : `[KeyboardService] ${level}`; | |
| 344 | + | ||
| 345 | + | switch (level) { | |
| 346 | + | case 'error': | |
| 347 | + | console.error(logMessage, data); | |
| 348 | + | break; | |
| 349 | + | case 'warn': | |
| 350 | + | console.warn(logMessage, data); | |
| 351 | + | break; | |
| 352 | + | default: | |
| 353 | + | console.log(logMessage, data); | |
| 354 | + | } | |
| 355 | + | } | |
| 356 | + | } | |
| 357 | + | ||
| 358 | + | // Create and export singleton instance with global shortcuts | |
| 359 | + | export const keyboardService = new KeyboardService({ | |
| 360 | + | debug: false, // Disable debug logging in production | |
| 361 | + | globalShortcuts: [ | |
| 362 | + | // Navigation shortcuts (migrated from controls module) | |
| 363 | + | { | |
| 364 | + | key: 'alt+arrowleft', | |
| 365 | + | handler: () => { | |
| 366 | + | if (window.history.length > 1) { | |
| 367 | + | window.history.back(); | |
| 368 | + | } | |
| 369 | + | }, | |
| 370 | + | description: 'Navigate back (Alt+Left Arrow)' | |
| 371 | + | }, | |
| 372 | + | { | |
| 373 | + | key: 'alt+arrowright', | |
| 374 | + | handler: () => { | |
| 375 | + | window.history.forward(); | |
| 376 | + | }, | |
| 377 | + | description: 'Navigate forward (Alt+Right Arrow)' | |
| 378 | + | }, | |
| 379 | + | // Global UI shortcuts (migrated from UCM JavaScript) | |
| 380 | + | { | |
| 381 | + | key: COMMON_SHORTCUTS.OMNIBOX_OPEN, | |
| 382 | + | handler: () => { | |
| 383 | + | try { | |
| 384 | + | if (window.__dumber_omnibox?.toggle) { | |
| 385 | + | console.log('🎯 Using omnibox API directly'); | |
| 386 | + | window.__dumber_omnibox.toggle(); | |
| 387 | + | } else if (typeof window.__dumber_toggle === 'function') { | |
| 388 | + | console.log('🎯 Using legacy toggle function'); | |
| 389 | + | window.__dumber_toggle(); | |
| 390 | + | } else { | |
| 391 | + | console.warn('⚠️ No omnibox toggle function available'); | |
| 392 | + | } | |
| 393 | + | } catch (error) { | |
| 394 | + | console.error('❌ Error in omnibox open handler:', error); | |
| 395 | + | } | |
| 396 | + | }, | |
| 397 | + | description: 'Open omnibox (Ctrl/Cmd+L)' | |
| 398 | + | }, | |
| 399 | + | { | |
| 400 | + | key: COMMON_SHORTCUTS.FIND_OPEN, | |
| 401 | + | handler: () => { | |
| 402 | + | try { | |
| 403 | + | if (window.__dumber_omnibox?.open) { | |
| 404 | + | console.log('🔍 Using omnibox find API directly'); | |
| 405 | + | window.__dumber_omnibox.open('find'); | |
| 406 | + | } else if (typeof window.__dumber_find_open === 'function') { | |
| 407 | + | console.log('🔍 Using legacy find function'); | |
| 408 | + | window.__dumber_find_open(); | |
| 409 | + | } else { | |
| 410 | + | console.warn('⚠️ No find function available'); | |
| 411 | + | } | |
| 412 | + | } catch (error) { | |
| 413 | + | console.error('❌ Error in find open handler:', error); | |
| 414 | + | } | |
| 415 | + | }, | |
| 416 | + | description: 'Open find bar (Ctrl/Cmd+F)' | |
| 417 | + | }, | |
| 418 | + | // Copy URL shortcut (Ctrl/Cmd+Shift+C) | |
| 419 | + | { | |
| 420 | + | key: 'cmdorctrl+shift+c', | |
| 421 | + | handler: async () => { | |
| 422 | + | try { | |
| 423 | + | const url = window.location.href; | |
| 424 | + | await navigator.clipboard.writeText(url); | |
| 425 | + | ||
| 426 | + | // Show toast notification | |
| 427 | + | if (typeof window.__dumber_showToast === 'function') { | |
| 428 | + | window.__dumber_showToast('URL copied to clipboard!', 2000, 'success'); | |
| 429 | + | } | |
| 430 | + | } catch (error) { | |
| 431 | + | console.error('Failed to copy URL:', error); | |
| 432 | + | ||
| 433 | + | // Show error toast | |
| 434 | + | if (typeof window.__dumber_showToast === 'function') { | |
| 435 | + | window.__dumber_showToast('Failed to copy URL', 2000, 'error'); | |
| 436 | + | } | |
| 437 | + | } | |
| 438 | + | }, | |
| 439 | + | description: 'Copy current URL to clipboard (Ctrl/Cmd+Shift+C)' | |
| 440 | + | } | |
| 441 | + | ] | |
| 442 | + | }); | |
| 443 | + | ||
| 444 | + | // Export types for use in components | |
| 445 | + | export type { ShortcutConfig, ComponentShortcuts, KeyboardServiceConfig } from './types'; | |
| 446 | + | export { COMMON_SHORTCUTS } from './types';⏎̸ | |
A gui/src/lib/keyboard/index.ts +17 -0
| @@ -0,0 +1,17 @@ | |||
| 1 | + | /** | |
| 2 | + | * Keyboard Service Module | |
| 3 | + | * | |
| 4 | + | * Centralized keyboard shortcut management for Dumber Browser. | |
| 5 | + | * Provides type-safe keyboard event handling and component integration. | |
| 6 | + | */ | |
| 7 | + | ||
| 8 | + | export { KeyboardService, keyboardService } from './KeyboardService'; | |
| 9 | + | export type { | |
| 10 | + | ShortcutConfig, | |
| 11 | + | ComponentShortcuts, | |
| 12 | + | KeyboardServiceConfig, | |
| 13 | + | KeyboardEventDetail, | |
| 14 | + | KeyboardEvent, | |
| 15 | + | KeyboardEventType | |
| 16 | + | } from './types'; | |
| 17 | + | export { MODIFIER_KEYS, COMMON_SHORTCUTS } from './types';⏎̸ | |
A gui/src/lib/keyboard/types.ts +101 -0
| @@ -0,0 +1,101 @@ | |||
| 1 | + | /** | |
| 2 | + | * Keyboard Service Types | |
| 3 | + | * | |
| 4 | + | * Type definitions for the unified keyboard shortcut system. | |
| 5 | + | * Provides type-safe interfaces for registering and handling keyboard shortcuts. | |
| 6 | + | */ | |
| 7 | + | ||
| 8 | + | export interface ShortcutConfig { | |
| 9 | + | /** The keyboard shortcut key combination (e.g., 'cmdorctrl+l', 'escape', 'enter') */ | |
| 10 | + | key: string; | |
| 11 | + | ||
| 12 | + | /** Function to execute when the shortcut is triggered */ | |
| 13 | + | handler: () => void; | |
| 14 | + | ||
| 15 | + | /** Whether to prevent the default browser behavior (default: true) */ | |
| 16 | + | preventDefault?: boolean; | |
| 17 | + | ||
| 18 | + | /** Whether to stop event propagation (default: true) */ | |
| 19 | + | stopPropagation?: boolean; | |
| 20 | + | ||
| 21 | + | /** Only trigger when this component is focused (default: false) */ | |
| 22 | + | whenFocused?: boolean; | |
| 23 | + | ||
| 24 | + | /** Optional description for debugging */ | |
| 25 | + | description?: string; | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | export interface KeyboardEventDetail { | |
| 29 | + | /** The original keyboard shortcut string */ | |
| 30 | + | shortcut: string; | |
| 31 | + | ||
| 32 | + | /** Timestamp when the event occurred */ | |
| 33 | + | timestamp: number; | |
| 34 | + | ||
| 35 | + | /** Component that should handle this event (if specified) */ | |
| 36 | + | targetComponent?: string; | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | export interface ComponentShortcuts { | |
| 40 | + | /** Unique component identifier */ | |
| 41 | + | componentId: string; | |
| 42 | + | ||
| 43 | + | /** Array of shortcuts registered by this component */ | |
| 44 | + | shortcuts: ShortcutConfig[]; | |
| 45 | + | ||
| 46 | + | /** Whether this component is currently focused */ | |
| 47 | + | focused: boolean; | |
| 48 | + | ||
| 49 | + | /** Optional cleanup function called when component is destroyed */ | |
| 50 | + | cleanup?: () => void; | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | export interface KeyboardServiceConfig { | |
| 54 | + | /** Enable debug logging for keyboard events */ | |
| 55 | + | debug?: boolean; | |
| 56 | + | ||
| 57 | + | /** Global shortcuts that work regardless of component focus */ | |
| 58 | + | globalShortcuts?: ShortcutConfig[]; | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | /** | |
| 62 | + | * Event types for keyboard service | |
| 63 | + | */ | |
| 64 | + | export type KeyboardEventType = | |
| 65 | + | | 'shortcut-triggered' | |
| 66 | + | | 'component-focused' | |
| 67 | + | | 'component-blurred' | |
| 68 | + | | 'shortcut-registered' | |
| 69 | + | | 'shortcut-unregistered'; | |
| 70 | + | ||
| 71 | + | export interface KeyboardEvent { | |
| 72 | + | type: KeyboardEventType; | |
| 73 | + | detail: KeyboardEventDetail | ComponentShortcuts | ShortcutConfig; | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | /** | |
| 77 | + | * Keyboard modifiers mapping | |
| 78 | + | */ | |
| 79 | + | export const MODIFIER_KEYS = { | |
| 80 | + | ctrl: 'ctrlKey', | |
| 81 | + | cmd: 'metaKey', | |
| 82 | + | cmdorctrl: navigator.platform.includes('Mac') ? 'metaKey' : 'ctrlKey', | |
| 83 | + | alt: 'altKey', | |
| 84 | + | shift: 'shiftKey' | |
| 85 | + | } as const; | |
| 86 | + | ||
| 87 | + | /** | |
| 88 | + | * Common shortcut patterns used throughout the application | |
| 89 | + | */ | |
| 90 | + | export const COMMON_SHORTCUTS = { | |
| 91 | + | OMNIBOX_OPEN: 'cmdorctrl+l', | |
| 92 | + | FIND_OPEN: 'cmdorctrl+f', | |
| 93 | + | ESCAPE: 'escape', | |
| 94 | + | ENTER: 'enter', | |
| 95 | + | ARROW_UP: 'arrowup', | |
| 96 | + | ARROW_DOWN: 'arrowdown', | |
| 97 | + | ARROW_LEFT: 'arrowleft', | |
| 98 | + | ARROW_RIGHT: 'arrowright', | |
| 99 | + | TAB: 'tab', | |
| 100 | + | SHIFT_TAB: 'shift+tab' | |
| 101 | + | } as const;⏎̸ | |
A gui/src/lib/styles.css +1 -0
| @@ -0,0 +1,1 @@ | |||
| 1 | + | @import '../styles/tailwind.css';⏎̸ | |
A gui/src/lib/types.ts +44 -0
| @@ -0,0 +1,44 @@ | |||
| 1 | + | // Global window API types for browser integration | |
| 2 | + | declare global { | |
| 3 | + | interface Window { | |
| 4 | + | // Toast system API | |
| 5 | + | __dumber_toast_loaded?: boolean; | |
| 6 | + | __dumber_showToast?: (message: string, duration?: number, type?: 'info' | 'success' | 'error') => number | void; | |
| 7 | + | __dumber_dismissToast?: (id: number) => void; | |
| 8 | + | __dumber_clearToasts?: () => void; | |
| 9 | + | __dumber_showZoomToast?: (zoomLevel: number) => void; | |
| 10 | + | ||
| 11 | + | // Theme integration | |
| 12 | + | __dumber_initial_theme?: string; | |
| 13 | + | __dumber_setTheme?: (theme: 'light' | 'dark') => void; | |
| 14 | + | ||
| 15 | + | // WebKit message handler | |
| 16 | + | webkit?: { | |
| 17 | + | messageHandlers?: { | |
| 18 | + | dumber?: { | |
| 19 | + | postMessage: (message: string) => void; | |
| 20 | + | }; | |
| 21 | + | }; | |
| 22 | + | }; | |
| 23 | + | } | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | export interface ToastAPI { | |
| 27 | + | show: (message: string, duration?: number, type?: 'info' | 'success' | 'error') => number; | |
| 28 | + | dismiss: (id: number) => void; | |
| 29 | + | clear: () => void; | |
| 30 | + | showZoom: (zoomLevel: number) => void; | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | export interface ThemeAPI { | |
| 34 | + | setTheme: (theme: 'light' | 'dark') => void; | |
| 35 | + | getCurrentTheme: () => 'light' | 'dark'; | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // Message types for WebKit communication | |
| 39 | + | export interface BrowserMessage { | |
| 40 | + | action: string; | |
| 41 | + | data?: unknown; | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | export {}; // Make this file a module⏎̸ | |
A gui/src/main.ts +73 -0
| @@ -0,0 +1,73 @@ | |||
| 1 | + | import { AppService } from './services/app.js'; | |
| 2 | + | import { BrowserControlsService } from './services/browser-controls.js'; | |
| 3 | + | import { DOMRenderer } from './utils/dom.js'; | |
| 4 | + | ||
| 5 | + | class DumberBrowserApp { | |
| 6 | + | private appService: AppService; | |
| 7 | + | private browserControls: BrowserControlsService; | |
| 8 | + | private domRenderer: DOMRenderer; | |
| 9 | + | ||
| 10 | + | constructor() { | |
| 11 | + | this.appService = new AppService(); | |
| 12 | + | this.browserControls = new BrowserControlsService(); | |
| 13 | + | this.domRenderer = new DOMRenderer(); | |
| 14 | + | } | |
| 15 | + | ||
| 16 | + | async initialize(): Promise<void> { | |
| 17 | + | try { | |
| 18 | + | // Show loading states | |
| 19 | + | this.domRenderer.showLoading('history'); | |
| 20 | + | this.domRenderer.showLoading('shortcuts'); | |
| 21 | + | ||
| 22 | + | // Initialize services | |
| 23 | + | await this.appService.initialize(); | |
| 24 | + | ||
| 25 | + | // Initialize browser controls | |
| 26 | + | await this.browserControls.initialize(); | |
| 27 | + | ||
| 28 | + | // Render the UI | |
| 29 | + | this.render(); | |
| 30 | + | ||
| 31 | + | console.log('✓ Dumber Browser initialized successfully'); | |
| 32 | + | } catch (error) { | |
| 33 | + | console.error('Failed to initialize Dumber Browser:', error); | |
| 34 | + | this.handleInitializationError(); | |
| 35 | + | } | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | private render(): void { | |
| 39 | + | try { | |
| 40 | + | // Render history | |
| 41 | + | const history = this.appService.getHistory(); | |
| 42 | + | this.domRenderer.displayHistory(history); | |
| 43 | + | ||
| 44 | + | // Render shortcuts | |
| 45 | + | const shortcuts = this.appService.getShortcuts(); | |
| 46 | + | this.domRenderer.displayShortcuts(shortcuts); | |
| 47 | + | } catch (error) { | |
| 48 | + | console.error('Failed to render UI:', error); | |
| 49 | + | this.domRenderer.showError('history', 'Failed to load history'); | |
| 50 | + | this.domRenderer.showError('shortcuts', 'Failed to load shortcuts'); | |
| 51 | + | } | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | private handleInitializationError(): void { | |
| 55 | + | this.domRenderer.showError('history', 'Failed to initialize application'); | |
| 56 | + | this.domRenderer.showError('shortcuts', 'Failed to initialize application'); | |
| 57 | + | } | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // Initialize the application when the DOM is ready | |
| 61 | + | function initializeApp(): void { | |
| 62 | + | const app = new DumberBrowserApp(); | |
| 63 | + | app.initialize().catch(error => { | |
| 64 | + | console.error('Critical error during app initialization:', error); | |
| 65 | + | }); | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // Wait for DOM to be ready | |
| 69 | + | if (document.readyState === 'loading') { | |
| 70 | + | document.addEventListener('DOMContentLoaded', initializeApp); | |
| 71 | + | } else { | |
| 72 | + | initializeApp(); | |
| 73 | + | }⏎̸ | |
A gui/src/pages/Homepage.svelte +407 -0
| @@ -0,0 +1,407 @@ | |||
| 1 | + | <script lang="ts"> | |
| 2 | + | import { onMount } from 'svelte'; | |
| 3 | + | ||
| 4 | + | interface HistoryItem { | |
| 5 | + | id: number; | |
| 6 | + | url: string; | |
| 7 | + | title: string; | |
| 8 | + | visit_count: number; | |
| 9 | + | last_visited: string; | |
| 10 | + | created_at: string; | |
| 11 | + | } | |
| 12 | + | ||
| 13 | + | interface Shortcut { | |
| 14 | + | key: string; | |
| 15 | + | description: string; | |
| 16 | + | action: () => void; | |
| 17 | + | } | |
| 18 | + | ||
| 19 | + | let historyItems = $state<HistoryItem[]>([]); | |
| 20 | + | let shortcuts = $state<Shortcut[]>([]); | |
| 21 | + | let historyLoading = $state(true); | |
| 22 | + | let shortcutsLoading = $state(true); | |
| 23 | + | ||
| 24 | + | // Initialize shortcuts (these are browser shortcuts, not dynamic from API) | |
| 25 | + | const initializeShortcuts = () => { | |
| 26 | + | shortcuts = [ | |
| 27 | + | { | |
| 28 | + | key: 'Ctrl+L', | |
| 29 | + | description: 'Focus address bar', | |
| 30 | + | action: () => { | |
| 31 | + | // This will be handled by the browser's keyboard shortcuts | |
| 32 | + | console.log('Ctrl+L triggered'); | |
| 33 | + | } | |
| 34 | + | }, | |
| 35 | + | { | |
| 36 | + | key: 'Ctrl+F', | |
| 37 | + | description: 'Find in page', | |
| 38 | + | action: () => { | |
| 39 | + | // This will be handled by the browser's keyboard shortcuts | |
| 40 | + | console.log('Ctrl+F triggered'); | |
| 41 | + | } | |
| 42 | + | }, | |
| 43 | + | { | |
| 44 | + | key: 'Ctrl+R', | |
| 45 | + | description: 'Reload page', | |
| 46 | + | action: () => { | |
| 47 | + | window.location.reload(); | |
| 48 | + | } | |
| 49 | + | }, | |
| 50 | + | { | |
| 51 | + | key: 'Ctrl+0', | |
| 52 | + | description: 'Reset zoom', | |
| 53 | + | action: () => { | |
| 54 | + | // This will be handled by the browser's zoom controls | |
| 55 | + | console.log('Ctrl+0 triggered'); | |
| 56 | + | } | |
| 57 | + | }, | |
| 58 | + | { | |
| 59 | + | key: 'Ctrl++', | |
| 60 | + | description: 'Zoom in', | |
| 61 | + | action: () => { | |
| 62 | + | // This will be handled by the browser's zoom controls | |
| 63 | + | console.log('Ctrl++ triggered'); | |
| 64 | + | } | |
| 65 | + | }, | |
| 66 | + | { | |
| 67 | + | key: 'Ctrl+-', | |
| 68 | + | description: 'Zoom out', | |
| 69 | + | action: () => { | |
| 70 | + | // This will be handled by the browser's zoom controls | |
| 71 | + | console.log('Ctrl+- triggered'); | |
| 72 | + | } | |
| 73 | + | } | |
| 74 | + | ]; | |
| 75 | + | shortcutsLoading = false; | |
| 76 | + | }; | |
| 77 | + | ||
| 78 | + | // Fetch recent history from the API | |
| 79 | + | const fetchHistory = async () => { | |
| 80 | + | try { | |
| 81 | + | const response = await fetch('dumb://homepage/api/history/recent?limit=20'); | |
| 82 | + | if (response.ok) { | |
| 83 | + | const data = await response.json(); | |
| 84 | + | historyItems = Array.isArray(data) ? data : []; | |
| 85 | + | } else { | |
| 86 | + | console.warn('Failed to fetch history:', response.status); | |
| 87 | + | historyItems = []; | |
| 88 | + | } | |
| 89 | + | } catch (error) { | |
| 90 | + | console.error('Error fetching history:', error); | |
| 91 | + | historyItems = []; | |
| 92 | + | } finally { | |
| 93 | + | historyLoading = false; | |
| 94 | + | } | |
| 95 | + | }; | |
| 96 | + | ||
| 97 | + | // Navigate to a URL when history item is clicked | |
| 98 | + | const navigateTo = (url: string) => { | |
| 99 | + | window.location.href = url; | |
| 100 | + | }; | |
| 101 | + | ||
| 102 | + | // Get domain from URL | |
| 103 | + | const getDomain = (url: string): string => { | |
| 104 | + | try { | |
| 105 | + | return new URL(url).hostname; | |
| 106 | + | } catch { | |
| 107 | + | return url; | |
| 108 | + | } | |
| 109 | + | }; | |
| 110 | + | ||
| 111 | + | // Format relative time | |
| 112 | + | const formatTime = (timestamp: string): string => { | |
| 113 | + | try { | |
| 114 | + | const date = new Date(timestamp); | |
| 115 | + | const now = new Date(); | |
| 116 | + | const diff = now.getTime() - date.getTime(); | |
| 117 | + | ||
| 118 | + | const minutes = Math.floor(diff / (1000 * 60)); | |
| 119 | + | const hours = Math.floor(diff / (1000 * 60 * 60)); | |
| 120 | + | const days = Math.floor(diff / (1000 * 60 * 60 * 24)); | |
| 121 | + | ||
| 122 | + | if (minutes < 1) return 'Just now'; | |
| 123 | + | if (minutes < 60) return `${minutes}m ago`; | |
| 124 | + | if (hours < 24) return `${hours}h ago`; | |
| 125 | + | if (days < 7) return `${days}d ago`; | |
| 126 | + | ||
| 127 | + | return date.toLocaleDateString(); | |
| 128 | + | } catch { | |
| 129 | + | return ''; | |
| 130 | + | } | |
| 131 | + | }; | |
| 132 | + | ||
| 133 | + | onMount(() => { | |
| 134 | + | initializeShortcuts(); | |
| 135 | + | fetchHistory(); | |
| 136 | + | }); | |
| 137 | + | ||
| 138 | + | // Combined loading state | |
| 139 | + | const loading = $derived(historyLoading || shortcutsLoading); | |
| 140 | + | </script> | |
| 141 | + | ||
| 142 | + | <div class="container"> | |
| 143 | + | <div class="history-section"> | |
| 144 | + | <h2 class="section-title">Recent History</h2> | |
| 145 | + | <div class="history-list"> | |
| 146 | + | {#if historyLoading} | |
| 147 | + | <div class="loading">Loading history...</div> | |
| 148 | + | {:else if historyItems.length === 0} | |
| 149 | + | <div class="empty-state"> | |
| 150 | + | <h3>No history yet</h3> | |
| 151 | + | <p>Start browsing to see your recent history here.</p> | |
| 152 | + | </div> | |
| 153 | + | {:else} | |
| 154 | + | {#each historyItems as item (item.url)} | |
| 155 | + | <div | |
| 156 | + | class="history-item" | |
| 157 | + | role="button" | |
| 158 | + | tabindex="0" | |
| 159 | + | onclick={() => navigateTo(item.url)} | |
| 160 | + | onkeydown={(e) => e.key === 'Enter' && navigateTo(item.url)} | |
| 161 | + | > | |
| 162 | + | <div class="history-line"> | |
| 163 | + | <div class="history-favicon-chip"> | |
| 164 | + | <div class="history-favicon-fallback">🌐</div> | |
| 165 | + | </div> | |
| 166 | + | <div class="history-title">{item.title || 'Untitled'}</div> | |
| 167 | + | <div class="history-sep">•</div> | |
| 168 | + | <div class="history-domain">{getDomain(item.url)}</div> | |
| 169 | + | <div class="history-sep">•</div> | |
| 170 | + | <div class="history-url">{item.url}</div> | |
| 171 | + | <div class="history-time">{formatTime(item.last_visited)}</div> | |
| 172 | + | </div> | |
| 173 | + | </div> | |
| 174 | + | {/each} | |
| 175 | + | {/if} | |
| 176 | + | </div> | |
| 177 | + | </div> | |
| 178 | + | ||
| 179 | + | <div class="shortcuts-section"> | |
| 180 | + | <h2 class="section-title">Keyboard Shortcuts</h2> | |
| 181 | + | <div class="shortcuts-grid"> | |
| 182 | + | {#if shortcutsLoading} | |
| 183 | + | <div class="loading">Loading shortcuts...</div> | |
| 184 | + | {:else} | |
| 185 | + | {#each shortcuts as shortcut (shortcut.key)} | |
| 186 | + | <div | |
| 187 | + | class="shortcut" | |
| 188 | + | role="button" | |
| 189 | + | tabindex="0" | |
| 190 | + | onclick={shortcut.action} | |
| 191 | + | onkeydown={(e) => e.key === 'Enter' && shortcut.action()} | |
| 192 | + | > | |
| 193 | + | <div class="shortcut-key">{shortcut.key}</div> | |
| 194 | + | <div class="shortcut-desc">{shortcut.description}</div> | |
| 195 | + | </div> | |
| 196 | + | {/each} | |
| 197 | + | {/if} | |
| 198 | + | </div> | |
| 199 | + | </div> | |
| 200 | + | </div> | |
| 201 | + | ||
| 202 | + | <style> | |
| 203 | + | /* Global styles - using CSS to match the original design */ | |
| 204 | + | :global(*) { | |
| 205 | + | margin: 0; | |
| 206 | + | padding: 0; | |
| 207 | + | box-sizing: border-box; | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | :global(body) { | |
| 211 | + | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| 212 | + | background: #1a1a1a; | |
| 213 | + | color: #ffffff; | |
| 214 | + | height: 100vh; | |
| 215 | + | display: flex; | |
| 216 | + | flex-direction: column; | |
| 217 | + | overflow-x: hidden; | |
| 218 | + | } | |
| 219 | + | ||
| 220 | + | .container { | |
| 221 | + | flex: 1; | |
| 222 | + | display: flex; | |
| 223 | + | max-width: 1200px; | |
| 224 | + | margin: 0 auto; | |
| 225 | + | width: 100%; | |
| 226 | + | padding: 2rem; | |
| 227 | + | gap: 2rem; | |
| 228 | + | overflow-x: hidden; | |
| 229 | + | } | |
| 230 | + | ||
| 231 | + | .history-section { | |
| 232 | + | flex: 1; | |
| 233 | + | min-height: 0; | |
| 234 | + | min-width: 0; | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | .shortcuts-section { | |
| 238 | + | flex: 1; | |
| 239 | + | min-height: 0; | |
| 240 | + | min-width: 0; | |
| 241 | + | } | |
| 242 | + | ||
| 243 | + | .section-title { | |
| 244 | + | font-size: 1.5rem; | |
| 245 | + | margin-bottom: 1rem; | |
| 246 | + | color: #ffffff; | |
| 247 | + | border-bottom: 2px solid #404040; | |
| 248 | + | padding-bottom: 0.5rem; | |
| 249 | + | } | |
| 250 | + | ||
| 251 | + | .history-list { | |
| 252 | + | overflow-y: auto; | |
| 253 | + | overflow-x: hidden; | |
| 254 | + | max-height: calc(100vh - 8rem); | |
| 255 | + | max-width: 100%; | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | .history-item { | |
| 259 | + | padding: 0.75rem; | |
| 260 | + | margin-bottom: 0.5rem; | |
| 261 | + | background: #2d2d2d; | |
| 262 | + | border-radius: 6px; | |
| 263 | + | cursor: pointer; | |
| 264 | + | transition: background 0.2s; | |
| 265 | + | border-left: 3px solid #404040; | |
| 266 | + | overflow: hidden; | |
| 267 | + | max-width: 100%; | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | .history-item:hover { | |
| 271 | + | background: #3d3d3d; | |
| 272 | + | border-left-color: #0066cc; | |
| 273 | + | } | |
| 274 | + | ||
| 275 | + | .history-line { | |
| 276 | + | display: flex; | |
| 277 | + | gap: 0.5rem; | |
| 278 | + | white-space: nowrap; | |
| 279 | + | align-items: center; | |
| 280 | + | overflow: hidden; | |
| 281 | + | width: 100%; | |
| 282 | + | min-width: 0; | |
| 283 | + | } | |
| 284 | + | ||
| 285 | + | .history-favicon-chip { | |
| 286 | + | flex: 0 0 20px; | |
| 287 | + | width: 20px; | |
| 288 | + | height: 20px; | |
| 289 | + | border-radius: 50%; | |
| 290 | + | background: #ccc; | |
| 291 | + | border: 1px solid rgba(0,0,0,.12); | |
| 292 | + | box-shadow: 0 1px 2px rgba(0,0,0,.12); | |
| 293 | + | display: flex; | |
| 294 | + | align-items: center; | |
| 295 | + | justify-content: center; | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | .history-favicon-img { | |
| 299 | + | width: 16px; | |
| 300 | + | height: 16px; | |
| 301 | + | filter: brightness(1.06) contrast(1.03); | |
| 302 | + | image-rendering: -webkit-optimize-contrast; | |
| 303 | + | } | |
| 304 | + | ||
| 305 | + | .history-favicon-fallback { | |
| 306 | + | font-size: 12px; | |
| 307 | + | } | |
| 308 | + | ||
| 309 | + | .history-title { | |
| 310 | + | font-size: 0.95rem; | |
| 311 | + | color: #e6e6e6; | |
| 312 | + | flex: 0 0 auto; | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | .history-domain { | |
| 316 | + | font-size: 0.9rem; | |
| 317 | + | color: #a5a5a5; | |
| 318 | + | flex: 0 0 auto; | |
| 319 | + | } | |
| 320 | + | ||
| 321 | + | .history-sep { | |
| 322 | + | color: #666; | |
| 323 | + | flex: 0 0 auto; | |
| 324 | + | } | |
| 325 | + | ||
| 326 | + | .history-url { | |
| 327 | + | font-size: 0.9rem; | |
| 328 | + | color: #7a7a7a; | |
| 329 | + | flex: 1 1 auto; | |
| 330 | + | min-width: 0; | |
| 331 | + | overflow: hidden; | |
| 332 | + | text-overflow: ellipsis; | |
| 333 | + | -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%); | |
| 334 | + | mask-image: linear-gradient(to right, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%); | |
| 335 | + | } | |
| 336 | + | ||
| 337 | + | .history-time { | |
| 338 | + | font-size: 0.85rem; | |
| 339 | + | color: #666; | |
| 340 | + | flex: 0 0 auto; | |
| 341 | + | margin-left: auto; | |
| 342 | + | } | |
| 343 | + | ||
| 344 | + | .shortcuts-grid { | |
| 345 | + | display: grid; | |
| 346 | + | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| 347 | + | gap: 1rem; | |
| 348 | + | max-height: calc(100vh - 8rem); | |
| 349 | + | overflow-y: auto; | |
| 350 | + | } | |
| 351 | + | ||
| 352 | + | .shortcut { | |
| 353 | + | padding: 1rem; | |
| 354 | + | background: #2d2d2d; | |
| 355 | + | border: 2px solid #404040; | |
| 356 | + | border-radius: 8px; | |
| 357 | + | cursor: pointer; | |
| 358 | + | transition: all 0.2s; | |
| 359 | + | text-align: center; | |
| 360 | + | } | |
| 361 | + | ||
| 362 | + | .shortcut:hover { | |
| 363 | + | background: #3d3d3d; | |
| 364 | + | border-color: #0066cc; | |
| 365 | + | transform: translateY(-2px); | |
| 366 | + | } | |
| 367 | + | ||
| 368 | + | .shortcut-key { | |
| 369 | + | font-weight: bold; | |
| 370 | + | color: #0066cc; | |
| 371 | + | margin-bottom: 0.5rem; | |
| 372 | + | font-size: 1.1rem; | |
| 373 | + | } | |
| 374 | + | ||
| 375 | + | .shortcut-desc { | |
| 376 | + | color: #888; | |
| 377 | + | font-size: 0.9rem; | |
| 378 | + | } | |
| 379 | + | ||
| 380 | + | .loading { | |
| 381 | + | padding: 2rem; | |
| 382 | + | text-align: center; | |
| 383 | + | color: #888; | |
| 384 | + | } | |
| 385 | + | ||
| 386 | + | .empty-state { | |
| 387 | + | padding: 3rem 2rem; | |
| 388 | + | text-align: center; | |
| 389 | + | color: #666; | |
| 390 | + | } | |
| 391 | + | ||
| 392 | + | .empty-state h3 { | |
| 393 | + | margin-bottom: 1rem; | |
| 394 | + | color: #888; | |
| 395 | + | } | |
| 396 | + | ||
| 397 | + | @media (max-width: 768px) { | |
| 398 | + | .container { | |
| 399 | + | flex-direction: column; | |
| 400 | + | padding: 1rem; | |
| 401 | + | } | |
| 402 | + | ||
| 403 | + | .shortcuts-grid { | |
| 404 | + | grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| 405 | + | } | |
| 406 | + | } | |
| 407 | + | </style>⏎̸ | |
A gui/src/pages/homepage.ts +9 -0
| @@ -0,0 +1,9 @@ | |||
| 1 | + | import { mount } from 'svelte'; | |
| 2 | + | import Homepage from './Homepage.svelte'; | |
| 3 | + | ||
| 4 | + | // Mount the Homepage component to the DOM | |
| 5 | + | const app = mount(Homepage, { | |
| 6 | + | target: document.body, | |
| 7 | + | }); | |
| 8 | + | ||
| 9 | + | export default app;⏎̸ | |
A gui/src/services/app.ts +105 -0
| @@ -0,0 +1,105 @@ | |||
| 1 | + | type HistoryEntry = { | |
| 2 | + | id: number; | |
| 3 | + | url: string; | |
| 4 | + | title: string; | |
| 5 | + | visit_count: number; | |
| 6 | + | last_visited: string | null; | |
| 7 | + | created_at: string | null; | |
| 8 | + | } | |
| 9 | + | ||
| 10 | + | export class AppService { | |
| 11 | + | private history: HistoryEntry[] = []; | |
| 12 | + | private shortcuts: Record<string, any> = {}; | |
| 13 | + | ||
| 14 | + | constructor() {} | |
| 15 | + | ||
| 16 | + | async initialize(): Promise<void> { | |
| 17 | + | try { | |
| 18 | + | await Promise.all([ | |
| 19 | + | this.loadHistory(), | |
| 20 | + | this.loadShortcuts() | |
| 21 | + | ]); | |
| 22 | + | } catch (error) { | |
| 23 | + | console.error('Failed to initialize app:', error); | |
| 24 | + | } | |
| 25 | + | } | |
| 26 | + | ||
| 27 | + | async loadHistory(): Promise<void> { | |
| 28 | + | try { | |
| 29 | + | const recentHistory: HistoryEntry[] = await fetch('/api/history/recent?limit=50').then(r => r.json()); | |
| 30 | + | this.history = recentHistory; | |
| 31 | + | } catch (error) { | |
| 32 | + | console.error('Failed to load history:', error); | |
| 33 | + | // Mock history for development/fallback | |
| 34 | + | this.history = [ | |
| 35 | + | { | |
| 36 | + | id: 1, | |
| 37 | + | url: 'https://github.com/wailsapp/wails', | |
| 38 | + | title: 'Wails Framework', | |
| 39 | + | visit_count: 3, | |
| 40 | + | last_visited: new Date().toISOString(), | |
| 41 | + | created_at: new Date().toISOString() | |
| 42 | + | }, | |
| 43 | + | { | |
| 44 | + | id: 2, | |
| 45 | + | url: 'https://go.dev', | |
| 46 | + | title: 'The Go Programming Language', | |
| 47 | + | visit_count: 2, | |
| 48 | + | last_visited: new Date().toISOString(), | |
| 49 | + | created_at: new Date().toISOString() | |
| 50 | + | }, | |
| 51 | + | { | |
| 52 | + | id: 3, | |
| 53 | + | url: 'https://developer.mozilla.org', | |
| 54 | + | title: 'MDN Web Docs', | |
| 55 | + | visit_count: 1, | |
| 56 | + | last_visited: new Date().toISOString(), | |
| 57 | + | created_at: new Date().toISOString() | |
| 58 | + | } | |
| 59 | + | ]; | |
| 60 | + | } | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | async loadShortcuts(): Promise<void> { | |
| 64 | + | try { | |
| 65 | + | const cfg = await fetch('/api/config').then(r => r.json()); | |
| 66 | + | const raw = cfg?.search_shortcuts || {}; | |
| 67 | + | // Normalize field casing from backend (supports URL/Description and url/description) | |
| 68 | + | const normalized: Record<string, { description: string; url: string }> = {}; | |
| 69 | + | for (const [key, value] of Object.entries(raw)) { | |
| 70 | + | const v: any = value as any; | |
| 71 | + | normalized[key] = { | |
| 72 | + | description: v.description ?? v.Description ?? '', | |
| 73 | + | url: v.url ?? v.URL ?? '' | |
| 74 | + | }; | |
| 75 | + | } | |
| 76 | + | this.shortcuts = normalized; | |
| 77 | + | } catch (error) { | |
| 78 | + | console.error('Failed to load shortcuts:', error); | |
| 79 | + | // Mock shortcuts for development/fallback | |
| 80 | + | this.shortcuts = { | |
| 81 | + | 'g': { description: 'Google Search', url: 'https://google.com/search?q={query}' }, | |
| 82 | + | 'gh': { description: 'GitHub Search', url: 'https://github.com/search?q={query}' }, | |
| 83 | + | 'so': { description: 'Stack Overflow', url: 'https://stackoverflow.com/search?q={query}' }, | |
| 84 | + | 'w': { description: 'Wikipedia', url: 'https://en.wikipedia.org/wiki/Special:Search?search={query}' } | |
| 85 | + | }; | |
| 86 | + | } | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | getHistory(): HistoryEntry[] { | |
| 90 | + | return this.history; | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | getShortcuts(): Record<string, any> { | |
| 94 | + | return this.shortcuts; | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | async copyToClipboard(text: string): Promise<void> { | |
| 98 | + | try { | |
| 99 | + | await navigator.clipboard.writeText(text); | |
| 100 | + | console.log('Copied to clipboard:', text); | |
| 101 | + | } catch (err) { | |
| 102 | + | console.error('Failed to copy:', err); | |
| 103 | + | } | |
| 104 | + | } | |
| 105 | + | } | |
A gui/src/services/browser-controls.ts +179 -0
| @@ -0,0 +1,179 @@ | |||
| 1 | + | import { NotificationService } from './notifications.js'; | |
| 2 | + | import { DebugConsoleService } from './debug-console.js'; | |
| 3 | + | ||
| 4 | + | export class BrowserControlsService { | |
| 5 | + | private currentURL = ''; | |
| 6 | + | private notifications = new NotificationService(); | |
| 7 | + | private debugConsole = new DebugConsoleService(); | |
| 8 | + | ||
| 9 | + | constructor() { | |
| 10 | + | // Debug logging with enhanced details | |
| 11 | + | this.debugConsole.addLog('info', 'frontend', 'init', 'BrowserControlsService initializing...'); | |
| 12 | + | this.debugConsole.addLog('info', 'frontend', 'init', 'Running without Wails bindings'); | |
| 13 | + | ||
| 14 | + | this.initializeEventListeners(); | |
| 15 | + | this.debugConsole.addLog('info', 'frontend', 'init', 'BrowserControlsService initialized ✓'); | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | ||
| 19 | + | private initializeEventListeners(): void { | |
| 20 | + | // Keyboard event handler for browser controls | |
| 21 | + | document.addEventListener('keydown', this.handleKeyboardEvent.bind(this)); | |
| 22 | + | ||
| 23 | + | // Mouse button handler for navigation | |
| 24 | + | document.addEventListener('mousedown', this.handleMouseEvent.bind(this)); | |
| 25 | + | ||
| 26 | + | // URL change listener (for SPA navigation) | |
| 27 | + | window.addEventListener('popstate', this.handleURLChange.bind(this)); | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | private async handleKeyboardEvent(event: KeyboardEvent): Promise<void> { | |
| 31 | + | // Skip F12 (debug console toggle) | |
| 32 | + | if (event.key === 'F12') { | |
| 33 | + | return; | |
| 34 | + | } | |
| 35 | + | ||
| 36 | + | // Log all keyboard events to debug console | |
| 37 | + | this.debugConsole.logKeyboardEvent(event); | |
| 38 | + | ||
| 39 | + | const { ctrlKey, metaKey, shiftKey, altKey, key } = event; | |
| 40 | + | const isCmd = ctrlKey || metaKey; | |
| 41 | + | ||
| 42 | + | // Zoom controls handled natively by GTK; don't intercept | |
| 43 | + | if (isCmd && (key === '+' || key === '=' || key === '-' || key === '0')) { | |
| 44 | + | return; // allow native handler to process | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | // Copy URL | |
| 48 | + | if (isCmd && shiftKey && key === 'C') { | |
| 49 | + | this.debugConsole.addLog('info', 'frontend', 'action', 'Copy URL triggered'); | |
| 50 | + | event.preventDefault(); | |
| 51 | + | await this.copyCurrentURL(); | |
| 52 | + | return; | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | // Navigation | |
| 56 | + | if (altKey && key === 'ArrowLeft') { | |
| 57 | + | this.debugConsole.addLog('info', 'frontend', 'action', 'Go Back triggered'); | |
| 58 | + | event.preventDefault(); | |
| 59 | + | history.back(); | |
| 60 | + | return; | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | if (altKey && key === 'ArrowRight') { | |
| 64 | + | this.debugConsole.addLog('info', 'frontend', 'action', 'Go Forward triggered'); | |
| 65 | + | event.preventDefault(); | |
| 66 | + | history.forward(); | |
| 67 | + | return; | |
| 68 | + | } | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | private async handleMouseEvent(event: MouseEvent): Promise<void> { | |
| 72 | + | // Log all mouse events to debug console | |
| 73 | + | this.debugConsole.logMouseEvent(event); | |
| 74 | + | ||
| 75 | + | // Mouse button 3 (back button) | |
| 76 | + | if (event.button === 3) { | |
| 77 | + | this.debugConsole.addLog('info', 'frontend', 'action', 'Mouse Back button triggered'); | |
| 78 | + | event.preventDefault(); | |
| 79 | + | await this.goBack(); | |
| 80 | + | return; | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // Mouse button 4 (forward button) | |
| 84 | + | if (event.button === 4) { | |
| 85 | + | this.debugConsole.addLog('info', 'frontend', 'action', 'Mouse Forward button triggered'); | |
| 86 | + | event.preventDefault(); | |
| 87 | + | await this.goForward(); | |
| 88 | + | return; | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | private handleURLChange(): void { | |
| 93 | + | this.setCurrentURL(window.location.href); | |
| 94 | + | this.loadSavedZoom(); | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // Zoom is handled natively; no JS-based zoom adjustments needed. | |
| 98 | + | ||
| 99 | + | async copyCurrentURL(): Promise<void> { | |
| 100 | + | try { | |
| 101 | + | const url = this.getCurrentURL(); | |
| 102 | + | await navigator.clipboard.writeText(url); | |
| 103 | + | ||
| 104 | + | // URL copied successfully - no backend notification needed | |
| 105 | + | ||
| 106 | + | this.notifications.show('URL copied to clipboard!', 'success'); | |
| 107 | + | } catch (error) { | |
| 108 | + | console.error('Failed to copy URL:', error); | |
| 109 | + | this.notifications.show('Failed to copy URL', 'error'); | |
| 110 | + | } | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | async goBack(): Promise<void> { | |
| 114 | + | this.debugConsole.addLog('info', 'frontend', 'service', 'Calling GoBack'); | |
| 115 | + | ||
| 116 | + | try { | |
| 117 | + | // await BrowserService.GoBack(); // TODO: Implement BrowserService | |
| 118 | + | this.debugConsole.logServiceCall('BrowserService', 'GoBack', []); | |
| 119 | + | history.back(); | |
| 120 | + | this.debugConsole.addLog('info', 'frontend', 'navigation', 'Browser navigated back'); | |
| 121 | + | } catch (error) { | |
| 122 | + | this.debugConsole.logServiceCall('BrowserService', 'GoBack', [], null, error as Error); | |
| 123 | + | console.error('Failed to go back:', error); | |
| 124 | + | } | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | async goForward(): Promise<void> { | |
| 128 | + | this.debugConsole.addLog('info', 'frontend', 'service', 'Calling GoForward'); | |
| 129 | + | ||
| 130 | + | try { | |
| 131 | + | // await BrowserService.GoForward(); // TODO: Implement BrowserService | |
| 132 | + | this.debugConsole.logServiceCall('BrowserService', 'GoForward', []); | |
| 133 | + | history.forward(); | |
| 134 | + | this.debugConsole.addLog('info', 'frontend', 'navigation', 'Browser navigated forward'); | |
| 135 | + | } catch (error) { | |
| 136 | + | this.debugConsole.logServiceCall('BrowserService', 'GoForward', [], null, error as Error); | |
| 137 | + | console.error('Failed to go forward:', error); | |
| 138 | + | } | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | getCurrentURL(): string { | |
| 142 | + | return this.currentURL || window.location.href; | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | setCurrentURL(url: string): void { | |
| 146 | + | this.currentURL = url; | |
| 147 | + | this.updateWindowTitle(url); | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | private async updateWindowTitle(url: string): Promise<void> { | |
| 151 | + | try { | |
| 152 | + | // Extract domain or path for title | |
| 153 | + | let title = 'Dumber Browser'; | |
| 154 | + | if (url && url !== '/') { | |
| 155 | + | const urlObj = new URL(url); | |
| 156 | + | title = `Dumber - ${urlObj.hostname}`; | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | document.title = title; | |
| 160 | + | ||
| 161 | + | // Backend title updates handled natively; no frontend call | |
| 162 | + | } catch (error) { | |
| 163 | + | console.error('Failed to update title:', error); | |
| 164 | + | } | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | async loadSavedZoom(): Promise<void> { | |
| 168 | + | // Zoom persistence applied natively on page load | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | async initialize(): Promise<void> { | |
| 172 | + | // Check if there's an initial URL from backend (direct navigation) | |
| 173 | + | // Set initial URL from browser location (homepage) | |
| 174 | + | this.setCurrentURL(window.location.href); | |
| 175 | + | ||
| 176 | + | // Load saved zoom level (only if we're staying on homepage) | |
| 177 | + | // Zoom handled natively | |
| 178 | + | } | |
| 179 | + | } | |
A gui/src/services/debug-console.ts +258 -0
| @@ -0,0 +1,258 @@ | |||
| 1 | + | export interface DebugLogEntry { | |
| 2 | + | timestamp: string; | |
| 3 | + | level: 'info' | 'warn' | 'error' | 'debug'; | |
| 4 | + | source: 'frontend' | 'backend'; | |
| 5 | + | category: string; | |
| 6 | + | message: string; | |
| 7 | + | data?: any; | |
| 8 | + | } | |
| 9 | + | ||
| 10 | + | export class DebugConsoleService { | |
| 11 | + | private logs: DebugLogEntry[] = []; | |
| 12 | + | private maxLogs = 1000; | |
| 13 | + | private isVisible = false; | |
| 14 | + | private debugElement: HTMLElement | null = null; | |
| 15 | + | private logsContainer: HTMLElement | null = null; | |
| 16 | + | ||
| 17 | + | constructor() { | |
| 18 | + | this.createDebugUI(); | |
| 19 | + | this.setupKeyboardShortcut(); | |
| 20 | + | this.interceptConsole(); | |
| 21 | + | } | |
| 22 | + | ||
| 23 | + | private createDebugUI(): void { | |
| 24 | + | // Create debug panel | |
| 25 | + | this.debugElement = document.createElement('div'); | |
| 26 | + | this.debugElement.id = 'debug-console'; | |
| 27 | + | this.debugElement.style.cssText = ` | |
| 28 | + | position: fixed; | |
| 29 | + | top: 0; | |
| 30 | + | right: 0; | |
| 31 | + | width: 50%; | |
| 32 | + | height: 100%; | |
| 33 | + | background: rgba(0, 0, 0, 0.95); | |
| 34 | + | color: #00ff00; | |
| 35 | + | font-family: 'Courier New', monospace; | |
| 36 | + | font-size: 12px; | |
| 37 | + | z-index: 10000; | |
| 38 | + | display: none; | |
| 39 | + | border-left: 2px solid #00ff00; | |
| 40 | + | `; | |
| 41 | + | ||
| 42 | + | // Create header | |
| 43 | + | const header = document.createElement('div'); | |
| 44 | + | header.style.cssText = ` | |
| 45 | + | padding: 10px; | |
| 46 | + | background: rgba(0, 255, 0, 0.1); | |
| 47 | + | border-bottom: 1px solid #00ff00; | |
| 48 | + | font-weight: bold; | |
| 49 | + | display: flex; | |
| 50 | + | justify-content: space-between; | |
| 51 | + | align-items: center; | |
| 52 | + | `; | |
| 53 | + | header.innerHTML = ` | |
| 54 | + | <span>🐛 DUMBER DEBUG CONSOLE</span> | |
| 55 | + | <div style="font-size: 10px;"> | |
| 56 | + | <span style="color: #888; margin-right: 10px;">F11: Inspect Services | F12: Toggle</span> | |
| 57 | + | <button id="clear-logs" style="background: none; border: 1px solid #00ff00; color: #00ff00; padding: 2px 8px; margin-right: 5px; cursor: pointer;">Clear</button> | |
| 58 | + | <button id="close-debug" style="background: none; border: 1px solid #00ff00; color: #00ff00; padding: 2px 8px; cursor: pointer;">Close</button> | |
| 59 | + | </div> | |
| 60 | + | `; | |
| 61 | + | ||
| 62 | + | // Create logs container | |
| 63 | + | this.logsContainer = document.createElement('div'); | |
| 64 | + | this.logsContainer.style.cssText = ` | |
| 65 | + | height: calc(100% - 50px); | |
| 66 | + | overflow-y: auto; | |
| 67 | + | padding: 10px; | |
| 68 | + | `; | |
| 69 | + | ||
| 70 | + | this.debugElement.appendChild(header); | |
| 71 | + | this.debugElement.appendChild(this.logsContainer); | |
| 72 | + | document.body.appendChild(this.debugElement); | |
| 73 | + | ||
| 74 | + | // Setup button handlers | |
| 75 | + | header.querySelector('#clear-logs')?.addEventListener('click', () => this.clearLogs()); | |
| 76 | + | header.querySelector('#close-debug')?.addEventListener('click', () => this.hide()); | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | private setupKeyboardShortcut(): void { | |
| 80 | + | document.addEventListener('keydown', (event) => { | |
| 81 | + | // F12 to toggle debug console | |
| 82 | + | if (event.key === 'F12') { | |
| 83 | + | event.preventDefault(); | |
| 84 | + | this.toggle(); | |
| 85 | + | } | |
| 86 | + | }); | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | private interceptConsole(): void { | |
| 90 | + | const originalConsole = { | |
| 91 | + | log: console.log, | |
| 92 | + | warn: console.warn, | |
| 93 | + | error: console.error, | |
| 94 | + | info: console.info, | |
| 95 | + | debug: console.debug | |
| 96 | + | }; | |
| 97 | + | ||
| 98 | + | console.log = (...args) => { | |
| 99 | + | this.addLog('info', 'frontend', 'console', args.join(' ')); | |
| 100 | + | originalConsole.log(...args); | |
| 101 | + | }; | |
| 102 | + | ||
| 103 | + | console.warn = (...args) => { | |
| 104 | + | this.addLog('warn', 'frontend', 'console', args.join(' ')); | |
| 105 | + | originalConsole.warn(...args); | |
| 106 | + | }; | |
| 107 | + | ||
| 108 | + | console.error = (...args) => { | |
| 109 | + | this.addLog('error', 'frontend', 'console', args.join(' ')); | |
| 110 | + | originalConsole.error(...args); | |
| 111 | + | }; | |
| 112 | + | ||
| 113 | + | console.info = (...args) => { | |
| 114 | + | this.addLog('info', 'frontend', 'console', args.join(' ')); | |
| 115 | + | originalConsole.info(...args); | |
| 116 | + | }; | |
| 117 | + | ||
| 118 | + | console.debug = (...args) => { | |
| 119 | + | this.addLog('debug', 'frontend', 'console', args.join(' ')); | |
| 120 | + | originalConsole.debug(...args); | |
| 121 | + | }; | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | public addLog(level: DebugLogEntry['level'], source: DebugLogEntry['source'], category: string, message: string, data?: any): void { | |
| 125 | + | const entry: DebugLogEntry = { | |
| 126 | + | timestamp: new Date().toISOString().split('T')[1]?.split('.')[0] || '', // HH:MM:SS format | |
| 127 | + | level, | |
| 128 | + | source, | |
| 129 | + | category, | |
| 130 | + | message, | |
| 131 | + | data | |
| 132 | + | }; | |
| 133 | + | ||
| 134 | + | this.logs.push(entry); | |
| 135 | + | ||
| 136 | + | // Keep only the last maxLogs entries | |
| 137 | + | if (this.logs.length > this.maxLogs) { | |
| 138 | + | this.logs.shift(); | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | this.updateDisplay(); | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | private updateDisplay(): void { | |
| 145 | + | if (!this.logsContainer) return; | |
| 146 | + | ||
| 147 | + | const logHTML = this.logs.map(log => { | |
| 148 | + | const levelColor = { | |
| 149 | + | info: '#00ff00', | |
| 150 | + | warn: '#ffff00', | |
| 151 | + | error: '#ff0000', | |
| 152 | + | debug: '#00ffff' | |
| 153 | + | }[log.level]; | |
| 154 | + | ||
| 155 | + | const sourceIcon = log.source === 'backend' ? '🖥️' : '🌐'; | |
| 156 | + | ||
| 157 | + | return ` | |
| 158 | + | <div style="margin-bottom: 2px; font-size: 11px;"> | |
| 159 | + | <span style="color: #888;">[${log.timestamp}]</span> | |
| 160 | + | <span style="color: ${levelColor};">${sourceIcon} ${log.level.toUpperCase()}</span> | |
| 161 | + | <span style="color: #aaa;">[${log.category}]</span> | |
| 162 | + | <span style="color: #fff;">${log.message}</span> | |
| 163 | + | ${log.data ? `<pre style="color: #ccc; font-size: 10px; margin: 2px 0;">${JSON.stringify(log.data, null, 2)}</pre>` : ''} | |
| 164 | + | </div> | |
| 165 | + | `; | |
| 166 | + | }).join(''); | |
| 167 | + | ||
| 168 | + | this.logsContainer.innerHTML = logHTML; | |
| 169 | + | ||
| 170 | + | // Auto-scroll to bottom | |
| 171 | + | this.logsContainer.scrollTop = this.logsContainer.scrollHeight; | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | public logKeyboardEvent(event: KeyboardEvent): void { | |
| 175 | + | const modifiers = []; | |
| 176 | + | if (event.ctrlKey) modifiers.push('Ctrl'); | |
| 177 | + | if (event.shiftKey) modifiers.push('Shift'); | |
| 178 | + | if (event.altKey) modifiers.push('Alt'); | |
| 179 | + | if (event.metaKey) modifiers.push('Meta'); | |
| 180 | + | ||
| 181 | + | const shortcut = modifiers.length > 0 ? `${modifiers.join('+')}+${event.key}` : event.key; | |
| 182 | + | ||
| 183 | + | this.addLog('info', 'frontend', 'keyboard', `Key pressed: ${shortcut}`, { | |
| 184 | + | key: event.key, | |
| 185 | + | code: event.code, | |
| 186 | + | modifiers, | |
| 187 | + | target: event.target?.constructor.name | |
| 188 | + | }); | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | public logMouseEvent(event: MouseEvent): void { | |
| 192 | + | const buttonNames: Record<number, string> = { | |
| 193 | + | 0: 'Left', | |
| 194 | + | 1: 'Middle', | |
| 195 | + | 2: 'Right', | |
| 196 | + | 3: 'Back', | |
| 197 | + | 4: 'Forward' | |
| 198 | + | }; | |
| 199 | + | ||
| 200 | + | this.addLog('info', 'frontend', 'mouse', `Mouse ${event.type}: ${buttonNames[event.button] || `Button${event.button}`}`, { | |
| 201 | + | button: event.button, | |
| 202 | + | clientX: event.clientX, | |
| 203 | + | clientY: event.clientY, | |
| 204 | + | target: event.target?.constructor.name | |
| 205 | + | }); | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | public logServiceCall(serviceName: string, methodName: string, params: any[], result?: any, error?: Error): void { | |
| 209 | + | if (error) { | |
| 210 | + | this.addLog('error', 'frontend', 'service', `${serviceName}.${methodName}() failed`, { | |
| 211 | + | params, | |
| 212 | + | error: error.message | |
| 213 | + | }); | |
| 214 | + | } else { | |
| 215 | + | this.addLog('info', 'frontend', 'service', `${serviceName}.${methodName}() called`, { | |
| 216 | + | params, | |
| 217 | + | result | |
| 218 | + | }); | |
| 219 | + | } | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | public logBackendMessage(message: string, data?: any): void { | |
| 223 | + | this.addLog('info', 'backend', 'service', message, data); | |
| 224 | + | } | |
| 225 | + | ||
| 226 | + | public show(): void { | |
| 227 | + | if (this.debugElement) { | |
| 228 | + | this.debugElement.style.display = 'block'; | |
| 229 | + | this.isVisible = true; | |
| 230 | + | this.addLog('info', 'frontend', 'debug', 'Debug console opened'); | |
| 231 | + | } | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | public hide(): void { | |
| 235 | + | if (this.debugElement) { | |
| 236 | + | this.debugElement.style.display = 'none'; | |
| 237 | + | this.isVisible = false; | |
| 238 | + | } | |
| 239 | + | } | |
| 240 | + | ||
| 241 | + | public toggle(): void { | |
| 242 | + | if (this.isVisible) { | |
| 243 | + | this.hide(); | |
| 244 | + | } else { | |
| 245 | + | this.show(); | |
| 246 | + | } | |
| 247 | + | } | |
| 248 | + | ||
| 249 | + | public clearLogs(): void { | |
| 250 | + | this.logs = []; | |
| 251 | + | this.updateDisplay(); | |
| 252 | + | this.addLog('info', 'frontend', 'debug', 'Logs cleared'); | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | public isDebugVisible(): boolean { | |
| 256 | + | return this.isVisible; | |
| 257 | + | } | |
| 258 | + | } | |
A gui/src/services/notifications.ts +91 -0
| @@ -0,0 +1,91 @@ | |||
| 1 | + | import type { NotificationOptions } from '../types/app.js'; | |
| 2 | + | ||
| 3 | + | export class NotificationService { | |
| 4 | + | private zoomNotification: HTMLElement | null = null; | |
| 5 | + | private generalNotification: HTMLElement | null = null; | |
| 6 | + | ||
| 7 | + | showZoom(message: string, duration = 2000): void { | |
| 8 | + | // Create or update zoom notification | |
| 9 | + | if (!this.zoomNotification) { | |
| 10 | + | this.zoomNotification = this.createNotificationElement('zoom-notification', { | |
| 11 | + | top: '20px', | |
| 12 | + | right: '20px', | |
| 13 | + | background: 'rgba(0, 0, 0, 0.8)', | |
| 14 | + | color: 'white' | |
| 15 | + | }); | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | this.updateNotification(this.zoomNotification, message, duration); | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | show(message: string, type: NotificationOptions['type'] = 'info', duration = 3000): void { | |
| 22 | + | // Create or update general notification | |
| 23 | + | if (!this.generalNotification) { | |
| 24 | + | this.generalNotification = this.createNotificationElement('general-notification', { | |
| 25 | + | top: '60px', | |
| 26 | + | right: '20px' | |
| 27 | + | }); | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | // Set colors based on type | |
| 31 | + | const colors = this.getNotificationColors(type); | |
| 32 | + | this.generalNotification.style.background = colors.background; | |
| 33 | + | this.generalNotification.style.color = colors.color; | |
| 34 | + | ||
| 35 | + | this.updateNotification(this.generalNotification, message, duration); | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | private createNotificationElement(id: string, baseStyles: Record<string, string>): HTMLElement { | |
| 39 | + | const notification = document.createElement('div'); | |
| 40 | + | notification.id = id; | |
| 41 | + | ||
| 42 | + | const styles = { | |
| 43 | + | position: 'fixed', | |
| 44 | + | padding: '10px 15px', | |
| 45 | + | borderRadius: '5px', | |
| 46 | + | fontSize: '14px', | |
| 47 | + | zIndex: '10000', | |
| 48 | + | transition: 'opacity 0.3s', | |
| 49 | + | opacity: '0', | |
| 50 | + | ...baseStyles | |
| 51 | + | }; | |
| 52 | + | ||
| 53 | + | notification.style.cssText = Object.entries(styles) | |
| 54 | + | .map(([key, value]) => `${this.camelToKebab(key)}: ${value}`) | |
| 55 | + | .join('; '); | |
| 56 | + | ||
| 57 | + | document.body.appendChild(notification); | |
| 58 | + | return notification; | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | private updateNotification(element: HTMLElement, message: string, duration: number): void { | |
| 62 | + | element.textContent = message; | |
| 63 | + | element.style.opacity = '1'; | |
| 64 | + | ||
| 65 | + | // Clear any existing timeout | |
| 66 | + | const existingTimeout = (element as any).timeout; | |
| 67 | + | if (existingTimeout) { | |
| 68 | + | clearTimeout(existingTimeout); | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // Hide after duration | |
| 72 | + | (element as any).timeout = setTimeout(() => { | |
| 73 | + | element.style.opacity = '0'; | |
| 74 | + | }, duration); | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | private getNotificationColors(type: NotificationOptions['type']): { background: string; color: string } { | |
| 78 | + | switch (type) { | |
| 79 | + | case 'error': | |
| 80 | + | return { background: 'rgba(220, 53, 69, 0.9)', color: 'white' }; | |
| 81 | + | case 'success': | |
| 82 | + | return { background: 'rgba(25, 135, 84, 0.9)', color: 'white' }; | |
| 83 | + | default: | |
| 84 | + | return { background: 'rgba(13, 110, 253, 0.9)', color: 'white' }; | |
| 85 | + | } | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | private camelToKebab(str: string): string { | |
| 89 | + | return str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`); | |
| 90 | + | } | |
| 91 | + | }⏎̸ | |
A gui/src/styles/tailwind.css +252 -0
| @@ -0,0 +1,252 @@ | |||
| 1 | + | @import "tailwindcss"; | |
| 2 | + | ||
| 3 | + | /* Define custom theme colors for v4 */ | |
| 4 | + | @theme { | |
| 5 | + | /* Light theme colors (default) */ | |
| 6 | + | --color-browser-bg: rgb(255 255 255); /* white */ | |
| 7 | + | --color-browser-surface: rgb(249 250 251); /* gray-50 */ | |
| 8 | + | --color-browser-text: rgb(17 24 39); /* gray-900 */ | |
| 9 | + | --color-browser-muted: rgb(107 114 128); /* gray-500 */ | |
| 10 | + | --color-browser-accent: rgb(59 130 246); /* blue-500 */ | |
| 11 | + | --color-browser-border: rgb(229 231 235); /* gray-200 */ | |
| 12 | + | } | |
| 13 | + | ||
| 14 | + | /* Dynamic theme switching via CSS variables */ | |
| 15 | + | :root { | |
| 16 | + | --dynamic-bg: var(--color-browser-bg); | |
| 17 | + | --dynamic-surface: var(--color-browser-surface); | |
| 18 | + | --dynamic-text: var(--color-browser-text); | |
| 19 | + | --dynamic-muted: var(--color-browser-muted); | |
| 20 | + | --dynamic-accent: var(--color-browser-accent); | |
| 21 | + | --dynamic-border: var(--color-browser-border); | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | /* Dark theme colors (applied via .dark class from GTK) */ | |
| 25 | + | .dark { | |
| 26 | + | --dynamic-bg: rgb(17 24 39); /* gray-900 */ | |
| 27 | + | --dynamic-surface: rgb(31 41 55); /* gray-800 */ | |
| 28 | + | --dynamic-text: rgb(243 244 246); /* gray-100 */ | |
| 29 | + | --dynamic-muted: rgb(156 163 175); /* gray-400 */ | |
| 30 | + | --dynamic-accent: rgb(96 165 250); /* blue-400 */ | |
| 31 | + | --dynamic-border: rgb(55 65 81); /* gray-700 */ | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | /* Base styles for browser UI components */ | |
| 35 | + | .browser-ui { | |
| 36 | + | background-color: var(--dynamic-bg); | |
| 37 | + | color: var(--dynamic-text); | |
| 38 | + | border-color: var(--dynamic-border); | |
| 39 | + | transition: colors 250ms; | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | /* Toast notification styles */ | |
| 43 | + | .toast-base { | |
| 44 | + | border-radius: 0.5rem; | |
| 45 | + | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); | |
| 46 | + | padding: 0.75rem 1rem; | |
| 47 | + | max-width: 24rem; | |
| 48 | + | pointer-events: auto; | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | .toast-success { | |
| 52 | + | background-color: rgb(240 253 244); | |
| 53 | + | color: rgb(22 163 74); | |
| 54 | + | border: 1px solid rgb(187 247 208); | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | .dark .toast-success { | |
| 58 | + | background-color: rgb(22 163 74 / 0.2); | |
| 59 | + | color: rgb(187 247 208); | |
| 60 | + | border-color: rgb(22 163 74); | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | .toast-error { | |
| 64 | + | background-color: rgb(254 242 242); | |
| 65 | + | color: rgb(220 38 38); | |
| 66 | + | border: 1px solid rgb(254 202 202); | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | .dark .toast-error { | |
| 70 | + | background-color: rgb(220 38 38 / 0.2); | |
| 71 | + | color: rgb(254 202 202); | |
| 72 | + | border-color: rgb(220 38 38); | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | .toast-info { | |
| 76 | + | background-color: rgb(239 246 255); | |
| 77 | + | color: rgb(59 130 246); | |
| 78 | + | border: 1px solid rgb(191 219 254); | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | .dark .toast-info { | |
| 82 | + | background-color: rgb(59 130 246 / 0.2); | |
| 83 | + | color: rgb(191 219 254); | |
| 84 | + | border-color: rgb(59 130 246); | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | /* Omnibox/Find bar styles */ | |
| 88 | + | .omnibox-base { | |
| 89 | + | background-color: var(--dynamic-bg); | |
| 90 | + | color: var(--dynamic-text); | |
| 91 | + | border: 2px solid var(--dynamic-border); | |
| 92 | + | border-radius: 0.375rem; | |
| 93 | + | box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); | |
| 94 | + | transition: all 150ms; | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | .omnibox-base:focus-within { | |
| 98 | + | border-color: var(--dynamic-accent); | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | .omnibox-input { | |
| 102 | + | width: 100%; | |
| 103 | + | padding: 0.5rem 0.75rem; | |
| 104 | + | background-color: transparent; | |
| 105 | + | color: var(--dynamic-text); | |
| 106 | + | outline: none; | |
| 107 | + | font-size: 0.875rem; | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | .omnibox-input::placeholder { | |
| 111 | + | color: var(--dynamic-muted); | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | .omnibox-results { | |
| 115 | + | background-color: var(--dynamic-bg); | |
| 116 | + | border: 1px solid var(--dynamic-border); | |
| 117 | + | border-radius: 0.375rem; | |
| 118 | + | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); | |
| 119 | + | max-height: 24rem; | |
| 120 | + | overflow-y: auto; | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | .omnibox-item { | |
| 124 | + | padding: 0.75rem 1rem; | |
| 125 | + | cursor: pointer; | |
| 126 | + | transition: colors 150ms; | |
| 127 | + | border-bottom: 1px solid var(--dynamic-border); | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | .omnibox-item:hover, | |
| 131 | + | .omnibox-item:focus { | |
| 132 | + | background-color: var(--dynamic-surface); | |
| 133 | + | outline: none; | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | .omnibox-item.selected { | |
| 137 | + | background-color: color-mix(in srgb, var(--dynamic-accent) 10%, transparent); | |
| 138 | + | color: var(--dynamic-accent); | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | /* Find bar specific styles */ | |
| 142 | + | .findbar { | |
| 143 | + | display: flex; | |
| 144 | + | align-items: center; | |
| 145 | + | gap: 0.5rem; | |
| 146 | + | padding: 0.5rem 0.75rem; | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | .findbar-input { | |
| 150 | + | flex: 1; | |
| 151 | + | background-color: transparent; | |
| 152 | + | color: var(--dynamic-text); | |
| 153 | + | outline: none; | |
| 154 | + | font-size: 0.875rem; | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | .findbar-input::placeholder { | |
| 158 | + | color: var(--dynamic-muted); | |
| 159 | + | } | |
| 160 | + | ||
| 161 | + | .findbar-button { | |
| 162 | + | padding: 0.25rem 0.5rem; | |
| 163 | + | color: var(--dynamic-muted); | |
| 164 | + | transition: colors 150ms; | |
| 165 | + | font-size: 0.875rem; | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | .findbar-button:hover { | |
| 169 | + | color: var(--dynamic-text); | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | .findbar-count { | |
| 173 | + | font-size: 0.75rem; | |
| 174 | + | color: var(--dynamic-muted); | |
| 175 | + | font-variant-numeric: tabular-nums; | |
| 176 | + | } | |
| 177 | + | ||
| 178 | + | /* Animation utilities */ | |
| 179 | + | .slide-in-top { | |
| 180 | + | animation: slide-in-top 0.25s ease-out; | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | .slide-out-top { | |
| 184 | + | animation: slide-out-top 0.25s ease-in; | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | .fade-in { | |
| 188 | + | animation: fade-in 0.15s ease-out; | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | .fade-out { | |
| 192 | + | animation: fade-out 0.15s ease-in; | |
| 193 | + | } | |
| 194 | + | ||
| 195 | + | @keyframes slide-in-top { | |
| 196 | + | from { | |
| 197 | + | transform: translateY(-100%); | |
| 198 | + | opacity: 0; | |
| 199 | + | } | |
| 200 | + | to { | |
| 201 | + | transform: translateY(0); | |
| 202 | + | opacity: 1; | |
| 203 | + | } | |
| 204 | + | } | |
| 205 | + | ||
| 206 | + | @keyframes slide-out-top { | |
| 207 | + | from { | |
| 208 | + | transform: translateY(0); | |
| 209 | + | opacity: 1; | |
| 210 | + | } | |
| 211 | + | to { | |
| 212 | + | transform: translateY(-100%); | |
| 213 | + | opacity: 0; | |
| 214 | + | } | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | @keyframes fade-in { | |
| 218 | + | from { opacity: 0; } | |
| 219 | + | to { opacity: 1; } | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | @keyframes fade-out { | |
| 223 | + | from { opacity: 1; } | |
| 224 | + | to { opacity: 0; } | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | /* Find highlighting styles for in-page search */ | |
| 228 | + | .find-highlight { | |
| 229 | + | background-color: rgb(255 235 59); /* yellow-400 */ | |
| 230 | + | color: rgb(0 0 0); /* black */ | |
| 231 | + | padding: 0 0.125rem; /* px-0.5 */ | |
| 232 | + | border-radius: 0.125rem; /* rounded-sm */ | |
| 233 | + | box-shadow: 0 0 0 1px rgb(200 185 0) inset; | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | .find-active { | |
| 237 | + | background-color: rgb(255 152 0) !important; /* orange-500 */ | |
| 238 | + | color: rgb(0 0 0); /* black */ | |
| 239 | + | box-shadow: 0 0 0 1px rgb(179 107 0) inset !important; | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | /* Utility for isolating component styles */ | |
| 243 | + | .browser-component-root { | |
| 244 | + | /* Reset any inherited styles from the website */ | |
| 245 | + | all: initial; | |
| 246 | + | /* Apply our design system */ | |
| 247 | + | font-family: Fira Sans, system-ui, -apple-system, sans-serif; | |
| 248 | + | box-sizing: border-box; | |
| 249 | + | * { | |
| 250 | + | box-sizing: border-box; | |
| 251 | + | } | |
| 252 | + | }⏎̸ | |
A gui/src/types/app.ts +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | import type { HistoryEntry, SearchShortcut } from './generated.js'; | |
| 2 | + | ||
| 3 | + | export interface AppState { | |
| 4 | + | currentURL: string; | |
| 5 | + | currentZoom: number; | |
| 6 | + | history: HistoryEntry[]; | |
| 7 | + | shortcuts: Record<string, SearchShortcut>; | |
| 8 | + | isLoading: boolean; | |
| 9 | + | } | |
| 10 | + | ||
| 11 | + | export interface NotificationOptions { | |
| 12 | + | message: string; | |
| 13 | + | type?: 'info' | 'success' | 'error'; | |
| 14 | + | duration?: number; | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | export interface KeyboardShortcut { | |
| 18 | + | key: string; | |
| 19 | + | ctrlKey?: boolean; | |
| 20 | + | metaKey?: boolean; | |
| 21 | + | shiftKey?: boolean; | |
| 22 | + | altKey?: boolean; | |
| 23 | + | handler: () => void | Promise<void>; | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | export { HistoryEntry, SearchShortcut } from './generated.js';⏎̸ | |
A gui/src/types/generated.ts +80 -0
| @@ -0,0 +1,80 @@ | |||
| 1 | + | // GENERATED FROM GO FILES: SEE THE GENERATOR SCRIPT | |
| 2 | + | // Auto-generated TypeScript types from Go structs | |
| 3 | + | // Generated on: 2025-09-09T09:57:41.059Z | |
| 4 | + | // Generator script: scripts/generate-types.js | |
| 5 | + | // Source files: internal/db/models.go, internal/parser/types.go | |
| 6 | + | // Do not edit manually - run 'node scripts/generate-types.js' to regenerate | |
| 7 | + | ||
| 8 | + | export interface History { | |
| 9 | + | id: number; | |
| 10 | + | url: string; | |
| 11 | + | title: string | null; | |
| 12 | + | visit_count: number | null; | |
| 13 | + | last_visited: string | null; | |
| 14 | + | created_at: string | null; | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | export interface Shortcut { | |
| 18 | + | id: number; | |
| 19 | + | shortcut: string; | |
| 20 | + | url_template: string; | |
| 21 | + | description: string | null; | |
| 22 | + | created_at: string | null; | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | export interface ZoomSetting { | |
| 26 | + | id: number; | |
| 27 | + | url: string; | |
| 28 | + | zoom_level: number; | |
| 29 | + | last_updated: string | null; | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | export interface ParseResult { | |
| 33 | + | type: InputType; | |
| 34 | + | url: string; | |
| 35 | + | query: string; | |
| 36 | + | confidence: number; | |
| 37 | + | fuzzy_matches?: FuzzyMatch[]; | |
| 38 | + | shortcut?: DetectedShortcut; | |
| 39 | + | processing_time: number; | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | export interface DetectedShortcut { | |
| 43 | + | key: string; | |
| 44 | + | query: string; | |
| 45 | + | url: string; | |
| 46 | + | description: string; | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | export interface FuzzyMatch { | |
| 50 | + | history_entry?: History; | |
| 51 | + | score: number; | |
| 52 | + | url_score: number; | |
| 53 | + | title_score: number; | |
| 54 | + | recency_score: number; | |
| 55 | + | visit_score: number; | |
| 56 | + | matched_field: string; | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | export interface FuzzyConfig { | |
| 60 | + | min_similarity_threshold: number; | |
| 61 | + | max_results: number; | |
| 62 | + | url_weight: number; | |
| 63 | + | title_weight: number; | |
| 64 | + | recency_weight: number; | |
| 65 | + | visit_weight: number; | |
| 66 | + | recency_decay_days: number; | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // Manual types and enums | |
| 70 | + | export enum InputType { | |
| 71 | + | InputTypeDirectURL = 0, | |
| 72 | + | InputTypeSearchShortcut = 1, | |
| 73 | + | InputTypeHistorySearch = 2, | |
| 74 | + | InputTypeFallbackSearch = 3 | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // Type aliases for frontend usage | |
| 78 | + | export type HistoryEntry = History; | |
| 79 | + | export type SearchShortcut = Shortcut; | |
| 80 | + | export type ZoomEntry = ZoomSetting; | |
A gui/src/utils/dom.ts +196 -0
| @@ -0,0 +1,196 @@ | |||
| 1 | + | type HistoryEntry = { id: number; url: string; title: string }; | |
| 2 | + | type SearchShortcut = { description: string; url: string }; | |
| 3 | + | ||
| 4 | + | export class DOMRenderer { | |
| 5 | + | private historyListElement: HTMLElement | null = null; | |
| 6 | + | private shortcutsElement: HTMLElement | null = null; | |
| 7 | + | ||
| 8 | + | constructor() { | |
| 9 | + | this.historyListElement = document.getElementById('historyList'); | |
| 10 | + | this.shortcutsElement = document.getElementById('shortcuts'); | |
| 11 | + | } | |
| 12 | + | ||
| 13 | + | displayHistory(historyEntries: HistoryEntry[]): void { | |
| 14 | + | if (!this.historyListElement) return; | |
| 15 | + | ||
| 16 | + | if (!historyEntries || historyEntries.length === 0) { | |
| 17 | + | this.historyListElement.innerHTML = ` | |
| 18 | + | <div class="empty-state"> | |
| 19 | + | <h3>No history yet</h3> | |
| 20 | + | <p>Use CLI commands to browse websites</p> | |
| 21 | + | </div> | |
| 22 | + | `; | |
| 23 | + | return; | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | this.historyListElement.innerHTML = ''; | |
| 27 | + | historyEntries.forEach(item => { | |
| 28 | + | const historyItem = this.createHistoryItem(item); | |
| 29 | + | this.historyListElement!.appendChild(historyItem); | |
| 30 | + | }); | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | displayShortcuts(shortcutsData: Record<string, SearchShortcut>): void { | |
| 34 | + | if (!this.shortcutsElement) return; | |
| 35 | + | ||
| 36 | + | if (!shortcutsData || Object.keys(shortcutsData).length === 0) { | |
| 37 | + | this.shortcutsElement.innerHTML = ` | |
| 38 | + | <div class="empty-state"> | |
| 39 | + | <h3>No shortcuts configured</h3> | |
| 40 | + | <p>Add shortcuts to your config file</p> | |
| 41 | + | </div> | |
| 42 | + | `; | |
| 43 | + | return; | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | this.shortcutsElement.innerHTML = ''; | |
| 47 | + | Object.entries(shortcutsData).forEach(([key, shortcut]) => { | |
| 48 | + | const shortcutEl = this.createShortcutElement(key, shortcut); | |
| 49 | + | this.shortcutsElement!.appendChild(shortcutEl); | |
| 50 | + | }); | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | showLoading(container: 'history' | 'shortcuts'): void { | |
| 54 | + | const element = container === 'history' ? this.historyListElement : this.shortcutsElement; | |
| 55 | + | if (element) { | |
| 56 | + | element.innerHTML = '<div class="loading">Loading...</div>'; | |
| 57 | + | } | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | showError(container: 'history' | 'shortcuts', message: string): void { | |
| 61 | + | const element = container === 'history' ? this.historyListElement : this.shortcutsElement; | |
| 62 | + | if (element) { | |
| 63 | + | element.innerHTML = ` | |
| 64 | + | <div class="empty-state"> | |
| 65 | + | <h3>Error</h3> | |
| 66 | + | <p>${message}</p> | |
| 67 | + | </div> | |
| 68 | + | `; | |
| 69 | + | } | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | private createHistoryItem(item: HistoryEntry): HTMLElement { | |
| 73 | + | const historyItem = document.createElement('div'); | |
| 74 | + | historyItem.className = 'history-item'; | |
| 75 | + | const parsed = this.safeParseURL(item.url); | |
| 76 | + | const title = item.title && item.title.trim() !== '' ? item.title : (parsed.host || 'Untitled'); | |
| 77 | + | ||
| 78 | + | const line = document.createElement('div'); | |
| 79 | + | line.className = 'history-line'; | |
| 80 | + | ||
| 81 | + | // Favicon chip (wrapper ensures perfect circle sizing) | |
| 82 | + | const iconWrap = document.createElement('div'); | |
| 83 | + | iconWrap.className = 'history-favicon-chip'; | |
| 84 | + | const icon = document.createElement('img'); | |
| 85 | + | icon.className = 'history-favicon-img'; | |
| 86 | + | icon.width = 16; icon.height = 16; | |
| 87 | + | icon.loading = 'lazy'; | |
| 88 | + | icon.referrerPolicy = 'no-referrer'; | |
| 89 | + | icon.src = this.buildFaviconURL(item.url); | |
| 90 | + | icon.addEventListener('error', () => { iconWrap.style.display = 'none'; }); | |
| 91 | + | iconWrap.appendChild(icon); | |
| 92 | + | ||
| 93 | + | const titleEl = document.createElement('span'); | |
| 94 | + | titleEl.className = 'history-title'; | |
| 95 | + | titleEl.textContent = title; | |
| 96 | + | ||
| 97 | + | const sep1 = document.createElement('span'); | |
| 98 | + | sep1.className = 'history-sep'; | |
| 99 | + | sep1.textContent = ' - '; | |
| 100 | + | ||
| 101 | + | const domainEl = document.createElement('span'); | |
| 102 | + | domainEl.className = 'history-domain'; | |
| 103 | + | domainEl.textContent = parsed.host || ''; | |
| 104 | + | ||
| 105 | + | const sep2 = document.createElement('span'); | |
| 106 | + | sep2.className = 'history-sep'; | |
| 107 | + | sep2.textContent = ' - '; | |
| 108 | + | ||
| 109 | + | const urlEl = document.createElement('span'); | |
| 110 | + | urlEl.className = 'history-url'; | |
| 111 | + | urlEl.textContent = item.url; | |
| 112 | + | ||
| 113 | + | line.appendChild(iconWrap); | |
| 114 | + | line.appendChild(titleEl); | |
| 115 | + | line.appendChild(sep1); | |
| 116 | + | line.appendChild(domainEl); | |
| 117 | + | line.appendChild(sep2); | |
| 118 | + | line.appendChild(urlEl); | |
| 119 | + | ||
| 120 | + | historyItem.appendChild(line); | |
| 121 | + | ||
| 122 | + | historyItem.addEventListener('click', () => { | |
| 123 | + | this.navigateToUrl(item.url); | |
| 124 | + | }); | |
| 125 | + | ||
| 126 | + | return historyItem; | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | private createShortcutElement(key: string, shortcut: SearchShortcut): HTMLElement { | |
| 130 | + | const shortcutEl = document.createElement('div'); | |
| 131 | + | shortcutEl.className = 'shortcut'; | |
| 132 | + | shortcutEl.innerHTML = ` | |
| 133 | + | <div class="shortcut-key">${this.escapeHtml(key)}:</div> | |
| 134 | + | <div class="shortcut-desc">${this.escapeHtml(shortcut.description)}</div> | |
| 135 | + | `; | |
| 136 | + | ||
| 137 | + | shortcutEl.addEventListener('click', () => { | |
| 138 | + | // Navigate to the base URL of the shortcut (remove %s template parameter) | |
| 139 | + | const baseUrl = this.extractBaseUrl(shortcut.url); | |
| 140 | + | this.navigateToUrl(baseUrl); | |
| 141 | + | }); | |
| 142 | + | ||
| 143 | + | return shortcutEl; | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | private async navigateToUrl(url: string): Promise<void> { | |
| 147 | + | console.log('Navigating to:', url); | |
| 148 | + | window.location.href = url; | |
| 149 | + | } | |
| 150 | + | ||
| 151 | + | private extractBaseUrl(templateUrl: string): string { | |
| 152 | + | try { | |
| 153 | + | // Support both %s and {query} placeholders | |
| 154 | + | const candidate = templateUrl.replace(/%s|\{query\}/g, ""); | |
| 155 | + | const url = new URL(candidate); | |
| 156 | + | // Remove empty query params left after placeholder removal | |
| 157 | + | const params = new URLSearchParams(url.search); | |
| 158 | + | for (const key of Array.from(params.keys())) { | |
| 159 | + | const v = params.get(key); | |
| 160 | + | if (v === null || v === "") { | |
| 161 | + | params.delete(key); | |
| 162 | + | } | |
| 163 | + | } | |
| 164 | + | url.search = params.toString(); | |
| 165 | + | return url.toString(); | |
| 166 | + | } catch (error) { | |
| 167 | + | console.error('Failed to parse shortcut URL:', templateUrl, error); | |
| 168 | + | throw error; | |
| 169 | + | } | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | private escapeHtml(text: string): string { | |
| 173 | + | const div = document.createElement('div'); | |
| 174 | + | div.textContent = text; | |
| 175 | + | return div.innerHTML; | |
| 176 | + | } | |
| 177 | + | ||
| 178 | + | private safeParseURL(raw: string): { host: string } { | |
| 179 | + | try { | |
| 180 | + | const u = new URL(raw); | |
| 181 | + | return { host: u.host }; | |
| 182 | + | } catch { | |
| 183 | + | return { host: '' }; | |
| 184 | + | } | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | private buildFaviconURL(raw: string): string { | |
| 188 | + | try { | |
| 189 | + | const u = new URL(raw); | |
| 190 | + | const scheme = u.protocol && u.protocol !== ':' ? u.protocol : 'https:'; | |
| 191 | + | return `${scheme}//${u.host}/favicon.ico`; | |
| 192 | + | } catch { | |
| 193 | + | return ''; | |
| 194 | + | } | |
| 195 | + | } | |
| 196 | + | } | |
A gui/src/utils/html-builder.ts +251 -0
| @@ -0,0 +1,251 @@ | |||
| 1 | + | export class HTMLBuilder { | |
| 2 | + | static createBaseHTML(): string { | |
| 3 | + | const faviconData = this.getFaviconDataURL(); | |
| 4 | + | return ` | |
| 5 | + | <!DOCTYPE html> | |
| 6 | + | <html lang="en"> | |
| 7 | + | <head> | |
| 8 | + | <meta charset="UTF-8"> | |
| 9 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| 10 | + | <title>Dumber Browser</title> | |
| 11 | + | <link rel="icon" type="image/svg+xml" href="${faviconData}"> | |
| 12 | + | <style> | |
| 13 | + | ${this.getStyles()} | |
| 14 | + | </style> | |
| 15 | + | </head> | |
| 16 | + | <body> | |
| 17 | + | <div class="container"> | |
| 18 | + | <div class="history-section"> | |
| 19 | + | <h2 class="section-title">Recent History</h2> | |
| 20 | + | <div id="historyList" class="history-list"> | |
| 21 | + | <div class="loading">Loading history...</div> | |
| 22 | + | </div> | |
| 23 | + | </div> | |
| 24 | + | ||
| 25 | + | <div class="shortcuts-section"> | |
| 26 | + | <h2 class="section-title">Search Shortcuts</h2> | |
| 27 | + | <div id="shortcuts" class="shortcuts-grid"> | |
| 28 | + | <div class="loading">Loading shortcuts...</div> | |
| 29 | + | </div> | |
| 30 | + | </div> | |
| 31 | + | </div> | |
| 32 | + | <script type="module" src="./main.js"></script> | |
| 33 | + | </body> | |
| 34 | + | </html>`; | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | private static getFaviconDataURL(): string { | |
| 38 | + | const svg = HTMLBuilder.getFaviconSVG(); | |
| 39 | + | // Minimal encoding for safe inline usage | |
| 40 | + | const encoded = encodeURIComponent(svg) | |
| 41 | + | .replace(/'/g, '%27') | |
| 42 | + | .replace(/\(/g, '%28') | |
| 43 | + | .replace(/\)/g, '%29'); | |
| 44 | + | return `data:image/svg+xml;utf8,${encoded}`; | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | static getFaviconSVG(): string { | |
| 48 | + | // Stylized D with speed bolt on a subtle dark rounded card | |
| 49 | + | return `<?xml version="1.0" encoding="UTF-8"?> | |
| 50 | + | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> | |
| 51 | + | <defs> | |
| 52 | + | <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1"> | |
| 53 | + | <stop offset="0%" stop-color="#121212"/> | |
| 54 | + | <stop offset="100%" stop-color="#1e1e1e"/> | |
| 55 | + | </linearGradient> | |
| 56 | + | <filter id="inset" x="-20%" y="-20%" width="140%" height="140%"> | |
| 57 | + | <feOffset dx="0" dy="1"/> | |
| 58 | + | <feGaussianBlur stdDeviation="0.6" result="blur"/> | |
| 59 | + | <feComposite in2="SourceAlpha" operator="out"/> | |
| 60 | + | <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> | |
| 61 | + | <feBlend in="SourceGraphic" mode="normal"/> | |
| 62 | + | </filter> | |
| 63 | + | </defs> | |
| 64 | + | <rect x="4" y="4" width="56" height="56" rx="14" ry="14" fill="url(#bg)" filter="url(#inset)"/> | |
| 65 | + | <rect x="4.5" y="4.5" width="55" height="55" rx="13.5" ry="13.5" fill="none" stroke="#252a2f" stroke-width="1"/> | |
| 66 | + | <!-- D glyph (slightly larger and wider) --> | |
| 67 | + | <path d="M20 16 L20 48 M20 16 H34 q12 0 12 16 t-12 16 H20" fill="none" stroke="#e9eef3" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" transform="translate(33,32) scale(1.12,1.10) translate(-33,-32)"/> | |
| 68 | + | <!-- Speed bolt accent (significantly larger, centered) --> | |
| 69 | + | <path d="M36 22 L32 34 h6 l-8 16 4-12 h-6 z" fill="#ff9800" opacity="0.95" transform="translate(33,32) scale(1.8) translate(-33,-32) translate(0,-3)"/> | |
| 70 | + | </svg>`; | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | private static getStyles(): string { | |
| 74 | + | return ` | |
| 75 | + | * { | |
| 76 | + | margin: 0; | |
| 77 | + | padding: 0; | |
| 78 | + | box-sizing: border-box; | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | body { | |
| 82 | + | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| 83 | + | background: #1a1a1a; | |
| 84 | + | color: #ffffff; | |
| 85 | + | height: 100vh; | |
| 86 | + | display: flex; | |
| 87 | + | flex-direction: column; | |
| 88 | + | overflow-x: hidden; /* prevent horizontal scroll from long content */ | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | .container { | |
| 92 | + | flex: 1; | |
| 93 | + | display: flex; | |
| 94 | + | max-width: 1200px; | |
| 95 | + | margin: 0 auto; | |
| 96 | + | width: 100%; | |
| 97 | + | padding: 2rem; | |
| 98 | + | gap: 2rem; | |
| 99 | + | overflow-x: hidden; | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | .history-section { | |
| 103 | + | flex: 1; | |
| 104 | + | min-height: 0; | |
| 105 | + | min-width: 0; /* allow flex child to shrink */ | |
| 106 | + | } | |
| 107 | + | ||
| 108 | + | .shortcuts-section { | |
| 109 | + | flex: 1; | |
| 110 | + | min-height: 0; | |
| 111 | + | min-width: 0; /* allow flex child to shrink */ | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | .section-title { | |
| 115 | + | font-size: 1.5rem; | |
| 116 | + | margin-bottom: 1rem; | |
| 117 | + | color: #ffffff; | |
| 118 | + | border-bottom: 2px solid #404040; | |
| 119 | + | padding-bottom: 0.5rem; | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | .history-list { | |
| 123 | + | overflow-y: auto; | |
| 124 | + | overflow-x: hidden; | |
| 125 | + | max-height: calc(100vh - 8rem); | |
| 126 | + | max-width: 100%; | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | .history-item { | |
| 130 | + | padding: 0.75rem; | |
| 131 | + | margin-bottom: 0.5rem; | |
| 132 | + | background: #2d2d2d; | |
| 133 | + | border-radius: 6px; | |
| 134 | + | cursor: pointer; | |
| 135 | + | transition: background 0.2s; | |
| 136 | + | border-left: 3px solid #404040; | |
| 137 | + | overflow: hidden; | |
| 138 | + | max-width: 100%; | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | .history-item:hover { | |
| 142 | + | background: #3d3d3d; | |
| 143 | + | border-left-color: #0066cc; | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | .history-line { | |
| 147 | + | display: flex; | |
| 148 | + | gap: 0.5rem; | |
| 149 | + | white-space: nowrap; | |
| 150 | + | align-items: center; | |
| 151 | + | overflow: hidden; | |
| 152 | + | width: 100%; | |
| 153 | + | min-width: 0; /* allow flex children to shrink */ | |
| 154 | + | } | |
| 155 | + | .history-favicon-chip { | |
| 156 | + | flex: 0 0 20px; | |
| 157 | + | width: 20px; height: 20px; | |
| 158 | + | border-radius: 50%; | |
| 159 | + | background: #ccc; | |
| 160 | + | border: 1px solid rgba(0,0,0,.12); | |
| 161 | + | box-shadow: 0 1px 2px rgba(0,0,0,.12); | |
| 162 | + | display: flex; | |
| 163 | + | align-items: center; | |
| 164 | + | justify-content: center; | |
| 165 | + | } | |
| 166 | + | .history-favicon-img { | |
| 167 | + | width: 16px; height: 16px; | |
| 168 | + | filter: brightness(1.06) contrast(1.03); | |
| 169 | + | image-rendering: -webkit-optimize-contrast; | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | .history-title { font-size: 0.95rem; color: #e6e6e6; flex: 0 0 auto; } | |
| 173 | + | .history-domain { font-size: 0.9rem; color: #a5a5a5; flex: 0 0 auto; } | |
| 174 | + | .history-sep { color: #666; flex: 0 0 auto; } | |
| 175 | + | .history-url { | |
| 176 | + | font-size: 0.9rem; | |
| 177 | + | color: #7a7a7a; /* darker than domain */ | |
| 178 | + | flex: 1 1 auto; | |
| 179 | + | min-width: 0; /* critical for flex truncation */ | |
| 180 | + | overflow: hidden; | |
| 181 | + | text-overflow: ellipsis; /* fallback */ | |
| 182 | + | -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%); | |
| 183 | + | mask-image: linear-gradient(to right, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%); | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | .shortcuts-grid { | |
| 187 | + | display: grid; | |
| 188 | + | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| 189 | + | gap: 1rem; | |
| 190 | + | max-height: calc(100vh - 8rem); | |
| 191 | + | overflow-y: auto; | |
| 192 | + | } | |
| 193 | + | ||
| 194 | + | .shortcut { | |
| 195 | + | padding: 1rem; | |
| 196 | + | background: #2d2d2d; | |
| 197 | + | border: 2px solid #404040; | |
| 198 | + | border-radius: 8px; | |
| 199 | + | cursor: pointer; | |
| 200 | + | transition: all 0.2s; | |
| 201 | + | text-align: center; | |
| 202 | + | } | |
| 203 | + | ||
| 204 | + | .shortcut:hover { | |
| 205 | + | background: #3d3d3d; | |
| 206 | + | border-color: #0066cc; | |
| 207 | + | transform: translateY(-2px); | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | .shortcut-key { | |
| 211 | + | font-weight: bold; | |
| 212 | + | color: #0066cc; | |
| 213 | + | margin-bottom: 0.5rem; | |
| 214 | + | font-size: 1.1rem; | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | .shortcut-desc { | |
| 218 | + | color: #888; | |
| 219 | + | font-size: 0.9rem; | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | .loading { | |
| 223 | + | padding: 2rem; | |
| 224 | + | text-align: center; | |
| 225 | + | color: #888; | |
| 226 | + | } | |
| 227 | + | ||
| 228 | + | .empty-state { | |
| 229 | + | padding: 3rem 2rem; | |
| 230 | + | text-align: center; | |
| 231 | + | color: #666; | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | .empty-state h3 { | |
| 235 | + | margin-bottom: 1rem; | |
| 236 | + | color: #888; | |
| 237 | + | } | |
| 238 | + | ||
| 239 | + | @media (max-width: 768px) { | |
| 240 | + | .container { | |
| 241 | + | flex-direction: column; | |
| 242 | + | padding: 1rem; | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | .shortcuts-grid { | |
| 246 | + | grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| 247 | + | } | |
| 248 | + | } | |
| 249 | + | `; | |
| 250 | + | } | |
| 251 | + | } | |
A gui/svelte.config.js +10 -0
| @@ -0,0 +1,10 @@ | |||
| 1 | + | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; | |
| 2 | + | ||
| 3 | + | export default { | |
| 4 | + | // Enable rune mode for Svelte 5 | |
| 5 | + | compilerOptions: { | |
| 6 | + | runes: true, | |
| 7 | + | }, | |
| 8 | + | // Use Vite's preprocessor for TypeScript and PostCSS | |
| 9 | + | preprocess: vitePreprocess(), | |
| 10 | + | };⏎̸ | |
A gui/tailwind.config.js +44 -0
| @@ -0,0 +1,44 @@ | |||
| 1 | + | /** @type {import('tailwindcss').Config} */ | |
| 2 | + | export default { | |
| 3 | + | content: [ | |
| 4 | + | './src/**/*.{html,js,ts,svelte}', | |
| 5 | + | ], | |
| 6 | + | theme: { | |
| 7 | + | extend: { | |
| 8 | + | // Custom design system colors | |
| 9 | + | colors: { | |
| 10 | + | // Browser-specific colors that work well in both themes | |
| 11 | + | browser: { | |
| 12 | + | bg: 'rgb(var(--browser-bg) / <alpha-value>)', | |
| 13 | + | surface: 'rgb(var(--browser-surface) / <alpha-value>)', | |
| 14 | + | text: 'rgb(var(--browser-text) / <alpha-value>)', | |
| 15 | + | muted: 'rgb(var(--browser-muted) / <alpha-value>)', | |
| 16 | + | accent: 'rgb(var(--browser-accent) / <alpha-value>)', | |
| 17 | + | border: 'rgb(var(--browser-border) / <alpha-value>)', | |
| 18 | + | } | |
| 19 | + | }, | |
| 20 | + | // Animation speeds optimized for browser UI | |
| 21 | + | transitionDuration: { | |
| 22 | + | '150': '150ms', // Fast interactions | |
| 23 | + | '250': '250ms', // UI feedback | |
| 24 | + | '400': '400ms', // Smooth transitions | |
| 25 | + | }, | |
| 26 | + | // Typography scale for browser UI | |
| 27 | + | fontSize: { | |
| 28 | + | 'xs': ['0.75rem', '1rem'], | |
| 29 | + | 'sm': ['0.875rem', '1.25rem'], | |
| 30 | + | 'base': ['1rem', '1.5rem'], | |
| 31 | + | 'lg': ['1.125rem', '1.75rem'], | |
| 32 | + | }, | |
| 33 | + | // Spacing for compact UI elements | |
| 34 | + | spacing: { | |
| 35 | + | '18': '4.5rem', | |
| 36 | + | '22': '5.5rem', | |
| 37 | + | } | |
| 38 | + | }, | |
| 39 | + | }, | |
| 40 | + | plugins: [], | |
| 41 | + | // Manual dark mode control (not system preference) | |
| 42 | + | // This allows GTK to control theme via CSS class | |
| 43 | + | darkMode: 'class', | |
| 44 | + | };⏎̸ | |
A gui/tsconfig.json +33 -0
| @@ -0,0 +1,33 @@ | |||
| 1 | + | { | |
| 2 | + | "compilerOptions": { | |
| 3 | + | "target": "ES2022", | |
| 4 | + | "module": "ESNext", | |
| 5 | + | "moduleResolution": "bundler", | |
| 6 | + | "lib": ["ES2022", "DOM", "DOM.Iterable"], | |
| 7 | + | "allowImportingTsExtensions": true, | |
| 8 | + | "moduleDetection": "force", | |
| 9 | + | "noEmit": true, | |
| 10 | + | "strict": true, | |
| 11 | + | "noUnusedLocals": true, | |
| 12 | + | "noUnusedParameters": true, | |
| 13 | + | "noFallthroughCasesInSwitch": true, | |
| 14 | + | "noUncheckedIndexedAccess": true, | |
| 15 | + | "skipLibCheck": true, | |
| 16 | + | "esModuleInterop": true, | |
| 17 | + | "allowSyntheticDefaultImports": true, | |
| 18 | + | "forceConsistentCasingInFileNames": true, | |
| 19 | + | "baseUrl": ".", | |
| 20 | + | "paths": { | |
| 21 | + | "$lib/*": ["src/lib/*"], | |
| 22 | + | "$components/*": ["src/components/*"] | |
| 23 | + | } | |
| 24 | + | }, | |
| 25 | + | "include": [ | |
| 26 | + | "src/**/*", | |
| 27 | + | "vite.config.ts" | |
| 28 | + | ], | |
| 29 | + | "exclude": [ | |
| 30 | + | "node_modules", | |
| 31 | + | "dist" | |
| 32 | + | ] | |
| 33 | + | }⏎̸ | |
A gui/vite-plugin-pages.ts +98 -0
| @@ -0,0 +1,98 @@ | |||
| 1 | + | import type { Plugin } from 'vite'; | |
| 2 | + | import { writeFileSync, readFileSync } from 'fs'; | |
| 3 | + | import { resolve } from 'path'; | |
| 4 | + | ||
| 5 | + | interface PageConfig { | |
| 6 | + | /** Page name (used for filename and script name) */ | |
| 7 | + | name: string; | |
| 8 | + | /** Page title */ | |
| 9 | + | title: string; | |
| 10 | + | /** Script filename (e.g., 'homepage.min.js') */ | |
| 11 | + | script: string; | |
| 12 | + | /** Optional CSS filename */ | |
| 13 | + | css?: string; | |
| 14 | + | /** Target filename (defaults to name + '.html') */ | |
| 15 | + | filename?: string; | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | // Load the favicon SVG from assets | |
| 19 | + | function getFaviconSVG(): string { | |
| 20 | + | const logoPath = resolve(__dirname, '..', 'assets', 'logo.svg'); | |
| 21 | + | return readFileSync(logoPath, 'utf-8'); | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | // Create favicon data URL for inline usage | |
| 25 | + | function getFaviconDataURL(): string { | |
| 26 | + | const svg = getFaviconSVG(); | |
| 27 | + | const encoded = encodeURIComponent(svg) | |
| 28 | + | .replace(/'/g, '%27') | |
| 29 | + | .replace(/\(/g, '%28') | |
| 30 | + | .replace(/\)/g, '%29'); | |
| 31 | + | return `data:image/svg+xml;utf8,${encoded}`; | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | // Generate HTML content for a page | |
| 35 | + | function generatePageHTML(config: PageConfig): string { | |
| 36 | + | const cssLink = config.css ? `<link rel="stylesheet" href="./${config.css}">` : ''; | |
| 37 | + | ||
| 38 | + | return `<!DOCTYPE html> | |
| 39 | + | <html lang="en"> | |
| 40 | + | <head> | |
| 41 | + | <meta charset="UTF-8"> | |
| 42 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| 43 | + | <title>${config.title}</title> | |
| 44 | + | <link rel="icon" type="image/svg+xml" href="${getFaviconDataURL()}"> | |
| 45 | + | ${cssLink} | |
| 46 | + | </head> | |
| 47 | + | <body> | |
| 48 | + | <script src="./${config.script}"></script> | |
| 49 | + | </body> | |
| 50 | + | </html>`; | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | /** | |
| 54 | + | * Vite plugin to generate dumb:// protocol pages | |
| 55 | + | * Supports multiple pages like homepage, config, about, etc. | |
| 56 | + | */ | |
| 57 | + | export function pageGenerator(pages: PageConfig[]): Plugin { | |
| 58 | + | return { | |
| 59 | + | name: 'dumb-page-generator', | |
| 60 | + | writeBundle() { | |
| 61 | + | const assetsDir = resolve(__dirname, '..', 'assets', 'gui'); | |
| 62 | + | ||
| 63 | + | try { | |
| 64 | + | // Generate HTML files for each page | |
| 65 | + | for (const page of pages) { | |
| 66 | + | const htmlContent = generatePageHTML(page); | |
| 67 | + | const filename = page.filename || `${page.name}.html`; | |
| 68 | + | writeFileSync(resolve(assetsDir, filename), htmlContent); | |
| 69 | + | console.log(`✓ Generated ${filename} for dumb://${page.name}`); | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Generate favicon.svg for scheme handler lookups | |
| 73 | + | const faviconContent = getFaviconSVG(); | |
| 74 | + | writeFileSync(resolve(assetsDir, 'favicon.svg'), faviconContent); | |
| 75 | + | console.log('✓ Generated favicon.svg'); | |
| 76 | + | ||
| 77 | + | } catch (error) { | |
| 78 | + | console.error('✗ Failed to generate page files:', error); | |
| 79 | + | throw error; | |
| 80 | + | } | |
| 81 | + | } | |
| 82 | + | }; | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | /** | |
| 86 | + | * Convenience function for homepage generation | |
| 87 | + | * @deprecated Use pageGenerator with homepage config instead | |
| 88 | + | */ | |
| 89 | + | export function homepageGenerator(): Plugin { | |
| 90 | + | return pageGenerator([ | |
| 91 | + | { | |
| 92 | + | name: 'homepage', | |
| 93 | + | title: 'Dumber Browser', | |
| 94 | + | script: 'homepage.min.js', | |
| 95 | + | filename: 'index.html', // Special case: homepage uses index.html | |
| 96 | + | } | |
| 97 | + | ]); | |
| 98 | + | }⏎̸ | |
A gui/vite.config.gui.ts +35 -0
| @@ -0,0 +1,35 @@ | |||
| 1 | + | import { defineConfig } from 'vite'; | |
| 2 | + | import { svelte } from '@sveltejs/vite-plugin-svelte'; | |
| 3 | + | import { resolve } from 'path'; | |
| 4 | + | ||
| 5 | + | export default defineConfig({ | |
| 6 | + | plugins: [ | |
| 7 | + | svelte(), | |
| 8 | + | ], | |
| 9 | + | build: { | |
| 10 | + | rollupOptions: { | |
| 11 | + | input: resolve(__dirname, 'src/injected/gui.ts'), | |
| 12 | + | output: { | |
| 13 | + | dir: '../assets/gui', | |
| 14 | + | format: 'iife', | |
| 15 | + | entryFileNames: 'gui.min.js', | |
| 16 | + | name: '__dumberGUI', | |
| 17 | + | inlineDynamicImports: true, | |
| 18 | + | assetFileNames: '[name].[ext]', // Don't hash asset names | |
| 19 | + | }, | |
| 20 | + | }, | |
| 21 | + | emptyOutDir: false, | |
| 22 | + | target: ['es2020', 'chrome91', 'firefox90'], | |
| 23 | + | minify: true, | |
| 24 | + | sourcemap: false, | |
| 25 | + | cssCodeSplit: false, // Keep CSS in single file | |
| 26 | + | assetsInlineLimit: 0, // Don't inline assets by default | |
| 27 | + | }, | |
| 28 | + | resolve: { | |
| 29 | + | alias: { | |
| 30 | + | // Alias for easier imports | |
| 31 | + | '$lib': resolve(__dirname, 'src/lib'), | |
| 32 | + | '$components': resolve(__dirname, 'src/components'), | |
| 33 | + | }, | |
| 34 | + | }, | |
| 35 | + | });⏎̸ | |
A gui/vite.config.homepage.ts +51 -0
| @@ -0,0 +1,51 @@ | |||
| 1 | + | import { defineConfig } from 'vite'; | |
| 2 | + | import { svelte } from '@sveltejs/vite-plugin-svelte'; | |
| 3 | + | import { resolve } from 'path'; | |
| 4 | + | import { pageGenerator } from './vite-plugin-pages'; | |
| 5 | + | ||
| 6 | + | export default defineConfig({ | |
| 7 | + | plugins: [ | |
| 8 | + | svelte(), | |
| 9 | + | pageGenerator([ | |
| 10 | + | { | |
| 11 | + | name: 'homepage', | |
| 12 | + | title: 'Dumber Browser', | |
| 13 | + | script: 'homepage.min.js', | |
| 14 | + | css: 'homepage.css', | |
| 15 | + | filename: 'index.html', // Special case: homepage uses index.html | |
| 16 | + | } | |
| 17 | + | ]), | |
| 18 | + | ], | |
| 19 | + | build: { | |
| 20 | + | rollupOptions: { | |
| 21 | + | input: resolve(__dirname, 'src/pages/homepage.ts'), | |
| 22 | + | output: { | |
| 23 | + | dir: '../assets/gui', | |
| 24 | + | format: 'iife', | |
| 25 | + | entryFileNames: 'homepage.min.js', | |
| 26 | + | name: '__dumberHomepage', | |
| 27 | + | inlineDynamicImports: true, | |
| 28 | + | assetFileNames: (assetInfo) => { | |
| 29 | + | // Keep CSS as homepage.css to avoid conflicts with the main GUI | |
| 30 | + | if (assetInfo.name?.endsWith('.css')) { | |
| 31 | + | return 'homepage.[ext]'; | |
| 32 | + | } | |
| 33 | + | return '[name].[ext]'; | |
| 34 | + | }, | |
| 35 | + | }, | |
| 36 | + | }, | |
| 37 | + | emptyOutDir: false, // Don't clear the directory (shared with GUI build) | |
| 38 | + | target: ['es2020', 'chrome91', 'firefox90'], | |
| 39 | + | minify: true, | |
| 40 | + | sourcemap: false, | |
| 41 | + | cssCodeSplit: false, // Keep CSS in single file | |
| 42 | + | assetsInlineLimit: 0, // Don't inline assets by default | |
| 43 | + | }, | |
| 44 | + | resolve: { | |
| 45 | + | alias: { | |
| 46 | + | // Alias for easier imports | |
| 47 | + | '$lib': resolve(__dirname, 'src/lib'), | |
| 48 | + | '$components': resolve(__dirname, 'src/components'), | |
| 49 | + | }, | |
| 50 | + | }, | |
| 51 | + | });⏎̸ | |