cbvirtua 1.0.47 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Signature.vue +127 -0
- package/canvas-example-main/canvas-example-main/.github/workflows/main.yml +62 -0
- package/canvas-example-main/canvas-example-main/README.md +13 -0
- package/canvas-example-main/canvas-example-main/curved.html +52 -0
- package/canvas-example-main/canvas-example-main/eslint.config.js +30 -0
- package/canvas-example-main/canvas-example-main/index.html +13 -0
- package/canvas-example-main/canvas-example-main/package.json +51 -0
- package/canvas-example-main/canvas-example-main/pnpm-lock.yaml +4760 -0
- package/canvas-example-main/canvas-example-main/postcss.config.js +6 -0
- package/canvas-example-main/canvas-example-main/public/vite.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/App.tsx +17 -0
- package/canvas-example-main/canvas-example-main/src/assets/github.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/assets/react.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/demo.css +539 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/demo_index.html +418 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.css +55 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.js +1 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.json +79 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.ttf +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.woff +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.woff2 +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/index.tsx +39 -0
- package/canvas-example-main/canvas-example-main/src/main.css +9 -0
- package/canvas-example-main/canvas-example-main/src/main.tsx +10 -0
- package/canvas-example-main/canvas-example-main/src/pages/2048/g2048.ts +14 -0
- package/canvas-example-main/canvas-example-main/src/pages/2048/index.tsx +21 -0
- package/canvas-example-main/canvas-example-main/src/pages/clock/index.tsx +103 -0
- package/canvas-example-main/canvas-example-main/src/pages/demo/index.tsx +21 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/editor/index.module.less +3 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/editor/index.tsx +99 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/header/index.module.less +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/header/index.tsx +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/material/index.module.less +59 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/material/index.tsx +85 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/setting/index.module.less +7 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/setting/index.tsx +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/application.ts +35 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/base.ts +17 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/factory.ts +14 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/shape.tsx +43 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/editor.ts +61 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/type.ts +6 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/index.module.less +7 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/index.tsx +32 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/component-config.ts +61 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/components.ts +43 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/layout.ts +40 -0
- package/canvas-example-main/canvas-example-main/src/pages/home/index.tsx +59 -0
- package/canvas-example-main/canvas-example-main/src/pages/jigsaw/index.tsx +3 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/bomber.png +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/index.tsx +138 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/mark.png +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/minesweeper.ts +345 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/utils.ts +24 -0
- package/canvas-example-main/canvas-example-main/src/pages/pageflip/index.tsx +200 -0
- package/canvas-example-main/canvas-example-main/src/pages/pageflip/page1.jpg +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/draw/index.ts +367 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/index.module.less +26 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/index.tsx +54 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/control.ts +174 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/editor.ts +91 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/index.raw.tsx +159 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/index.tsx +36 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/shape.ts +248 -0
- package/canvas-example-main/canvas-example-main/src/router.tsx +53 -0
- package/canvas-example-main/canvas-example-main/src/utils/storage.ts +48 -0
- package/canvas-example-main/canvas-example-main/src/vite-env.d.ts +1 -0
- package/canvas-example-main/canvas-example-main/tailwind.config.js +8 -0
- package/canvas-example-main/canvas-example-main/tsconfig.app.json +30 -0
- package/canvas-example-main/canvas-example-main/tsconfig.json +7 -0
- package/canvas-example-main/canvas-example-main/tsconfig.node.json +22 -0
- package/canvas-example-main/canvas-example-main/vite.config.ts +18 -0
- package/package.json +1 -1
package/Signature.vue
CHANGED
|
@@ -364,3 +364,130 @@ onMounted(() => {
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
</style>
|
|
367
|
+
<template>
|
|
368
|
+
<div class="progress-bar">
|
|
369
|
+
<div class="bg"></div>
|
|
370
|
+
<div class="bar" :style="{ width: progress + '%' }"></div>
|
|
371
|
+
<div class="label">{{ progress }}%</div>
|
|
372
|
+
</div>
|
|
373
|
+
</template>
|
|
374
|
+
|
|
375
|
+
<script>
|
|
376
|
+
export default {
|
|
377
|
+
data() {
|
|
378
|
+
return {
|
|
379
|
+
progress: 0,
|
|
380
|
+
isPlaying: false,
|
|
381
|
+
isCompleted: false
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
mounted() {
|
|
385
|
+
this.start();
|
|
386
|
+
},
|
|
387
|
+
methods: {
|
|
388
|
+
start() {
|
|
389
|
+
this.isPlaying = true;
|
|
390
|
+
this.animateProgress(90)
|
|
391
|
+
.then(() => {
|
|
392
|
+
if (!this.isCompleted) {
|
|
393
|
+
this.animateProgress(100);
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
.catch((error) => {
|
|
397
|
+
console.error('Progress error', error);
|
|
398
|
+
});
|
|
399
|
+
},
|
|
400
|
+
animateProgress(target) {
|
|
401
|
+
return new Promise((resolve, reject) => {
|
|
402
|
+
let start = this.progress;
|
|
403
|
+
const end = target;
|
|
404
|
+
const duration = (target - start) * 150;
|
|
405
|
+
|
|
406
|
+
const doAnimation = () => {
|
|
407
|
+
const elapsed = Date.now() - startTime;
|
|
408
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
409
|
+
|
|
410
|
+
this.progress = start + ((end - start) * progress);
|
|
411
|
+
|
|
412
|
+
if (progress === 1) {
|
|
413
|
+
resolve();
|
|
414
|
+
} else if (this.isCompleted) {
|
|
415
|
+
resolve();
|
|
416
|
+
} else {
|
|
417
|
+
requestAnimationFrame(doAnimation);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const startTime = Date.now();
|
|
422
|
+
requestAnimationFrame(doAnimation);
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
finish() {
|
|
426
|
+
this.isCompleted = true;
|
|
427
|
+
this.progress = 100;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
</script>
|
|
432
|
+
|
|
433
|
+
<div class="progress" :style="{width, height}">
|
|
434
|
+
<svg viewBox="0 0 96 96" class="svg-circle-progress" style="width: 96px; height: 96px;">
|
|
435
|
+
<circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10" class="svg-progress"
|
|
436
|
+
style="stroke-dasharray: 275, 279.602;stroke:#eee;">
|
|
437
|
+
</circle>
|
|
438
|
+
<circle r="40" cx="48" cy="48" fill="none" stroke-miterlimit="20" stroke-width="10"
|
|
439
|
+
class="svg-progress"
|
|
440
|
+
:style="`stroke-dasharray: ${progressValue}, 279.602;stroke:${color};`">
|
|
441
|
+
</circle>
|
|
442
|
+
</svg>
|
|
443
|
+
<div class="mask">
|
|
444
|
+
{{ progress}}%
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
<script setup>
|
|
448
|
+
import { ref, toRefs, watch } from 'vue'
|
|
449
|
+
|
|
450
|
+
const props = defineProps({
|
|
451
|
+
progress: {
|
|
452
|
+
type: Number,
|
|
453
|
+
default: () => 20
|
|
454
|
+
},
|
|
455
|
+
color: {
|
|
456
|
+
type: String,
|
|
457
|
+
default: () => "#FFAFAF"
|
|
458
|
+
},
|
|
459
|
+
width: {
|
|
460
|
+
type: String,
|
|
461
|
+
default: () => "210px"
|
|
462
|
+
},
|
|
463
|
+
height: {
|
|
464
|
+
type: String,
|
|
465
|
+
default: () => "100px"
|
|
466
|
+
},
|
|
467
|
+
})
|
|
468
|
+
const { height, width, color, progress } = toRefs(props)
|
|
469
|
+
const progressValue = ref((progress.value / 100) * 250)
|
|
470
|
+
|
|
471
|
+
watch(progress, (newValue) => {
|
|
472
|
+
progressValue.value = (newValue / 100) * 250
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
</script>
|
|
476
|
+
<style lang="css" scoped>
|
|
477
|
+
.progress {
|
|
478
|
+
display: inline-block;
|
|
479
|
+
position: relative;
|
|
480
|
+
height: 100px;
|
|
481
|
+
text-align: center;
|
|
482
|
+
}
|
|
483
|
+
.svg-circle-progress {
|
|
484
|
+
position: relative;
|
|
485
|
+
transform: rotate(-90deg);
|
|
486
|
+
}
|
|
487
|
+
.svg-progress {
|
|
488
|
+
stroke: #2196f3;
|
|
489
|
+
stroke-linecap: round;
|
|
490
|
+
transition: all .3s linear;
|
|
491
|
+
}
|
|
492
|
+
</style>
|
|
493
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# This is a basic workflow to help you get started with Actions
|
|
2
|
+
|
|
3
|
+
name: CI
|
|
4
|
+
|
|
5
|
+
# Controls when the action will run.
|
|
6
|
+
on:
|
|
7
|
+
# Triggers the workflow on push or pull request events but only for the master branch
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
paths:
|
|
11
|
+
- 'src/**'
|
|
12
|
+
- '.github/workflows/main.yml'
|
|
13
|
+
|
|
14
|
+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
15
|
+
jobs:
|
|
16
|
+
# This workflow contains a single job called "build"
|
|
17
|
+
build:
|
|
18
|
+
# The type of runner that the job will run on
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
# Steps represent a sequence of tasks that will be executed as part of the job
|
|
22
|
+
steps:
|
|
23
|
+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
24
|
+
- uses: actions/checkout@v2
|
|
25
|
+
|
|
26
|
+
- name: Use Node.js 18.20.4
|
|
27
|
+
uses: actions/setup-node@v1
|
|
28
|
+
with:
|
|
29
|
+
node-version: 18.20.4
|
|
30
|
+
|
|
31
|
+
- name: Install pnpm
|
|
32
|
+
run: npm i pnpm@9 -g
|
|
33
|
+
|
|
34
|
+
- name: Install Packages
|
|
35
|
+
run: pnpm install
|
|
36
|
+
|
|
37
|
+
- name: Build
|
|
38
|
+
run: pnpm build
|
|
39
|
+
|
|
40
|
+
# 推到服务器
|
|
41
|
+
- name: rsync deployments
|
|
42
|
+
uses: burnett01/rsync-deployments@5.2.1
|
|
43
|
+
with:
|
|
44
|
+
switches: -avzr --delete
|
|
45
|
+
path: dist/
|
|
46
|
+
remote_path: /root/project/canvas/
|
|
47
|
+
remote_host: ${{ secrets.SSH_HOST }}
|
|
48
|
+
remote_port: ${{ secrets.SSH_PORT }}
|
|
49
|
+
remote_user: ${{ secrets.SSH_USER }}
|
|
50
|
+
remote_key: ${{ secrets.DEPLOY_KEY }}
|
|
51
|
+
|
|
52
|
+
# nginx 重启
|
|
53
|
+
- name: Restart server # 第三步,重启服务
|
|
54
|
+
uses: appleboy/ssh-action@master
|
|
55
|
+
with:
|
|
56
|
+
host: ${{ secrets.SSH_HOST }} # 下面三个配置与上一步类似
|
|
57
|
+
username: ${{ secrets.SSH_USER }}
|
|
58
|
+
port: ${{ secrets.SSH_PORT }} # SSH端口
|
|
59
|
+
key: ${{ secrets.DEPLOY_KEY }}
|
|
60
|
+
# 重启的脚本,根据自身情况做相应改动,一般要做的是migrate数据库以及重启服务器
|
|
61
|
+
script: |
|
|
62
|
+
nginx -s reload
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# canvas-example
|
|
2
|
+
|
|
3
|
+
canvas 学习项目
|
|
4
|
+
|
|
5
|
+
## 应用
|
|
6
|
+
|
|
7
|
+
[扫雷小游戏-在线体验](https://canvas.xjq.icu/minesweeper)
|
|
8
|
+
|
|
9
|
+
[扫雷小游戏-源码位置](https://github.com/xjq7/canvas-example/tree/main/src/pages/minesweeper)
|
|
10
|
+
|
|
11
|
+
[原生 Canvas 练习项目](https://canvas.xjq.icu/practice)
|
|
12
|
+
|
|
13
|
+
[原生 Canvas 练习项目-源码位置](https://github.com/xjq7/canvas-example/tree/main/src/pages/practice)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Document</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<canvas
|
|
10
|
+
id="canvas"
|
|
11
|
+
width="500"
|
|
12
|
+
height="500"
|
|
13
|
+
style="border: 1px solid #000000"
|
|
14
|
+
>
|
|
15
|
+
</canvas>
|
|
16
|
+
<script>
|
|
17
|
+
const canvas = document.querySelector('#canvas');
|
|
18
|
+
const ctx = canvas.getContext('2d');
|
|
19
|
+
|
|
20
|
+
// 脸
|
|
21
|
+
ctx.beginPath();
|
|
22
|
+
ctx.arc(200, 200, 50, 0, Math.PI * 2);
|
|
23
|
+
ctx.stroke();
|
|
24
|
+
|
|
25
|
+
// 左眼
|
|
26
|
+
ctx.beginPath();
|
|
27
|
+
ctx.arc(185, 185, 5, Math.PI, Math.PI * 2);
|
|
28
|
+
ctx.stroke();
|
|
29
|
+
|
|
30
|
+
// 右眼
|
|
31
|
+
ctx.beginPath();
|
|
32
|
+
ctx.arc(216, 185, 5, Math.PI, Math.PI * 2);
|
|
33
|
+
ctx.stroke();
|
|
34
|
+
|
|
35
|
+
// 嘴
|
|
36
|
+
ctx.beginPath();
|
|
37
|
+
ctx.arc(200, 215, 10, Math.PI / 8, (Math.PI * 7) / 8);
|
|
38
|
+
ctx.stroke();
|
|
39
|
+
|
|
40
|
+
// 头发
|
|
41
|
+
ctx.beginPath();
|
|
42
|
+
ctx.moveTo(75, 40);
|
|
43
|
+
ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
|
|
44
|
+
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
|
|
45
|
+
ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
|
|
46
|
+
ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
|
|
47
|
+
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
|
|
48
|
+
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
|
|
49
|
+
ctx.fill();
|
|
50
|
+
</script>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ['dist'] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 2020,
|
|
14
|
+
globals: globals.browser,
|
|
15
|
+
},
|
|
16
|
+
plugins: {
|
|
17
|
+
'react-hooks': reactHooks,
|
|
18
|
+
'react-refresh': reactRefresh,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
...reactHooks.configs.recommended.rules,
|
|
22
|
+
'react-refresh/only-export-components': [
|
|
23
|
+
'warn',
|
|
24
|
+
{ allowConstantExport: true },
|
|
25
|
+
],
|
|
26
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
27
|
+
'@typescript-eslint/no-empty-object-type': 'warn',
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>xjq7 canvas example</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cc",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc -b && vite build",
|
|
9
|
+
"lint": "eslint .",
|
|
10
|
+
"preview": "vite preview"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@leafer-in/animate": "^1.0.9",
|
|
14
|
+
"@leafer-in/editor": "^1.0.9",
|
|
15
|
+
"@leafer-in/state": "^1.0.9",
|
|
16
|
+
"@leafer-in/view": "^1.0.9",
|
|
17
|
+
"allotment": "^1.20.2",
|
|
18
|
+
"antd": "^5.20.1",
|
|
19
|
+
"classnames": "^2.5.1",
|
|
20
|
+
"leafer-ui": "^1.0.4",
|
|
21
|
+
"leafer-x-ruler": "^1.0.13",
|
|
22
|
+
"lodash": "^4.17.21",
|
|
23
|
+
"pixi.js": "^8.5.1",
|
|
24
|
+
"react": "^18.3.1",
|
|
25
|
+
"react-dom": "^18.3.1",
|
|
26
|
+
"react-router-dom": "^6.26.1",
|
|
27
|
+
"react-use": "^17.5.1",
|
|
28
|
+
"zustand": "^5.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
32
|
+
"@babel/plugin-proposal-decorators": "^7.25.9",
|
|
33
|
+
"@eslint/js": "^9.9.0",
|
|
34
|
+
"@types/lodash": "^4.17.10",
|
|
35
|
+
"@types/node": "^22.7.7",
|
|
36
|
+
"@types/react": "^18.3.3",
|
|
37
|
+
"@types/react-dom": "^18.3.0",
|
|
38
|
+
"@vitejs/plugin-react-swc": "^3.5.0",
|
|
39
|
+
"autoprefixer": "^10.4.20",
|
|
40
|
+
"eslint": "^9.9.0",
|
|
41
|
+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
|
42
|
+
"eslint-plugin-react-refresh": "^0.4.9",
|
|
43
|
+
"globals": "^15.9.0",
|
|
44
|
+
"less": "^4.2.0",
|
|
45
|
+
"postcss": "^8.4.47",
|
|
46
|
+
"tailwindcss": "^3.4.13",
|
|
47
|
+
"typescript": "^5.5.3",
|
|
48
|
+
"typescript-eslint": "^8.0.1",
|
|
49
|
+
"vite": "^5.4.1"
|
|
50
|
+
}
|
|
51
|
+
}
|