├── .github └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── public └── vite.svg ├── src ├── counter.ts ├── gradient.ts ├── main.ts ├── style.css ├── typescript.svg ├── utils.ts └── vite-env.d.ts ├── tsconfig.json └── vite.config.ts /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy 2 | on: 3 | push: 4 | branches: [ master ] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-node@v2 12 | 13 | - uses: pnpm/action-setup@v2.2.2 14 | with: 15 | version: 7.13.3 16 | run_install: true 17 | 18 | - name: Install and Build 🔧 19 | run: | 20 | pnpm run build 21 | 22 | - name: Deploy 🚀 23 | uses: JamesIves/github-pages-deploy-action@v4.2.5 24 | with: 25 | branch: gh-pages 26 | folder: ./dist 27 | 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

Gradient Picker

3 | 4 |

A website that allows you to create your own gradient

5 | 6 |

Open website

7 | 8 | ![image](https://user-images.githubusercontent.com/45036724/212474185-215a71b8-6bdd-4930-8598-b80ac22ecd07.png) 9 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Gradient Picker 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

GradientPicker

17 |
18 |
19 | 20 |
21 | 25 | 32 |
33 | 34 |
35 |
36 |
CSS Value
37 |
38 | Copied! 39 | 40 |
41 |
42 | 43 |
44 |
45 | 46 | 47 | 48 |
49 |
50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gradient-picker", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "gradient-picker", 9 | "version": "0.0.0", 10 | "devDependencies": { 11 | "typescript": "^4.9.3", 12 | "vite": "^4.0.0" 13 | } 14 | }, 15 | "node_modules/@esbuild/android-arm": { 16 | "version": "0.16.17", 17 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", 18 | "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", 19 | "cpu": [ 20 | "arm" 21 | ], 22 | "dev": true, 23 | "optional": true, 24 | "os": [ 25 | "android" 26 | ], 27 | "engines": { 28 | "node": ">=12" 29 | } 30 | }, 31 | "node_modules/@esbuild/android-arm64": { 32 | "version": "0.16.17", 33 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", 34 | "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", 35 | "cpu": [ 36 | "arm64" 37 | ], 38 | "dev": true, 39 | "optional": true, 40 | "os": [ 41 | "android" 42 | ], 43 | "engines": { 44 | "node": ">=12" 45 | } 46 | }, 47 | "node_modules/@esbuild/android-x64": { 48 | "version": "0.16.17", 49 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", 50 | "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", 51 | "cpu": [ 52 | "x64" 53 | ], 54 | "dev": true, 55 | "optional": true, 56 | "os": [ 57 | "android" 58 | ], 59 | "engines": { 60 | "node": ">=12" 61 | } 62 | }, 63 | "node_modules/@esbuild/darwin-arm64": { 64 | "version": "0.16.17", 65 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", 66 | "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", 67 | "cpu": [ 68 | "arm64" 69 | ], 70 | "dev": true, 71 | "optional": true, 72 | "os": [ 73 | "darwin" 74 | ], 75 | "engines": { 76 | "node": ">=12" 77 | } 78 | }, 79 | "node_modules/@esbuild/darwin-x64": { 80 | "version": "0.16.17", 81 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", 82 | "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", 83 | "cpu": [ 84 | "x64" 85 | ], 86 | "dev": true, 87 | "optional": true, 88 | "os": [ 89 | "darwin" 90 | ], 91 | "engines": { 92 | "node": ">=12" 93 | } 94 | }, 95 | "node_modules/@esbuild/freebsd-arm64": { 96 | "version": "0.16.17", 97 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", 98 | "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", 99 | "cpu": [ 100 | "arm64" 101 | ], 102 | "dev": true, 103 | "optional": true, 104 | "os": [ 105 | "freebsd" 106 | ], 107 | "engines": { 108 | "node": ">=12" 109 | } 110 | }, 111 | "node_modules/@esbuild/freebsd-x64": { 112 | "version": "0.16.17", 113 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", 114 | "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", 115 | "cpu": [ 116 | "x64" 117 | ], 118 | "dev": true, 119 | "optional": true, 120 | "os": [ 121 | "freebsd" 122 | ], 123 | "engines": { 124 | "node": ">=12" 125 | } 126 | }, 127 | "node_modules/@esbuild/linux-arm": { 128 | "version": "0.16.17", 129 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", 130 | "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", 131 | "cpu": [ 132 | "arm" 133 | ], 134 | "dev": true, 135 | "optional": true, 136 | "os": [ 137 | "linux" 138 | ], 139 | "engines": { 140 | "node": ">=12" 141 | } 142 | }, 143 | "node_modules/@esbuild/linux-arm64": { 144 | "version": "0.16.17", 145 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", 146 | "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", 147 | "cpu": [ 148 | "arm64" 149 | ], 150 | "dev": true, 151 | "optional": true, 152 | "os": [ 153 | "linux" 154 | ], 155 | "engines": { 156 | "node": ">=12" 157 | } 158 | }, 159 | "node_modules/@esbuild/linux-ia32": { 160 | "version": "0.16.17", 161 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", 162 | "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", 163 | "cpu": [ 164 | "ia32" 165 | ], 166 | "dev": true, 167 | "optional": true, 168 | "os": [ 169 | "linux" 170 | ], 171 | "engines": { 172 | "node": ">=12" 173 | } 174 | }, 175 | "node_modules/@esbuild/linux-loong64": { 176 | "version": "0.16.17", 177 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", 178 | "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", 179 | "cpu": [ 180 | "loong64" 181 | ], 182 | "dev": true, 183 | "optional": true, 184 | "os": [ 185 | "linux" 186 | ], 187 | "engines": { 188 | "node": ">=12" 189 | } 190 | }, 191 | "node_modules/@esbuild/linux-mips64el": { 192 | "version": "0.16.17", 193 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", 194 | "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", 195 | "cpu": [ 196 | "mips64el" 197 | ], 198 | "dev": true, 199 | "optional": true, 200 | "os": [ 201 | "linux" 202 | ], 203 | "engines": { 204 | "node": ">=12" 205 | } 206 | }, 207 | "node_modules/@esbuild/linux-ppc64": { 208 | "version": "0.16.17", 209 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", 210 | "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", 211 | "cpu": [ 212 | "ppc64" 213 | ], 214 | "dev": true, 215 | "optional": true, 216 | "os": [ 217 | "linux" 218 | ], 219 | "engines": { 220 | "node": ">=12" 221 | } 222 | }, 223 | "node_modules/@esbuild/linux-riscv64": { 224 | "version": "0.16.17", 225 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", 226 | "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", 227 | "cpu": [ 228 | "riscv64" 229 | ], 230 | "dev": true, 231 | "optional": true, 232 | "os": [ 233 | "linux" 234 | ], 235 | "engines": { 236 | "node": ">=12" 237 | } 238 | }, 239 | "node_modules/@esbuild/linux-s390x": { 240 | "version": "0.16.17", 241 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", 242 | "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", 243 | "cpu": [ 244 | "s390x" 245 | ], 246 | "dev": true, 247 | "optional": true, 248 | "os": [ 249 | "linux" 250 | ], 251 | "engines": { 252 | "node": ">=12" 253 | } 254 | }, 255 | "node_modules/@esbuild/linux-x64": { 256 | "version": "0.16.17", 257 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", 258 | "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", 259 | "cpu": [ 260 | "x64" 261 | ], 262 | "dev": true, 263 | "optional": true, 264 | "os": [ 265 | "linux" 266 | ], 267 | "engines": { 268 | "node": ">=12" 269 | } 270 | }, 271 | "node_modules/@esbuild/netbsd-x64": { 272 | "version": "0.16.17", 273 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", 274 | "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", 275 | "cpu": [ 276 | "x64" 277 | ], 278 | "dev": true, 279 | "optional": true, 280 | "os": [ 281 | "netbsd" 282 | ], 283 | "engines": { 284 | "node": ">=12" 285 | } 286 | }, 287 | "node_modules/@esbuild/openbsd-x64": { 288 | "version": "0.16.17", 289 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", 290 | "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", 291 | "cpu": [ 292 | "x64" 293 | ], 294 | "dev": true, 295 | "optional": true, 296 | "os": [ 297 | "openbsd" 298 | ], 299 | "engines": { 300 | "node": ">=12" 301 | } 302 | }, 303 | "node_modules/@esbuild/sunos-x64": { 304 | "version": "0.16.17", 305 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", 306 | "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", 307 | "cpu": [ 308 | "x64" 309 | ], 310 | "dev": true, 311 | "optional": true, 312 | "os": [ 313 | "sunos" 314 | ], 315 | "engines": { 316 | "node": ">=12" 317 | } 318 | }, 319 | "node_modules/@esbuild/win32-arm64": { 320 | "version": "0.16.17", 321 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", 322 | "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", 323 | "cpu": [ 324 | "arm64" 325 | ], 326 | "dev": true, 327 | "optional": true, 328 | "os": [ 329 | "win32" 330 | ], 331 | "engines": { 332 | "node": ">=12" 333 | } 334 | }, 335 | "node_modules/@esbuild/win32-ia32": { 336 | "version": "0.16.17", 337 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", 338 | "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", 339 | "cpu": [ 340 | "ia32" 341 | ], 342 | "dev": true, 343 | "optional": true, 344 | "os": [ 345 | "win32" 346 | ], 347 | "engines": { 348 | "node": ">=12" 349 | } 350 | }, 351 | "node_modules/@esbuild/win32-x64": { 352 | "version": "0.16.17", 353 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", 354 | "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", 355 | "cpu": [ 356 | "x64" 357 | ], 358 | "dev": true, 359 | "optional": true, 360 | "os": [ 361 | "win32" 362 | ], 363 | "engines": { 364 | "node": ">=12" 365 | } 366 | }, 367 | "node_modules/esbuild": { 368 | "version": "0.16.17", 369 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", 370 | "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", 371 | "dev": true, 372 | "hasInstallScript": true, 373 | "bin": { 374 | "esbuild": "bin/esbuild" 375 | }, 376 | "engines": { 377 | "node": ">=12" 378 | }, 379 | "optionalDependencies": { 380 | "@esbuild/android-arm": "0.16.17", 381 | "@esbuild/android-arm64": "0.16.17", 382 | "@esbuild/android-x64": "0.16.17", 383 | "@esbuild/darwin-arm64": "0.16.17", 384 | "@esbuild/darwin-x64": "0.16.17", 385 | "@esbuild/freebsd-arm64": "0.16.17", 386 | "@esbuild/freebsd-x64": "0.16.17", 387 | "@esbuild/linux-arm": "0.16.17", 388 | "@esbuild/linux-arm64": "0.16.17", 389 | "@esbuild/linux-ia32": "0.16.17", 390 | "@esbuild/linux-loong64": "0.16.17", 391 | "@esbuild/linux-mips64el": "0.16.17", 392 | "@esbuild/linux-ppc64": "0.16.17", 393 | "@esbuild/linux-riscv64": "0.16.17", 394 | "@esbuild/linux-s390x": "0.16.17", 395 | "@esbuild/linux-x64": "0.16.17", 396 | "@esbuild/netbsd-x64": "0.16.17", 397 | "@esbuild/openbsd-x64": "0.16.17", 398 | "@esbuild/sunos-x64": "0.16.17", 399 | "@esbuild/win32-arm64": "0.16.17", 400 | "@esbuild/win32-ia32": "0.16.17", 401 | "@esbuild/win32-x64": "0.16.17" 402 | } 403 | }, 404 | "node_modules/fsevents": { 405 | "version": "2.3.2", 406 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 407 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 408 | "dev": true, 409 | "hasInstallScript": true, 410 | "optional": true, 411 | "os": [ 412 | "darwin" 413 | ], 414 | "engines": { 415 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 416 | } 417 | }, 418 | "node_modules/function-bind": { 419 | "version": "1.1.1", 420 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 421 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 422 | "dev": true 423 | }, 424 | "node_modules/has": { 425 | "version": "1.0.3", 426 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 427 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 428 | "dev": true, 429 | "dependencies": { 430 | "function-bind": "^1.1.1" 431 | }, 432 | "engines": { 433 | "node": ">= 0.4.0" 434 | } 435 | }, 436 | "node_modules/is-core-module": { 437 | "version": "2.11.0", 438 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 439 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 440 | "dev": true, 441 | "dependencies": { 442 | "has": "^1.0.3" 443 | }, 444 | "funding": { 445 | "url": "https://github.com/sponsors/ljharb" 446 | } 447 | }, 448 | "node_modules/nanoid": { 449 | "version": "3.3.4", 450 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 451 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 452 | "dev": true, 453 | "bin": { 454 | "nanoid": "bin/nanoid.cjs" 455 | }, 456 | "engines": { 457 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 458 | } 459 | }, 460 | "node_modules/path-parse": { 461 | "version": "1.0.7", 462 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 463 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 464 | "dev": true 465 | }, 466 | "node_modules/picocolors": { 467 | "version": "1.0.0", 468 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 469 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 470 | "dev": true 471 | }, 472 | "node_modules/postcss": { 473 | "version": "8.4.21", 474 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", 475 | "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", 476 | "dev": true, 477 | "funding": [ 478 | { 479 | "type": "opencollective", 480 | "url": "https://opencollective.com/postcss/" 481 | }, 482 | { 483 | "type": "tidelift", 484 | "url": "https://tidelift.com/funding/github/npm/postcss" 485 | } 486 | ], 487 | "dependencies": { 488 | "nanoid": "^3.3.4", 489 | "picocolors": "^1.0.0", 490 | "source-map-js": "^1.0.2" 491 | }, 492 | "engines": { 493 | "node": "^10 || ^12 || >=14" 494 | } 495 | }, 496 | "node_modules/resolve": { 497 | "version": "1.22.1", 498 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 499 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 500 | "dev": true, 501 | "dependencies": { 502 | "is-core-module": "^2.9.0", 503 | "path-parse": "^1.0.7", 504 | "supports-preserve-symlinks-flag": "^1.0.0" 505 | }, 506 | "bin": { 507 | "resolve": "bin/resolve" 508 | }, 509 | "funding": { 510 | "url": "https://github.com/sponsors/ljharb" 511 | } 512 | }, 513 | "node_modules/rollup": { 514 | "version": "3.10.0", 515 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.0.tgz", 516 | "integrity": "sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==", 517 | "dev": true, 518 | "bin": { 519 | "rollup": "dist/bin/rollup" 520 | }, 521 | "engines": { 522 | "node": ">=14.18.0", 523 | "npm": ">=8.0.0" 524 | }, 525 | "optionalDependencies": { 526 | "fsevents": "~2.3.2" 527 | } 528 | }, 529 | "node_modules/source-map-js": { 530 | "version": "1.0.2", 531 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 532 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 533 | "dev": true, 534 | "engines": { 535 | "node": ">=0.10.0" 536 | } 537 | }, 538 | "node_modules/supports-preserve-symlinks-flag": { 539 | "version": "1.0.0", 540 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 541 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 542 | "dev": true, 543 | "engines": { 544 | "node": ">= 0.4" 545 | }, 546 | "funding": { 547 | "url": "https://github.com/sponsors/ljharb" 548 | } 549 | }, 550 | "node_modules/typescript": { 551 | "version": "4.9.4", 552 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 553 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", 554 | "dev": true, 555 | "bin": { 556 | "tsc": "bin/tsc", 557 | "tsserver": "bin/tsserver" 558 | }, 559 | "engines": { 560 | "node": ">=4.2.0" 561 | } 562 | }, 563 | "node_modules/vite": { 564 | "version": "4.0.4", 565 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz", 566 | "integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==", 567 | "dev": true, 568 | "dependencies": { 569 | "esbuild": "^0.16.3", 570 | "postcss": "^8.4.20", 571 | "resolve": "^1.22.1", 572 | "rollup": "^3.7.0" 573 | }, 574 | "bin": { 575 | "vite": "bin/vite.js" 576 | }, 577 | "engines": { 578 | "node": "^14.18.0 || >=16.0.0" 579 | }, 580 | "optionalDependencies": { 581 | "fsevents": "~2.3.2" 582 | }, 583 | "peerDependencies": { 584 | "@types/node": ">= 14", 585 | "less": "*", 586 | "sass": "*", 587 | "stylus": "*", 588 | "sugarss": "*", 589 | "terser": "^5.4.0" 590 | }, 591 | "peerDependenciesMeta": { 592 | "@types/node": { 593 | "optional": true 594 | }, 595 | "less": { 596 | "optional": true 597 | }, 598 | "sass": { 599 | "optional": true 600 | }, 601 | "stylus": { 602 | "optional": true 603 | }, 604 | "sugarss": { 605 | "optional": true 606 | }, 607 | "terser": { 608 | "optional": true 609 | } 610 | } 611 | } 612 | }, 613 | "dependencies": { 614 | "@esbuild/android-arm": { 615 | "version": "0.16.17", 616 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", 617 | "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", 618 | "dev": true, 619 | "optional": true 620 | }, 621 | "@esbuild/android-arm64": { 622 | "version": "0.16.17", 623 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", 624 | "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", 625 | "dev": true, 626 | "optional": true 627 | }, 628 | "@esbuild/android-x64": { 629 | "version": "0.16.17", 630 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", 631 | "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", 632 | "dev": true, 633 | "optional": true 634 | }, 635 | "@esbuild/darwin-arm64": { 636 | "version": "0.16.17", 637 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", 638 | "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", 639 | "dev": true, 640 | "optional": true 641 | }, 642 | "@esbuild/darwin-x64": { 643 | "version": "0.16.17", 644 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", 645 | "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", 646 | "dev": true, 647 | "optional": true 648 | }, 649 | "@esbuild/freebsd-arm64": { 650 | "version": "0.16.17", 651 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", 652 | "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", 653 | "dev": true, 654 | "optional": true 655 | }, 656 | "@esbuild/freebsd-x64": { 657 | "version": "0.16.17", 658 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", 659 | "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", 660 | "dev": true, 661 | "optional": true 662 | }, 663 | "@esbuild/linux-arm": { 664 | "version": "0.16.17", 665 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", 666 | "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", 667 | "dev": true, 668 | "optional": true 669 | }, 670 | "@esbuild/linux-arm64": { 671 | "version": "0.16.17", 672 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", 673 | "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", 674 | "dev": true, 675 | "optional": true 676 | }, 677 | "@esbuild/linux-ia32": { 678 | "version": "0.16.17", 679 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", 680 | "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", 681 | "dev": true, 682 | "optional": true 683 | }, 684 | "@esbuild/linux-loong64": { 685 | "version": "0.16.17", 686 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", 687 | "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", 688 | "dev": true, 689 | "optional": true 690 | }, 691 | "@esbuild/linux-mips64el": { 692 | "version": "0.16.17", 693 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", 694 | "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", 695 | "dev": true, 696 | "optional": true 697 | }, 698 | "@esbuild/linux-ppc64": { 699 | "version": "0.16.17", 700 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", 701 | "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", 702 | "dev": true, 703 | "optional": true 704 | }, 705 | "@esbuild/linux-riscv64": { 706 | "version": "0.16.17", 707 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", 708 | "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", 709 | "dev": true, 710 | "optional": true 711 | }, 712 | "@esbuild/linux-s390x": { 713 | "version": "0.16.17", 714 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", 715 | "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", 716 | "dev": true, 717 | "optional": true 718 | }, 719 | "@esbuild/linux-x64": { 720 | "version": "0.16.17", 721 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", 722 | "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", 723 | "dev": true, 724 | "optional": true 725 | }, 726 | "@esbuild/netbsd-x64": { 727 | "version": "0.16.17", 728 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", 729 | "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", 730 | "dev": true, 731 | "optional": true 732 | }, 733 | "@esbuild/openbsd-x64": { 734 | "version": "0.16.17", 735 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", 736 | "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", 737 | "dev": true, 738 | "optional": true 739 | }, 740 | "@esbuild/sunos-x64": { 741 | "version": "0.16.17", 742 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", 743 | "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", 744 | "dev": true, 745 | "optional": true 746 | }, 747 | "@esbuild/win32-arm64": { 748 | "version": "0.16.17", 749 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", 750 | "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", 751 | "dev": true, 752 | "optional": true 753 | }, 754 | "@esbuild/win32-ia32": { 755 | "version": "0.16.17", 756 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", 757 | "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", 758 | "dev": true, 759 | "optional": true 760 | }, 761 | "@esbuild/win32-x64": { 762 | "version": "0.16.17", 763 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", 764 | "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", 765 | "dev": true, 766 | "optional": true 767 | }, 768 | "esbuild": { 769 | "version": "0.16.17", 770 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", 771 | "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", 772 | "dev": true, 773 | "requires": { 774 | "@esbuild/android-arm": "0.16.17", 775 | "@esbuild/android-arm64": "0.16.17", 776 | "@esbuild/android-x64": "0.16.17", 777 | "@esbuild/darwin-arm64": "0.16.17", 778 | "@esbuild/darwin-x64": "0.16.17", 779 | "@esbuild/freebsd-arm64": "0.16.17", 780 | "@esbuild/freebsd-x64": "0.16.17", 781 | "@esbuild/linux-arm": "0.16.17", 782 | "@esbuild/linux-arm64": "0.16.17", 783 | "@esbuild/linux-ia32": "0.16.17", 784 | "@esbuild/linux-loong64": "0.16.17", 785 | "@esbuild/linux-mips64el": "0.16.17", 786 | "@esbuild/linux-ppc64": "0.16.17", 787 | "@esbuild/linux-riscv64": "0.16.17", 788 | "@esbuild/linux-s390x": "0.16.17", 789 | "@esbuild/linux-x64": "0.16.17", 790 | "@esbuild/netbsd-x64": "0.16.17", 791 | "@esbuild/openbsd-x64": "0.16.17", 792 | "@esbuild/sunos-x64": "0.16.17", 793 | "@esbuild/win32-arm64": "0.16.17", 794 | "@esbuild/win32-ia32": "0.16.17", 795 | "@esbuild/win32-x64": "0.16.17" 796 | } 797 | }, 798 | "fsevents": { 799 | "version": "2.3.2", 800 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 801 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 802 | "dev": true, 803 | "optional": true 804 | }, 805 | "function-bind": { 806 | "version": "1.1.1", 807 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 808 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 809 | "dev": true 810 | }, 811 | "has": { 812 | "version": "1.0.3", 813 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 814 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 815 | "dev": true, 816 | "requires": { 817 | "function-bind": "^1.1.1" 818 | } 819 | }, 820 | "is-core-module": { 821 | "version": "2.11.0", 822 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 823 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 824 | "dev": true, 825 | "requires": { 826 | "has": "^1.0.3" 827 | } 828 | }, 829 | "nanoid": { 830 | "version": "3.3.4", 831 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 832 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 833 | "dev": true 834 | }, 835 | "path-parse": { 836 | "version": "1.0.7", 837 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 838 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 839 | "dev": true 840 | }, 841 | "picocolors": { 842 | "version": "1.0.0", 843 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 844 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 845 | "dev": true 846 | }, 847 | "postcss": { 848 | "version": "8.4.21", 849 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", 850 | "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", 851 | "dev": true, 852 | "requires": { 853 | "nanoid": "^3.3.4", 854 | "picocolors": "^1.0.0", 855 | "source-map-js": "^1.0.2" 856 | } 857 | }, 858 | "resolve": { 859 | "version": "1.22.1", 860 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 861 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 862 | "dev": true, 863 | "requires": { 864 | "is-core-module": "^2.9.0", 865 | "path-parse": "^1.0.7", 866 | "supports-preserve-symlinks-flag": "^1.0.0" 867 | } 868 | }, 869 | "rollup": { 870 | "version": "3.10.0", 871 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.0.tgz", 872 | "integrity": "sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==", 873 | "dev": true, 874 | "requires": { 875 | "fsevents": "~2.3.2" 876 | } 877 | }, 878 | "source-map-js": { 879 | "version": "1.0.2", 880 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 881 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 882 | "dev": true 883 | }, 884 | "supports-preserve-symlinks-flag": { 885 | "version": "1.0.0", 886 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 887 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 888 | "dev": true 889 | }, 890 | "typescript": { 891 | "version": "4.9.4", 892 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 893 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", 894 | "dev": true 895 | }, 896 | "vite": { 897 | "version": "4.0.4", 898 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz", 899 | "integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==", 900 | "dev": true, 901 | "requires": { 902 | "esbuild": "^0.16.3", 903 | "fsevents": "~2.3.2", 904 | "postcss": "^8.4.20", 905 | "resolve": "^1.22.1", 906 | "rollup": "^3.7.0" 907 | } 908 | } 909 | } 910 | } 911 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gradient-picker", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.9.3", 13 | "vite": "^4.0.0" 14 | } 15 | } -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | typescript: ^4.9.3 5 | vite: ^4.0.0 6 | 7 | devDependencies: 8 | typescript: 4.9.4 9 | vite: 4.0.4 10 | 11 | packages: 12 | 13 | /@esbuild/android-arm/0.16.17: 14 | resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} 15 | engines: {node: '>=12'} 16 | cpu: [arm] 17 | os: [android] 18 | requiresBuild: true 19 | dev: true 20 | optional: true 21 | 22 | /@esbuild/android-arm64/0.16.17: 23 | resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} 24 | engines: {node: '>=12'} 25 | cpu: [arm64] 26 | os: [android] 27 | requiresBuild: true 28 | dev: true 29 | optional: true 30 | 31 | /@esbuild/android-x64/0.16.17: 32 | resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} 33 | engines: {node: '>=12'} 34 | cpu: [x64] 35 | os: [android] 36 | requiresBuild: true 37 | dev: true 38 | optional: true 39 | 40 | /@esbuild/darwin-arm64/0.16.17: 41 | resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} 42 | engines: {node: '>=12'} 43 | cpu: [arm64] 44 | os: [darwin] 45 | requiresBuild: true 46 | dev: true 47 | optional: true 48 | 49 | /@esbuild/darwin-x64/0.16.17: 50 | resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} 51 | engines: {node: '>=12'} 52 | cpu: [x64] 53 | os: [darwin] 54 | requiresBuild: true 55 | dev: true 56 | optional: true 57 | 58 | /@esbuild/freebsd-arm64/0.16.17: 59 | resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} 60 | engines: {node: '>=12'} 61 | cpu: [arm64] 62 | os: [freebsd] 63 | requiresBuild: true 64 | dev: true 65 | optional: true 66 | 67 | /@esbuild/freebsd-x64/0.16.17: 68 | resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} 69 | engines: {node: '>=12'} 70 | cpu: [x64] 71 | os: [freebsd] 72 | requiresBuild: true 73 | dev: true 74 | optional: true 75 | 76 | /@esbuild/linux-arm/0.16.17: 77 | resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} 78 | engines: {node: '>=12'} 79 | cpu: [arm] 80 | os: [linux] 81 | requiresBuild: true 82 | dev: true 83 | optional: true 84 | 85 | /@esbuild/linux-arm64/0.16.17: 86 | resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} 87 | engines: {node: '>=12'} 88 | cpu: [arm64] 89 | os: [linux] 90 | requiresBuild: true 91 | dev: true 92 | optional: true 93 | 94 | /@esbuild/linux-ia32/0.16.17: 95 | resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} 96 | engines: {node: '>=12'} 97 | cpu: [ia32] 98 | os: [linux] 99 | requiresBuild: true 100 | dev: true 101 | optional: true 102 | 103 | /@esbuild/linux-loong64/0.16.17: 104 | resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} 105 | engines: {node: '>=12'} 106 | cpu: [loong64] 107 | os: [linux] 108 | requiresBuild: true 109 | dev: true 110 | optional: true 111 | 112 | /@esbuild/linux-mips64el/0.16.17: 113 | resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} 114 | engines: {node: '>=12'} 115 | cpu: [mips64el] 116 | os: [linux] 117 | requiresBuild: true 118 | dev: true 119 | optional: true 120 | 121 | /@esbuild/linux-ppc64/0.16.17: 122 | resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} 123 | engines: {node: '>=12'} 124 | cpu: [ppc64] 125 | os: [linux] 126 | requiresBuild: true 127 | dev: true 128 | optional: true 129 | 130 | /@esbuild/linux-riscv64/0.16.17: 131 | resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} 132 | engines: {node: '>=12'} 133 | cpu: [riscv64] 134 | os: [linux] 135 | requiresBuild: true 136 | dev: true 137 | optional: true 138 | 139 | /@esbuild/linux-s390x/0.16.17: 140 | resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} 141 | engines: {node: '>=12'} 142 | cpu: [s390x] 143 | os: [linux] 144 | requiresBuild: true 145 | dev: true 146 | optional: true 147 | 148 | /@esbuild/linux-x64/0.16.17: 149 | resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} 150 | engines: {node: '>=12'} 151 | cpu: [x64] 152 | os: [linux] 153 | requiresBuild: true 154 | dev: true 155 | optional: true 156 | 157 | /@esbuild/netbsd-x64/0.16.17: 158 | resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} 159 | engines: {node: '>=12'} 160 | cpu: [x64] 161 | os: [netbsd] 162 | requiresBuild: true 163 | dev: true 164 | optional: true 165 | 166 | /@esbuild/openbsd-x64/0.16.17: 167 | resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} 168 | engines: {node: '>=12'} 169 | cpu: [x64] 170 | os: [openbsd] 171 | requiresBuild: true 172 | dev: true 173 | optional: true 174 | 175 | /@esbuild/sunos-x64/0.16.17: 176 | resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} 177 | engines: {node: '>=12'} 178 | cpu: [x64] 179 | os: [sunos] 180 | requiresBuild: true 181 | dev: true 182 | optional: true 183 | 184 | /@esbuild/win32-arm64/0.16.17: 185 | resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} 186 | engines: {node: '>=12'} 187 | cpu: [arm64] 188 | os: [win32] 189 | requiresBuild: true 190 | dev: true 191 | optional: true 192 | 193 | /@esbuild/win32-ia32/0.16.17: 194 | resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} 195 | engines: {node: '>=12'} 196 | cpu: [ia32] 197 | os: [win32] 198 | requiresBuild: true 199 | dev: true 200 | optional: true 201 | 202 | /@esbuild/win32-x64/0.16.17: 203 | resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} 204 | engines: {node: '>=12'} 205 | cpu: [x64] 206 | os: [win32] 207 | requiresBuild: true 208 | dev: true 209 | optional: true 210 | 211 | /esbuild/0.16.17: 212 | resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} 213 | engines: {node: '>=12'} 214 | hasBin: true 215 | requiresBuild: true 216 | optionalDependencies: 217 | '@esbuild/android-arm': 0.16.17 218 | '@esbuild/android-arm64': 0.16.17 219 | '@esbuild/android-x64': 0.16.17 220 | '@esbuild/darwin-arm64': 0.16.17 221 | '@esbuild/darwin-x64': 0.16.17 222 | '@esbuild/freebsd-arm64': 0.16.17 223 | '@esbuild/freebsd-x64': 0.16.17 224 | '@esbuild/linux-arm': 0.16.17 225 | '@esbuild/linux-arm64': 0.16.17 226 | '@esbuild/linux-ia32': 0.16.17 227 | '@esbuild/linux-loong64': 0.16.17 228 | '@esbuild/linux-mips64el': 0.16.17 229 | '@esbuild/linux-ppc64': 0.16.17 230 | '@esbuild/linux-riscv64': 0.16.17 231 | '@esbuild/linux-s390x': 0.16.17 232 | '@esbuild/linux-x64': 0.16.17 233 | '@esbuild/netbsd-x64': 0.16.17 234 | '@esbuild/openbsd-x64': 0.16.17 235 | '@esbuild/sunos-x64': 0.16.17 236 | '@esbuild/win32-arm64': 0.16.17 237 | '@esbuild/win32-ia32': 0.16.17 238 | '@esbuild/win32-x64': 0.16.17 239 | dev: true 240 | 241 | /fsevents/2.3.2: 242 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 243 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 244 | os: [darwin] 245 | requiresBuild: true 246 | dev: true 247 | optional: true 248 | 249 | /function-bind/1.1.1: 250 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 251 | dev: true 252 | 253 | /has/1.0.3: 254 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 255 | engines: {node: '>= 0.4.0'} 256 | dependencies: 257 | function-bind: 1.1.1 258 | dev: true 259 | 260 | /is-core-module/2.11.0: 261 | resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} 262 | dependencies: 263 | has: 1.0.3 264 | dev: true 265 | 266 | /nanoid/3.3.4: 267 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} 268 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 269 | hasBin: true 270 | dev: true 271 | 272 | /path-parse/1.0.7: 273 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 274 | dev: true 275 | 276 | /picocolors/1.0.0: 277 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 278 | dev: true 279 | 280 | /postcss/8.4.21: 281 | resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} 282 | engines: {node: ^10 || ^12 || >=14} 283 | dependencies: 284 | nanoid: 3.3.4 285 | picocolors: 1.0.0 286 | source-map-js: 1.0.2 287 | dev: true 288 | 289 | /resolve/1.22.1: 290 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} 291 | hasBin: true 292 | dependencies: 293 | is-core-module: 2.11.0 294 | path-parse: 1.0.7 295 | supports-preserve-symlinks-flag: 1.0.0 296 | dev: true 297 | 298 | /rollup/3.10.0: 299 | resolution: {integrity: sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==} 300 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 301 | hasBin: true 302 | optionalDependencies: 303 | fsevents: 2.3.2 304 | dev: true 305 | 306 | /source-map-js/1.0.2: 307 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 308 | engines: {node: '>=0.10.0'} 309 | dev: true 310 | 311 | /supports-preserve-symlinks-flag/1.0.0: 312 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 313 | engines: {node: '>= 0.4'} 314 | dev: true 315 | 316 | /typescript/4.9.4: 317 | resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} 318 | engines: {node: '>=4.2.0'} 319 | hasBin: true 320 | dev: true 321 | 322 | /vite/4.0.4: 323 | resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} 324 | engines: {node: ^14.18.0 || >=16.0.0} 325 | hasBin: true 326 | peerDependencies: 327 | '@types/node': '>= 14' 328 | less: '*' 329 | sass: '*' 330 | stylus: '*' 331 | sugarss: '*' 332 | terser: ^5.4.0 333 | peerDependenciesMeta: 334 | '@types/node': 335 | optional: true 336 | less: 337 | optional: true 338 | sass: 339 | optional: true 340 | stylus: 341 | optional: true 342 | sugarss: 343 | optional: true 344 | terser: 345 | optional: true 346 | dependencies: 347 | esbuild: 0.16.17 348 | postcss: 8.4.21 349 | resolve: 1.22.1 350 | rollup: 3.10.0 351 | optionalDependencies: 352 | fsevents: 2.3.2 353 | dev: true 354 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/counter.ts: -------------------------------------------------------------------------------- 1 | export function setupCounter(element: HTMLButtonElement) { 2 | let counter = 0 3 | const setCounter = (count: number) => { 4 | counter = count 5 | element.innerHTML = `count is ${counter}` 6 | } 7 | element.addEventListener('click', () => setCounter(counter + 1)) 8 | setCounter(0) 9 | } 10 | -------------------------------------------------------------------------------- /src/gradient.ts: -------------------------------------------------------------------------------- 1 | import { createElement } from "./utils" 2 | 3 | interface Props { 4 | el: HTMLElement 5 | previewEl: HTMLElement 6 | colorHandlersEl: HTMLElement 7 | } 8 | 9 | type GradientDirection = "top" | "left" | "center" | "bottom" | "right" 10 | type GradientType = "linear" | "radial" 11 | type GradientStop = { 12 | color: string 13 | position: number 14 | } 15 | 16 | export class GradientPicker { 17 | direction: GradientDirection = "right" 18 | el: Props['el'] 19 | previewEl: Props['previewEl'] 20 | colorHandlersEl: Props['colorHandlersEl'] 21 | type: GradientType = "linear" 22 | stops: GradientStop[] = [] 23 | isDragging = false 24 | 25 | constructor({ el, previewEl, colorHandlersEl }: Props) { 26 | this.el = el 27 | this.previewEl = previewEl 28 | this.colorHandlersEl = colorHandlersEl 29 | this.previewEl.append(this.colorHandlersEl) 30 | this.addColorStop("#3494E6", .5) 31 | this.addColorStop("#EC6EAD", 99) 32 | 33 | this.listener() 34 | } 35 | 36 | /** 37 | * Add color to the gradient 38 | * @param color The color string (HEX/RGB/any supported css color format) 39 | * @param position The position of the stop (0-100) 40 | */ 41 | addColorStop(color: string, position: number) { 42 | this.stops.push({ color, position }) 43 | this.createStopHandler(this.stops.length-1) 44 | this.updateElementBackground() 45 | } 46 | 47 | changeGradientType(type: GradientType) { 48 | this.type = type 49 | this.updateElementBackground() 50 | } 51 | 52 | getGradientString(type: GradientType = this.type, direction: GradientDirection = this.direction) { 53 | const round = (num: number) => Math.round(num * 100) / 100 54 | const colorConcat = [...this.stops] 55 | .sort((a,b) => a.position - b.position) 56 | .map(stop => ` ${stop.color} ${round(stop.position)}%`).join(',') 57 | 58 | if(type === 'radial') { 59 | const radialPositions: Record = { 60 | "bottom": "at center bottom", 61 | "center": "", 62 | "left": "at left center", 63 | "right": "at center right", 64 | "top": "at center top", 65 | } 66 | return `radial-gradient(circle ${radialPositions[direction]}, ${colorConcat})` 67 | } 68 | 69 | return `linear-gradient(to ${direction},${colorConcat})` 70 | } 71 | 72 | private updateElementBackground() { 73 | const gradientString = this.getGradientString() 74 | this.el.style.backgroundImage = gradientString 75 | this.previewEl.style.backgroundImage = this.getGradientString('linear', 'right') 76 | let cssTextbox = document.getElementById('css')! 77 | cssTextbox.textContent = gradientString 78 | } 79 | 80 | private createStopHandler(stopIndex: number) { 81 | const colorStop = this.stops[stopIndex] 82 | 83 | // Handler bar 84 | const handler = createElement('div', { class: 'color__handler', 'data-index': stopIndex.toString() }, { '--handler-position': `${colorStop.position}%` }) 85 | 86 | // Handler remover 87 | const handlerButtons = createElement('div', { class: 'color__handler-buttons', 'data-index': stopIndex.toString() }, { '--handler-position': `${colorStop.position}%` }) 88 | const handlerRemover = createElement('div', { class: 'color__handler-remover' }) 89 | 90 | // Color picker 91 | const inputColorWrapper = createElement('div', { 92 | type: 'color', 93 | class: 'color__input-wrapper', 94 | }) 95 | const inputColor = createElement('input', { 96 | type: 'color', 97 | class: 'color__input', 98 | value: colorStop.color 99 | }) 100 | inputColorWrapper.append(inputColor) 101 | 102 | inputColor.addEventListener('input', e => this.onColorChange(e as InputEvent, stopIndex)) 103 | handler.addEventListener('mousedown', e => this.onHandlerMouseDown(e)) 104 | handler.addEventListener('mouseup', e => this.onHandlerMouseUp(e)) 105 | this.previewEl.addEventListener('mousemove', e => this.onHandlerMouseMove(e)) 106 | handlerRemover.addEventListener('click', () => { 107 | this.stops.splice(stopIndex, 1) 108 | handler.remove() 109 | handlerButtons.remove() 110 | this.updateElementBackground() 111 | }) 112 | 113 | handlerButtons.append(handlerRemover, inputColorWrapper) 114 | this.colorHandlersEl.append(handler) 115 | this.previewEl.append(handlerButtons) 116 | } 117 | 118 | onHandlerMouseDown(event: MouseEvent) { 119 | let handlerEl = event.target as HTMLElement 120 | handlerEl.classList.add('active') 121 | this.isDragging = true 122 | } 123 | 124 | onHandlerMouseMove(event: MouseEvent) { 125 | if(!this.isDragging) return 126 | 127 | let handlerEl = document.querySelector('.color__handler.active') 128 | if(!handlerEl?.classList.contains('active')) return 129 | const stopIndex = ~~(handlerEl.getAttribute('data-index') || 0) 130 | 131 | const newStopPosition = this.getPercentage(event.clientX) 132 | 133 | if(newStopPosition < 0.5 || newStopPosition > 99.5) return 134 | 135 | this.changePosition(stopIndex, newStopPosition) 136 | this.updateElementBackground() 137 | } 138 | 139 | onHandlerMouseUp(event: MouseEvent) { 140 | let handlerEl = event.target as HTMLElement 141 | handlerEl.classList.remove('active') 142 | this.isDragging = false 143 | } 144 | 145 | changeColor(stopIndex: number, color: string) { 146 | this.stops[stopIndex].color = color 147 | } 148 | 149 | changePosition(stopIndex: number, position: number) { 150 | this.stops[stopIndex].position = position 151 | this.previewEl.querySelectorAll(`div[data-index='${stopIndex}']`).forEach((el) => (el as HTMLElement).style.setProperty('--handler-position', position+'%')) 152 | } 153 | 154 | onColorChange(event: InputEvent, index: number) { 155 | this.changeColor(index, (event.target as HTMLInputElement).value) 156 | this.updateElementBackground() 157 | } 158 | 159 | getPercentage(mouseX: number) { 160 | const rect = this.previewEl.getBoundingClientRect() 161 | const clickPosition = mouseX - rect.x 162 | const elementWidth = getComputedStyle(this.previewEl).width.slice(0, -2) 163 | const newStopPosition = clickPosition/~~elementWidth * 100 164 | 165 | return newStopPosition 166 | } 167 | 168 | listener() { 169 | this.previewEl.addEventListener('click', e => { 170 | if((e.target as HTMLElement).classList.contains('color__handler') || this.isDragging) return 171 | if(!this.colorHandlersEl.contains(e.target as HTMLElement)) return 172 | 173 | const newStopPosition = this.getPercentage(e.clientX) 174 | 175 | this.addColorStop("#333333", newStopPosition) 176 | }) 177 | const directionInput = document.getElementById('direction') as HTMLInputElement 178 | const typeInput = document.getElementById('type') as HTMLInputElement 179 | 180 | directionInput?.addEventListener('input', () => { 181 | this.direction = directionInput.value as GradientDirection 182 | this.updateElementBackground() 183 | }) 184 | typeInput?.addEventListener('input', () => { 185 | this.type = typeInput.value as GradientType 186 | 187 | this.updateElementBackground() 188 | }) 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { GradientPicker } from './gradient' 2 | import './style.css' 3 | 4 | const app = document.getElementById('app')! 5 | const preview = document.getElementById('preview')! 6 | const colorHandlers = document.createElement('div') 7 | colorHandlers.classList.add('color__handlers') 8 | 9 | // TODO: publish UI library 10 | new GradientPicker({ 11 | el: app, 12 | previewEl: preview, 13 | colorHandlersEl: colorHandlers, 14 | }) 15 | 16 | const copyCssButton = document.getElementById('copy-css') 17 | copyCssButton?.addEventListener('click', () => { 18 | let textarea = document.querySelector("#css") as HTMLTextAreaElement; 19 | navigator.clipboard.writeText(textarea.value); 20 | 21 | // Show "Copied!" text 22 | const copiedEl = document.getElementById('copied') 23 | copiedEl?.classList.add('show') 24 | setTimeout(() => copiedEl?.classList.remove('show'), 500); 25 | }) -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | :root { 7 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 8 | font-size: 16px; 9 | line-height: 24px; 10 | font-weight: 400; 11 | 12 | background-color: #242424; 13 | 14 | font-synthesis: none; 15 | text-rendering: optimizeLegibility; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | -webkit-text-size-adjust: 100%; 19 | } 20 | 21 | .center-both { 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | } 26 | 27 | a { 28 | font-weight: 500; 29 | color: #646cff; 30 | text-decoration: inherit; 31 | } 32 | a:hover { 33 | color: #535bf2; 34 | } 35 | 36 | body { 37 | margin: 0; 38 | min-width: 320px; 39 | min-height: 100vh; 40 | font-family: 'Noto Sans Tangsa'; 41 | } 42 | 43 | .container { 44 | width: min(500px, 100%); 45 | } 46 | 47 | h1 { 48 | font-size: clamp(3em, 5vw, 4em); 49 | font-family: 'Kaushan Script', 'arial'; 50 | color: white; 51 | line-height: 1.1; 52 | margin-bottom: 2rem; 53 | text-align: center; 54 | text-shadow: 3px 2px 5px #311e1e; 55 | } 56 | 57 | a { 58 | color: rgb(241, 241, 241); 59 | margin-top: 2rem; 60 | display: block; 61 | filter: drop-shadow(1px 3px 2px rgb(83, 83, 83)); 62 | } 63 | a:hover { 64 | color: white; 65 | } 66 | #app { 67 | height: 100vh; 68 | width: 100%; 69 | margin: 0 auto; 70 | padding: 2rem; 71 | text-align: center; 72 | } 73 | 74 | .card { 75 | background-color: white; 76 | padding: 2rem 1rem 1rem; 77 | border-radius: 1rem; 78 | } 79 | 80 | .color-preview { 81 | height: 3rem; 82 | border: 1px solid rgb(188, 188, 188); 83 | border-radius: 50rem; 84 | box-shadow: 1px 1px 3px rgb(140, 138, 138); 85 | cursor: crosshair; 86 | position: relative; 87 | } 88 | .color__handlers { 89 | height: 100%; 90 | border-radius: 50rem; 91 | overflow: hidden; 92 | position: relative; 93 | z-index: 3; 94 | } 95 | .color__handler { 96 | height: 100%; 97 | position: absolute; 98 | left: var(--handler-position); 99 | width: 5px; 100 | transform: translateX(-2.5px); 101 | background-color: rgba(31, 30, 30, 0.623); 102 | } 103 | 104 | .color__handler:hover { 105 | cursor: col-resize; 106 | } 107 | 108 | .color__handler-remover { 109 | width: 1.2rem; 110 | border: 1px solid #555; 111 | height: 1.2rem; 112 | cursor: pointer; 113 | background-color: white; 114 | box-shadow: 1px 1px 2px #ccc;; 115 | border-radius: 50%; 116 | position: absolute; 117 | top: -1.5rem; 118 | left: var(--handler-position); 119 | transform: translateX(-50%) 120 | } 121 | .color__handler-remover:after { 122 | content: 'x'; 123 | color: #555; 124 | position: absolute; 125 | left: 4px; 126 | top: -5px; 127 | } 128 | .color__handler-remover:before { 129 | content: ''; 130 | top: 100%; 131 | /* background-color: rgb(72, 72, 72); */ 132 | position: absolute; 133 | width: 1px; 134 | height: 20px; 135 | z-index: 1; 136 | } 137 | .color__handler-remover:hover { 138 | border-color: rgb(229, 64, 64); 139 | } 140 | .color__handler-remover:hover:after { 141 | color: rgb(229, 64, 64); 142 | } 143 | .color__input { 144 | border: none; 145 | border-radius: 50%; 146 | transform: translate(-2px,-2px); 147 | } 148 | .color__input-wrapper { 149 | width: 1.3rem; 150 | height: 1.3rem; 151 | border: 1px solid white; 152 | border-radius: 50%; 153 | overflow: hidden; 154 | border: .1rem solid white; 155 | outline: 1px solid #bbb; 156 | position: absolute; 157 | left: var(--handler-position); 158 | cursor: pointer; 159 | top: 110%; 160 | transform: translateX(-50%); 161 | } 162 | .options { 163 | display: flex; 164 | gap: 1rem; 165 | } 166 | select, textarea { 167 | padding: .5rem; 168 | width: 100% 169 | } 170 | select { 171 | background-color: white; 172 | border: 1px solid #928b8b; 173 | border-radius: .5rem; 174 | margin-top: 2rem; 175 | } 176 | .css-box__header { 177 | border: 1px solid #928b8b; 178 | display: flex; 179 | justify-content: space-between; 180 | padding: .5rem; 181 | margin-top: 1rem;; 182 | border-top-left-radius: .5rem; 183 | border-top-right-radius: .5rem; 184 | } 185 | .css-box__header h6 { 186 | margin: 0; 187 | } 188 | textarea { 189 | border: none; 190 | border-bottom-left-radius: .5rem; 191 | border: 1px solid #928b8b; 192 | border-top: none; 193 | border-bottom-right-radius: .5rem; 194 | } 195 | #copied { 196 | display: none; 197 | color: green; 198 | margin-right: .5rem; 199 | } 200 | .show { 201 | display: inline-block !important; 202 | } 203 | #copy-css { 204 | color: white; 205 | background-color: #535bf2; 206 | padding: .3rem .5rem; 207 | border-radius: .4rem; 208 | cursor: pointer; 209 | border: none; 210 | } 211 | #copy-css:hover { 212 | background-color: #6169ff; 213 | } -------------------------------------------------------------------------------- /src/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | 2 | export function createElement(tagName: K, attrs?: Record, styles?: Record): HTMLElementTagNameMap[K] { 3 | const el = document.createElement(tagName) 4 | 5 | for(const attr in attrs) { 6 | el.setAttribute(attr, attrs[attr]) 7 | } 8 | 9 | for(const style in styles) { 10 | el.style.setProperty(style, styles[style]) 11 | } 12 | 13 | return el 14 | } -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | 3 | export default defineConfig({ 4 | base: '/gradient-picker/', 5 | }) --------------------------------------------------------------------------------