diff --git a/.gitignore b/.gitignore index c446014..f1820e8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,12 @@ WebServer/tools/logs/* WebServer/soft/* !WebServer/soft/soft.rar Backend/admin/frontend/wailsjs* -.cursorrules \ No newline at end of file + +# Frontend +front_vue/node_modules/ +front_vue/dist/ +front_vue/src/auto-imports.d.ts +front_vue/src/components.d.ts + +# Cursor +.cursorrules diff --git a/front_vue/index.html b/front_vue/index.html new file mode 100644 index 0000000..452c608 --- /dev/null +++ b/front_vue/index.html @@ -0,0 +1,13 @@ + + + + + + vServer Admin Panel + + + +
+ + + diff --git a/front_vue/package-lock.json b/front_vue/package-lock.json new file mode 100644 index 0000000..c42a5d8 --- /dev/null +++ b/front_vue/package-lock.json @@ -0,0 +1,2185 @@ +{ + "name": "vserver-admin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vserver-admin", + "version": "1.0.0", + "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", + "pinia": "^3.0.4", + "vue": "^3.5.27", + "vue-i18n": "^11.2.8", + "vue-router": "^5.0.2" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.4", + "unplugin-auto-import": "^21.0.0", + "unplugin-vue-components": "^31.0.0", + "vite": "^7.3.1" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz", + "integrity": "sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", + "engines": { + "node": ">=6" + } + }, + "node_modules/@intlify/core-base": { + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.2.8.tgz", + "integrity": "sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "11.2.8", + "@intlify/shared": "11.2.8" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.2.8.tgz", + "integrity": "sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "11.2.8", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.2.8.tgz", + "integrity": "sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "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, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", + "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue-macros/common": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", + "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.27", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", + "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", + "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.27", + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", + "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz", + "integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz", + "integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz", + "integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/runtime-core": "3.5.27", + "@vue/shared": "3.5.27", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz", + "integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "vue": "3.5.27" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", + "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", + "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "ast-kit": "^2.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "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/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/devtools-api": "^7.7.7" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.5.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/unimport": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.6.0.tgz", + "integrity": "sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "pkg-types": "^2.3.0", + "scule": "^1.3.0", + "strip-literal": "^3.1.0", + "tinyglobby": "^0.2.15", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unimport/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-21.0.0.tgz", + "integrity": "sha512-vWuC8SwqJmxZFYwPojhOhOXDb5xFhNNcEVb9K/RFkyk/3VnfaOjzitWN7v+8DEKpMjSsY2AEGXNgt6I0yQrhRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "picomatch": "^4.0.3", + "unimport": "^5.6.0", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^4.0.0", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-vue-components": { + "version": "31.0.0", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-31.0.0.tgz", + "integrity": "sha512-4ULwfTZTLuWJ7+S9P7TrcStYLsSRkk6vy2jt/WTfgUEUb0nW9//xxmrfhyHUEVpZ2UKRRwfRb8Yy15PDbVZf+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "obug": "^2.1.1", + "picomatch": "^4.0.3", + "tinyglobby": "^0.2.15", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2 || ^4.0.0", + "vue": "^3.0.0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", + "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-sfc": "3.5.27", + "@vue/runtime-dom": "3.5.27", + "@vue/server-renderer": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-i18n": { + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.2.8.tgz", + "integrity": "sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.2.8", + "@intlify/shared": "11.2.8", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-i18n/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/vue-router": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.2.tgz", + "integrity": "sha512-YFhwaE5c5JcJpNB1arpkl4/GnO32wiUWRB+OEj1T0DlDxEZoOfbltl2xEwktNU/9o1sGcGburIXSpbLpPFe/6w==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.6", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.0.0", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.17", + "pinia": "^3.0.4", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + } + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.6.tgz", + "integrity": "sha512-+lGBI+WTvJmnU2FZqHhEB8J1DXcvNlDeEalz77iYgOdY1jTj1ipSBaKj3sRhYcy+kqA8v/BSuvOz1XJucfQmUA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.0.6" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-kit": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.6.tgz", + "integrity": "sha512-9zXZPTJW72OteDXeSa5RVML3zWDCRcO5t77aJqSs228mdopYj5AiTpihozbsfFJ0IodfNs7pSgOGO3qfCuxDtw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.0.6", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^2.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-shared": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.6.tgz", + "integrity": "sha512-Pp1JylTqlgMJvxW6MGyfTF8vGvlBSCAvMFaDCYa82Mgw7TT5eE5kkHgDvmOGHWeJE4zIDfCpCxHapsK2LtIAJg==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/vue-router/node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + } + } +} diff --git a/front_vue/package.json b/front_vue/package.json new file mode 100644 index 0000000..2e3f716 --- /dev/null +++ b/front_vue/package.json @@ -0,0 +1,23 @@ +{ + "name": "vserver-admin", + "private": true, + "version": "1.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", + "pinia": "^3.0.4", + "vue": "^3.5.27", + "vue-i18n": "^11.2.8", + "vue-router": "^5.0.2" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.4", + "unplugin-auto-import": "^21.0.0", + "unplugin-vue-components": "^31.0.0", + "vite": "^7.3.1" + } +} diff --git a/front_vue/src/App.vue b/front_vue/src/App.vue new file mode 100644 index 0000000..9d93560 --- /dev/null +++ b/front_vue/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/front_vue/src/Core/api/index.js b/front_vue/src/Core/api/index.js new file mode 100644 index 0000000..4e1a679 --- /dev/null +++ b/front_vue/src/Core/api/index.js @@ -0,0 +1,6 @@ +import { mockApi } from './mock.js' +import { wailsApi } from './wails.js' + +const isWails = typeof window !== 'undefined' && window?.go?.admin?.App + +export const api = isWails ? wailsApi : mockApi diff --git a/front_vue/src/Core/api/mock-data/certs.json b/front_vue/src/Core/api/mock-data/certs.json new file mode 100644 index 0000000..3a92451 --- /dev/null +++ b/front_vue/src/Core/api/mock-data/certs.json @@ -0,0 +1,42 @@ +[ + { + "domain": "voxsel.ru", + "issuer": "R13", + "not_before": "2026-01-07", + "not_after": "2026-04-07", + "days_left": 79, + "is_expired": false, + "has_cert": true, + "dns_names": ["*.voxsel.com", "*.voxsel.ru", "voxsel.com", "voxsel.ru"] + }, + { + "domain": "finance.voxsel.ru", + "issuer": "E8", + "not_before": "2026-01-17", + "not_after": "2026-04-17", + "days_left": 89, + "is_expired": false, + "has_cert": true, + "dns_names": ["finance.voxsel.ru"] + }, + { + "domain": "test.local", + "issuer": "Let's Encrypt", + "not_before": "2025-01-01", + "not_after": "2025-03-31", + "days_left": 73, + "is_expired": false, + "has_cert": true, + "dns_names": ["test.local", "*.test.local", "test.com"] + }, + { + "domain": "api.example.com", + "issuer": "Let's Encrypt", + "not_before": "2024-10-01", + "not_after": "2024-12-30", + "days_left": -18, + "is_expired": true, + "has_cert": true, + "dns_names": ["api.example.com", "*.api.example.com"] + } +] diff --git a/front_vue/src/Core/api/mock-data/config.json b/front_vue/src/Core/api/mock-data/config.json new file mode 100644 index 0000000..b82db34 --- /dev/null +++ b/front_vue/src/Core/api/mock-data/config.json @@ -0,0 +1,10 @@ +{ + "Soft_Settings": { + "php_port": 8000, + "php_host": "localhost", + "mysql_port": 3306, + "mysql_host": "127.0.0.1", + "proxy_enabled": true, + "ACME_enabled": true + } +} diff --git a/front_vue/src/Core/api/mock-data/proxies.json b/front_vue/src/Core/api/mock-data/proxies.json new file mode 100644 index 0000000..bb6d65e --- /dev/null +++ b/front_vue/src/Core/api/mock-data/proxies.json @@ -0,0 +1,29 @@ +[ + { + "Enable": true, + "ExternalDomain": "git.example.ru", + "LocalAddress": "127.0.0.1", + "LocalPort": "3333", + "ServiceHTTPSuse": false, + "AutoHTTPS": true, + "AutoCreateSSL": false + }, + { + "Enable": true, + "ExternalDomain": "api.example.com", + "LocalAddress": "127.0.0.1", + "LocalPort": "8080", + "ServiceHTTPSuse": true, + "AutoHTTPS": false, + "AutoCreateSSL": true + }, + { + "Enable": false, + "ExternalDomain": "test.example.net", + "LocalAddress": "127.0.0.1", + "LocalPort": "5000", + "ServiceHTTPSuse": false, + "AutoHTTPS": false, + "AutoCreateSSL": false + } +] diff --git a/front_vue/src/Core/api/mock-data/services.json b/front_vue/src/Core/api/mock-data/services.json new file mode 100644 index 0000000..ea74c21 --- /dev/null +++ b/front_vue/src/Core/api/mock-data/services.json @@ -0,0 +1,7 @@ +[ + { "name": "HTTP", "status": true, "port": "80", "info": "" }, + { "name": "HTTPS", "status": true, "port": "443", "info": "" }, + { "name": "MySQL", "status": true, "port": "3306", "info": "" }, + { "name": "PHP", "status": true, "port": "8000-8003", "info": "" }, + { "name": "Proxy", "status": true, "port": "", "info": "2 из 3" } +] diff --git a/front_vue/src/Core/api/mock-data/sites.json b/front_vue/src/Core/api/mock-data/sites.json new file mode 100644 index 0000000..da5272f --- /dev/null +++ b/front_vue/src/Core/api/mock-data/sites.json @@ -0,0 +1,29 @@ +[ + { + "name": "Локальный сайт", + "host": "127.0.0.1", + "alias": ["localhost"], + "status": "active", + "root_file": "index.html", + "root_file_routing": true, + "AutoCreateSSL": false + }, + { + "name": "Тестовый проект", + "host": "test.local", + "alias": ["*.test.local", "test.com"], + "status": "active", + "root_file": "index.php", + "root_file_routing": false, + "AutoCreateSSL": false + }, + { + "name": "API сервис", + "host": "api.example.com", + "alias": ["*.api.example.com"], + "status": "inactive", + "root_file": "index.php", + "root_file_routing": true, + "AutoCreateSSL": true + } +] diff --git a/front_vue/src/Core/api/mock-data/vaccess.json b/front_vue/src/Core/api/mock-data/vaccess.json new file mode 100644 index 0000000..bb03dcd --- /dev/null +++ b/front_vue/src/Core/api/mock-data/vaccess.json @@ -0,0 +1,20 @@ +{ + "rules": [ + { + "type": "Disable", + "type_file": ["*.php"], + "path_access": ["/uploads/*"], + "ip_list": [], + "exceptions_dir": [], + "url_error": "404" + }, + { + "type": "Allow", + "type_file": [], + "path_access": ["/admin/*"], + "ip_list": ["192.168.1.100", "127.0.0.1"], + "exceptions_dir": ["/admin/public/*"], + "url_error": "404" + } + ] +} diff --git a/front_vue/src/Core/api/mock.js b/front_vue/src/Core/api/mock.js new file mode 100644 index 0000000..4c7e806 --- /dev/null +++ b/front_vue/src/Core/api/mock.js @@ -0,0 +1,121 @@ +import servicesData from './mock-data/services.json' +import sitesData from './mock-data/sites.json' +import proxiesData from './mock-data/proxies.json' +import configData from './mock-data/config.json' +import certsData from './mock-data/certs.json' +import vaccessData from './mock-data/vaccess.json' + +const delay = (ms = 300) => new Promise(r => setTimeout(r, ms)) + +export const mockApi = { + async getAllServicesStatus() { + await delay(200) + return JSON.parse(JSON.stringify(servicesData)) + }, + + async checkServicesReady() { + await delay(100) + return true + }, + + async startServer() { await delay(500); return 'OK' }, + async stopServer() { await delay(500); return 'OK' }, + async startHTTPService() { await delay(300); return 'OK' }, + async stopHTTPService() { await delay(300); return 'OK' }, + async startHTTPSService() { await delay(300); return 'OK' }, + async stopHTTPSService() { await delay(300); return 'OK' }, + async startMySQLService() { await delay(300); return 'OK' }, + async stopMySQLService() { await delay(300); return 'OK' }, + async startPHPService() { await delay(300); return 'OK' }, + async stopPHPService() { await delay(300); return 'OK' }, + async enableProxyService() { await delay(200); return 'OK' }, + async disableProxyService() { await delay(200); return 'OK' }, + async enableACMEService() { await delay(200); return 'OK' }, + async disableACMEService() { await delay(200); return 'OK' }, + async restartAllServices() { await delay(1000); return 'OK' }, + + async getSitesList() { + await delay(200) + return JSON.parse(JSON.stringify(sitesData)) + }, + + async createNewSite(siteJSON) { + await delay(500) + return 'OK' + }, + + async deleteSite(host) { + await delay(500) + return 'OK' + }, + + async openSiteFolder(host) { + await delay(100) + }, + + async uploadCertificate(host, certType, certDataBase64) { + await delay(300) + return 'OK' + }, + + async getProxyList() { + await delay(200) + return JSON.parse(JSON.stringify(proxiesData)) + }, + + async getVAccessRules(host, isProxy) { + await delay(200) + return JSON.parse(JSON.stringify(vaccessData)) + }, + + async saveVAccessRules(host, isProxy, configJSON) { + await delay(300) + return 'OK' + }, + + async getConfig() { + await delay(200) + return JSON.parse(JSON.stringify(configData)) + }, + + async saveConfig(configJSON) { + await delay(400) + return 'OK' + }, + + async reloadConfig() { + await delay(200) + return 'OK' + }, + + async obtainSSLCertificate(domain) { + await delay(1500) + return 'OK' + }, + + async obtainAllSSLCertificates() { + await delay(2000) + return 'OK' + }, + + async getCertInfo(domain) { + await delay(200) + const cert = certsData.find(c => c.domain === domain) + return cert || { has_cert: false } + }, + + async getAllCertsInfo() { + await delay(300) + return JSON.parse(JSON.stringify(certsData)) + }, + + async deleteCertificate(domain) { + await delay(300) + return 'OK' + }, + + async reloadSSLCertificates() { + await delay(300) + return 'OK' + }, +} diff --git a/front_vue/src/Core/api/wails.js b/front_vue/src/Core/api/wails.js new file mode 100644 index 0000000..01cc949 --- /dev/null +++ b/front_vue/src/Core/api/wails.js @@ -0,0 +1,95 @@ +const app = () => window.go.admin.App + +export const wailsApi = { + async getAllServicesStatus() { + return await app().GetAllServicesStatus() + }, + + async checkServicesReady() { + return await app().CheckServicesReady() + }, + + async startServer() { return await app().StartServer() }, + async stopServer() { return await app().StopServer() }, + async startHTTPService() { return await app().StartHTTPService() }, + async stopHTTPService() { return await app().StopHTTPService() }, + async startHTTPSService() { return await app().StartHTTPSService() }, + async stopHTTPSService() { return await app().StopHTTPSService() }, + async startMySQLService() { return await app().StartMySQLService() }, + async stopMySQLService() { return await app().StopMySQLService() }, + async startPHPService() { return await app().StartPHPService() }, + async stopPHPService() { return await app().StopPHPService() }, + async enableProxyService() { return await app().EnableProxyService() }, + async disableProxyService() { return await app().DisableProxyService() }, + async enableACMEService() { return await app().EnableACMEService() }, + async disableACMEService() { return await app().DisableACMEService() }, + async restartAllServices() { return await app().RestartAllServices() }, + + async getSitesList() { + return await app().GetSitesList() + }, + + async createNewSite(siteJSON) { + return await app().CreateNewSite(siteJSON) + }, + + async deleteSite(host) { + return await app().DeleteSite(host) + }, + + async openSiteFolder(host) { + return await app().OpenSiteFolder(host) + }, + + async uploadCertificate(host, certType, certDataBase64) { + return await app().UploadCertificate(host, certType, certDataBase64) + }, + + async getProxyList() { + return await app().GetProxyList() + }, + + async getVAccessRules(host, isProxy) { + return await app().GetVAccessRules(host, isProxy) + }, + + async saveVAccessRules(host, isProxy, configJSON) { + return await app().SaveVAccessRules(host, isProxy, configJSON) + }, + + async getConfig() { + return await app().GetConfig() + }, + + async saveConfig(configJSON) { + return await app().SaveConfig(configJSON) + }, + + async reloadConfig() { + return await app().ReloadConfig() + }, + + async obtainSSLCertificate(domain) { + return await app().ObtainSSLCertificate(domain) + }, + + async obtainAllSSLCertificates() { + return await app().ObtainAllSSLCertificates() + }, + + async getCertInfo(domain) { + return await app().GetCertInfo(domain) + }, + + async getAllCertsInfo() { + return await app().GetAllCertsInfo() + }, + + async deleteCertificate(domain) { + return await app().DeleteCertificate(domain) + }, + + async reloadSSLCertificates() { + return await app().ReloadSSLCertificates() + }, +} diff --git a/front_vue/src/Core/composables/useModal.js b/front_vue/src/Core/composables/useModal.js new file mode 100644 index 0000000..5d674ab --- /dev/null +++ b/front_vue/src/Core/composables/useModal.js @@ -0,0 +1,42 @@ +const isOpen = ref(false) +const title = ref('') +const content = ref(null) +const onSave = ref(null) +const onDelete = ref(null) + +export function useModal() { + const open = (options = {}) => { + title.value = options.title || '' + content.value = options.content || null + onSave.value = options.onSave || null + onDelete.value = options.onDelete || null + isOpen.value = true + } + + const close = () => { + isOpen.value = false + title.value = '' + content.value = null + onSave.value = null + onDelete.value = null + } + + const save = async () => { + if (onSave.value) await onSave.value() + } + + const remove = async () => { + if (onDelete.value) await onDelete.value() + } + + return { + isOpen: readonly(isOpen), + title: readonly(title), + content: readonly(content), + hasDelete: computed(() => !!onDelete.value), + open, + close, + save, + remove, + } +} diff --git a/front_vue/src/Core/composables/useNotification.js b/front_vue/src/Core/composables/useNotification.js new file mode 100644 index 0000000..13f6e8c --- /dev/null +++ b/front_vue/src/Core/composables/useNotification.js @@ -0,0 +1,37 @@ +const notifications = ref([]) +let nextId = 0 + +export function useNotification() { + const show = (message, type = 'info', duration = 2000) => { + const id = nextId++ + notifications.value.push({ id, message, type }) + + if (duration > 0) { + setTimeout(() => { + remove(id) + }, duration) + } + + return id + } + + const remove = (id) => { + const index = notifications.value.findIndex(n => n.id === id) + if (index !== -1) { + notifications.value.splice(index, 1) + } + } + + const success = (message, duration = 2000) => show(message, 'success', duration) + const error = (message, duration = 3000) => show(message, 'error', duration) + const info = (message, duration = 2000) => show(message, 'info', duration) + + return { + notifications: readonly(notifications), + show, + success, + error, + info, + remove, + } +} diff --git a/front_vue/src/Core/composables/useTheme.js b/front_vue/src/Core/composables/useTheme.js new file mode 100644 index 0000000..cafe412 --- /dev/null +++ b/front_vue/src/Core/composables/useTheme.js @@ -0,0 +1,16 @@ +import { useAppStore } from '@core/stores/app.js' + +export function useTheme() { + const appStore = useAppStore() + + const initTheme = () => { + document.documentElement.setAttribute('data-theme', appStore.theme) + } + + return { + theme: computed(() => appStore.theme), + isDark: computed(() => appStore.isDark), + toggleTheme: () => appStore.toggleTheme(), + initTheme, + } +} diff --git a/front_vue/src/Core/composables/useWailsEvents.js b/front_vue/src/Core/composables/useWailsEvents.js new file mode 100644 index 0000000..f8ff01f --- /dev/null +++ b/front_vue/src/Core/composables/useWailsEvents.js @@ -0,0 +1,17 @@ +export function useWailsEvents() { + const isWails = typeof window !== 'undefined' && window?.runtime?.EventsOn + + const on = (eventName, callback) => { + if (isWails) { + window.runtime.EventsOn(eventName, callback) + } + } + + const off = (eventName) => { + if (isWails && window.runtime.EventsOff) { + window.runtime.EventsOff(eventName) + } + } + + return { on, off, isWails } +} diff --git a/front_vue/src/Core/constants.js b/front_vue/src/Core/constants.js new file mode 100644 index 0000000..e289591 --- /dev/null +++ b/front_vue/src/Core/constants.js @@ -0,0 +1,45 @@ +export const SERVICE_NAMES = { + HTTP: 'http', + HTTPS: 'https', + MYSQL: 'mysql', + PHP: 'php', + PROXY: 'proxy', +} + +export const SITE_STATUS = { + ACTIVE: 'active', + INACTIVE: 'inactive', +} + +export const PROXY_STATUS = { + ENABLED: 'enable', + DISABLED: 'disable', +} + +export const VACCESS_TYPE = { + ALLOW: 'Allow', + DISABLE: 'Disable', +} + +export const CERT_MODE = { + NONE: 'none', + AUTO: 'auto', + UPLOAD: 'upload', +} + +export const THEME = { + DARK: 'dark', + LIGHT: 'light', +} + +export const LOCALE = { + RU: 'ru', + EN: 'en', +} + +export const STORAGE_KEYS = { + THEME: 'vserver-theme', + LOCALE: 'vserver-locale', +} + +export const AUTO_REFRESH_INTERVAL = 5000 diff --git a/front_vue/src/Core/i18n/en.json b/front_vue/src/Core/i18n/en.json new file mode 100644 index 0000000..46d74c0 --- /dev/null +++ b/front_vue/src/Core/i18n/en.json @@ -0,0 +1,204 @@ +{ + "app": { + "title": "vServer Admin Panel", + "logo": "vServer", + "footer": "vServer Admin Panel © 2025 | Author: Sumaneev Roman", + "loading": "Starting vServer..." + }, + "nav": { + "dashboard": "Dashboard", + "settings": "Settings" + }, + "window": { + "minimize": "Minimize", + "maximize": "Maximize", + "close": "Close" + }, + "server": { + "running": "Server is running", + "stopped": "Server is stopped", + "start": "Start", + "stop": "Stop" + }, + "services": { + "title": "Services Status", + "port": "Port", + "ports": "Ports", + "rules": "Rules", + "starting": "Starting", + "http": "HTTP", + "https": "HTTPS", + "mysql": "MySQL", + "php": "PHP", + "proxy": "Proxy" + }, + "sites": { + "title": "Sites List", + "add": "Add Site", + "create": "Create New Site", + "createBtn": "Create Site", + "createDesc": "Fill in the site information and optionally upload SSL certificates", + "name": "Name", + "host": "Host", + "alias": "Alias", + "status": "Status", + "rootFile": "Root File", + "actions": "Actions", + "openFolder": "Open Folder", + "editVaccess": "vAccess", + "edit": "Edit", + "formName": "Site Name", + "formNamePlaceholder": "My new site", + "formHost": "Host (domain)", + "formHostPlaceholder": "example.com", + "formHostHint": "Enter domain without protocol (e.g.: example.com or 192.168.1.100)", + "formAlias": "Alias (aliases)", + "formAliasPlaceholder": "*.example.com, www.example.com, alias.com", + "formAliasHint": "Enter aliases separated by commas", + "formRootFile": "Root file", + "formStatus": "Status", + "formRouting": "Root file routing", + "formRoutingHint": "If enabled, all requests to non-existent files will be redirected to the root file", + "deleteTitle": "Delete Site", + "deleteConfirm": "Are you sure you want to delete site \"{name}\" ({host})?", + "deleteWarning": "This action is IRREVERSIBLE!" + }, + "proxies": { + "title": "Proxy Services", + "add": "Add Proxy", + "create": "Create Proxy Service", + "createBtn": "Create Proxy", + "createDesc": "Configure proxying of an external domain to a local service", + "externalDomain": "External Domain", + "localAddress": "Local Address", + "localPort": "Local Port", + "httpsCol": "HTTPS", + "autoHttps": "Auto HTTPS", + "status": "Status", + "actions": "Actions", + "formDomain": "External Domain", + "formDomainPlaceholder": "example.com", + "formDomainHint": "Domain that will receive requests (e.g.: git.example.ru)", + "formLocalAddr": "Local Address", + "formLocalPort": "Local Port", + "formServiceHttps": "HTTPS to service", + "formServiceHttpsHint": "Use HTTPS when connecting to the local service", + "formAutoHttps": "Auto HTTPS", + "formAutoHttpsHint": "Automatically redirect HTTP requests to HTTPS", + "deleteTitle": "Delete Proxy", + "deleteConfirm": "Are you sure you want to delete proxy \"{domain}\"?" + }, + "settings": { + "title": "Server Settings", + "save": "Save & Restart", + "saving": "Saving...", + "restarting": "Restarting services...", + "mysql": "MySQL Server", + "php": "PHP Server", + "proxyManager": "Proxy Manager", + "certManager": "Cert Manager", + "hostAddr": "Host Address", + "port": "Port", + "proxyHint": "Applied instantly without server restart. When disabled, all proxy rules will be turned off.", + "certHint": "Automatic SSL certificate issuance from Let's Encrypt for domains with \"Auto SSL\" enabled." + }, + "vaccess": { + "title": "vAccess Access Rules", + "subtitle": "Manage access rules for the site", + "save": "Save Changes", + "addRule": "Add Rule", + "rulesTab": "Access Rules", + "helpTab": "Help", + "type": "Type", + "files": "Extensions", + "paths": "Access Paths", + "ips": "IP Addresses", + "exceptions": "Exceptions", + "error": "Error", + "empty": "No access rules", + "emptyDesc": "Add the first rule to start managing access", + "createRule": "Create Rule", + "allow": "Allow", + "disable": "Disable", + "helpPrinciple": "How it works", + "helpParams": "Rule Parameters", + "helpPatterns": "Patterns", + "helpExamples": "Rule Examples" + }, + "certs": { + "title": "Certificate Management", + "subtitle": "View and manage SSL certificates for the domain", + "status": "Status", + "issuer": "Issuer", + "issued": "Issued", + "expires": "Expires", + "active": "Active", + "expired": "Expired", + "noCert": "No certificate", + "localDomain": "Local domain", + "wildcardCover": "Covered by wildcard", + "issue": "Issue Certificate", + "issueDirect": "Issue Direct", + "renew": "Renew", + "delete": "Delete", + "daysLeft": "{n} days", + "mode": "Certificate Mode", + "modeNone": "No certificate (fallback)", + "modeAuto": "Automatic certificate creation", + "modeUpload": "Upload certificate files", + "certFile": "Certificate (*.crt)", + "keyFile": "Private Key (*.key)", + "caFile": "CA Bundle (*.crt)", + "caHint": "CA Bundle is optional but recommended for full certificate chain", + "selectFile": "Choose file..." + }, + "common": { + "back": "Back", + "save": "Save", + "cancel": "Cancel", + "delete": "Delete", + "create": "Create", + "edit": "Edit", + "add": "Add", + "enabled": "Enabled", + "disabled": "Disabled", + "yes": "Yes", + "no": "No", + "active": "active", + "inactive": "inactive", + "required": "Required field", + "basicInfo": "Basic Information", + "sslCerts": "SSL Certificates (optional)", + "loading": "Loading...", + "errorPrefix": "Error" + }, + "notify": { + "settingsSaved": "Settings saved and services restarted!", + "settingsTestMode": "Settings saved (test mode)", + "dataSaved": "Data saved (test mode)", + "siteCreated": "Site created successfully!", + "siteDeleted": "Site deleted successfully!", + "proxyDeleted": "Proxy deleted successfully!", + "changesSaved": "Changes saved and applied!", + "serversRestarted": "Servers restarted!", + "certIssued": "Certificate issued successfully!", + "certRenewed": "Certificate renewed successfully!", + "certDeleted": "Certificate deleted", + "proxyEnabled": "Proxy Manager enabled", + "proxyDisabled": "Proxy Manager disabled", + "certManagerEnabled": "Cert Manager enabled", + "certManagerDisabled": "Cert Manager disabled", + "deletingProxy": "Deleting proxy...", + "deletingSite": "Deleting site...", + "requestingCert": "Requesting certificate...", + "restartingHttp": "Restarting HTTP/HTTPS..." + }, + "theme": { + "dark": "Dark theme", + "light": "Light theme" + }, + "lang": { + "ru": "Русский", + "en": "English" + } +} diff --git a/front_vue/src/Core/i18n/index.js b/front_vue/src/Core/i18n/index.js new file mode 100644 index 0000000..8438bea --- /dev/null +++ b/front_vue/src/Core/i18n/index.js @@ -0,0 +1,15 @@ +import { createI18n } from 'vue-i18n' +import ru from './ru.json' +import en from './en.json' +import { STORAGE_KEYS, LOCALE } from '@core/constants.js' + +const savedLocale = localStorage.getItem(STORAGE_KEYS.LOCALE) || LOCALE.RU + +const i18n = createI18n({ + legacy: false, + locale: savedLocale, + fallbackLocale: LOCALE.RU, + messages: { ru, en }, +}) + +export default i18n diff --git a/front_vue/src/Core/i18n/ru.json b/front_vue/src/Core/i18n/ru.json new file mode 100644 index 0000000..fa84309 --- /dev/null +++ b/front_vue/src/Core/i18n/ru.json @@ -0,0 +1,204 @@ +{ + "app": { + "title": "vServer Admin Panel", + "logo": "vServer", + "footer": "vServer Admin Panel © 2025 | Автор: Суманеев Роман", + "loading": "Запуск vServer..." + }, + "nav": { + "dashboard": "Главная", + "settings": "Настройки" + }, + "window": { + "minimize": "Свернуть", + "maximize": "Развернуть", + "close": "Закрыть" + }, + "server": { + "running": "Сервер запущен", + "stopped": "Сервер остановлен", + "start": "Запустить", + "stop": "Остановить" + }, + "services": { + "title": "Статус сервисов", + "port": "Порт", + "ports": "Порты", + "rules": "Правил", + "starting": "Запуск", + "http": "HTTP", + "https": "HTTPS", + "mysql": "MySQL", + "php": "PHP", + "proxy": "Proxy" + }, + "sites": { + "title": "Список сайтов", + "add": "Добавить сайт", + "create": "Создание нового сайта", + "createBtn": "Создать сайт", + "createDesc": "Заполните информацию о сайте и при необходимости загрузите SSL сертификаты", + "name": "Имя", + "host": "Host", + "alias": "Alias", + "status": "Статус", + "rootFile": "Root File", + "actions": "Действия", + "openFolder": "Открыть папку", + "editVaccess": "vAccess", + "edit": "Редактировать", + "formName": "Название сайта", + "formNamePlaceholder": "Мой новый сайт", + "formHost": "Host (домен)", + "formHostPlaceholder": "example.com", + "formHostHint": "Введите домен без протокола (например: example.com или 192.168.1.100)", + "formAlias": "Alias (псевдонимы)", + "formAliasPlaceholder": "*.example.com, www.example.com, alias.com", + "formAliasHint": "Введите псевдонимы через запятую", + "formRootFile": "Root файл", + "formStatus": "Статус", + "formRouting": "Root file routing", + "formRoutingHint": "Если включено, все запросы к несуществующим файлам будут перенаправляться на root файл", + "deleteTitle": "Удалить сайт", + "deleteConfirm": "Вы действительно хотите удалить сайт \"{name}\" ({host})?", + "deleteWarning": "Это действие НЕОБРАТИМО!" + }, + "proxies": { + "title": "Прокси сервисы", + "add": "Добавить прокси", + "create": "Создание прокси сервиса", + "createBtn": "Создать прокси", + "createDesc": "Настройте проксирование внешнего домена на локальный сервис", + "externalDomain": "Внешний домен", + "localAddress": "Локальный адрес", + "localPort": "Локальный порт", + "httpsCol": "HTTPS", + "autoHttps": "Auto HTTPS", + "status": "Статус", + "actions": "Действия", + "formDomain": "Внешний домен", + "formDomainPlaceholder": "example.com", + "formDomainHint": "Домен, на который будут приходить запросы (например: git.example.ru)", + "formLocalAddr": "Локальный адрес", + "formLocalPort": "Локальный порт", + "formServiceHttps": "HTTPS к сервису", + "formServiceHttpsHint": "Использовать HTTPS при подключении к локальному сервису", + "formAutoHttps": "Авто HTTPS", + "formAutoHttpsHint": "Автоматически перенаправлять HTTP запросы на HTTPS", + "deleteTitle": "Удалить прокси", + "deleteConfirm": "Вы действительно хотите удалить прокси \"{domain}\"?" + }, + "settings": { + "title": "Настройки серверов", + "save": "Сохранить и перезапустить", + "saving": "Сохранение...", + "restarting": "Перезапуск сервисов...", + "mysql": "MySQL сервер", + "php": "PHP сервер", + "proxyManager": "Proxy Manager", + "certManager": "Cert Manager", + "hostAddr": "Host адрес", + "port": "Порт", + "proxyHint": "Применяется моментально без перезапуска серверов. При выключении все прокси правила будут отключены.", + "certHint": "Автоматическое получение SSL сертификатов от Let's Encrypt для доменов с включённым \"Авто SSL\"." + }, + "vaccess": { + "title": "Правила доступа vAccess", + "subtitle": "Управление правилами доступа для сайта", + "save": "Сохранить изменения", + "addRule": "Добавить правило", + "rulesTab": "Правила доступа", + "helpTab": "Инструкция", + "type": "Тип", + "files": "Расширения", + "paths": "Пути доступа", + "ips": "IP адреса", + "exceptions": "Исключения", + "error": "Ошибка", + "empty": "Нет правил доступа", + "emptyDesc": "Добавьте первое правило, чтобы начать управление доступом", + "createRule": "Создать правило", + "allow": "Allow", + "disable": "Disable", + "helpPrinciple": "Принцип работы", + "helpParams": "Параметры правил", + "helpPatterns": "Паттерны", + "helpExamples": "Примеры правил" + }, + "certs": { + "title": "Управление сертификатами", + "subtitle": "Просмотр и управление SSL сертификатами для домена", + "status": "Статус", + "issuer": "Издатель", + "issued": "Выдан", + "expires": "Истекает", + "active": "Активен", + "expired": "Истёк", + "noCert": "Нет сертификата", + "localDomain": "Локальный домен", + "wildcardCover": "Покрыт wildcard", + "issue": "Выпустить сертификат", + "issueDirect": "Выпустить прямой", + "renew": "Перевыпустить", + "delete": "Удалить", + "daysLeft": "{n} дн.", + "mode": "Режим сертификата", + "modeNone": "Без сертификата (fallback)", + "modeAuto": "Автоматическое создание сертификата", + "modeUpload": "Загрузить файлы сертификата", + "certFile": "Certificate (*.crt)", + "keyFile": "Private Key (*.key)", + "caFile": "CA Bundle (*.crt)", + "caHint": "CA Bundle опционален, но рекомендуется для полной цепочки сертификации", + "selectFile": "Выберите файл..." + }, + "common": { + "back": "Назад", + "save": "Сохранить", + "cancel": "Отмена", + "delete": "Удалить", + "create": "Создать", + "edit": "Редактировать", + "add": "Добавить", + "enabled": "Включён", + "disabled": "Отключён", + "yes": "Да", + "no": "Нет", + "active": "active", + "inactive": "inactive", + "required": "Обязательное поле", + "basicInfo": "Основная информация", + "sslCerts": "SSL Сертификаты (опционально)", + "loading": "Загрузка...", + "errorPrefix": "Ошибка" + }, + "notify": { + "settingsSaved": "Настройки сохранены и сервисы перезапущены!", + "settingsTestMode": "Настройки сохранены (тестовый режим)", + "dataSaved": "Данные сохранены (тестовый режим)", + "siteCreated": "Сайт успешно создан!", + "siteDeleted": "Сайт успешно удалён!", + "proxyDeleted": "Прокси успешно удалён!", + "changesSaved": "Изменения сохранены и применены!", + "serversRestarted": "Серверы перезапущены!", + "certIssued": "Сертификат успешно выпущен!", + "certRenewed": "Сертификат успешно перевыпущен!", + "certDeleted": "Сертификат удалён", + "proxyEnabled": "Proxy Manager включен", + "proxyDisabled": "Proxy Manager отключен", + "certManagerEnabled": "Cert Manager включен", + "certManagerDisabled": "Cert Manager отключен", + "deletingProxy": "Удаление прокси...", + "deletingSite": "Удаление сайта...", + "requestingCert": "Запрос сертификата...", + "restartingHttp": "Перезапуск HTTP/HTTPS..." + }, + "theme": { + "dark": "Тёмная тема", + "light": "Светлая тема" + }, + "lang": { + "ru": "Русский", + "en": "English" + } +} diff --git a/front_vue/src/Core/router/index.js b/front_vue/src/Core/router/index.js new file mode 100644 index 0000000..13d37b0 --- /dev/null +++ b/front_vue/src/Core/router/index.js @@ -0,0 +1,55 @@ +import { createRouter, createWebHashHistory } from 'vue-router' + +const routes = [ + { + path: '/', + name: 'dashboard', + component: () => import('@design/views/DashboardView.vue'), + }, + { + path: '/settings', + name: 'settings', + component: () => import('@design/views/SettingsView.vue'), + }, + { + path: '/sites/create', + name: 'site-create', + component: () => import('@design/views/SiteCreateView.vue'), + }, + { + path: '/proxies/create', + name: 'proxy-create', + component: () => import('@design/views/ProxyCreateView.vue'), + }, + { + path: '/sites/edit/:host', + name: 'site-edit', + component: () => import('@design/views/SiteEditView.vue'), + props: true, + }, + { + path: '/proxies/edit/:domain', + name: 'proxy-edit', + component: () => import('@design/views/ProxyEditView.vue'), + props: true, + }, + { + path: '/vaccess/:host', + name: 'vaccess', + component: () => import('@design/views/VAccessView.vue'), + props: true, + }, + { + path: '/certs/:host', + name: 'certs', + component: () => import('@design/views/CertManagerView.vue'), + props: true, + }, +] + +const router = createRouter({ + history: createWebHashHistory(), + routes, +}) + +export default router diff --git a/front_vue/src/Core/stores/app.js b/front_vue/src/Core/stores/app.js new file mode 100644 index 0000000..fe7e390 --- /dev/null +++ b/front_vue/src/Core/stores/app.js @@ -0,0 +1,36 @@ +import { defineStore } from 'pinia' +import { STORAGE_KEYS, THEME, LOCALE } from '@core/constants.js' + +export const useAppStore = defineStore('app', { + state: () => ({ + theme: localStorage.getItem(STORAGE_KEYS.THEME) || THEME.DARK, + locale: localStorage.getItem(STORAGE_KEYS.LOCALE) || LOCALE.RU, + loading: true, + serverRunning: false, + }), + + getters: { + isDark: (state) => state.theme === THEME.DARK, + }, + + actions: { + toggleTheme() { + this.theme = this.isDark ? THEME.LIGHT : THEME.DARK + localStorage.setItem(STORAGE_KEYS.THEME, this.theme) + document.documentElement.setAttribute('data-theme', this.theme) + }, + + setLocale(locale) { + this.locale = locale + localStorage.setItem(STORAGE_KEYS.LOCALE, locale) + }, + + setLoading(value) { + this.loading = value + }, + + setServerRunning(value) { + this.serverRunning = value + }, + }, +}) diff --git a/front_vue/src/Core/stores/certs.js b/front_vue/src/Core/stores/certs.js new file mode 100644 index 0000000..592517d --- /dev/null +++ b/front_vue/src/Core/stores/certs.js @@ -0,0 +1,45 @@ +import { defineStore } from 'pinia' +import { api } from '@core/api/index.js' + +export const useCertsStore = defineStore('certs', { + state: () => ({ + list: [], + loaded: false, + }), + + actions: { + async loadAll() { + const data = await api.getAllCertsInfo() + if (data) { + this.list = data + this.loaded = true + } + }, + + async getInfo(domain) { + return await api.getCertInfo(domain) + }, + + async issue(domain) { + const result = await api.obtainSSLCertificate(domain) + await this.loadAll() + return result + }, + + async renew(domain) { + const result = await api.obtainSSLCertificate(domain) + await this.loadAll() + return result + }, + + async remove(domain) { + const result = await api.deleteCertificate(domain) + await this.loadAll() + return result + }, + + async reload() { + return await api.reloadSSLCertificates() + }, + }, +}) diff --git a/front_vue/src/Core/stores/config.js b/front_vue/src/Core/stores/config.js new file mode 100644 index 0000000..007af75 --- /dev/null +++ b/front_vue/src/Core/stores/config.js @@ -0,0 +1,51 @@ +import { defineStore } from 'pinia' +import { api } from '@core/api/index.js' + +export const useConfigStore = defineStore('config', { + state: () => ({ + data: null, + loaded: false, + }), + + getters: { + softSettings: (state) => state.data?.Soft_Settings || {}, + }, + + actions: { + async load() { + const config = await api.getConfig() + if (config) { + this.data = config + this.loaded = true + } + }, + + async save(configData) { + const result = await api.saveConfig(JSON.stringify(configData, null, 4)) + if (result && !String(result).startsWith('Error')) { + this.data = configData + } + return result + }, + + async enableProxy() { + return await api.enableProxyService() + }, + + async disableProxy() { + return await api.disableProxyService() + }, + + async enableACME() { + return await api.enableACMEService() + }, + + async disableACME() { + return await api.disableACMEService() + }, + + async restartAll() { + return await api.restartAllServices() + }, + }, +}) diff --git a/front_vue/src/Core/stores/proxies.js b/front_vue/src/Core/stores/proxies.js new file mode 100644 index 0000000..d9137c6 --- /dev/null +++ b/front_vue/src/Core/stores/proxies.js @@ -0,0 +1,19 @@ +import { defineStore } from 'pinia' +import { api } from '@core/api/index.js' + +export const useProxiesStore = defineStore('proxies', { + state: () => ({ + list: [], + loaded: false, + }), + + actions: { + async load() { + const data = await api.getProxyList() + if (data) { + this.list = data + this.loaded = true + } + }, + }, +}) diff --git a/front_vue/src/Core/stores/services.js b/front_vue/src/Core/stores/services.js new file mode 100644 index 0000000..e15fdb5 --- /dev/null +++ b/front_vue/src/Core/stores/services.js @@ -0,0 +1,41 @@ +import { defineStore } from 'pinia' +import { api } from '@core/api/index.js' + +export const useServicesStore = defineStore('services', { + state: () => ({ + list: [], + loaded: false, + }), + + actions: { + async load() { + const data = await api.getAllServicesStatus() + if (data) { + this.list = Array.isArray(data) ? data : [data] + this.loaded = true + } + }, + + async startService(name) { + const methods = { + HTTP: () => api.startHTTPService(), + HTTPS: () => api.startHTTPSService(), + MySQL: () => api.startMySQLService(), + PHP: () => api.startPHPService(), + } + if (methods[name]) await methods[name]() + await this.load() + }, + + async stopService(name) { + const methods = { + HTTP: () => api.stopHTTPService(), + HTTPS: () => api.stopHTTPSService(), + MySQL: () => api.stopMySQLService(), + PHP: () => api.stopPHPService(), + } + if (methods[name]) await methods[name]() + await this.load() + }, + }, +}) diff --git a/front_vue/src/Core/stores/sites.js b/front_vue/src/Core/stores/sites.js new file mode 100644 index 0000000..7137ee8 --- /dev/null +++ b/front_vue/src/Core/stores/sites.js @@ -0,0 +1,43 @@ +import { defineStore } from 'pinia' +import { api } from '@core/api/index.js' + +export const useSitesStore = defineStore('sites', { + state: () => ({ + list: [], + loaded: false, + }), + + actions: { + async load() { + const data = await api.getSitesList() + if (data) { + this.list = data + this.loaded = true + } + }, + + async create(siteData) { + const result = await api.createNewSite(JSON.stringify(siteData)) + if (result && !String(result).startsWith('Error')) { + await this.load() + } + return result + }, + + async remove(host) { + const result = await api.deleteSite(host) + if (result && !String(result).startsWith('Error')) { + await this.load() + } + return result + }, + + async openFolder(host) { + await api.openSiteFolder(host) + }, + + async uploadCert(host, certType, certDataBase64) { + return await api.uploadCertificate(host, certType, certDataBase64) + }, + }, +}) diff --git a/front_vue/src/Design/assets/css/base.css b/front_vue/src/Design/assets/css/base.css new file mode 100644 index 0000000..08c3b87 --- /dev/null +++ b/front_vue/src/Design/assets/css/base.css @@ -0,0 +1,79 @@ +/* ============================================ + Base Styles — сброс и общие стили + ============================================ */ + +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-size: var(--text-base); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + font-family: var(--font-sans); + background: var(--bg-primary); + color: var(--text-primary); + line-height: 1.5; + overflow: hidden; + height: 100vh; + width: 100vw; +} + +#app { + height: 100vh; + width: 100vw; + display: flex; + flex-direction: column; +} + +a { + color: var(--accent-purple-light); + text-decoration: none; +} + +a:hover { + color: var(--accent-purple); +} + +code { + font-family: var(--font-mono); + background: rgba(var(--accent-rgb), 0.1); + padding: 3px 8px; + border-radius: var(--radius-sm); + font-size: var(--text-sm); + color: var(--accent-purple-light); + border: 1px solid var(--glass-border); +} + +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: var(--scrollbar-bg); +} + +::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--accent-purple); +} + +::selection { + background: var(--selection-bg); + color: var(--text-primary); +} + +input, select, textarea, button { + font-family: inherit; + font-size: inherit; +} diff --git a/front_vue/src/Design/assets/css/forms.css b/front_vue/src/Design/assets/css/forms.css new file mode 100644 index 0000000..bced6da --- /dev/null +++ b/front_vue/src/Design/assets/css/forms.css @@ -0,0 +1,112 @@ +/* ============================================ + Общие стили форм + ============================================ */ + +.vaccess-page { + animation: fadeIn var(--transition-slow); +} + +.form-section { + padding: var(--space-xl); + background: rgba(var(--accent-rgb), 0.02); + border-radius: var(--radius-xl); + border: 1px solid var(--glass-border); + transition: all var(--transition-base); +} + +.form-section:hover { + background: rgba(var(--accent-rgb), 0.04); + border-color: rgba(var(--accent-rgb), 0.2); +} + +.settings-form { + display: flex; + flex-direction: column; + gap: var(--space-md); +} + +.form-subsection-title { + font-size: var(--text-lg); + font-weight: var(--font-semibold); + color: var(--text-primary); + margin: 0 0 var(--space-lg) 0; + display: flex; + align-items: center; + gap: var(--space-md); + padding-bottom: var(--space-sm); + border-bottom: 1px solid rgba(var(--accent-rgb), 0.1); +} + +.form-subsection-title i { + color: var(--accent-purple-light); + font-size: 16px; +} + +.form-group { + display: flex; + flex-direction: column; + gap: var(--space-sm); +} + +.form-label { + font-size: 12px; + font-weight: var(--font-semibold); + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.form-label-row { + display: flex; + align-items: center; + gap: var(--space-sm); +} + +.form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-md); +} + +.form-row-3 { + grid-template-columns: 1fr 1fr 1fr; +} + +/* Status toggle buttons */ +.status-toggle { + display: flex; + gap: var(--space-sm); +} + +.status-btn { + flex: 1; + padding: 10px var(--space-md); + background: rgba(var(--muted-rgb), 0.1); + border: 1px solid rgba(var(--muted-rgb), 0.3); + border-radius: var(--radius-md); + color: var(--text-muted); + font-size: var(--text-base); + font-weight: var(--font-semibold); + cursor: pointer; + transition: all var(--transition-base); + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-sm); +} + +.status-btn:hover { + background: rgba(var(--muted-rgb), 0.15); +} + +.status-btn.active { + background: rgba(var(--success-rgb), 0.2); + border-color: rgba(var(--success-rgb), 0.5); + color: var(--accent-green); +} + +.status-btn:last-child.active { + background: rgba(var(--danger-rgb), 0.2); + border-color: rgba(var(--danger-rgb), 0.5); + color: var(--accent-red); +} diff --git a/front_vue/src/Design/assets/css/tables.css b/front_vue/src/Design/assets/css/tables.css new file mode 100644 index 0000000..325bd4b --- /dev/null +++ b/front_vue/src/Design/assets/css/tables.css @@ -0,0 +1,168 @@ +/* ============================================ + Общие стили таблиц + ============================================ */ + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-lg); +} + +.section-title { + font-size: var(--text-md); + font-weight: var(--font-bold); + color: var(--text-primary); + margin: 0; + text-transform: uppercase; + letter-spacing: 1.5px; + display: flex; + align-items: center; + gap: var(--space-lg); +} + +.section-title::before { + content: ''; + width: 4px; + height: 16px; + background: linear-gradient(180deg, var(--accent-purple), var(--accent-purple-light)); + border-radius: 2px; + flex-shrink: 0; +} + +.table-container { + background: var(--glass-bg-light); + backdrop-filter: var(--backdrop-blur); + border: 1px solid var(--glass-border); + border-radius: var(--radius-xl); + overflow: hidden; + box-shadow: var(--shadow-md); +} + +.data-table { + width: 100%; + border-collapse: collapse; +} + +.data-table thead { + background: var(--table-header-bg); +} + +.data-table thead tr { + border-bottom: 1px solid var(--table-border); +} + +.data-table th { + padding: 18px 20px; + text-align: left; + font-size: var(--text-sm); + font-weight: var(--font-bold); + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 1.2px; +} + +.data-table th:last-child { + width: 160px; + text-align: center; +} + +.data-table tbody tr { + border-bottom: 1px solid var(--table-border); + transition: all var(--transition-base); +} + +.data-table tbody tr:hover { + background: var(--table-hover-bg); +} + +.data-table td { + padding: 16px 20px; + font-size: var(--text-base); + color: var(--text-primary); +} + +.data-table td:last-child { + text-align: center; + display: flex; + gap: var(--space-xs); + justify-content: center; + align-items: center; +} + +.data-table code { + font-family: var(--font-mono); + font-size: var(--text-sm); +} + +.clickable-link { + color: var(--link-color); + cursor: pointer; + transition: all var(--transition-base); + display: inline-flex; + align-items: center; + gap: var(--space-xs); +} + +.clickable-link:hover { + color: var(--link-hover-color); + text-decoration: underline; +} + +.clickable-link i { + font-size: var(--text-xs); +} + +/* Cert icons */ +.cert-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + margin-right: 8px; + border-radius: var(--radius-sm); + font-size: 12px; +} + +.cert-valid { + background: rgba(var(--success-rgb), 0.2); + color: var(--accent-green); + border: 1px solid rgba(var(--success-rgb), 0.4); +} + +.cert-expired { + background: rgba(var(--danger-rgb), 0.2); + color: var(--accent-red); + border: 1px solid rgba(var(--danger-rgb), 0.4); +} + +.cert-none { + background: rgba(var(--muted-rgb), 0.15); + color: var(--text-muted); + border: 1px solid rgba(var(--muted-rgb), 0.3); + opacity: 0.5; +} + +/* Icon buttons */ +.icon-btn { + width: 32px; + height: 32px; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; + background: var(--btn-icon-bg); + border: 1px solid var(--btn-icon-border); + border-radius: var(--radius-md); + color: var(--btn-icon-color); + font-size: var(--text-md); + cursor: pointer; + transition: all var(--transition-base); +} + +.icon-btn:hover { + background: var(--btn-icon-hover-bg); + border-color: var(--btn-icon-hover-border); + transform: translateY(-1px); +} diff --git a/front_vue/src/Design/assets/css/themes/dark.css b/front_vue/src/Design/assets/css/themes/dark.css new file mode 100644 index 0000000..84ec903 --- /dev/null +++ b/front_vue/src/Design/assets/css/themes/dark.css @@ -0,0 +1,98 @@ +/* ============================================ + Тёмная тема (по умолчанию) + ============================================ */ + +[data-theme="dark"] { + /* Background */ + --bg-primary: #0b101f; + --bg-secondary: #121420; + --bg-tertiary: #0d0f1c; + + /* Glass Effect */ + --glass-bg: rgba(20, 20, 40, 0.4); + --glass-bg-light: rgba(20, 20, 40, 0.3); + --glass-bg-dark: rgba(10, 14, 26, 0.5); + --glass-border: rgba(139, 92, 246, 0.15); + --glass-border-hover: rgba(139, 92, 246, 0.3); + + /* Accent */ + --accent-blue: #5b21b6; + --accent-blue-light: #7c3aed; + --accent-purple: #8b5cf6; + --accent-purple-light: #a78bfa; + --accent-cyan: #06b6d4; + --accent-green: #10b981; + --accent-red: #ef4444; + --accent-yellow: #f59e0b; + + /* Text */ + --text-primary: #e2e8f0; + --text-secondary: #94a3b8; + --text-muted: #64748b; + + /* Shadows */ + --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3); + --shadow-md: 0 8px 32px rgba(0, 0, 0, 0.5); + --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.7); + --shadow-purple: 0 8px 32px rgba(139, 92, 246, 0.3); + --shadow-green: 0 4px 12px rgba(16, 185, 129, 0.3); + --shadow-red: 0 4px 12px rgba(239, 68, 68, 0.3); + + /* Sidebar */ + --sidebar-bg: rgba(10, 14, 26, 0.95); + --sidebar-border: rgba(139, 92, 246, 0.15); + --nav-color: #94a3b8; + --nav-hover-bg: rgba(139, 92, 246, 0.1); + --nav-hover-color: #a78bfa; + --nav-active-bg: rgba(139, 92, 246, 0.15); + --nav-active-color: #a78bfa; + --nav-indicator: linear-gradient(180deg, #8b5cf6, #a78bfa); + + /* Titlebar */ + --titlebar-bg: rgba(10, 14, 26, 0.5); + --titlebar-border: rgba(139, 92, 246, 0.15); + + /* Tables */ + --table-header-bg: rgba(139, 92, 246, 0.12); + --table-hover-bg: rgba(139, 92, 246, 0.08); + --table-border: rgba(255, 255, 255, 0.05); + + /* Компоненты */ + --card-hover-shadow: 0 8px 32px rgba(139, 92, 246, 0.3); + --card-border-hover: rgba(139, 92, 246, 0.3); + --service-card-gradient: linear-gradient(90deg, #8b5cf6, #a78bfa, #06b6d4); + --btn-icon-bg: rgba(139, 92, 246, 0.1); + --btn-icon-border: rgba(139, 92, 246, 0.3); + --btn-icon-color: #a78bfa; + --btn-icon-hover-bg: rgba(139, 92, 246, 0.25); + --btn-icon-hover-border: rgba(139, 92, 246, 0.5); + --btn-primary-bg: rgba(139, 92, 246, 0.15); + --btn-primary-border: rgba(139, 92, 246, 0.3); + --btn-primary-color: #a78bfa; + --btn-primary-hover-bg: rgba(139, 92, 246, 0.25); + --btn-primary-hover-border: rgba(139, 92, 246, 0.5); + --cert-tag-bg: rgba(139, 92, 246, 0.15); + --cert-tag-color: #a78bfa; + --link-color: #a78bfa; + --link-hover-color: #8b5cf6; + + /* Scrollbar */ + --scrollbar-bg: rgba(20, 20, 40, 0.3); + --scrollbar-thumb: rgba(139, 92, 246, 0.3); + + /* RGB base — для alpha-композитинга: rgba(var(--x-rgb), 0.15) */ + --accent-rgb: 139, 92, 246; + --success-rgb: 16, 185, 129; + --danger-rgb: 239, 68, 68; + --warning-rgb: 245, 158, 11; + --info-rgb: 6, 182, 212; + --muted-rgb: 100, 116, 139; + + /* Utility */ + --overlay-bg: rgba(0, 0, 0, 0.6); + --selection-bg: rgba(139, 92, 246, 0.3); + --input-focus-shadow: 0 0 0 2px rgba(139, 92, 246, 0.15); + --subtle-overlay: rgba(255, 255, 255, 0.02); + --divider-subtle: rgba(255, 255, 255, 0.1); + --warning-icon-color: rgba(251, 191, 36, 0.9); +} diff --git a/front_vue/src/Design/assets/css/themes/light.css b/front_vue/src/Design/assets/css/themes/light.css new file mode 100644 index 0000000..573d6aa --- /dev/null +++ b/front_vue/src/Design/assets/css/themes/light.css @@ -0,0 +1,98 @@ +/* ============================================ + Светлая тема — мягкая, нейтральная палитра + ============================================ */ + +[data-theme="light"] { + /* Background */ + --bg-primary: #f8fafc; + --bg-secondary: #ffffff; + --bg-tertiary: #f1f5f9; + + /* Glass Effect — нейтральные серые */ + --glass-bg: rgba(255, 255, 255, 0.8); + --glass-bg-light: rgba(255, 255, 255, 0.6); + --glass-bg-dark: rgba(248, 250, 252, 0.9); + --glass-border: rgba(226, 232, 240, 1); + --glass-border-hover: rgba(203, 213, 225, 1); + + /* Accent — нейтральный slate */ + --accent-blue: #334155; + --accent-blue-light: #475569; + --accent-purple: #334155; + --accent-purple-light: #475569; + --accent-cyan: #0891b2; + --accent-green: #16a34a; + --accent-red: #dc2626; + --accent-yellow: #d97706; + + /* Text */ + --text-primary: #1e293b; + --text-secondary: #475569; + --text-muted: #94a3b8; + + /* Shadows — мягкие без цвета */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.1); + --shadow-purple: 0 2px 8px rgba(0, 0, 0, 0.08); + --shadow-green: 0 2px 8px rgba(0, 0, 0, 0.06); + --shadow-red: 0 2px 8px rgba(0, 0, 0, 0.06); + + /* Sidebar */ + --sidebar-bg: #ffffff; + --sidebar-border: #e2e8f0; + --nav-color: #94a3b8; + --nav-hover-bg: #f1f5f9; + --nav-hover-color: #475569; + --nav-active-bg: #f1f5f9; + --nav-active-color: #1e293b; + --nav-indicator: linear-gradient(180deg, #475569, #64748b); + + /* Titlebar */ + --titlebar-bg: #ffffff; + --titlebar-border: #e2e8f0; + + /* Tables */ + --table-header-bg: #f8fafc; + --table-hover-bg: #f8fafc; + --table-border: #f1f5f9; + + /* Компоненты — нейтральные акценты */ + --card-hover-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + --card-border-hover: #cbd5e1; + --service-card-gradient: linear-gradient(90deg, #64748b, #94a3b8, #cbd5e1); + --btn-icon-bg: transparent; + --btn-icon-border: transparent; + --btn-icon-color: #94a3b8; + --btn-icon-hover-bg: #e2e8f0; + --btn-icon-hover-border: #cbd5e1; + --btn-primary-bg: #475569; + --btn-primary-border: #475569; + --btn-primary-color: #ffffff; + --btn-primary-hover-bg: #334155; + --btn-primary-hover-border: #1e293b; + --cert-tag-bg: rgba(241, 245, 249, 1); + --cert-tag-color: #475569; + --link-color: #334155; + --link-hover-color: #1e293b; + + /* Scrollbar */ + --scrollbar-bg: #f1f5f9; + --scrollbar-thumb: #cbd5e1; + + /* RGB base — для alpha-композитинга: rgba(var(--x-rgb), 0.15) */ + --accent-rgb: 51, 65, 85; + --success-rgb: 22, 163, 74; + --danger-rgb: 220, 38, 38; + --warning-rgb: 217, 119, 6; + --info-rgb: 8, 145, 178; + --muted-rgb: 100, 116, 139; + + /* Utility */ + --overlay-bg: rgba(0, 0, 0, 0.5); + --selection-bg: rgba(51, 65, 85, 0.15); + --input-focus-shadow: 0 0 0 2px rgba(51, 65, 85, 0.12); + --subtle-overlay: rgba(0, 0, 0, 0.02); + --divider-subtle: rgba(0, 0, 0, 0.06); + --warning-icon-color: rgba(217, 119, 6, 0.9); +} diff --git a/front_vue/src/Design/assets/css/transitions.css b/front_vue/src/Design/assets/css/transitions.css new file mode 100644 index 0000000..81a6086 --- /dev/null +++ b/front_vue/src/Design/assets/css/transitions.css @@ -0,0 +1,77 @@ +/* ============================================ + Vue Transitions + ============================================ */ + +/* Fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity var(--transition-base); +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +/* Slide Up */ +.slide-up-enter-active, +.slide-up-leave-active { + transition: all var(--transition-slow); +} + +.slide-up-enter-from { + opacity: 0; + transform: translateY(20px); +} + +.slide-up-leave-to { + opacity: 0; + transform: translateY(-10px); +} + +/* Slide Right */ +.slide-right-enter-active, +.slide-right-leave-active { + transition: all var(--transition-slow); +} + +.slide-right-enter-from { + opacity: 0; + transform: translateX(-20px); +} + +.slide-right-leave-to { + opacity: 0; + transform: translateX(20px); +} + +/* Scale */ +.scale-enter-active, +.scale-leave-active { + transition: all var(--transition-slow); +} + +.scale-enter-from, +.scale-leave-to { + opacity: 0; + transform: scale(0.95); +} + +/* Notification slide */ +.notification-enter-active { + transition: all 0.3s ease-out; +} + +.notification-leave-active { + transition: all 0.2s ease-in; +} + +.notification-enter-from { + opacity: 0; + transform: translateX(100%); +} + +.notification-leave-to { + opacity: 0; + transform: translateX(100%); +} diff --git a/front_vue/src/Design/assets/css/variables.css b/front_vue/src/Design/assets/css/variables.css new file mode 100644 index 0000000..884db87 --- /dev/null +++ b/front_vue/src/Design/assets/css/variables.css @@ -0,0 +1,62 @@ +/* ============================================ + CSS Design Tokens — общие для всех тем + ============================================ */ + +:root { + /* Spacing */ + --space-xs: 4px; + --space-sm: 8px; + --space-md: 16px; + --space-lg: 24px; + --space-xl: 32px; + --space-2xl: 48px; + --space-3xl: 60px; + + /* Border Radius */ + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + --radius-full: 50%; + + /* Transitions */ + --transition-fast: 0.15s ease; + --transition-base: 0.2s ease; + --transition-slow: 0.3s ease; + --transition-bounce: 0.3s cubic-bezier(0.4, 0, 0.2, 1); + + /* Typography */ + --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + --font-mono: 'Consolas', 'Courier New', monospace; + + /* Font Sizes */ + --text-xs: 10px; + --text-sm: 11px; + --text-base: 13px; + --text-md: 14px; + --text-lg: 16px; + --text-xl: 18px; + --text-2xl: 20px; + --text-3xl: 28px; + + /* Font Weights */ + --font-normal: 400; + --font-medium: 500; + --font-semibold: 600; + --font-bold: 700; + + /* Z-Index Scale */ + --z-base: 1; + --z-dropdown: 100; + --z-modal: 9998; + --z-notification: 9999; + --z-loader: 10000; + + /* Layout */ + --header-height: 60px; + --sidebar-width: 80px; + + /* Backdrop Filter */ + --backdrop-blur: blur(20px) saturate(180%); + --backdrop-blur-light: blur(10px); +} diff --git a/front_vue/src/Design/components/certs/CertCard.vue b/front_vue/src/Design/components/certs/CertCard.vue new file mode 100644 index 0000000..88a9a1a --- /dev/null +++ b/front_vue/src/Design/components/certs/CertCard.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/certs/CertGrid.vue b/front_vue/src/Design/components/certs/CertGrid.vue new file mode 100644 index 0000000..adc81fd --- /dev/null +++ b/front_vue/src/Design/components/certs/CertGrid.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/layout/AppFooter.vue b/front_vue/src/Design/components/layout/AppFooter.vue new file mode 100644 index 0000000..6af5c97 --- /dev/null +++ b/front_vue/src/Design/components/layout/AppFooter.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/front_vue/src/Design/components/layout/Breadcrumbs.vue b/front_vue/src/Design/components/layout/Breadcrumbs.vue new file mode 100644 index 0000000..5e5fd4d --- /dev/null +++ b/front_vue/src/Design/components/layout/Breadcrumbs.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/front_vue/src/Design/components/layout/PageHeader.vue b/front_vue/src/Design/components/layout/PageHeader.vue new file mode 100644 index 0000000..2208e68 --- /dev/null +++ b/front_vue/src/Design/components/layout/PageHeader.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/front_vue/src/Design/components/layout/Sidebar.vue b/front_vue/src/Design/components/layout/Sidebar.vue new file mode 100644 index 0000000..62bf678 --- /dev/null +++ b/front_vue/src/Design/components/layout/Sidebar.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/front_vue/src/Design/components/layout/TitleBar.vue b/front_vue/src/Design/components/layout/TitleBar.vue new file mode 100644 index 0000000..7690b8b --- /dev/null +++ b/front_vue/src/Design/components/layout/TitleBar.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/front_vue/src/Design/components/proxies/ProxiesTable.vue b/front_vue/src/Design/components/proxies/ProxiesTable.vue new file mode 100644 index 0000000..f66491b --- /dev/null +++ b/front_vue/src/Design/components/proxies/ProxiesTable.vue @@ -0,0 +1,94 @@ + + + diff --git a/front_vue/src/Design/components/proxies/ProxyEditModal.vue b/front_vue/src/Design/components/proxies/ProxyEditModal.vue new file mode 100644 index 0000000..3e64cbd --- /dev/null +++ b/front_vue/src/Design/components/proxies/ProxyEditModal.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/proxies/ProxyForm.vue b/front_vue/src/Design/components/proxies/ProxyForm.vue new file mode 100644 index 0000000..3e64cbd --- /dev/null +++ b/front_vue/src/Design/components/proxies/ProxyForm.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/services/ServiceCard.vue b/front_vue/src/Design/components/services/ServiceCard.vue new file mode 100644 index 0000000..e973913 --- /dev/null +++ b/front_vue/src/Design/components/services/ServiceCard.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/front_vue/src/Design/components/services/ServicesGrid.vue b/front_vue/src/Design/components/services/ServicesGrid.vue new file mode 100644 index 0000000..53cf8e8 --- /dev/null +++ b/front_vue/src/Design/components/services/ServicesGrid.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/front_vue/src/Design/components/services/test.txt b/front_vue/src/Design/components/services/test.txt new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/front_vue/src/Design/components/services/test.txt @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/front_vue/src/Design/components/sites/SiteEditModal.vue b/front_vue/src/Design/components/sites/SiteEditModal.vue new file mode 100644 index 0000000..3e64cbd --- /dev/null +++ b/front_vue/src/Design/components/sites/SiteEditModal.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/sites/SiteForm.vue b/front_vue/src/Design/components/sites/SiteForm.vue new file mode 100644 index 0000000..3e64cbd --- /dev/null +++ b/front_vue/src/Design/components/sites/SiteForm.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/sites/SitesTable.vue b/front_vue/src/Design/components/sites/SitesTable.vue new file mode 100644 index 0000000..f12c8f4 --- /dev/null +++ b/front_vue/src/Design/components/sites/SitesTable.vue @@ -0,0 +1,110 @@ + + + diff --git a/front_vue/src/Design/components/ui/SslUploadSection.vue b/front_vue/src/Design/components/ui/SslUploadSection.vue new file mode 100644 index 0000000..9d13962 --- /dev/null +++ b/front_vue/src/Design/components/ui/SslUploadSection.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VBadge.vue b/front_vue/src/Design/components/ui/VBadge.vue new file mode 100644 index 0000000..8373a74 --- /dev/null +++ b/front_vue/src/Design/components/ui/VBadge.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VButton.vue b/front_vue/src/Design/components/ui/VButton.vue new file mode 100644 index 0000000..907b306 --- /dev/null +++ b/front_vue/src/Design/components/ui/VButton.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VCard.vue b/front_vue/src/Design/components/ui/VCard.vue new file mode 100644 index 0000000..70ad4f4 --- /dev/null +++ b/front_vue/src/Design/components/ui/VCard.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VFileUpload.vue b/front_vue/src/Design/components/ui/VFileUpload.vue new file mode 100644 index 0000000..6484205 --- /dev/null +++ b/front_vue/src/Design/components/ui/VFileUpload.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VInput.vue b/front_vue/src/Design/components/ui/VInput.vue new file mode 100644 index 0000000..8b6255b --- /dev/null +++ b/front_vue/src/Design/components/ui/VInput.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VLoader.vue b/front_vue/src/Design/components/ui/VLoader.vue new file mode 100644 index 0000000..ace69e1 --- /dev/null +++ b/front_vue/src/Design/components/ui/VLoader.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VModal.vue b/front_vue/src/Design/components/ui/VModal.vue new file mode 100644 index 0000000..a7b1c71 --- /dev/null +++ b/front_vue/src/Design/components/ui/VModal.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VNotification.vue b/front_vue/src/Design/components/ui/VNotification.vue new file mode 100644 index 0000000..707ada1 --- /dev/null +++ b/front_vue/src/Design/components/ui/VNotification.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VSelect.vue b/front_vue/src/Design/components/ui/VSelect.vue new file mode 100644 index 0000000..e4842e0 --- /dev/null +++ b/front_vue/src/Design/components/ui/VSelect.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VTable.vue b/front_vue/src/Design/components/ui/VTable.vue new file mode 100644 index 0000000..e90a53b --- /dev/null +++ b/front_vue/src/Design/components/ui/VTable.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VToggle.vue b/front_vue/src/Design/components/ui/VToggle.vue new file mode 100644 index 0000000..8056c42 --- /dev/null +++ b/front_vue/src/Design/components/ui/VToggle.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/front_vue/src/Design/components/ui/VTooltip.vue b/front_vue/src/Design/components/ui/VTooltip.vue new file mode 100644 index 0000000..12e13fa --- /dev/null +++ b/front_vue/src/Design/components/ui/VTooltip.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/front_vue/src/Design/components/vaccess/FieldEditor.vue b/front_vue/src/Design/components/vaccess/FieldEditor.vue new file mode 100644 index 0000000..4457751 --- /dev/null +++ b/front_vue/src/Design/components/vaccess/FieldEditor.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/vaccess/VAccessHelp.vue b/front_vue/src/Design/components/vaccess/VAccessHelp.vue new file mode 100644 index 0000000..a95d3b3 --- /dev/null +++ b/front_vue/src/Design/components/vaccess/VAccessHelp.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/vaccess/VAccessRuleRow.vue b/front_vue/src/Design/components/vaccess/VAccessRuleRow.vue new file mode 100644 index 0000000..61f01a1 --- /dev/null +++ b/front_vue/src/Design/components/vaccess/VAccessRuleRow.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/components/vaccess/VAccessRulesTable.vue b/front_vue/src/Design/components/vaccess/VAccessRulesTable.vue new file mode 100644 index 0000000..d651aee --- /dev/null +++ b/front_vue/src/Design/components/vaccess/VAccessRulesTable.vue @@ -0,0 +1 @@ +`n diff --git a/front_vue/src/Design/layouts/MainLayout.vue b/front_vue/src/Design/layouts/MainLayout.vue new file mode 100644 index 0000000..293e458 --- /dev/null +++ b/front_vue/src/Design/layouts/MainLayout.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/front_vue/src/Design/views/CertManagerView.vue b/front_vue/src/Design/views/CertManagerView.vue new file mode 100644 index 0000000..cac5759 --- /dev/null +++ b/front_vue/src/Design/views/CertManagerView.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/front_vue/src/Design/views/DashboardView.vue b/front_vue/src/Design/views/DashboardView.vue new file mode 100644 index 0000000..3b06b05 --- /dev/null +++ b/front_vue/src/Design/views/DashboardView.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/front_vue/src/Design/views/ProxyCreateView.vue b/front_vue/src/Design/views/ProxyCreateView.vue new file mode 100644 index 0000000..7ef075e --- /dev/null +++ b/front_vue/src/Design/views/ProxyCreateView.vue @@ -0,0 +1,72 @@ + + + diff --git a/front_vue/src/Design/views/ProxyEditView.vue b/front_vue/src/Design/views/ProxyEditView.vue new file mode 100644 index 0000000..8596370 --- /dev/null +++ b/front_vue/src/Design/views/ProxyEditView.vue @@ -0,0 +1,109 @@ + + + diff --git a/front_vue/src/Design/views/SettingsView.vue b/front_vue/src/Design/views/SettingsView.vue new file mode 100644 index 0000000..6a00d7f --- /dev/null +++ b/front_vue/src/Design/views/SettingsView.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/front_vue/src/Design/views/SiteCreateView.vue b/front_vue/src/Design/views/SiteCreateView.vue new file mode 100644 index 0000000..e2a7ebb --- /dev/null +++ b/front_vue/src/Design/views/SiteCreateView.vue @@ -0,0 +1,89 @@ + + + diff --git a/front_vue/src/Design/views/SiteEditView.vue b/front_vue/src/Design/views/SiteEditView.vue new file mode 100644 index 0000000..3d26f97 --- /dev/null +++ b/front_vue/src/Design/views/SiteEditView.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/front_vue/src/Design/views/VAccessView.vue b/front_vue/src/Design/views/VAccessView.vue new file mode 100644 index 0000000..232cf8f --- /dev/null +++ b/front_vue/src/Design/views/VAccessView.vue @@ -0,0 +1,548 @@ + + + + + diff --git a/front_vue/src/main.js b/front_vue/src/main.js new file mode 100644 index 0000000..466718b --- /dev/null +++ b/front_vue/src/main.js @@ -0,0 +1,22 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import router from '@core/router/index.js' +import i18n from '@core/i18n/index.js' +import App from './App.vue' + +import '@design/assets/css/variables.css' +import '@design/assets/css/themes/dark.css' +import '@design/assets/css/themes/light.css' +import '@design/assets/css/base.css' +import '@design/assets/css/forms.css' +import '@design/assets/css/tables.css' +import '@design/assets/css/transitions.css' +import '@fortawesome/fontawesome-free/css/all.min.css' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(i18n) + +app.mount('#app') diff --git a/front_vue/vite.config.js b/front_vue/vite.config.js new file mode 100644 index 0000000..20eccca --- /dev/null +++ b/front_vue/vite.config.js @@ -0,0 +1,51 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [ + vue(), + + AutoImport({ + imports: [ + 'vue', + 'vue-router', + 'vue-i18n', + 'pinia', + ], + dirs: [ + 'src/Core/composables', + 'src/Core/stores', + ], + vueTemplate: true, + dts: 'src/auto-imports.d.ts', + }), + + Components({ + dirs: [ + 'src/Design/components/ui', + 'src/Design/components/layout', + 'src/Design/components/services', + 'src/Design/components/sites', + 'src/Design/components/proxies', + 'src/Design/components/vaccess', + 'src/Design/components/certs', + ], + dts: 'src/components.d.ts', + }), + ], + + server: { + port: 4444, + }, + + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + '@core': resolve(__dirname, 'src/Core'), + '@design': resolve(__dirname, 'src/Design'), + }, + }, +})