diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..2206350 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run build:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/.gitignore b/.gitignore index a547bf3..4d94e69 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ dist-ssr *.njsproj *.sln *.sw? + +protocol/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 24b57bf..b48b18d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,13 @@ "name": "web", "version": "0.0.0", "dependencies": { + "@tailwindcss/vite": "^4.1.17", + "konva": "^10.0.12", "pyodide": "^0.27.4", "react": "^19.2.0", - "react-dom": "^19.2.0" + "react-dom": "^19.2.0", + "react-konva": "^19.2.1", + "tailwindcss": "^4.1.17" }, "devDependencies": { "@eslint/js": "^9.39.1", @@ -298,7 +302,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "aix" @@ -314,7 +317,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -330,7 +332,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -346,7 +347,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "android" @@ -362,7 +362,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -378,7 +377,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -394,7 +392,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -410,7 +407,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -426,7 +422,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -442,7 +437,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -458,7 +452,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "linux" @@ -474,7 +467,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -490,7 +482,6 @@ "cpu": [ "mips64el" ], - "dev": true, "optional": true, "os": [ "linux" @@ -506,7 +497,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -522,7 +512,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -538,7 +527,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -554,7 +542,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -570,7 +557,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -586,7 +572,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -602,7 +587,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -618,7 +602,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -634,7 +617,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openharmony" @@ -650,7 +632,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "sunos" @@ -666,7 +647,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -682,7 +662,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -698,7 +677,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -905,7 +883,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -915,7 +892,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -925,7 +901,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -933,14 +908,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -959,7 +932,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -972,7 +944,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -985,7 +956,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -998,7 +968,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1011,7 +980,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -1024,7 +992,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -1037,7 +1004,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1050,7 +1016,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1063,7 +1028,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1076,7 +1040,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1089,7 +1052,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1102,7 +1064,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1115,7 +1076,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1128,7 +1088,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1141,7 +1100,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1154,7 +1112,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1167,7 +1124,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1180,7 +1136,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openharmony" @@ -1193,7 +1148,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1206,7 +1160,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1219,7 +1172,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1232,12 +1184,268 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" ] }, + "node_modules/@tailwindcss/node": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", + "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.17" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", + "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-x64": "4.1.17", + "@tailwindcss/oxide-freebsd-x64": "4.1.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-x64-musl": "4.1.17", + "@tailwindcss/oxide-wasm32-wasi": "4.1.17", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", + "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", + "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", + "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", + "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", + "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", + "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", + "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", + "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", + "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", + "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.6.0", + "@emnapi/runtime": "^1.6.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.7", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", + "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", + "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.17.tgz", + "integrity": "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.17", + "@tailwindcss/oxide": "4.1.17", + "tailwindcss": "4.1.17" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1282,8 +1490,7 @@ "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -1295,7 +1502,7 @@ "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", - "dev": true, + "devOptional": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1304,7 +1511,6 @@ "version": "19.2.7", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", - "dev": true, "dependencies": { "csstype": "^3.2.2" } @@ -1318,6 +1524,15 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/react-reconciler": { + "version": "0.32.3", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.32.3.tgz", + "integrity": "sha512-cMi5ZrLG7UtbL7LTK6hq9w/EZIRk4Mf1Z5qHoI+qBh7/WkYkFXQ7gOto2yfUvPzF5ERMAhaXS5eTQ2SAnHjLzA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.48.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", @@ -1887,8 +2102,7 @@ "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, "node_modules/debug": { "version": "4.4.3", @@ -1913,17 +2127,38 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.262", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", "dev": true }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -2177,7 +2412,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "engines": { "node": ">=12.0.0" }, @@ -2253,7 +2487,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -2296,6 +2529,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -2408,6 +2647,36 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/its-fine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz", + "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==", + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.28.9" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2477,6 +2746,26 @@ "json-buffer": "3.0.1" } }, + "node_modules/konva": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/konva/-/konva-10.0.12.tgz", + "integrity": "sha512-DHmkeG5FbW6tLCkbMQTi1ihWycfzljrn0V7umUUuewxx7aoINcI71ksgBX9fTPNXhlsK4/JoMgKwI/iCde+BRw==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2490,6 +2779,255 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2520,6 +3058,15 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2542,7 +3089,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -2669,14 +3215,12 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "engines": { "node": ">=12" }, @@ -2688,7 +3232,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2760,6 +3303,52 @@ "react": "^19.2.0" } }, + "node_modules/react-konva": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-19.2.1.tgz", + "integrity": "sha512-sqZWCzQGpdMrU5aeunR0oxUY8UeCPbU8gnAYxMtAn6BT4coeSpiATKOctsoxRu6F56TAcF+s0c6Lul9ansNqQA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.32.3", + "its-fine": "^2.0.0", + "react-reconciler": "0.33.0", + "scheduler": "0.27.0" + }, + "peerDependencies": { + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0 || ^10.0.0", + "react": "^19.2.0", + "react-dom": "^19.2.0" + } + }, + "node_modules/react-reconciler": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.33.0.tgz", + "integrity": "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, "node_modules/react-refresh": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", @@ -2806,7 +3395,6 @@ "version": "4.53.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", - "dev": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2882,7 +3470,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2911,11 +3498,29 @@ "node": ">=8" } }, + "node_modules/tailwindcss": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" @@ -3003,7 +3608,7 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true + "devOptional": true }, "node_modules/update-browserslist-db": { "version": "1.1.4", @@ -3048,7 +3653,6 @@ "version": "7.2.4", "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", - "dev": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", diff --git a/package.json b/package.json index aedf1ce..4458565 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,13 @@ "preview": "vite preview" }, "dependencies": { + "@tailwindcss/vite": "^4.1.17", + "konva": "^10.0.12", + "pyodide": "^0.27.4", "react": "^19.2.0", "react-dom": "^19.2.0", - "pyodide": "^0.27.4" + "react-konva": "^19.2.1", + "tailwindcss": "^4.1.17" }, "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/src/App.css b/src/App.css index 4fb4c6c..5eaacb4 100644 --- a/src/App.css +++ b/src/App.css @@ -1,763 +1,6 @@ -:root { - --primary-color: #0066cc; - --secondary-color: #6c757d; - --danger-color: #dc3545; - --success-color: #28a745; - --warning-color: #ffc107; - --info-color: #17a2b8; - --background: #f5f5f5; - --panel-background: #ffffff; - --border-color: #dee2e6; - --text-color: #212529; - --text-muted: #6c757d; -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: var(--background); - color: var(--text-color); -} - -.app { - min-height: 100vh; - display: flex; - flex-direction: column; -} - -.app-header { - background-color: var(--panel-background); - padding: 1.5rem 2rem; - border-bottom: 1px solid var(--border-color); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.app-header h1 { - font-size: 1.75rem; - font-weight: 600; - margin-bottom: 0.5rem; -} - -.error-message { - background-color: #f8d7da; - color: #721c24; - padding: 0.75rem 1rem; - border-radius: 4px; - margin-top: 1rem; - border: 1px solid #f5c6cb; -} - -.app-content { - flex: 1; - display: grid; - grid-template-columns: 400px 1fr; - gap: 1.5rem; - padding: 1.5rem; - max-width: 1600px; - width: 100%; - margin: 0 auto; -} - -.left-panel { - display: flex; - flex-direction: column; - gap: 1.5rem; -} - -.right-panel { - display: flex; - flex-direction: column; -} - -.connection-panel, -.file-upload-panel, -.progress-panel, -.canvas-panel { - background-color: var(--panel-background); - padding: 1.5rem; - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -h2 { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 1rem; - padding-bottom: 0.5rem; - border-bottom: 2px solid var(--border-color); -} - -h3 { - font-size: 1rem; - font-weight: 600; - margin: 1rem 0 0.5rem 0; -} - -.detail-row { - display: flex; - justify-content: space-between; - padding: 0.5rem 0; - border-bottom: 1px solid var(--border-color); -} - -.detail-row:last-child { - border-bottom: none; -} - -.detail-row .label { - font-weight: 500; - color: var(--text-muted); -} - -.detail-row .value { - font-weight: 600; -} - -.status-bar { - display: flex; - align-items: center; - gap: 1rem; - margin-bottom: 1rem; - padding: 0.75rem; - background-color: var(--background); - border-radius: 4px; -} - -.status-indicator { - padding: 0.5rem 1rem; - border-radius: 4px; - font-weight: 600; - font-size: 0.875rem; - text-transform: uppercase; -} - -.status-indicator.status-16 { /* IDLE */ - background-color: #d1ecf1; - color: #0c5460; -} - -.status-indicator.status-17 { /* SEWING_WAIT */ - background-color: #d4edda; - color: #155724; -} - -.status-indicator.status-48 { /* SEWING */ - background-color: #fff3cd; - color: #856404; -} - -.status-indicator.status-49 { /* SEWING_COMPLETE */ - background-color: #d4edda; - color: #155724; -} - -.status-indicator.status-64 { /* COLOR_CHANGE_WAIT */ - background-color: #fff3cd; - color: #856404; -} - -.error-indicator { - background-color: #f8d7da; - color: #721c24; - padding: 0.5rem 1rem; - border-radius: 4px; - font-weight: 600; - font-size: 0.875rem; -} - -.polling-indicator { - color: var(--primary-color); - font-size: 0.75rem; - animation: pulse 1s ease-in-out infinite; -} - -@keyframes pulse { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.3; - } -} - -.connection-actions, -.progress-actions { - display: flex; - gap: 0.75rem; - margin-top: 1rem; - flex-wrap: wrap; -} - -button { - padding: 0.75rem 1.5rem; - border: none; - border-radius: 4px; - font-size: 0.875rem; - font-weight: 600; - cursor: pointer; - transition: all 0.2s; -} - -button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.btn-primary { - background-color: var(--primary-color); - color: white; -} - -.btn-primary:hover:not(:disabled) { - background-color: #0052a3; -} - -.btn-secondary { - background-color: var(--secondary-color); - color: white; -} - -.btn-secondary:hover:not(:disabled) { - background-color: #5a6268; -} - -.btn-danger { - background-color: var(--danger-color); - color: white; -} - -.btn-danger:hover:not(:disabled) { - background-color: #c82333; -} - -.file-input { - display: none; -} - -.progress-bar { - height: 8px; - background-color: var(--border-color); - border-radius: 4px; - overflow: hidden; - margin: 1rem 0; -} - -.progress-fill { - height: 100%; - background-color: var(--primary-color); - transition: width 0.3s; -} - -/* Canvas container with Konva */ -.canvas-container { - position: relative; - width: 100%; - height: 600px; - border: 1px solid var(--border-color); - border-radius: 4px; - background-color: #fafafa; - overflow: hidden; -} - -.canvas-placeholder { - display: flex; - align-items: center; - justify-content: center; - height: 600px; - color: var(--text-muted); - font-style: italic; -} - -/* Canvas overlay elements */ -.canvas-legend { - position: absolute; - top: 10px; - left: 10px; - background: rgba(255, 255, 255, 0.95); - padding: 12px; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - z-index: 10; - backdrop-filter: blur(4px); - max-width: 150px; -} - -.canvas-legend h4 { - margin: 0 0 8px 0; - font-size: 13px; - font-weight: 600; - color: var(--text-color); - border-bottom: 1px solid var(--border-color); - padding-bottom: 6px; -} - -.legend-item { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 6px; -} - -.legend-item:last-child { - margin-bottom: 0; -} - -.legend-swatch { - width: 20px; - height: 20px; - border-radius: 3px; - border: 1px solid #000; - flex-shrink: 0; -} - -.legend-label { - font-size: 12px; - color: var(--text-color); -} - -.canvas-dimensions { - position: absolute; - bottom: 165px; - right: 20px; - background: rgba(255, 255, 255, 0.95); - padding: 8px 16px; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - z-index: 11; - backdrop-filter: blur(4px); - font-size: 14px; - font-weight: 600; - color: var(--text-color); -} - -.canvas-offset-info { - position: absolute; - bottom: 80px; - right: 20px; - background: rgba(255, 255, 255, 0.95); - padding: 10px 14px; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - z-index: 11; - backdrop-filter: blur(4px); - min-width: 180px; -} - -.offset-label { - font-size: 11px; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 4px; -} - -.offset-value { - font-size: 13px; - font-weight: 600; - color: var(--primary-color); - margin-bottom: 4px; -} - -.offset-hint { - font-size: 10px; - color: var(--text-muted); - font-style: italic; -} - -/* Zoom controls */ -.zoom-controls { - position: absolute; - bottom: 20px; - right: 20px; - display: flex; - gap: 8px; - align-items: center; - background: rgba(255, 255, 255, 0.95); - padding: 8px 12px; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - z-index: 10; - backdrop-filter: blur(4px); -} - -.zoom-btn { - width: 32px; - height: 32px; - padding: 0; - font-size: 18px; - font-weight: bold; - border: 1px solid var(--border-color); - background: white; - cursor: pointer; - border-radius: 4px; - transition: all 0.2s; - display: flex; - align-items: center; - justify-content: center; -} - -.zoom-btn:hover:not(:disabled) { - background: var(--primary-color); - color: white; - border-color: var(--primary-color); - transform: translateY(-1px); - box-shadow: 0 2px 6px rgba(0, 102, 204, 0.3); -} - -.zoom-btn:active:not(:disabled) { - transform: translateY(0); -} - -.zoom-level { - min-width: 50px; - text-align: center; - font-size: 13px; - font-weight: 600; - color: var(--text-color); - user-select: none; -} - -.zoom-reset { - margin-left: 4px; - font-size: 20px; -} - -.status-message { - padding: 1rem; - border-radius: 4px; - margin: 1rem 0; - font-weight: 500; -} - -.status-message.success { - background-color: #d4edda; - color: #155724; - border: 1px solid #c3e6cb; -} - -.status-message.warning { - background-color: #fff3cd; - color: #856404; - border: 1px solid #ffeeba; -} - -.status-message.info { - background-color: #d1ecf1; - color: #0c5460; - border: 1px solid #bee5eb; -} - -/* Color Block Progress Styles */ -.color-blocks { - margin-top: 1.5rem; - padding-top: 1rem; - border-top: 1px solid var(--border-color); -} - -.color-block-list { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.color-block-item { - padding: 0.75rem; - border-radius: 4px; - background-color: var(--background); - border: 2px solid transparent; - transition: all 0.3s; -} - -.color-block-item.completed { - border-color: var(--success-color); - background-color: #f0f9f4; -} - -.color-block-item.current { - border-color: var(--primary-color); - background-color: #e7f3ff; - box-shadow: 0 2px 8px rgba(0, 102, 204, 0.2); -} - -.color-block-item.pending { - opacity: 0.6; -} - -.block-header { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.color-swatch { - width: 24px; - height: 24px; - border-radius: 4px; - border: 2px solid var(--border-color); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} - -.block-label { - font-weight: 600; - flex: 1; -} - -.block-status { - font-size: 1.25rem; - font-weight: bold; - color: var(--text-muted); -} - -.color-block-item.completed .block-status { - color: var(--success-color); -} - -.color-block-item.current .block-status { - color: var(--primary-color); -} - -.block-stitches { - font-size: 0.875rem; - color: var(--text-muted); -} - -.block-progress-bar { - margin-top: 0.5rem; - height: 4px; - background-color: #fff; - border-radius: 2px; - overflow: hidden; -} - -.block-progress-fill { - height: 100%; - background-color: var(--primary-color); - transition: width 0.3s; -} - -@media (max-width: 1024px) { - .app-content { - grid-template-columns: 1fr; - } -} - -/* ========================================================================== - State-Based UX Safety Styles - ========================================================================== */ - -/* Confirmation Dialog Styles */ -.confirm-dialog-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; -} - -.confirm-dialog { - background-color: var(--panel-background); - border-radius: 8px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); - max-width: 500px; - width: 90%; - margin: 1rem; -} - -.confirm-dialog-danger { - border-top: 4px solid #dc3545; -} - -.confirm-dialog-warning { - border-top: 4px solid #ffc107; -} - -.confirm-dialog-header { - padding: 1.5rem; - border-bottom: 1px solid var(--border-color); -} - -.confirm-dialog-header h3 { - margin: 0; - font-size: 1.25rem; - font-weight: 600; -} - -.confirm-dialog-body { - padding: 1.5rem; -} - -.confirm-dialog-body p { - margin: 0; - line-height: 1.5; - color: var(--text-color); -} - -.confirm-dialog-actions { - padding: 1rem 1.5rem; - display: flex; - gap: 0.75rem; - justify-content: flex-end; - border-top: 1px solid var(--border-color); -} - -/* Enhanced Status Badge */ -.status-badge { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.5rem 1rem; - border-radius: 4px; - font-weight: 600; - font-size: 0.875rem; -} - -.status-badge-idle, -.status-badge-info { - background-color: #d1ecf1; - color: #0c5460; - border: 1px solid #bee5eb; -} - -.status-badge-active, -.status-badge-waiting, -.status-badge-warning { - background-color: #fff3cd; - color: #856404; - border: 1px solid #ffeeba; -} - -.status-badge-complete, -.status-badge-success { - background-color: #d4edda; - color: #155724; - border: 1px solid #c3e6cb; -} - -.status-badge-interrupted, -.status-badge-error, -.status-badge-danger { - background-color: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; -} - -.status-icon { - font-size: 1.1rem; - line-height: 1; -} - -.status-text { - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* State Indicator Component */ -.state-indicator { - display: flex; - align-items: center; - gap: 1rem; - padding: 1rem; - border-radius: 8px; - margin: 1rem 0; - border-left: 4px solid transparent; -} - -.state-indicator-idle, -.state-indicator-info { - background-color: #e7f3ff; - border-left-color: #0066cc; -} - -.state-indicator-active, -.state-indicator-waiting, -.state-indicator-warning { - background-color: #fff8e1; - border-left-color: #ffc107; -} - -.state-indicator-complete, -.state-indicator-success { - background-color: #e8f5e9; - border-left-color: #28a745; -} - -.state-indicator-interrupted, -.state-indicator-error, -.state-indicator-danger { - background-color: #ffebee; - border-left-color: #dc3545; -} - -.state-icon { - font-size: 2rem; - line-height: 1; -} - -.state-info { - flex: 1; -} - -.state-label { - font-weight: 600; - font-size: 1rem; - margin-bottom: 0.25rem; -} - -.state-description { - font-size: 0.875rem; - color: #666; -} - -/* Enhanced Progress Visualization */ -.progress-bar { - height: 12px; - background-color: var(--border-color); - border-radius: 6px; - overflow: hidden; - margin: 1rem 0; - position: relative; - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); -} - -.progress-fill { - height: 100%; - background: linear-gradient(90deg, var(--primary-color), #0052a3); - transition: width 0.3s ease; - position: relative; - overflow: hidden; -} - -.progress-fill::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.3), - transparent - ); - animation: shimmer 2s infinite; -} +@import "tailwindcss"; +/* Custom animations for shimmer effect */ @keyframes shimmer { 0% { transform: translateX(-100%); @@ -766,38 +9,3 @@ button:disabled { transform: translateX(100%); } } - -/* Button enhancements for safety */ -button.btn-danger:hover:not(:disabled) { - background-color: #c82333; - box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3); - transform: translateY(-1px); -} - -button.btn-primary:hover:not(:disabled) { - box-shadow: 0 2px 8px rgba(0, 102, 204, 0.3); - transform: translateY(-1px); -} - -button.btn-secondary:hover:not(:disabled) { - box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3); - transform: translateY(-1px); -} - -button:active:not(:disabled) { - transform: translateY(0); -} - -/* Info message styles */ -.status-message.info { - background-color: #d1ecf1; - color: #0c5460; - border: 1px solid #bee5eb; -} - -/* Enhanced visual feedback for disabled state */ -button:disabled { - opacity: 0.5; - cursor: not-allowed; - filter: grayscale(0.3); -} diff --git a/src/App.tsx b/src/App.tsx index 68f7368..61f83f0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -49,22 +49,22 @@ function App() { }, []); return ( -
-
-

Brother Embroidery Machine Controller

+
+
+

Brother Embroidery Machine Controller

{machine.error && ( -
{machine.error}
+
{machine.error}
)} {pyodideError && ( -
Python Error: {pyodideError}
+
Python Error: {pyodideError}
)} {!pyodideReady && !pyodideError && ( -
Initializing Python environment...
+
Initializing Python environment...
)}
-
-
+
+
-
+
+
e.stopPropagation()} role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-message" > -
-

{title}

+
+

{title}

-
-

{message}

+
+

{message}

-
+
diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx index 5a172fa..b2dcccc 100644 --- a/src/components/FileUpload.tsx +++ b/src/components/FileUpload.tsx @@ -62,43 +62,43 @@ export function FileUpload({ }, [pesData, fileName, onUpload, patternOffset]); return ( -
-

Pattern File

+
+

Pattern File

-
+
-