├── .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 | 
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 |
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 | })
--------------------------------------------------------------------------------