From 2cf748fa36540a08474b214047c29787364d14b8 Mon Sep 17 00:00:00 2001 From: karim gabriele varano Date: Sat, 9 May 2026 01:53:15 +0200 Subject: [PATCH] =?UTF-8?q?Initial=20commit=20=E2=80=94=20RAPPORT=20App=20?= =?UTF-8?q?(Stand=20Mai=202026)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 27 + README.md | 16 + eslint.config.js | 21 + index.html | 14 + package-lock.json | 2703 +++++++++++++ package.json | 29 + public/erste-schritte.html | 179 + public/favicon.svg | 1 + public/icons.svg | 24 + src-tauri/.gitignore | 4 + src-tauri/Cargo.lock | 5295 +++++++++++++++++++++++++ src-tauri/Cargo.toml | 25 + src-tauri/build.rs | 3 + src-tauri/capabilities/default.json | 12 + src-tauri/icons/128x128.png | Bin 0 -> 11059 bytes src-tauri/icons/128x128@2x.png | Bin 0 -> 23137 bytes src-tauri/icons/32x32.png | Bin 0 -> 2225 bytes src-tauri/icons/Square107x107Logo.png | Bin 0 -> 9202 bytes src-tauri/icons/Square142x142Logo.png | Bin 0 -> 12530 bytes src-tauri/icons/Square150x150Logo.png | Bin 0 -> 13032 bytes src-tauri/icons/Square284x284Logo.png | Bin 0 -> 25943 bytes src-tauri/icons/Square30x30Logo.png | Bin 0 -> 2078 bytes src-tauri/icons/Square310x310Logo.png | Bin 0 -> 28507 bytes src-tauri/icons/Square44x44Logo.png | Bin 0 -> 3419 bytes src-tauri/icons/Square71x71Logo.png | Bin 0 -> 6027 bytes src-tauri/icons/Square89x89Logo.png | Bin 0 -> 7551 bytes src-tauri/icons/StoreLogo.png | Bin 0 -> 3971 bytes src-tauri/icons/icon.icns | Bin 0 -> 64413 bytes src-tauri/icons/icon.ico | Bin 0 -> 37710 bytes src-tauri/icons/icon.png | Bin 0 -> 49979 bytes src-tauri/src/lib.rs | 16 + src-tauri/src/main.rs | 6 + src-tauri/tauri.conf.json | 37 + src/App.css | 184 + src/App.jsx | 684 ++++ src/App.jsx.bak | 451 +++ src/assets/hero.png | Bin 0 -> 13057 bytes src/assets/react.svg | 1 + src/assets/vite.svg | 1 + src/components/UI.jsx | 469 +++ src/components/UI.jsx.bak | 444 +++ src/constants.js | 252 ++ src/index.css | 3 + src/main.jsx | 10 + src/print/PrintComponents.jsx | 1686 ++++++++ src/utils.js | 540 +++ src/views/Buchhaltung.jsx | 374 ++ src/views/Clients.jsx | 452 +++ src/views/Contacts.jsx | 456 +++ src/views/Dashboard.jsx | 762 ++++ src/views/Dashboard.jsx.bak | 252 ++ src/views/Dokumente.jsx | 194 + src/views/Invoices.jsx | 1467 +++++++ src/views/Letters.jsx | 114 + src/views/Lieferscheine.jsx | 294 ++ src/views/Loehne.jsx | 344 ++ src/views/Login.jsx | 148 + src/views/MigrationScreen.jsx | 141 + src/views/Mitarbeiter.jsx | 1284 ++++++ src/views/Personen.jsx | 682 ++++ src/views/Pinnwand.jsx | 417 ++ src/views/Projects.jsx | 1781 +++++++++ src/views/Protokolle.jsx | 978 +++++ src/views/Quotes.jsx | 980 +++++ src/views/Settings.jsx | 840 ++++ src/views/Setup.jsx | 416 ++ src/views/Spesen.jsx | 914 +++++ src/views/StudioBudget.jsx | 847 ++++ src/views/Time.jsx | 1494 +++++++ vite.config.js | 7 + 70 files changed, 28775 insertions(+) create mode 100755 .gitignore create mode 100755 README.md create mode 100755 eslint.config.js create mode 100755 index.html create mode 100755 package-lock.json create mode 100755 package.json create mode 100755 public/erste-schritte.html create mode 100755 public/favicon.svg create mode 100755 public/icons.svg create mode 100755 src-tauri/.gitignore create mode 100755 src-tauri/Cargo.lock create mode 100755 src-tauri/Cargo.toml create mode 100755 src-tauri/build.rs create mode 100755 src-tauri/capabilities/default.json create mode 100755 src-tauri/icons/128x128.png create mode 100755 src-tauri/icons/128x128@2x.png create mode 100755 src-tauri/icons/32x32.png create mode 100755 src-tauri/icons/Square107x107Logo.png create mode 100755 src-tauri/icons/Square142x142Logo.png create mode 100755 src-tauri/icons/Square150x150Logo.png create mode 100755 src-tauri/icons/Square284x284Logo.png create mode 100755 src-tauri/icons/Square30x30Logo.png create mode 100755 src-tauri/icons/Square310x310Logo.png create mode 100755 src-tauri/icons/Square44x44Logo.png create mode 100755 src-tauri/icons/Square71x71Logo.png create mode 100755 src-tauri/icons/Square89x89Logo.png create mode 100755 src-tauri/icons/StoreLogo.png create mode 100755 src-tauri/icons/icon.icns create mode 100755 src-tauri/icons/icon.ico create mode 100755 src-tauri/icons/icon.png create mode 100755 src-tauri/src/lib.rs create mode 100755 src-tauri/src/main.rs create mode 100755 src-tauri/tauri.conf.json create mode 100755 src/App.css create mode 100755 src/App.jsx create mode 100755 src/App.jsx.bak create mode 100755 src/assets/hero.png create mode 100755 src/assets/react.svg create mode 100755 src/assets/vite.svg create mode 100755 src/components/UI.jsx create mode 100755 src/components/UI.jsx.bak create mode 100755 src/constants.js create mode 100755 src/index.css create mode 100755 src/main.jsx create mode 100755 src/print/PrintComponents.jsx create mode 100755 src/utils.js create mode 100755 src/views/Buchhaltung.jsx create mode 100755 src/views/Clients.jsx create mode 100755 src/views/Contacts.jsx create mode 100755 src/views/Dashboard.jsx create mode 100755 src/views/Dashboard.jsx.bak create mode 100755 src/views/Dokumente.jsx create mode 100755 src/views/Invoices.jsx create mode 100755 src/views/Letters.jsx create mode 100755 src/views/Lieferscheine.jsx create mode 100755 src/views/Loehne.jsx create mode 100755 src/views/Login.jsx create mode 100644 src/views/MigrationScreen.jsx create mode 100755 src/views/Mitarbeiter.jsx create mode 100755 src/views/Personen.jsx create mode 100755 src/views/Pinnwand.jsx create mode 100755 src/views/Projects.jsx create mode 100755 src/views/Protokolle.jsx create mode 100755 src/views/Quotes.jsx create mode 100755 src/views/Settings.jsx create mode 100755 src/views/Setup.jsx create mode 100755 src/views/Spesen.jsx create mode 100755 src/views/StudioBudget.jsx create mode 100755 src/views/Time.jsx create mode 100755 vite.config.js diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..245445d --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Claude Code +.claude/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100755 index 0000000..a36934d --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/eslint.config.js b/eslint.config.js new file mode 100755 index 0000000..ea36dd3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,21 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + globals: globals.browser, + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + }, +]) diff --git a/index.html b/index.html new file mode 100755 index 0000000..12ab3c7 --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + rapportv01 + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100755 index 0000000..8a5f1c1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2703 @@ +{ + "name": "rapportv01", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "rapportv01", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.5", + "react-dom": "^19.2.5" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@tauri-apps/api": "^2.10.1", + "@tauri-apps/cli": "^2.10.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.2.1", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.5.0", + "vite": "^8.0.10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "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==", + "dev": true, + "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-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tauri-apps/api": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", + "integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz", + "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.10.1", + "@tauri-apps/cli-darwin-x64": "2.10.1", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", + "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", + "@tauri-apps/cli-linux-arm64-musl": "2.10.1", + "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-musl": "2.10.1", + "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", + "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", + "@tauri-apps/cli-win32-x64-msvc": "2.10.1" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz", + "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz", + "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz", + "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz", + "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz", + "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz", + "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz", + "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz", + "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz", + "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz", + "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz", + "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "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/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz", + "integrity": "sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001790", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", + "integrity": "sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.344", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", + "integrity": "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "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/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", + "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "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==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "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==", + "dev": true, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "dev": true, + "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/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.5" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" + }, + "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", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100755 index 0000000..673246b --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "rapportv01", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.5", + "react-dom": "^19.2.5" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@tauri-apps/api": "^2.10.1", + "@tauri-apps/cli": "^2.10.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.2.1", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.5.0", + "vite": "^8.0.10" + } +} diff --git a/public/erste-schritte.html b/public/erste-schritte.html new file mode 100755 index 0000000..2271495 --- /dev/null +++ b/public/erste-schritte.html @@ -0,0 +1,179 @@ + + + + + + Erste Schritte — Rapport + + + + + + + + + +

Erste Schritte

+

Rapport ist eine lokale Studio-Administrationssoftware für Architekturbüros. Alle Daten bleiben auf deinem Gerät — kein Server, kein Login.

+ +
+ +
+
1
+
+
Einstellungen konfigurieren
+
Bevor du beginnst, trage die Stammdaten deines Studios ein. Diese erscheinen auf allen Dokumenten und Rechnungen.
+
+
Studio-NameErscheint in der Sidebar und auf Druckdokumenten
+
IBANFür den QR-Einzahlungsschein auf Rechnungen (QR-IBAN empfohlen)
+
MwSt-SatzStandardmässig 8.1 %
+
StundensätzePro Rolle, werden für Honorarberechnungen verwendet
+
+
+
+ +
+
2
+
+
Ersten Kunden anlegen
+
Unter Personen kannst du Kunden und Kontakte verwalten. Kunden werden mit Projekten und Rechnungen verknüpft. Name und Adresse sind für Dokumente erforderlich.
+
+
+ +
+
3
+
+
Mitarbeiter erfassen
+
Unter Mitarbeiter legst du dein Team an. Wichtig sind Pensum, Wochenstunden und Eintrittsdatum — diese fliessen in die Zeiterfassung und Lohnabrechnung ein.
+
+
+ +
+
4
+
+
Erstes Projekt erstellen
+
Unter Projekte erfasst du dein Bauvorhaben. Vergib eine Projektnummer, wähle den Auftraggeber und setze den Status. Optional kannst du eine Offerte verknüpfen, um das Stundenbudget abzuleiten.
+
+
SIA-PhasenAktiviere nur die für das Projekt relevanten Phasen
+
AbrechnungsartStundenbasis oder Pauschal
+
+
+
+ +
+
5
+
+
Zeit erfassen
+
Unter Zeiterfassung buchst du Stunden auf Projekte und Phasen. Die Wochenansicht erlaubt das visuelle Planen per Drag & Drop. Der Monatssaldo zeigt jederzeit Stand bis heute.
+
+
+ +
+
6
+
+
Erste Rechnung stellen
+
Unter Rechnungen erstellst du Rechnungen mit Positionen, MwSt und QR-Einzahlungsschein. Rechnungen lassen sich als PDF drucken und mit einem Status versehen (Entwurf → Gesendet → Bezahlt).
+
+
+ +
+ +
+
Datenspeicherung
+

Alle Daten werden ausschliesslich lokal im Browser gespeichert (localStorage). Es gibt keinen Server, keine Cloud, keine Synchronisation. Erstelle regelmässig ein Backup über Einstellungen → Datenbank exportieren.

+
+ +
+ Lokal gespeichert + Kein Login erforderlich + SIA 102 Honorare + QR-Rechnung + Lohnabrechnung + PDF-Export + Zeiterfassung + AGPL-3.0 +
+ + + + + diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100755 index 0000000..6893eb1 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/icons.svg b/public/icons.svg new file mode 100755 index 0000000..e952219 --- /dev/null +++ b/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100755 index 0000000..502406b --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,4 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +/gen/schemas diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100755 index 0000000..bd50df6 --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,5295 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "app" +version = "0.2.0" +dependencies = [ + "log", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-log", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-unit" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" +dependencies = [ + "rust_decimal", + "schemars 1.2.1", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.11.1", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.29.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "matches", + "phf 0.10.1", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.13.1", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.1", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser 0.36.0", + "foldhash 0.2.0", + "html5ever 0.38.0", + "precomputed-hash", + "selectors 0.36.1", + "tendril 0.5.0", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.2+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fern" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" +dependencies = [ + "log", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.11.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever 0.14.1", + "match_token", +] + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever 0.38.0", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "js-sys" +version = "0.3.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.11.1", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kuchikiki" +version = "0.8.8-speedreader" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" +dependencies = [ + "cssparser 0.29.6", + "html5ever 0.29.1", + "indexmap 2.14.0", + "selectors 0.24.0", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "libc", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +dependencies = [ + "value-bag", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache 0.8.9", + "string_cache_codegen 0.5.4", + "tendril 0.4.3", +] + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril 0.5.0", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "muda" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9fec5a4e89860383d778d10563a605838f8f0b2f9303868937e5ff32e86177" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 2.0.18", + "windows-sys 0.60.2", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.11.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.11.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared 0.8.0", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros 0.13.1", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.6", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.6", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.2", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher 1.0.2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +dependencies = [ + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.11+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quick-xml" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.6", + "rkyv", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.117", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "selectors" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +dependencies = [ + "bitflags 1.3.2", + "cssparser 0.29.6", + "derive_more 0.99.20", + "fxhash", + "log", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc 0.2.0", + "smallvec", +] + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.11.1", + "cssparser 0.36.0", + "derive_more 2.1.1", + "log", + "new_debug_unreachable", + "phf 0.13.1", + "phf_codegen 0.13.1", + "precomputed-hash", + "rustc-hash", + "servo_arc 0.4.3", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "servo_arc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.13.1", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.34.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" +dependencies = [ + "bitflags 2.11.1", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "parking_lot", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.18", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml 0.9.12+spec-1.1.0", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.117", + "tauri-utils", + "thiserror 2.0.18", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "toml 0.9.12+spec-1.1.0", + "walkdir", +] + +[[package]] +name = "tauri-plugin-log" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7545bd67f070a4500432c826e2e0682146a1d6712aee22a2786490156b574d93" +dependencies = [ + "android_logger", + "byte-unit", + "fern", + "log", + "objc2", + "objc2-foundation", + "serde", + "serde_json", + "serde_repr", + "swift-rs", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "tauri-runtime" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever 0.29.1", + "http", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "tendril" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +dependencies = [ + "new_debug_unreachable", + "utf-8", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.2", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.2", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.2", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 2.0.18", + "windows-sys 0.60.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" +dependencies = [ + "phf 0.13.1", + "phf_codegen 0.13.1", + "string_cache 0.9.0", + "string_cache_codegen 0.6.1", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.14.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.54.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "javascriptcore-rs", + "jni", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100755 index 0000000..980baf0 --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "app" +version = "0.2.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.77.2" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2.5.6", features = [] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +log = "0.4" +tauri = { version = "2.10.3", features = [] } +tauri-plugin-log = "2" diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100755 index 0000000..795b9b7 --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100755 index 0000000..5203780 --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,12 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "core:webview:allow-print" + ] +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100755 index 0000000000000000000000000000000000000000..77e7d2338e9d8ccffc731198dc584906627c903f GIT binary patch literal 11059 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 IM6N<$g7Cm5Jpcdz literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100755 index 0000000000000000000000000000000000000000..dc2b22cea563cca761896877ed8d72502c8fa241 GIT binary patch literal 13032 zcmVP)bMO1Ub7vAjATv96H#=bt3<_Dy|~1imM2$;wr8pu!^e)tl}yHtGJ4*2(02N0;{-+z$&id za&bw;Ey#UQivJP;9yEuS*)~3G=g%Ur-s>Pj9HoJTfM7OZ1|zm#jSPOJ2? zF|uq0iC`U5hW0z7^yu%IK$1G`X-g{mo1)UIJG!J7xA&;)oBHKFeHt}IkcnP^mjocQ zP}mi)BrB%Pz(Tcz=bivC85Sj#KIS>IT0duAP3p2~<=S}_eq%flEe9O%dwkdy{>u+O zD|;!eQbn#ZQK<@P9cc(wb4=d0rBi+8#UsAQU+a`ML^Xk^@OfT|OR<7fmG5a_A)w&U z>^K}QN{i{``f1C?4qQ8LRPu^QfYou#FaQyw2qH!ufC$8~x#(a%Gi|_I83P_wAcr+R z0I)4l&+97>`yPJokoUp;y;6$^c9~DMQL_{jz}}O<%GggaoiYVX=!Lb(^FGuN|MK)o z?INy(OiC<FvAzCZY;Bje<3;#oOR{X| zx{AOWVc!=eM8X7{9L{g?=;YF?ru2Vra)q{tpD+T-Cgw1J>0M9;k_kY@C7JBV$#q8p z4?VCm{Qq9>5cm23_;52wfG)ELtdSw5Q0-YUU9e9rHzs^;TJ)#0Y7-yg{yx}Nndgk4 zOXk!DvJ+H6fQk0s8-qW;e|zw|?QtOy@-VQ!Kzi9DQ+kOFb0?kjpaT0zP8b46B1%3p zJ@&P4&F*=8R79I<>4IegjUYHi^+=0CaLNOXImW077bi}tOwPM#OzN6`Q*PScrR)Go zgUEto;1_{4oG0TPjuh2I^VD+I@S_FY|5!3U_9;*=0v?t)G6D5=(pKOS%oI$o#3BpE z4qQ1gVmE9CPqHsXb+2s8pxQ?ixK7$wAszuwzIx8Imb+i1{%NI zhAFW71Uy6;B`nh@TTmDM#P82*+cm4koYe#034SLH)>AD?tn5K0>I@t^xNp98R^KnL zp5F75jFf_qiae4IAZK(@M@5>ZVE8?(^uqCp>k>>pxT#&)>=8k$(~0sY`q?q6o^` zBkJ=ae54>asCcnTvIra zeAh`6D?~#a_$jj@UN55%YB#0)tBYa?ACAOQ2Qb@8=uUACDN zjHMIepOGXn@SPVUA5$#LLdkWa;*BQ-uuv_a`U|Vn^Rp$rYiojusiuySDnC$J4hbm$ z8!iw8lOd4isIqlOx3YFuue!0RUwR$075a6tM>mOO0_kd6sQmzeB5tllRGG*Tg_YO% z&2bYV=8RLzjQJ4Eo>v|)ClG;2$nt~j$HPT=sA`I~qnQ$ng=3;0{jSN9-`h}jtqP7J zO2!i*xeA^jMLokHAS}SC{Ax+(%1IT8wEDBsOTBeXUQEOVnki3@sw`X2q?{r+FQ((YLUj6KhtQpGnX>1CMjcajR+mU0X#AuT=d@XZv+ zCt zS=&{%+^dPk=TDFQ$JNt%eu5m;U?ml9yeL{SLT2+3-~aw`d*C};I@Q+@EC_rm zG7Qp^4X^_rYEd%*5>QnHvZOBczE4i+{Xt!+b~@21UXwW(zAX)M3icrR#+s_dtDBY8 zVZ|QS_+r5V3pc!9r{h_*POi=Cf&u4)R{ zf;}GaT!$<5rXcACv}2F}E%Q_VPZoBqR7DoDA*7LOc!qC2dSxCW{Ie7x>olfktH?*o7*SGo}m=e*?sE8O7kWL^uQWUrs%n}Tb%7P7H zd+IYy{y$079yWffAb|y7kP=L^Zk-*ycS^;;LS|w}Be%O6)q;rbKafzr+*JOFJ6{d` z2>2h%ClhY$o(NAW6HNBYmfVpLd!Ih&|L>4UJf~D?i}1EV$(nHvvfC#jqP;e%M4OT@ zl;&63l+8ZL9+seW!2t^a1S-Qkf1I}Llhb;B%5;GZ3RJMcNki)X>e|W$&o+6U0|QqA z!^a*8S(+G728oHrJ6X}}eLk+sjdN?0mr>i1qPa+Bhn*$#^a}0V)h)jJdQ&t8RLGD^ zu7V0eqbfj;Dy$Ovx#`h6(DKREZQ=&8WJx_qPwVGjsG0f75ot@A$`t(hNXl*E0D?c! zqx;iN--EZUFI|T214^M>NKf1|REe@;2Ckph_cPrR$Z#Yv78I~>Q{zBVeq{2%m#adl zNelw9xo|$1)(f7W)USEkZd_G)R$~uo4y(3oT2vp2-`A;Qq(-@yDNi-|pS^8;*@gIR zols8p;6m>ibI<0FNqk~{tu_x!&xSgwv0#9OB3)y|tPR`YD<;OiLBK^91Up+5X!Dd~ z!4er05?@PL>qr1G1JhCJ59l>J>EC(8dQyK4^g%TL3&bh#iW6+VmQhgLIb`ag3tobToBAF$HlMqd-V#Yi6-(- z%rS5UAOeqO9Dps6Jlv=3+!s|g@9&d0AB@R6TL;7gQBCLok0=pVm|)t42dcC#!&C?g z@g{Qn%OzLecfP*YE19L7!^=WQaKqoA_SA~h`7j0qD5tsM8+ND0frCnLRt4DtM$bj53kPZ}!=|&t_kg5o|8NDNM zAqc!Okq<@1p1WU*+;H=pu7@m*r&?$CdaU;Wv*42P1J}LOre048zaigyz~Y{uPTAR` zw6n)VAclrn1)$1$V{+4rt?FZITfC2L>-KEu(*(Xb3IYfM#Sk0I1d8o9W_cDes4@#3 z4sblgCmX#FFB|K*_LR!hxt1ZYY&<>w9I#c-u1Q`oI$(UQD=9@~!FD~hX2b&v1GSjD z{{DvKmoVV5`H=T-%MbeRhp@-fok?Kav5^MwJ7KV?5Jy%z_BYZCI`iKb02o-5_w9&$ z{il^3FJ;S3IlLAzy2Xq6C}*rVqHN5VV@_VDyR1s4!yoq0La2-mva(5~#+jo7=H!r9 zEVnGn>`U5h2m9q6dwS(9Z3ALL5iO9i?)F^3y+E(-<#z9j`+L+4^(CpfmPwCmYvGPq z7GYkmRd#BrKKHqp?-?u|V=kr#6$G#lP_~o8@(xcBL=GkkV);gbi8h?KD8sIoh6yut zs;81}2`@Y}gAta3b67YkIqw7Y@f&AUXcwre6>;)I-+1zr^e4n4>)QPP^XR_dFLri{ z2ZD;l)0f>Ua=;qHgifvJ5BVObFHg?3O`4TdbV}1~GNV#I=h*|kXNb$?X$71?%B4B5 z2^K^QQ`~H4-jHNej6XA3Iq}>?Wy85FSU!5xbH7|DMmsxfNv7Q5$;WQMPBmCw<|XQl zGoyDc85jE$KO*q5Py)PF)p3qZ0CygnM;fB}@b2)p@7oro6g;%A6ReYFq$qZ96HIpemlB}CP zzkkfkk0z?8Tx^CaCs2x${7 z4YA=g6?rH11LUO*&oeO){PAf$Kblga&H3iqlFQI8lUyjz!qJ4y!bphiP2y%zJlcKA%LjeKHkx&BDP0`dXBUBmbpD^d&qT^>@tCftN zVG9zWrcS7#*`j4?L=CC_mTiB-LVL%EAN+oyy20|Y>Y!b6$KuWnC8}2YhN2DOc=inM zxqz7pK#!bJ8~@<#3+*RwSzUf92vEz7@+{~2sI?VH;>lI1#Wp#@V&V|oomDdE= z1h50QVAiZ#!RdmC6@qIeA)z2?anlHtS9i?4>h|VKzO}Dy)|Gc?k=hvmCQF3hVFyue zwu`a~03>Q>(|Qg#PHzoZ^e740PEIxf_?d<=r@5vd1Pyc^13h2cpU-@>l-01x`P>F0wkm_8#{}ndrOS+oAtKK zOxB2%SQrVUhHgogZpBVL=i`Uo_sxAB(=PcANFzT03PP#O=8}xQg-Zbaf>O#8@7yhF z0~#nIfsny%8%_6lFZJ2thbQ)b9kVKc>CacfU?VGrQOl1_>i-6|tR(q*WVQpW?v&Wp zoswGcy|Y$n@T@AIIo55)Z{z_B6VIt2i6D*4lA6&i7u@{xk@?p=q) zWkNE>XG1uE%I*MA6}qrbSieAKRi>65J41KADUy*8O!v^Ny@N$a($(Tnm)|&a#LcB2;&_kk)S0E zFwn!TOFs8hymInN=so;-E^!jbzQ_sYlNH_jOECL*U8f z2`cw453>iDX+pHoh!LNYk?JGJMvg$TeoLT+J$!$Q{Vv$WP7(~9dc0l8qVn!<3JtQmBh|L0>TZ`Z%8rpC7$}Nxo+;{NR$1PbU`2?Ra z+K)pj*B|jbL5}r^$Qxh0ZIWoywtji%j&5b6D)Kbbe8WzbD%qsW%SIEMX8ZlPXByY+ zPG+UGsY`2kZ7k#xET9=Bg|scX{wXlj>+-RwP(oRPBw1dsr1Z8lmh67v$HAtT9+YC; zNlWrz%rLK18BRAywz#WTZrs?W{&h}W;-gF#d8R@>+W>Jn23IZoz0r4PUy7oX$twYn z_p|_^7xAzFc$szFgUz;a2)wup*m`EWs|<$~Sa5rYl9@6)mt1#OymI0^WYPx*D&FDK zVv1jqQ~lAhtxtSAuzS^=Vxpf}ib_mxNJh}*n}3!0FjO(W-(K>~IW^i9BDG{pl^HAp zk42}TtmW3Iy8W^J!QTXAi{#tb4Ox2wC}eD)8}P6yo}!!sPC63e0oSdaVFMNS0AptC z)N?=H-LT+#)fNtF1wml41V{QNU^Bk3jtas!sDD%2jXWTF)4JGUhtYpfz znJvFL;B|-N(q4hu1xS!WyiPDuhEXwYbo&{X-%Ir*apqd(tojUygUF&~=#}gKcx`y+ z3lA|c%@|53OiPBxP+UH$sj!EMf8G_iFXEGGuR68uKZzzdeYUde&4t6t4N!jyp5}k9 zD|_FjHu*IyS#v7~9!XXR4=v3B8a%#en^Zd-llIC2DL`PQ^>^o-kKJo3KA#9-nw%MR zkV4Gkm(^JN{+iYIUZk|{*=wpn33IKugc{<7Esz3|Dcrru^Zi(|y#4y=y}uJhCRsYq z>|t+c#eHF@{x4l$y`I=^RZP?=usE%e}crAHaxwZtaM99LvN>`K9 z&bV~2Js~v9f}K}-(XgvROl=YL0V_6T@yBBjPzGatP@pnB0XfjM|HZnee>`1o-@lg~ zv!jNsx*2V&pu)rlxBKt;!iwrsx3>D8#!^&8_XmYw~_RXHf({r&2eeqFTPP|3q5v5>kp4buvi z`?{xJ@>8H05NN_+K;>`U`CQHOzrFy|kHNl@hC@odljOoe*&UtY&YM=2UwnF{F%t_v zr1!`v3X_w!c@|TawH3rCSDo}sHu6-|ZP@zpODdJGs zQn}b%nDvPoesjCL<)v0-i&qMffMR=siWLCQ&x-3bhP_gC@b{1lgP&v7HggqJ>1K3w zAyzuSCi!7(n38R(Gq0G2sKRR<^2#(pYZV5txU|wuv$VD%+OXgzK~M0k&>TR;&`|fp zIvT52+zFCOBfw2zxfdfNU}XqREEvU(E%^TlgJ>~b)G%g;#rN1SGK zqPc8*{2JA3M6kV+NRQv;kau5}Y~gUf=e7M&d50?HPtXpVjfK)mWIBnSa?Z`VCm0lL zE@iS5w-}!hMfCngt-kkSA>NY!7F`-Cpn5C7nA5%+JLFO9bR&y=T0ZY^%zrlo{ihtG zotjkvqJCh)z|HAqblDeCfE3-(?)yi-hJ6BT*9FYb01Jeb0H%=dgZUzdRlky2AfJg(dsX|nv_=i(d0m{?-gd~{Ou+Yrah+P30tzQL1i?DcHi-YJ1?Xw#wS=r<(5Lg`|w0n$J2 ztWOj0;(%Vr@^e5`fgJ{c*89Tg{dY(T^JADOTd$5wQc#1- z5BdLq!=Z+%!L9qiqJk&@t&pmoG(S~RI}Q9Ii)2|T1Gf&u`h28p$8+D4ds;dz*&`1p zPgMvDr(D`&# zFf}>naW4>0B(g;wZw&w9V87h$L1|?dNS}8{4Kf1K>RdFuC6WRfhaSHtrfoB(s8Vp> znuo<$R{}yf5|0DA2Y3+^3`IR|TE4IxA2aj(WcB3p^l;TwQ}&kO*@>p!r^GsTtL=MN zK=|lcslTHi2wKoTz)GD!{tN@y$gV>SgWR?#`oxrqfpc=5dCfUC32d{ta`=(mfuH!~ zp|h=q1XyTKVJE#*#e_wm5{aF)m_{j*G`L$mr1$hoZ;Vb_ zbh8$$9BZTf$BQn~Luo)b4b+^nluTN5y^`qbiZpGwJN){yKNJRflVI<;3-oLcMFo>KpFXWRaUmPTcw(dzuqXcgJHr3bF+fxKW~>e~u;65vX)#|ophs$EU|cUN zZxC%ONfFd&>+7Db16ypA5@5%>1u9I@G0Mk|Z(VTB|0K%mX9`A=KzNB!$AF_5dy4XT z^$yAm*<0Rz+Qr|Bj-B<%>h%v?sUCcFJ#$-%zWYv6tT*fh5YVNu)eZD_K5L_IN4%6=0SbX53NsK^6y{U$(sGVtec6=#kfs|9* z_dG|n0g_jx&f9=0HR_a^hn9Wy^<>GInNl)pPyqi?;~iCGx(yOM#EkKdoop~|T2sSy z&F9{@E;f15WzrzheFmla!1Kdy%Q!^+g7K*f?>Vo1S6v7|rHeU(imO1ul1xKN{@3Qn zb=aa3+lLLu&EcZ)P6bpgM!4z}1PaNrIwsxWnE2cGtVoxM*e+ZOW~`b<*_bgc=X`M$ z6M@Rt6HaDDR$eNYikM1`)kEOfwk^2kvBcOJ^AM;Uj6-BgVMwMgMa_Url<&-o-tpb} z9nYu|i-4g%r~(eor~|$5>#Zf9-P%2*t8x#YM6aWmh&;PfFO~oG+Ol?p_8{9sF;5pE?r0wi~`wR1z_y{wYTi&A6Mv|K& zG^$h60N?boiHQ&2e?jZsW%YgkZs|Z7Thz*RG%+qrg~lYq6^+5)KeosFkds_Ee8Z_+ zr5n&7HUeeiX|~wFURR<>q=DW8V!Wpr8>Z!31i`_eC+ygiMW2jUPMV)@$v%HSQ`5oV zuZ>Q>=-Z;H@w>qdQ0W%6v0EVe#TSfCUUb(v9cyoy+x?e_myKZ>pE4ojI+;IhR~ZoM zkq`9vUis;!($6Aig}Gp47?*1{0}`ABB#!9~*CN@Tokz%f1X<9Nq;LG}>%!ZX|ClDCeehieU9(7?{#aP9Rke6@>O;%M z#;>a@HBRTFxirdzW0H&v0#v3bT5>FO^s} zG2F3?Ss+TX_W)%`Pvog$GI7d^@v~ClQ8TEi<6F956H#bv^ z8to=JC8jB8@760mTS*1JE`Ug4UwN^5$<_{eSIA?_Cu(?=;O@3l;B=2R@yhy@vZeRA z*3}OFn+jG>b=#}v(iFYkP~~J>R#4^U+xVX(ETtDu0Pcpoq$=7}D5)3|^slU`od0r* z^io7Uv4hlI4np(PSm{k@dv^)LmqMIGKAQL8gJ#7#Ca*HA)rlgiyPLwJ? zV8Nq5W$F1|6!-olCMOK3`=(VDXTIDbZj7iWe&)5yA)Uc*vWubxt-T?$DIE1`yRuh8 z9wsH9bYUURncUi|?6`Gp`T31e`N&8Bm8%jft%mSGjcoCf+13=1RX1A6@iBa$q3q;9 zN1AGK5wkXTG$cLIE%3-r{ z60n@cssgce(Pl}K1AmTB14BFFlCa|cRij6?x!s|TeDKuH3vurij7V-B z9i1K!f@Dc}a`$g7z42?SOFo>^ZLD(?N7A@rw^X5>t|PR7@9DP#Le|hiBb)gmHMR?6 zHg(3G5O4e57X*jMbWPRUX>9r1c0ZSI=m`OWll4ozc6GMh_qc%$VI5R`jorRYzt~*z zsm*QDwlD;hxqdzYl)|v6LX5%TBnZ(+bUAdCo!wz!2AVH2j<``c!80X1f~V`i4z;Uk zttInJ2^TgT0V|81cxSWs$d2XC`wsqEEj|j)B4yYl?cGP7*y)-@A_9|c+Ct)wua(|% z{XffRz1|^iEAe2jF2I~U@}~2<7%N0~9DtSRKSG3TB^DBo;KKXMCRmCO*j39S`RXt< zt{`w+vTMcdsJh(flZCnWz|WDAeQSRq4)p3E6{URU^ME?DBOWVUp_*gK+stvc(}2RK zi(oh52&$C_0{4A-d1b@zwg!JL02=*{>Kn0Tajw!0=#IE@W!TH;|cNk4a_f(n;=u|h{` z5hd2Ki#m;#Xjc1-Kv4Wrs$}#Tp3bKI5HA$+Rf#Aq8AMzv*8Tr$QWuSynG94mfHwz{ zM$B!-Aok?K{t;#}UcL6dD~O%~HdoCnRT)!bKw?>wOU<)zN*6@PHF!fA={G6?Q3^kc z4@m8+oBR(yx!-@+_8w&~-u)q`sfab4844o;SdJY6UQ@Jf7Y2WG$XntVOjS=hH@s)f zU){MB42a7j9q1dVdG1#WTF<|6O)^wH5nEMKXS$epoYyntEliJJRN+N|U8J$$}105MfH@m$**6tSOHS{>$R8)2_fS(O0j?R8K8 z`1Fpmuev`vX4XeAEQ20n1|aquByRe8L~NDB;1O)wxvFa2gI9??hg;kLRi^FGn6OoL zT7@ycBdYG-(XFi7+%7NQ(&=4!I3~91j1nw%z#d%o5Ot|3G>L^gk0_@4HMOs0iyo{P zBQV20E{(vwNyE~DRSn6?`uV;?TUUc2FSz2(VG0eZu4F7x{rqpQ3{N=g4?UBY-kK;M zzl2FXi61R*x=tgHQpUR~|#$QlHw zCCnc&HmKfoh>4qm*f!waF4|K_WZ96<2``4;n2ewcnNdVxK zNFrXI>CXOe{)+abXtaGmjv|=Cik%5OvUfGeIU!3a8G)^wh8$Q<`4YncBz-m7#dDq{HE&P(|PEa$?)Sm38bI4scw&lG=V$*REdHiV^KX==fG zM~P0Ia(})rdXiyvwplv5zHj=n&)C$p0bKY_d3d@R&?UR zo6JyU2s}$;$V%MP1Dza+ghrIbj{X0M=x+1oei9fO!xjK2vXi5y&TU`(*?XJb|Gj-$ zc+?pHGRzGc5d%zzO%-O;AyzZ{4s3Z;m~!qnvoAb=+te~m(_dN^op#~Z%hx^lbyEsq zjo(SubS>>AAcf}`P1tOb35LNi`xR#ZX(gi@Qe&oH8Xq(BA5B3G)R*W7*`Mb6ZPKklsm)zZTfP@xPVM#@#lksX{SW zkAo+XOG6t+G~vVK0eA$89=*7Z$J_wI+bEX@wit-;=1CG@sb1Z0jVDi8q@VsBz;xXnTTF zA<*|Ku&{d!&I$}1*z}0!v}Hfgy^*?X$kMdb;-&Gino}0_oPO!o%U=G=k4$e^F4R7x zneoKY85e!7uVKNLK>CDDHCTgEh&Lv&u}c-0lcsJesI ztV};qFNy43bC(?JXvNYnl6`O)H`YS3wROQYf72_*j}^5=)|ljNCAlN5ccN_9iXU2z)XIKi z&@MqQQTB#f&;8OW7Ah|l3ItpnRC>YyJF28*=@(xxBsGZN1%M={g9^tl=7qh&8?$Wp ziXX`F?g2}Z3r1QEF|ab5<0GM6D}UqbIk=t4s+>y+J-4@jaZdS4$2OmL(*`?IStjJ! zi(%L#Rj{)3@C9GqsQF9B;djW1@Wl>?uvgyR<{jakFZ^bRT4xq6u!vKDAkowSso46& zO%AV@+fB#8Wuy!(Tr=^|vah~sRE)1bHu85QHK9$nK7wll^;h3=(JdH=pNQ9 zw;~l={&ph;TayT)D?`qQbBPUeCk-{WEcAdpT?hBENY%JRMg1AL**W!@LRKC}sL1}v zz=S!U_9VJrQQP}*!R!G_*tJa6<>sl_FPJ+(l!?pB(;CSoT~{0 zlznZxUw~K|_Kc8erpkYKg_MwPn`ENH)-(Ic{{-*vUd+%I;YP?=QrXx_P?nTr-;tV? zcVBEn_!Pc%LGpOR0xZY&07E_z)zpE`P0{+ZKLxBZJ=Xp+`-4Ps5E<$Cs8biGMxS1{deI1BRd0F2L16(yWTC>lvitDAa8+v4k<=p8rvW7wOEVn#&no&TKPb+ST7 zt^WO`5V_dvOgt;h$sEH5Eb6F4S?N5`C}P6z=o#k;Ml$!-i_{s83+mL={bi&3>(9Op zRBW}{-?kZC^C(Yq5hXGGzP6ia;{8eS)1CTB%PgrG)jj*lpR}L(k$ZJDG79^Y5`p(M z&3%wM4qotv#LBHtem%VXxrdkOY~1vm?X6>WjR3?V zkc*5aD(laR*U!D41uH6~WV8|7^DYV@C7xmeWGluXDSc~^RW<-du8E52#=RC?tA#w2 zQ9h=jXXg9A)js=U4?xK3Y-*%zPI3x^%R0a+B4Fc{$ibH%saW^GO_uBv3W>9N+wXMY zO_vPwCxTrCEChNzhcCQkeWHB)+;@y21 zf5Y$z#_DW`j}+{82ruz8A0WJW*JlhAqb7pan1QlLvUUyrKnHYU@dn|;1FSa{Qy};dL^#vO^aRRT zxN2gebnNU@Rm0L$*|>#(^95gi$?%tra{*lZtutvQ;4omt4F?Q%hylqMm6OqC09T8o#oDQs zz=m&H8d$2W`ocgHR9U`oouP(nL6U^|%tQ;i^xeqNk2H9#=&A477(r$PXBuI!>}l7I1qRa5%PxD zy8|lxd}gX4IncRx?dX5ru}~c7jaw%fs7^SrGT_1}KGlHGx`Ea$X&k9ZO7 z;XvcY$0eKfC2FTGvp{u$6fuTs%*e2PKTv(#euC&z)t1L@s@U-GtrlYU1dpsc>4BBL zrNP|-Y6=W)|KZoxd%K(dp;gu|(F5fbAiZo3K6j zV&=#MSQ=2atcYNc3;xc1>#En@e|cov^82vC2XIscnW=En04se;7N1lHhap3dIn=n} zK2M@&H;YtH1@%~EJ5AeIT1C2VZ0B&Hj>^Nl8IK6Gf#B(H-Ce!;(HqJ({`t#twBra* zeZexqlUViri*PuRJXZEsiFCMS3wpvL-XMXv;MF~o7JnsKQa1yCjq`ITj(_7`U;gA} zHef;$)|mwap(NQE#^LKZ_-c61>RP2%!Kb&gf(KN7CXcU+d1N zK%(B`JG^Z<)f3pb17ni!8MRmNz{*@R&sKm#!%=V8NY^N>9StD6G+sOHL#fg+XG5IN z&xdhh5ZN+0gN~~8jSYA0bgjGn7W};RImBV?sT08Fot+U(1K#d~>jH;gd(7Li?Mb<( zr3IgjonX?}#z=vs5*LB>78S``FG4^Y_%4D?NFerDtyPSlm#k=5k}4ZB8)A@?0B9u~ z7-k>cHi%V4@Nc z6xF8-GH-aR*ziIvIUq5;k0xWCQnIgEj(0c8v9A4cysJ@6^z~p?1BW62*p}p@pZQ)g z%HLbSdNauQsO5AUNan-_O(&?FQE@yFO?f2@OBX5$yr&*>YHHKZ<+2R@27%{sIcm;% z2j+G|wv%m*_&!THFMi;*c@#uwLyIU~j(LjIsp`Rr)OO~F2rw#f+|W06Frn!_X?#Z0 zd)OE+0_*L8#@@~?q;LKE(IJOLVU+JGsMuR^6@gV;MPL>P>F0dn{6sXk$oVW?FP%9 z#bTK(aNIw!*|LAWOg0+~=Re|NK=HrZU^)K3Xp80WZ?z0i{2%!LqW-Jk|Dpa@!T&}5 zSHXW#|5fncz5W+`}gh|COThyPrs(`1`TB56}6a{)X*CQ2Hw@ z#<%iM!{$5$&6@E9UV#K%g26?di~%Kyn9x871t2&nvB1NvKa=_{b?H-YUW(p036dg= z{e|+{XEQk81+1P}aKgWbGKMlhX-C+F9kU9DR!4X~35*W#Z=(=0L@vaNCeJeNrWDhh zY$vg*Eglh*`!o8NQW077Jwt$`u$L$DE1xufh(1LXAQ^p4;yt3f^<|btpkG1CS2M71UG|3~^b8$WlrLEv1&(>LYTztZBMj9Xh#O6zZv%P$Q_~ zc`(Es&T|X#ZRjjh$ZtH~+}>%=5`U)84Lx`uqyab|K}bq($e_8nUx`znPS!bPM%PC8 zIdb-AOgP(f_{xo3_Uscn?8s2aST_oQVo=Ym($sht*?*iTHVsi9nQ%hX$n#_X&I*E= zsalXuZ^sV&@P{xe8AQEr1+oFOYwSV%_<%e zJ@ODq-=vlhgiR!+?_)^+T)948Hk~est<#7|B@99a)zJn@|J~+lEO@YLkoXWFDS^)e zBWnZ^h_YNK>9U>kI&0`%x{i0t_+6Wi=LYa03IjMXreG`8jQ{6U$4vRt5=CseM$90j zG=Xw9RC#Y%kfD=uHjZ>v()F1VPVfdGWA&Nu&b4X;04Jt^2xoEuu~b!}i9x6!1V>o! z)4nGYpIugVUM_u(tGz6L1&*k#AVyLc=m4w!6Gm|Wa~>DsJ0mbIn5BP7X7Um`o@ylD ztI1Y6rMqD(w-7;@faH7~RPWX#;8F+8`IQ3W8G-mhi`Ks#)UVpyZzFf!MB<-Qt|d^I zJCL#)3VSmyDboL)IvkKi6O_ejsF2fjW+}S-c;_{X?NfKZei7nJlp+6bj0LChn_Emk zJd#t%tWOF^vn_+)t$v#}zs`E%+oggYMWRmRG}TmXpg3?`YdSm&01ik1*jIrl?Z~@* zZtDBnVA_GH)GkB7w1Xf&O(ymSe^6o||yGYTn z2g(IQPtm`W;N1{@L4G!$Q%$rX<)pc##PdVj#FVecQR`8Oe&^PczzUoI8F9vaQTBuf z2S_ai8hX|2va(hcaC+IdtNK`7m;;a-U6EbNiuccSaIA9_HgP(r7xk|{ za(Ye5dZCT`#gd-Ga3``4DZH)+_h)sR4E9zWDa{KVB2#d@1%j)|7g(s+kYbam21{LN z^O~>HNDmj&^A@P&FWX|xTj8-j3Bb^pO7_JE{$*Lt4LqX6vM3(MkV>D$tHDjazLMM7 zF_u$$6)f1}E#xTi0I|(#Ks-57-)4^IslV&5QxbpEY=`#4xtmDv%ls&GqbIN&;-G*> zfhuiH9H4ldGGo{g5B1AXCh~clW$%YUSvKjq6Q!D?)w(9(#I(aQinC*ladr{`n4sNU9c#MFC~kVlZnTgb{5sq^K?6?x~7 z`wMzKGGhs4B3g<*O8ql!1zLTgnOts_Ve}q7J^sf#INHlj3`n$-SZ1M!@wAoLai< zes{oHQQE+ypQGDrS~B?^GPrHk6SJhWty&AN*DT9WC0sqGQnZI0u>I$br7t|*W(IFQ zH+T!yKlpr}G51nzM$OOFzxM)#b*;5(%6HQuOsW@}wc^UMr!rvl!W0II>q6`H(|n-0 ztFh8Wh37=Zl-?;-F<(O_0M-wmNK?9#fIM1GpQU5W!n=XlyJ#k%l^|46tnuT!&_+-X zogu(#nx*;m{m88Df0EMc-C*K48>$o|zFTMz1n1&=%64qt{Oq&$XqW4%ii#K*bSjMi~&}DcB)DWwl|o1sf}*hQfz%)t@01MCn5V8JLy_rewe1AM8&o z^v(U!H@Z4yXha@UaWCEz^Cg4tTMZPz%cv|=M48y_c~hA!Bom#SbFT-$xHZeMn|WC1uW5s^;9z=YeQo`ATAmy<~# zWKo}Fe(EPD)hrZ9dAIO@1Ih+wu|htq$kl?PtU^JTN(jq}wtS|jBrk&}rhr@Dk`GlT z8UYCRss*RO?1ui{rxXy8MhN74@F1?M6vuzZm-}qn)zFS9Q1@TjqJm^2KyaqU64vLl zJ=>uI$Uc1rSCa|#$`lab*CAfaWp=;$n<0OT$CPI=o3ZKrSn@3p=Z4COiPs7_wh)a& zJciAP?0ZvAwZzaJHk1}l(tseQIAQdcp%xpxfm~Lm{x34}O?M>g*_&j;U_)ZPji?9) z9)Mu9N+2&7$`V>7v7s{&=l8+ClW8>godbUo$1jD2R-WxC0&{f&u3GH)P=KK@Y(y5= z=jZ-z-n;UmgDl4e@gO-^^T-sGBGS+~ZZPk|W_$mgDE}0Kx5I|wU(aQSGr^;%_ zF=*Lj9W^?e80qQTD#1QwHbNtLWbWr zJ=EWW6qi-_nUQCi8AMBBt z&qKke1F*Y{Tmy{ArMx|H zz@~{89LmNT^2gBiW--6kCa#}Dy+mTE09nmiTskCf0_S#V+5OJ9^4?IvD}!p^@Dvx{ zev9&T^-MOyTb@Nqym;+XnFU{;+(lpqbprSzMyH*w$FcHELX+iUhLl_K_tOeAdI zkU_!N0iF$P)r(Ca;td6>xsOoDY$n~#eORS%ens?2*?UYl!#D(lv>M} z-P^~;2K#m^t*5kp-jjG`f#Hxjb7@pNR zD*ph~V+z!|utjvNS)aLmD|dO#pW1c?k+Zp~?|t#&FpQ>emw%<<;^>)JiKv8PrcDn2 zL;PQD$40{%DNfGkYEPGzq&art40Ing`m$Ou5%Y>?Cm#hOC(mU8;DM(2A!Re#M9n(GWx5h>%L!%dy>o; zJfGl{`vsX|tlsPscMs7-Eev+Ef!txc7HOBedzNFEMRU>u`)vGyYRdhOYf0)%9#mqs zoUL_j7Pl!%EWR|7|A#SVf_=y&67rS8t@=Kv+@wwz#v9ZQHl%nd(}ADff}iV33>(KY{hzWXVN=2uhu@d)@+^fNhBl<8P@tPswf@ zwySQz0agl$S3|!r-C=JdqnYjzuDJDmWvAEM)%_%wm@-BMvk*e*=LG4o75im3XOCFn zsqXeJ2P~I@DN?cwuXiqgbViSz)t$iwDuqUc4)mscOu-!DaoiiK-jvg50q55$XM+WY z!5OlA6ractu$vNLxrK1qo>;=hTgU#?7e3dWcm|rQ9RCI;gFzHEiMR_tdG;??`PF(> z=4zH!%?l+mLKD;H=(v@4ykH})EK)+{%H^qN%-}p5=Bo3o_ncp`o7Y1Y6W1*+A7VXU z_Uva)e(3FK;5H}O-jIZyp`0Q`orHNk)iq@79nITJjOFR{Mn#?B z!054zdmK0sG1Mb1R@(blw5J6(fwM=heeJ?`t&h(v?_5Y=L0kcF&ki3m!?A09OL#wg ziG32zRjh)&TtC&PaevaHsDM6=mU-f3{wcL6fZT+MjBMd}&P49~6)BBLV;Z066$pW6 z6B88i;(zOJM}B>2it~WT)M3sZVybH*y#KtXD05CX;(AWTx=QYlrYfrR0BR(lL3ABG z7OioXEq@L{YK^s;o}Py}jo6Wqj1DTAjC16(4Al(QqCiEAD$Pf;ClGA>?V)P1amT-v z2su(*?riKfxCxFk;yUZYx9v3Zl^?>lkigjMRWs2QyhIY4(>90kaWh(o6|fX*Y5W&q z;&&uUh7N2!fb99~hId2b1A5;oqHu-|>lFg|`l~+kL%4*{2EB_Jc~ z4_t-xNd?4hze=Khc$-&s+#l0A;SUn-0xGU9VMMG-q4M}y{cWw0C~3<-h}5{GTtVdU z#1Rwt@Of38uLEJ^!eKM+DlUttOqGlf%YtgJ;p%c%3F0he(c-CFS}8UOZ%#c7%|b=5 z1$NdtdbyuWT8@v;1UBUFcX;C%;__Xt=9<3*f_(KpLONPSHCNgPx`?ZvZOS`qopWAjpmZINNH{8 z^4%WtRwheGEn4t@EOm&}c4=s~JtLoUfb$Qj<*a&*NH@eDk3UPTrV(SU;ufz7UvDA1 z&#m(IQ}4C#%Hp;svG$XIv={I(4VA-I$O4UgdHH!|Mb8U4Iki(uq8kFPV3vNRn zoo$OfcO~mL+D(GfYZY1)Mly8yQEhJ_y=^IQ5{~__j9#$Q$V|=4 z=gH}HRZ#i^j_{m!O&lY-^qi$ch0NGD(`V_PHuG^?xQbMj{5F8)sCNx_D{vStCdo}6 zlzoxz$py|q0~8j7D^NkIMhl3dMrC&jzXFZda3b`2%WqtTX-X0vOKGYcV4<#rjZpfc zm1s(%X5DHLKCb(1JdT+c>-#KjJ++0zdSYtEsY}WU6M3x+f0br`2<^sV?GT8R3 z4`LA)6gPKgP|ne6C+~8aE8Xx`Mr4qJ(q#u+MUP?7T2ktzF}%Akb1h)atnn?Ez+_|O zZe4T(lAuvf4MiY&_W=FtgBtgF)KGUj6-Xpj3XnbEj5|ndEbf;ym={!2Zcm?4BfMne zw&-_z3I5hiQW6Av(4bb^RU1afTc(ZG-jZY+o84_w!E)4{xG2^t3r3DKWer~$XE~j2 zYA(3ji%-wqZlQjhm+3X(Mr9M|{MjNcW&xH8o>DZ}I~kS@wBJqbd=5IFaYZINe^*MO zm#IxLt`qKmfSehz<}%7=RPg}oj?y9j>FHbyMd3(f!1v*xcK3Oi4`ctaRX?g7Ai`8D zk3lR8hv*ZZKSQ-;;Ksu~FG4W{HbrYW*&)C{JeC3*)>{Hf1UZiU$G`e2!tCO_9!?B1 zqNw%-v!$S$F}d8x)zVT4FQzBylNh4Z zmFV>$g?|*ERfXd%IKdynz9wtm;1dA%#~M30F|g_etZA%{Pumj+qD%^2oB#RwrpOKm z$acmTsavqtFEN0!fdawRYB`J)aZ~fm9vF z5?F!RG@>CGkSEUPo28CeoAoOdKSgb*=}N|{dohZfsLU+~(8P|QY(<)eHe&PETg)PP z8>|?<){gL+%L#1JqL(TtPGnbX2iBPOKypyJms&$>hv&exTe*CeFTZ^Sy*R=MJ!d~u zy!@0T7IXc#y;i^+OzIaU!D%jOs}EDqKL;HI;;Xm7@?@ z*$!9p)?<3@9j$g3t5|O+rqXlwCqcbHswB}IG`$L8%fNi;A&e`X)U|SC*wrSRtZ0kHD@It zsN{k^nDvx+`J!QQbQqtPVrX!CJ%+-&u#NhR8Vmm8sB4K@ioX5@V4N08-%KzcQ>PZ}3FtGlaTO)i(0p=4$D9|PfOajtMtHcQXg zDd6l%+kTsOAT#SuA^%>FIA;8Slr%y1=V4dZbhBj?IVfyNl%u^+u$-tz0EcvxC5i+_ zlyL|vB63!{9B#jr2cylcXr~tB^!5F$ze*hn5)8AzkxMp?m9fopPV{n-zS$G5G|x5TOSn>ut$n=xY8UEoCa79RKd){ z(Qi`Gz_VL% z(V8T}j=<808PlL%vMZxDO2Nxt*U7KDiy2NQ4Mc`k$%vqA;x5hi67d!{3hYAHEA%wi zejZ9R&okI;qd)YhNh}dYPLe!g++kC(!k(QyWP|1@#N=bEjto(nGwpvJy-xydOn{r& zAd6;70n2Lyge%(cbh0rAQHj)~nU&Fc*w~MU+t9VmdRi?;ku*HThg}gGnzqy<87To% zyx26ZwF8Sj*?)u$>NMRA&=45XYogbe?i(U^^>EIFXVS1Arx`cmGDgLmO(5tn|DZW?|DnF$)D3 z>;^!MsM1iHWS&hMclYMZK4&|b+_GgKs93+>Rp8I|4$Jm-b}=`W zu}$2O2HyEy`|D#$+#-&l?OghpVFtAWbdE!fG&bBVrLh6!8YM*XIuG~z@bTwN*Uiri zGoOcltLKX6U_XExQGW$oY`jZ0(rT$8<%PGQ!UcM@TMfW&2gmd51hi zcEzH0+(jWMt2)CFFIwxEugSpNE9y&u6X|*nRsa2?qs0bcBd;w_WJP$$u}2z)pA{9! z=xUfLE;23%jXX|GRepk<93_P!jMV4dOg544t#T}x6*Ks`F z7ZX%X1$WB%`u;gP;5Y-AIu#bv9O~F{ZzzU``&&d8SREWhX=RbR(cj_0t{EF@n&~&$ zDPUl(y&HxRJ~y*L?1|DZ<5}pjaV8I2U5#ccuGk=ruPVS(RDR7_QljPrGm2#mZikcQ z-A(6{mh6x0xE>IE5G;KVz8GUg0X#X1)xPADaArNW35r$4cSTB~*{lgYe#TVpNau-3 zmYKI@JC2O62S7RL@tAQ@*A!Fy#3|9RZ1Zqfmf4=9F$babooNlo=?93fsUcQ6()dt@ zPM3{6SB4m9a2r}=dp+dDMXVfVGFzs6U#Wr{4m&bTsA?D#Np#tZd=TWR%2T;% zPT4`7sV*rOyR>KqtgRb%Y8bGzo|CRU&NDw)!o%*B5m9o6Uc#Ml@UsC7#N>h4XPs0wqvFhrpsdEE)pfS_c(? zf_n`zEQt~;I7{Cpm^0EhOb9*=g#ja?hh;6UI&b;aopD`v*b}})VANFgg>@7cPf+?f z2>V46h5mg&&5HbG;-i?eb+dgd&X7Qzb_6oDCOC-E4=ab**CV2OYOlwr`q@Y)39&VJ z28PFgf_=m~G>GLq{pBz>i_q{Q zv-wDaC+|A>`M%6v)ZlD2#USI6kma%sVVdLF&Uj}l`2-Aw#uvG!rCn$d)~a+AGaVY| z9HRhNT<79%aSU4$bwg(!%((D|C)2=i8$DQ?w@+p43U^xN7v69i4tF}2jwchWkZRVF``6YZOQq=>dW~|`{ zu@6NMW*tI-$4#R20<4`&7>#c8DOm1ak<>Uj`FJ}0f)#vWXcoU-g$$8a@v{$~)ieV=>E^P(D;cR(XBKKI<6p)%;gXDcjvq zpfL&=5i1uSDdX1q8whUJ)--76GmAl?;`$t;c+Mjg(Clak6EQj#nriVM#3)N+#em?$ zhLElbo@x3X`V2ibBBgA6H* zmGDr4og85nqz^bi>5T<|W8m0Cp$KU%rn5$b#ww5F*On) zAl?4nt~4FRU$6XLfZ&Zmpuu=e7H2W9er@&-3)Yr=wB3fv6Fm#shn&b!_s3w1Y*w{- z1!NS>Bmu;9JfhmbGxOkV47h+ybzC!V{nMF|&~)YRhU0$n z1V;}}Z6uvY2GpXv6C2s(*l=i!1ujp-kDr>CnTC)?6c2 z>PjhU|H#rpaTJ6P%>#2F#3}(XehunQ#7?wM`)^i+^ytq_JP`?VNKrP3anryx719vR z<=J?6543nm0$3&M&G2q5S@TSQLdmFhMTJNu8=*kYe<(HRVA4(bvvA_b3yZs6$zv}C zFjE;63+)o3rcCAdjlc^wLE3JSru)u9#K>Y2gOoeAJ27?(X-1H2*)nJOig*i0ny0pyeMetJYvx2d$Wa%kvR%=zb{7WMeQ{)ZQVY<*0cBATwed3hbwiye;C3;>N@p zdr+UP`Gl|jjPtockM(Y-7$pV@YSG>)794s2W(X&R<8gAcl-JT1akcvduQGl_(sE}J zA08-nJSS@Z%y(#in}t3YF|id}Hx~N>;>sUq*$;>Y%q8o0(zwVK-*6q!jyHz&y zdIh(O^8(Ed%ovLt;zovG9~TKZK^hCKPCNb3&b>2x^*7@CAE*9FiF7J{sNLlG^W0B) z+YU^r3-S)_pt26zE*E8lxfO*OmOQ!4+RI(#>iw z*ZNT6*T;LGtGp3)OZc+^2{Rc8=)p2P-PJZyx65epv>Xz|oNrYUxc>HU(&E8|G{esM zXtfYsP{lBjkbOzi!Ltj>s^4=bS3Qo#oilQEuXb_wRUKQK()Fn!O4X`7*MuN!3jwj0OUHkp8bl>0}0ZCkWm@qvXgl8)>8iGE{8IBm1)c% z6))g*!C-v42>GVZ)BAgsSZWLss>{<(l8B{vh4-dIn(v`)AYV2#Cy(Z$q{ODK81OXz zrkhJh=C9{1rG1|v$4Ym9b5k)^q7uOYlu-r+l33-p{BPy{Uv54`u6ko~^|!G>$DwE$ z&mzZq*@|E+BHF&SjIXDK`;pZ#3rD1>cf9MLQ7L>>mY{KZ_9dMrcLdnw5R(G2A0Ulz zR0uiQPUwl!T@MxIhOBPu7g#Q_Iz)vq=940oJiEgq53_;y+Z$`{`)x9rZXDKn#Tv0t z=oA8*uq_+!O=5OErk|bLo&k<}>vHQ68A}b2YJa$isk?N*BPNl=`OJY(`#*KQ>`Xl_ zt%}n}ra)aPfK$l1fAxQFGVlIKMlTWs#_smRM1D|2wUQ0%(0exGe85VmS+T>TAMNZH zO;Lp*XPg%sqdN$+H8|HUx?R-(KhnKZ(wzVVh#k9wj1n1wI8caTz3{v&M*9CwjXR1%V#NyTPh!#=7Nw%c$vwum#;yq*klH`0j;UQcj@=}?^kPjNztD!v}H zec>mMmq^%psd#RKL6Z__DlWP}3r|=3-@m-Is`?);2@xf+EcG>5**^ln5Lr5TeJfYq zjwIi=MsK|M#h^0~gRFR(ikKL%h5emw#=ZG?19mlsHPuC9WK_M8u5ZT9=&U3-X$Ld6 zlw_cr9ER3(T6!^=D*uMD#vJDKFb?0R7>Q9*69Fdgd52!#kc_U>b`cjONt>Gt3`aJz zF_;BL{=IL}Y%s_Bz=jx%z*+;&ZV0|53bXy1UOpN7?e_j^`}Zp^&x_izgS}hD;1Gj~ zh&6@X&DTTpu!z^PiQS5b*unt#BM@LkhL% zHBM7`PJMy@Xk~t>+e-eou4awmSo$zgQUPq2nt%Cqt$m&xIG2|PiJ@1J1A@65&W!z~ zswpyxu;|yH@aapxp2~gVwID4Yxj^3nrgjaese%VIOhdD4yqG^fcfix+SC~Y&j>+I; zAU{4bVr%;nG7|eA=Pf>vM!nIhabx=(3Um$b<AF}?5H#`Z<8@&CH1qM810N@!gt`AJSzhBl&45kClrBtg8v(iV( zAd^g$+{g3Svyp#(Ct;=f826sU_2j14*fiD<=;{=O9wvB4tEg{m^IT7F%Iqr<{v`bg z0i2-&hzEjwfr6q8gm-%5+Y22|Sb}iww5I61ScGSz`8dgXD=$=&=%6Brm^wiq5D44& zk{&zWQK&*lH}wJo0x&lxYZMF}-eqYuLcy@l+t^~ioT9IUP&L)11i-e! z3|R+0RR1}Ox!WnvcOs@d7K+tXdsI4s{2OIk^0@W$Fw}7Qvm#K}XQOsfOy1UM&n#?5 zJBLyt=N&QmF6l{s<+Se}69^FpwU1b%LJzem<`|Uwy)xn7Jm&Y7z8$#<9Vfzy#w45A()&5SGTvDmpYysPFO^3&Zgww7c5 zZ^AV$8I4TPwGgf)iF+h1j$X$mOar%#ky`yaQ{9Y+Vq?ji*Xr#<)*!Im3vg_)g6##MK6`Og?AA!1fTFV1c+u z>ZJ-Yl0rNPxQA+cWqMOQqjP&eHE5N2})8J zQHA@Cs6Obl25ybO26e%91-hC6I#UF%T!$jzhz-kH_gh%7ds?8w8bV&#oIc9~_=Clv zajpfiji9|iSd{bo5L2PvvXBA+6oGLixEA(9uYCXPfhx+Oav%CMR|b71g?xsVwho;R z(DHt>&Z}lep2?zsiK#!{V~CTrXn^aV3lN+ll?|gb^wYeb4WGkiW(mScQo>Y(sGjy1 z23nS%MC=*$tm#GZF6`%9crXK=A20=hAV7&PiP-)h9N^#91Eu|rC+VZmS6{##j^9xp zw#SdZ!MDPCvdDDOjk^P@N_DM20iN!a$7%(I9aMngR2>M_3~&8c%>1-E=z(HtiCr`) zq6aR6hkc%H9q$9Ec>*;9C#VH2=)OteSAWrO=BwC8Oe6+GZPbwMxIKODol4ZeY4bH` zP>D-wjbVA_@wG9@^iq8aCQYm8Y2dC#|3)7?jnqvq$!LjXPE#X-y-uJGLT`Bx$rA00@$$eKSDN`Lj1J`B{E;YWiPCDNH2wIB96cYw(Y*KGYL~Wbs4x+JfGtXLG z|JJ)mdalEkfK#|%RPN02zrgM1B@o6IbSW=`a%3PJptUc0O*y`wWY(41AqskQ*3d)N zs!+&Xxbc4kuQgTQ?$71g)2RAbb0+}=R0`$3&P@6szfadqjM{at3j65|@OmS+QKSM2 zsj3dNSA#haRAXG+E-I(%Xl7Aq?8MR!q%y@y^xC_Bckcf3pP2`@*cD%k%5biUZ47)3 zT8^wv+s^dFb!8+o$u-}3aUe^EJFUcxb;WoSm5B(_Jy!7b1G2_&#w^EF<67mqb5??M z0ZPs^D;$3C>%}hm*0RtDU$Sldcv=o72>jJbB5^t1D#RDS=-xu62Nfwt8RuC->?!4r z&J<1IMt!=UR0ZYeSL+ClN=DZi7mD;kjiaO11yzsAR7~3XUHUVB9lt#(%y=zj=^Y76 zVws11CJeo>Dk7}rkWL_vq*#A!jzBfW@W#N3PrcgDy(y12&yP+7v85^h4-nR zVVLX@ywytCbw?~PCwrVpvX$fX82ZaD%(fp@3TQEiOw><(^$9pBd|%bpS3huE$X$v7 z1;6XO=@bNJ>AUQ)S2NPbImXD8z*S{e?@(cnPREF)t*Uv!riUeFSSVkM$KGn%J`1IK zRO))_!x}6j>CTSz&hHyv1DTl=(lFnQDlA7q?zjZd@hGly15z9>0M({7rQ6UnMb&1< zN7sH~9H3!XvqH_aC|fMc!W7bKUc%4TR@v4279mX1-Gu+!$NcTCO|(C#R(hIt4&Mg= zIM)XydX>T=7dO7Wo`SkqP4n~4E%5#pGQvsL%ZDF;tLRS1Pi$BMX#ycO)R=B z{#Q4JP(kqU zrXVb?{1*w!+C2TJ2nNo0ACQGBb|Kzj0(+3c-KAX+INLZ51;Xo6O{xB-@_AF|~831S=~?%b#e0KFV}%)djnl zjoNa1b}zR!XXX-}2dW9GQHD{xAqlLoZJu%lqDdG+ytq(>?p8+g(TnA(*g+YRXIHpX zo3-($R|R%{k!Z~m*2=)Y1yReMusO}t??C?s*u?^;kJ2nASLLofLzEQBIZR7{I;RJG zsTeygr5_e$2xT*hs&IF(48nk!mv!>2Gnykp4_ek{997D$4iY<4hHF{-L>N{l?#Llj zfEOx$DNPKKZx|5e3XCpuNTm$;H!U-|m*SSE(+V|`rT;*@AV+oYMo|b5y7`T}FnJe$ zUt0@pbKk(b+WIoEY%N3kYNc9B_Q-)_dGMGq>yQAjP499)_h&J*j5&g`H47O4!yZ|E21uw7^+Z4b}C(2^YJlQ~B@A~9N$#`al z4UAzOBRh_!V2^KYtb7bkmEPXu*WYd1$xbo?35T19)dR`jr9@b#+no;tE~aGfdzpz| zKC&XC?O9Illn*}?n(W5)E!}8*C(q@P;~!smhoZ8^nW;l(zy?frqs_k@D|6%577E)& zL3JI=-Ef=0duWbqv4;7#P`+3u7YN9kR9N*Z+QlW9VKjV1k{f6I>XUtgHN)A3NF4O1 zaa-6WP_wZnT_P`W2lsGZxW)bT_`~V4b;&=^ZTn6xLXtRKTZ~f%gwwOtrT;@=t#hHo z_HgpY6s8FkWJ=JXTdf_+#TrcOw9mNx`OUo~ZvCZgBi7x2bfamXQVtcMdT)Dv)D6Jq zBRZ_hM91-^E&Y{8g2KLvWG%okumcfo^bfW*-?t6_c{S{PzZ~WtyMD@Z_L{Pe$_yJ$ zyvK*oA;Se=)ol9K+saK)5SO4U=}PZ{@h}#YwIee+-nP#W_MfFlb{Qf!!1H(oGG`1G)6O@_l z*qV$aTjoHiq}>`$Z#vGtwD9e_(51TK!=-!sRc34b<_5lhMnKLer$1zyA%_jmw#I$a; z72fvz=`OmVrB_j+EaxU5hj#{t^&o)-cRhmMC($`zrJ`Sz zsZ3`gLl`0qwDV_s9vR~vUxd`Bz(c09bwK`I3Zh?WrW-z9rsnM_dXADz5Q26`K6Pp(D71F1!;OFPtDf#4uUb0kr!B_BMtO<)ERoghZ{uNGTR^1vRq8SY$$zjMgajQ5V%`iujO5nZn;o+ z-MA_Pn!nMQq*mh8Lfk6DH;}Y8C-O5l`tK{8yu0Et*g?p8l8$c*!5M^&93ShWS@1kN zqHR>_6FAhhDh_~S(VtL9A<2JgF)fEprQV+BL_NVq1;&siL_HA-2e=v-?}c_>nnk6( z&GVm0ljJAoT}%O7D4Mp7Y7E8x^`L$^pBJ2~tS`WyKVc3Bh)gA=!+xyq`_p?rvue%D z$e7FTi45x>sQ#?RWGEf!4jqhc^fYYRZ6keiPN|v$#dios1L`nbtf|r?h^!GJxho{4GMd>PXPll7xb@MPApNlTt zH}(bV#)H=?Lt2E{;H&I->fB$m=PWi|e`#jU3V4eTpj6*e_lh6?cy+>>n(6bsOs(cw z_;d+Y)itOs1I5v#G9G$dlboB^Mm}`MX@%z$&h7n_oAf`}cMtQmMKnIn^pNFau%l;) zl8$2b@ldEpkGjsy-J|<}jwvO;j|XXZ!r{IHSoFJMHTML%Jn)y9)BlWUZd=#o?LPXm z61pR`!CGXoTGf;_!>OXgR96^`|7;aMr$3pK!YhhYSK6LYHwfg()jvMYe@L3@j40s7 zRccEt%J_3Xz?}!o;n)j>PKww{n>dUfvLAnG|LSa`DPRnlI`=hWxNWHv&j;dQS=2W7)=vBmRH!5lNxoBO2io5JZ zU02CDbkGbL+O)&P?Ylk2Tc4lxANS zsfW!9f^vk1nk)#^n$h6izbKKC(I6rvY?q68wyHL&m*i~=1XB!$qJTV^>Ky3guB zf7#zR)Tf4Snr)UxJmgrxgYVh~Ww+F7<3#P$L*#h_DBHi%4ulQfZ>H>jt(&j0{pL2? z^=h7ok4h^L1j?~Fb3PEK|qJisqqws66mlVBxG085+kBVkg&~%Z~dX2g^ zdSTw+;R}tnV^F5pcjVH_akk5W$zi5p#Fhq>4bFeB@cph7S|k%Rt`RE%itivMCm%U@ z5r0MquFeT3d?v|_QNas?6@e%wSL8@Xr!P5{*cBcX=fsTUjwH+6z)xqxvYI@G07C-~ zpGPqOjBUUMulH)OZ7DaOc7g%tua3HxQd@1q$6h0I_L(j8F1Y_(2?dlJy2MAP$${uh z%zF5h6xZ*5f}Su$Vx3i%Qsh(Y*0aN`>fM&VbV`60ln61^gAJG++f#`Oz*c)rAPp)x zrle@r0t^=*%SmjZ_X#b{#Lf^GeG4X#C#@qoXI0-88l+o&(hgW1N4Q*$*Hh;SV+(7YK!+EW6ZPc|95 zpBFUc6>+W!C#zWYe?Bqo<9C7-mD%IpewIL0Xxe+BQ+4kJKv?v$+y&g`6uO(?^bl=U z_H(O*qgzTm9f2ppSBQ=*J%&zI+I9&0TIa1LS;D>G+bL8@8q4Mo6-=Jf1DUJiM7Xsk#dZ+$ZL(ac z6kaJilRB=KP-Nae#<{N zHcOU^{izbqm4mh3O?g&MxWKr$XID?2dJ4FOIS%}#O1w3Q3Mr*kO310YBrKOFJFZHL2h6+Z*60xqdpcen*uiFIEf^feN}L& z1yu(rPs!`np>yD9BI#2jM4up5))FbMw5#pZmFGF^31m6ypyWS6nmfhe@casok2(ek zoE zMPP!QH2iBdoW1hIw|Fc|&!Q^#+AHxIKLfkc zt}|aX8GZOZ)wS{nnr*N@!Ml#I_5@ef4^3x`>{uIcO1_v}{FRD04I{q2ow)|@zo2LS z^(Pc;Bjk`Paq1L&dw)NL7`CHFi2oMpF%e9ETv4%s%m50M*QCRZdOws{MG2n^>D|nD z9_qYw%z;9%TP4Q`8MN!j+Y_y7)COu=khztSJF# zbHcATEH?6$Bz^zqwaHRHV#-Y(nJTTSgqK=rKeiF_)^mL4f1a@2z-dib5-Zn=5gsD7 zfLGawE+jRJKK$W3H4o;AxO!I^y!X+Ve_G#X4KvYIu~{`fKI6g7O=VH^#Sl*ioy!H> zy0C*RjV7I68_?&RqddPQ%|dHkVwb{BK5q7OpeN2|Kq}?2@}$QUT4dWnr}mfSPntGf z!0%}L7G}y^SS2Ufw%cxYOMW)BvAAL-1{$9dsF!iT zgAxHGma*)7ca0RY=og>8qJG*(z)`$yNR^JE=bCDR^03xj5m0C;o9aFxS44o38qtzv%OQe_MBrm+Zi(fpbu$6PGqvmZD+^-)H*cX@l)2W;nyb z(q5`WGCD16f6#(O{X9U5`E|i67QA)4$%~KJd3lstdU*IQqhm=KKCc?dS+>7d^bm&g zOXcZp&dT(UF-shfS&iu!%^3(`ZqT7=Cvy?NV-tolTF<4Fa>zoG{pH-D6V}s5U1tS< z4BwjDpuZ@BWQ^JA9Mu#7Ah_~~@-E`3@jM3F29$eODd<#5Q(=j$ z;_hA72I$cVq?i@Ku_`Qd6aD$y1G7jEW3&Tu3Xa2-W4eqQ{`FV!8?EJn*UM^~2aVli z)_@akW-GJ|Eh(J^FSx=Ms@m|VR}m_kcjw!R-(DNm04zF5TUo5OM{?zV=6K}K7>PUr~$~m5&1Vg#1yw4zmm>iGw{pgt6SESd>o?j<=!wH4H z{EM{OjhI!5XsIaL(~1G#h-0}aVD(jdY}b7v7udctzczKI*%^`>06xlS;kw5^-)Rx6 zynePm{W*$bz;bCqm= zGH3|Cs8dqg$T0yKehUU;>=W}NGij&U9XZw&EZkb(ie^i3O@OOw*vn1JPlse zw06~QORcx!_O8ENb?mxceBzES&XHg#u+{%6{1tIezqWjhpacQErYQpj9A_#1`hCgYD zaBCpW?7A_wqJQDv_(er_X(VYP`s5R}%6b}j;7h6K2M?iN<~hRdD!Pyym$I)w0)Hs1 z8~VDzw%eg1ck=Un`k0nkMC#?mr@>8#-BI%~AQ{1GxSa0mTv>9Cr4j3Q62PFY8ln@c zTVDetJhDfrej!pk8;DD%gT%Pl_(Ze9HMz=+$(A%|z)Y>CA$rJ)mO1Iw;clxyZNXS3 zMph{@iqDq|NVoyK?ohNRFDwUg+2946n}6If3e3!N0~K39ao{yKUr(aBPxMxN1cFH4a6m#Os4uN{xe7G|qemy%?Ac4q^!LPQR*AzaOuKdoz@G$L<3O}(M73a!keR=N0 z@Rq|$5lpd<|L7G7V;)@E2XW0JY{{gxYQ;bvvXVZ72w z3HTC;TjItw(ECpqzUdm85`3J?9}qdM4iDycrhZ9KZ9|Xi6Z(@7b%`1m?(yNGx_ziL zu8Hz3!L*eJk;a-jF5h^!3xf72n)Z*(a=-EitXaI15{reCVq8uv*OWp6k`u+dUYPT93a|!*QxV%i9SN_qC;7@*f)ptL=_w!;nvG0D= zOQ)a|ZP@odww4}In!re0v5oSnre|(=pyIxzRhR)&aX39uCjV4_U4-1xA4x2A;S+Jd zDd47mvK2@)#k~mLNuyCe-{8UN;E0-cH^NLb;8;d9gP5z z30?QZuu*5>Qx)$9k^4tdC@-nhd(7x^q}LLMr3R`k(;`8wjJ_Gc4`9s)yj{KwY_1DR zZyM5yqC51l3>w}32<85<+H+bVo30*`EN5GwP{l_#;Uf6mN!-n2m*Gttd|E!+;Gq>$ z6ZyM%ml=T~Qiz~%o9diVL$^WEk&9i+e3k%P`(h3K_GUb5-w-lHkoi|KJqG^{;jbJX z^%T`1$D#7&LN8p-QLXTat@ZL{$YWS40y7~HCW$tJLv`TE=h9nlyBmj^KHw~?iEG0n zWZP0kv7yHReOE=#65cRq0`3dOl18cbEbBQF{AyXT1PmOx==9QATd12C1+4csbtY8> zjYNN|@u}*g_RF~`IK5X|l%?}X&v^KnNo`HJ_G2Fz)&XOWNDyD{*(&iCWXK$HQru7a zy9B<%3R9zlPaVFjP5ke-U0dE+xf&Snl8Eqg`vM~Ag;~hzG(oW6%=?brE}GT_CexTc z6nfvKzLottUdex8ll_0TV}rqxmI&dKs)RHHpLo-%)X(Z+!GH6-Dy>Ja@XV3b zVn>8xLjl6nd$+#&vue`8Z%(r&U3x6{XW+Z3(O+JL?5d7I1$9TwTY~`-W{5(A%vip0 zZFN0lGP}}ba+UBE3z&cyHeDq2-xA($`laS`hVjdM*sWu6Oq6dlh+nt=Z7Vkr1Li8S zHFB;*i^?7C4T83w+$lgkuhw&lX7CaG2<&DN7rmEGkEb)F@aY;Q%&q&oS23|aW8Yg8 zMInD;*?A1a!^?LHdrjVr2&E`>oL7Eaa=Ml!@SYEz>M&=Y5`Dp^m*jJjJxL;N=znT4 z&To4xy(HKQz-0ZCLc+lQ#>VC+EAFS=?0c9j-Pv!{DGcN47~?x#m4u*_32fflG9M3R zlD!?P8AKUXLzqnNN+2Dso|T5_i*lcTU+^+^U|pVSr581WheEM; zK&HY!`q1+SkqwF8xu~Z$e|}8X%(QZuwH{OdV9x16S-LH`9&7W=P%D?6dy`%eLMUY4Kuv0_rOr%4$qgmWOJ8 z#cY(MMG294_-8lX0@E%(Dmyv(!N{aLmPmups#fpKiQJh)Sh<#=!|HO9Dd7=EG;J{1 z(_C*lc)HFAz!r(a7U*-?2ne-#>!1l8@?ctCA$mV9H%(Q6f zfh{y^{$Y*)09pNeK((B+;TPR2#O6g8SUBi1LdU<~IrBEOAFz;rBIhhpPwb+K=G!c1 zZS^LM;etPnS(%R7P_@z>UDY?n1(=TQHH#CE$URN^43qV=D~n;ckeZ6#^IaK1#F6b$|v`Id4-wbjEEiVR&aMHNYk`Ei(s|$O;@V6EMHOxxmN@fo> z#(gg~h0}-H-uFGu7p#}F8p~^HWb6%5f6eZ#t{J;D2`@KWStSE^^QhRi5-jJ!%7SLB z9M*=(M)~r;H62g1vrD-8xva8drw8QBD>}n*dTw+5s}ul|jr_^?YFZf7>rk-CNB9fm zp>U_fE01M4@A1Tey!tkQ*s`9F&W`j@sz0xx6&Ea!%lo16*S>59Lpq>M#l6|fg2+-y zyj{W9>u-EruTbCF-`9Lzu8(PM;YMF%5z+L~&~ zr`a+Ca|@ntTT8*AfLya7?d;l&@gD`dlyX$`Hqp=b=hEY`a&3+yEQ=q1R;HDhi77B3 z|I-A&D#&U%%p1mDttts8wVztxl~5ysT!2+nq-5PDPc zP_jz;l^rN6fx})W&Suk}T&QISLoN_tudY=E=HVFjAhI3=n6kjpQdnxq}~kjIxBeHbkyk`vkiB zUo*EIhA6~FP4iuI1Dz}vB30BxJB2s4dyGTL%dK()R58=J8q>%z0%Cw7=-f~3`|tAo zU@}yuZ$7O)K;R`ao_z*}MdsEY8S|3oZ`D1<;7c6Iou7BnFo%F{P&g|EF}klrb1c7x zIEVQ!k!-I~c_O96H~Tp<&>}moTsIc<07*ymoQU<>;}8Ke>sNBk9Nr0yT}pVtK5z zS7cc({-6rSi}KNc;HC*y86z3+q)^kdNLin$NRQQOB=(`+(eNo<5WQaRowJ}aOiWW7 zIHr|7ep%~JSYGgGH~NJS&mmkwOJK0+IH-}I+AQqUE!!< z{E~lnzdIgPAPx;kh2!XWNvRtHm|NSe2UKB{ZUvzN8AZ6Q%ZCmf0I20q2fh>gP^_{3 z>y@+OPr<0y0%Z}_GWeqg)gTHX!E?sg`|Z3OznkFbjI3>8=M4OtkhUo4bxjhy@zyC} zaZ%svP6zh!TGa>M52Ap-KFCCSqXn1-4DI`g+WmyQ`lJ)SX}dyH`Q9T$;uT%Df>E%4 zDN`0*&k5kvq!RgN;6|Y#L20uL1wE7B|>&_l2F4w9tM53K7RE2y<$< z7y?&LOGFBmWFsd)T%;UOF14x|e|b#>=2S764&$qhH>7V#^M=Z@wr~^$f{$`{qCO5r zA@K|$lKFm(Hzv&JjI78#y&3&pLOOl;RuO&U&jM~MhQx_@WreCmuNZ zDNSP=LO~47GXl@U)SDz^;Ys+ZiI7<_>zq=_b(oBv^h|`6?go=%8kPDznzvAeUGbdQ z?c#0~Q}?!8foHx~Uu><(8}+eA9Fq1C4;4I(80-2{@FsqGghP|F%7jZqEf=e*kl%P8 zdiJaT6}tQD$9w9e7Uw&2!nl#2NB%&mcMPa;Y_Pr)3Q zO$2Kjm&X>r;6qYgSceskbj^8IAxj?&K>vs^-B~5_B~f*|IlkxHgMuh{!}ShaFSyYC z4OkTztT3<@`=p8+eQQb;S#TB8y*M&3`vzBzjiFwcOm?6mv&U(p%?js3*XpbO>mWvb za;o`uns=)?41klv5q};cEqO6j|Bh7f;P8>$=(#>CMFOi09Q5C5_5Py?jT5 z0c5sV59i$ZE|OZQw4`~(pJ%hL#udY!-z9V-lPEb-w6dE?rj{AmwI`-)Oq3asknF3C z-gtCT_thftzyVMz^iXa*W$O|V^5y_XYfHgB-mKHut7Fk$GKk~(cXZCdx+b~8GSS7A z`{&79<}M&Fl-BAZ`D3(4+S$yTO;*HcS~UJaIB0*$x2!t&1l=2DO_aE;@a`5|u?u=fB{d8Xjv$@zjovV%Sz@$0=AJQ}>)7>Q~_A7?-q^GF{JDur}#EkUS9zitqY znBD#l5C4G5eLw?u;YrWdX@3JZ74aL%i#F?ZiWQjId5z{Rv64cPUt2H`-qTgHjA8~A zxR3%R2^{1M2tKK=*6NEugJa+#?cIWKK!ugr>bbbW?mc zWmR%9>_;stWwq<_?3eqzZlwgZlYH zBZE`uAqTA<8!ZJrZ!_Z$p%0H=#9!GL*J;BrqGyz`7vSO1L+ysJl)&JN2%7I&ozQ!8 zE;grt=_S4uq&2?5K&TP%01z}{VXsjf3YiVqd^{O`9v_XWLkur9te1q$FP6+;8K28N(_i?W-=oFpKqB z2bw-B35KENMuY2cwh{H~YNv-A^A#B7klY347I>$`id%;CgN6P=qb?q&?XBN2KL|+W z?!Yh=@i)^>G&7hK0lf^4&7v{?9J=&d&@3hBbS5ujBsLX4&i4cCjsqEW`B z8S#_^MD7TZkG9xZ{}72e?F0@7aKPC|Taqncq~{jY`nT0U4;iY|9-s=$5CxDWDQ%@8 zY!8)q`vwQeE<-OdKWr|aIr0P0>i?&i%`P=5wSjo0>7M&;i~u*_Q4mdfRcw`Cmt$IZ!Lah} zKZ8`10+KD!OMX%$S9U^ryEb>@N$oJG!>^KFXknnmsGnOj3y*3sJ;3_!Doy4EOVXpM z&R*mmba5J!GO1{x2_TCNNhy0EEPq` zx?U&~tTxPZ_>9&K;*tN7fqBDNnATZKSP zA@YygUBs4%zg0vG6ro@SoW^xRqffvptBnixm(Xbr{q3K2q48>X5S!XSH(*S|Kpuao`sqTp**iX7xb&pkP zaRi@Yg>HbpVAd*fV|}sJj-r$5SJ;zx+f{ynMxKRd!8Ml0z?^z=z?0e!ai)V+67jxn zJ-^OZo5|KOY!>TTr*X5C*U95mPvi^XKW)d%!_({~nxt;Eo5MF3q>yR3>02jiOL}S+ zd9K~a3}zhqHQ92&r9{VL?KJe+AXk?E6(e=;iX_bmj#GJ?#G}0#t=!KZ!aqU8_vy}gjz7bC9yHYRgTJj{bN zOr3JItcb(Ir8>qh6L#89HQAxzo^ zxt**37%2U@a!sX2_HmAL;lDVLw(PIUB7yqGbE^8>&i@+_@;{*+{~Hj}_g_}X|8vyG o|4se)Z|nU3B#e9n+`qw(q}Hedq+~;3fhllG^6GMRG8U2l2aHE0rvLx| literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100755 index 0000000000000000000000000000000000000000..60bf0eadf75c86e5d25cc1da13fe5ecc2c39c559 GIT binary patch literal 2078 zcmV+(2;ujMP)%q2v2@fKtSxpMXgijv z)fq>Pk#L19Fsu4()DBYp45dn$d|w7L$xim4(ghvO{2KV_ z+$Hm-4+=-lCvt6F`pHd82H&_b<~Ep`2qG%4yaCtnEHo$PE&9r=><>InhMM}#Bal70 zUf^jnRszc83E!|N`Rx5SryfTxDP-4{&|41om~VDuv~w6qd_&luzjUVa)#`{hUuj_d z;-TjOk+N;g#m|ICGUpTKol4b;)1*uMHFL8MKCv|ZGRhN>F6J+sEPnK@OTq0qxW^;f zg69Z@bb;=ln|bV!1*zxYUSeI~E&nck;GNdstHrvQ!1<(5!-Ux5Sj-IZ@~z9_hm@9c zE=m9VKe5%jFN9tTX%YuDVJH!eouF`WsM|Wyn`O<*Zm_?u*sYJ{@7&uK*yeKV5{&S) zf#D@;b0Y7ma@VA6+_UYN`OwQ}B0oEqG|om0!Iap5_k7kT+~I_CKtiX80<7AJ0rPaZ z$s@I8-V)2;;r=XZJJD}8sl};Mn=-J3lr@S-XWVVx+a1}{8floz^ZAs;b2h>Rf?{4D z^A`SaVe^surn)X<`3X?*m}zB|{wl#5hVBPZ8SoJ>C^ggHJ& zx0Sp1si3Y+b8e32LIJZ*~&~tlQ1KZVPQ14EFNvvQ_c$BZaG4nui zke92eo8#uY4zLT0B79WUpPv6pSzi13~yl3@aY!Vu178d^4!sM@D=Xy%{JJJL?)ngsl-cqztS?SeY zO~&FDDw{A}5^59%@@`tejg+Ez9(j=&w@AtmakDw%=5h#Acvjf}6hIna>VW==n%wuW zCZH7%=)I1>o{a}fmn#of&BN852^-5mIThw!4j|1IO27=2!$K6yTml7F-~ax}>{KQn zjE2;Xz?@;%>N~$rG97V&c+7&{K$p>Y#^~L7Cb$Xw{ErmEDfhcxH^RoXMF^p8&I4{Q zxRJ`)US#I2eyHR#ESu;RU?yxh-ZOLm3(FF9_x?mxK=kz9&3dZ0L&1z8uv*~egMsD8 zd)R?N6h_bl5S7nlEzr1Es~V=hBY@**wzB?9AT$HY%MG=k_y=&W!NR0AJkVX#dURK~ z_2?_Gpf0HyL{)>vU6ICNaT?DSsfHClwJam54_rP4XwZ=jbBfkyMAasONq0b2&-iAz zBvH5gX{-OjyP?a+_H(P4zygd3HYa(W*-1Y$Yw;KR?s)h$5h#jE-$y08_f<%$sdOf7 z_$KU5AS}l0v`x4-Fg$zlYTz4XY8HKy`fjHgzkGsvIoKYcseu!oae!Q=Y8%(}ec|C< zoEbp@x~w>~BB;^Six{6>uj#+KrjZ|wE4j8-`G01;LAUvP8La~Av50E6zu%( zZY|w^R=t)Fm)B;i7OZi~W-o%i6Ra$VVl8{NmL1voxX>*yAjzj}sjk!d6ucbxl|v0H zpBijfwOJHk8)-|xibe~OjME1Qpjh+UKQ3v0dkbg-j|+CHR{8pk0ANTN33RsnE7<-1 z>mZ_t(1Vpgg{5|`!W&TAnw=gBb)0;o;?SSI6~1`*ub=^P<-=l{CUUA~50uWpwR{i} z@h5!Hn literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100755 index 0000000000000000000000000000000000000000..c8ca0ad132e0184b64cd2e4a38cfceab3c4b3a46 GIT binary patch literal 28507 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100755 index 0000000000000000000000000000000000000000..8756459b63d6e8dd6003b97613befbe2743441cb GIT binary patch literal 3419 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100755 index 0000000000000000000000000000000000000000..2c8023cc824417a29378a68471b8fb3af33fdeb0 GIT binary patch literal 6027 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�rop@t+= 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 V#?y`xQ)U1F002ovPDHLkV1n!EW;y@> literal 0 HcmV?d00001 diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100755 index 0000000000000000000000000000000000000000..17d142c0a43208db62ca28b86a3239329ac93aea GIT binary patch literal 3971 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100755 index 0000000000000000000000000000000000000000..1bf69b8dde150aadb1b8142196ea5bede16b2356 GIT binary patch literal 64413 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 YUZV;0WBSa3IG5A literal 0 HcmV?d00001 diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100755 index 0000000000000000000000000000000000000000..06c23c82fea615c9394c4c7f487392e3f0a2fd4a GIT binary patch literal 37710 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
j#(n6`cTK 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 div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/src/App.jsx b/src/App.jsx new file mode 100755 index 0000000..71f927f --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,684 @@ +import React, { useState, useEffect, useCallback, useRef } from "react"; +import { STORAGE_KEY, NAV_ITEMS, defaultData } from "./constants.js"; +import { migrateDashboardLayout } from "./utils.js"; +import Dashboard from "./views/Dashboard.jsx"; +import { Projects, ProjectDetail } from "./views/Projects.jsx"; +import Time from "./views/Time.jsx"; +import { Spesen, InternalExpenses } from "./views/Spesen.jsx"; +import Protokolle from "./views/Protokolle.jsx"; +import Lieferscheine from "./views/Lieferscheine.jsx"; +import Buchhaltung from "./views/Buchhaltung.jsx"; +import Invoices from "./views/Invoices.jsx"; +import Quotes from "./views/Quotes.jsx"; +import Personen from "./views/Personen.jsx"; +import Letters from "./views/Letters.jsx"; +import Settings from "./views/Settings.jsx"; +import StudioBudget from "./views/StudioBudget.jsx"; +import Loehne from "./views/Loehne.jsx"; +import Mitarbeiter from "./views/Mitarbeiter.jsx"; +import Pinnwand from "./views/Pinnwand.jsx"; +import Dokumente from "./views/Dokumente.jsx"; +import { PrintView } from "./print/PrintComponents.jsx"; +import Login from "./views/Login.jsx"; +import Setup from "./views/Setup.jsx"; +import MigrationScreen from "./views/MigrationScreen.jsx"; + +export default function App() { + const [data, setData] = useState(() => { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (stored) { + const parsed = JSON.parse(stored); + let merged = { ...defaultData, ...parsed, settings: { ...defaultData.settings, ...parsed.settings } }; + + // Migrate: clients[] + contacts[] → persons[] + if (!merged.persons && (merged.clients?.length || merged.contacts?.length)) { + const idMap = {}; + const persons = []; + const usedContactIds = new Set(); + for (const c of merged.clients || []) { + const linked = (merged.contacts || []).find(ct => ct.id === c.linkedContactId); + persons.push({ + ...c, + isAuftraggeber: true, + isPartner: !!linked, + type: c.type || linked?.type || "", + note: c.note || linked?.note || "", + honorarOffers: c.honorarOffers || linked?.honorarOffers || [], + contacts: c.contacts?.length ? c.contacts : (linked?.contacts || []), + linkedContactId: undefined, + linkedClientId: undefined, + }); + if (linked) { usedContactIds.add(linked.id); idMap[linked.id] = c.id; } + } + for (const ct of merged.contacts || []) { + if (usedContactIds.has(ct.id)) continue; + persons.push({ ...ct, isAuftraggeber: false, isPartner: true, linkedClientId: undefined }); + } + const remapProjects = (merged.projects || []).map(p => ({ + ...p, + projectContacts: (p.projectContacts || []).map(pc => ({ ...pc, contactId: idMap[pc.contactId] || pc.contactId })), + })); + const remapProtocols = (merged.protocols || []).map(p => ({ + ...p, + entries: (p.entries || []).map(e => ({ ...e, assignee: e.assignee ? (idMap[e.assignee] || e.assignee) : e.assignee })), + })); + merged = { ...merged, persons, projects: remapProjects, protocols: remapProtocols, clients: undefined, contacts: undefined }; + } + + // Migrate: projects linked to SIA/manual quotes should be pauschal (not stundensatz) + const allQuotes = merged.quotes || []; + const projects = (merged.projects || []).map(p => { + if ((p.billingType || p.type || "stundensatz") === "stundensatz" && (p.linkedQuotes || []).length > 0) { + const linkedQs = (p.linkedQuotes || []).map(lq => allQuotes.find(q => q.id === lq.quoteId)).filter(Boolean); + if (linkedQs.some(q => q.mode === "sia" || q.mode === "manual")) { + return { ...p, billingType: "pauschal", budget: p.budget || p.budgetAmount || 0 }; + } + } + return p; + }); + // Migrate: add r-projektleiter if missing, seed dashboardTemplateId from defaultData + const roleDefMap = (defaultData.appRoles || []).reduce((acc, r) => { acc[r.id] = r; return acc; }, {}); + const roles = (merged.appRoles || defaultData.appRoles).map(r => ({ + ...r, + dashboardTemplateId: r.dashboardTemplateId || roleDefMap[r.id]?.dashboardTemplateId || null, + permissions: (() => { + let perms = r.permissions; + if (perms && r.id === "r-projektleiter" && !perms.includes("mitarbeiter")) perms = [...perms, "mitarbeiter"]; + if (perms && !perms.includes("settings")) perms = [...perms, "settings"]; + return perms; + })(), + })); + if (!roles.find(r => r.id === "r-projektleiter") && roleDefMap["r-projektleiter"]) { + const adminIdx = roles.findIndex(r => r.id === "r-admin"); + roles.splice(adminIdx + 1, 0, roleDefMap["r-projektleiter"]); + } + // Migrate user-level dashboardWidgets to Row[] format + const users = (merged.users || []).map(u => ({ + ...u, + dashboardWidgets: u.dashboardWidgets ? migrateDashboardLayout(u.dashboardWidgets) : undefined, + })); + // Ensure dashboardTemplates exist (old data won't have them) + const dashboardTemplates = merged.dashboardTemplates?.length ? merged.dashboardTemplates : defaultData.dashboardTemplates; + return { ...merged, projects, appRoles: roles, users, dashboardTemplates }; + } + } catch {} + return defaultData; + }); + const [isNewInstall] = useState(() => !localStorage.getItem(STORAGE_KEY)); + const [currentUser, setCurrentUser] = useState(() => { + try { return JSON.parse(sessionStorage.getItem("rapport_user")) || null; } catch { return null; } + }); + const handleLogin = (user) => { + sessionStorage.setItem("rapport_user", JSON.stringify(user)); + setCurrentUser(user); + }; + const handleLogout = () => { + sessionStorage.removeItem("rapport_user"); + setCurrentUser(null); + }; + const handleSetupComplete = (newData) => { + localStorage.setItem("rapport_v0_5_migrated", "1"); + save(newData); + const adminUser = (newData.users || []).find(u => u.role === "admin"); + if (adminUser) handleLogin(adminUser); + }; + const userPermissions = (() => { + if (!currentUser || currentUser.role === "admin") return null; + const role = (data.appRoles || []).find(r => r.id === currentUser.appRoleId); + if (role) return role.permissions; // null = alle + return currentUser.permissions || null; // Fallback für alte Einträge ohne Rolle + })(); + const currentUserRecord = (data.users || []).find(u => u.id === currentUser?.id); + const userInitials = (() => { + const parts = ((currentUser?.displayName || currentUser?.username) || "").trim().split(/\s+/).filter(Boolean); + if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); + return (parts[0] || "?")[0].toUpperCase(); + })(); + const visibleNavItems = userPermissions === null ? NAV_ITEMS : NAV_ITEMS.map(item => { + if (item.children) { + const ch = item.children.filter(c => userPermissions.includes(c.id)); + return ch.length > 0 ? { ...item, children: ch } : null; + } + return userPermissions.includes(item.id) ? item : null; + }).filter(Boolean); + const allAccessibleViews = visibleNavItems.flatMap(item => item.children ? item.children.map(c => c.id) : [item.id]); + const [view, setView] = useState(() => { + if (!userPermissions) return "dashboard"; + return userPermissions.includes("dashboard") ? "dashboard" : (userPermissions[0] || "dashboard"); + }); + const navHistRef = useRef([view]); + const navPosRef = useRef(0); + const [navCanBack, setNavCanBack] = useState(false); + const [navCanForward, setNavCanForward] = useState(false); + + const navigate = (newView) => { + const pos = navPosRef.current; + const hist = navHistRef.current; + if (hist[pos] === newView) return; + const trimmed = [...hist.slice(0, pos + 1), newView]; + navHistRef.current = trimmed; + navPosRef.current = trimmed.length - 1; + setView(newView); + setNavCanBack(true); + setNavCanForward(false); + }; + const goBack = () => { + const pos = navPosRef.current; + if (pos <= 0) return; + navPosRef.current = pos - 1; + setView(navHistRef.current[pos - 1]); + setNavCanBack(pos - 1 > 0); + setNavCanForward(true); + }; + const goForward = () => { + const pos = navPosRef.current; + const hist = navHistRef.current; + if (pos >= hist.length - 1) return; + navPosRef.current = pos + 1; + setView(hist[pos + 1]); + setNavCanBack(true); + setNavCanForward(pos + 1 < hist.length - 1); + }; + + const [selectedProjectId, setSelectedProjectId] = useState(null); + const [modal, setModal] = useState(null); + const [printContent, setPrintContent] = useState(null); + const [darkMode, setDarkMode] = useState(() => localStorage.getItem("rapport_dark") === "1"); + const [showChangelog, setShowChangelog] = useState(() => localStorage.getItem("rapport_changelog_seen") !== "0.5"); + const [changelogVersion, setChangelogVersion] = useState("0.5"); + const [navOpen, setNavOpen] = useState(false); + const [expandedNav, setExpandedNav] = useState(new Set(["buchhaltung"])); + const [sidebarCollapsed, setSidebarCollapsed] = useState(() => localStorage.getItem("rapport_sidebar_collapsed") === "1"); + const [isMobile, setIsMobile] = useState(() => window.matchMedia("(max-width: 768px)").matches); + useEffect(() => { + const mq = window.matchMedia("(max-width: 768px)"); + const handler = (e) => setIsMobile(e.matches); + mq.addEventListener("change", handler); + return () => mq.removeEventListener("change", handler); + }, []); + const collapsed = sidebarCollapsed && !isMobile; + const [uiZoom, setUiZoom] = useState(() => parseFloat(localStorage.getItem("rapport_zoom") || "1")); + + // Persist dark mode + useEffect(() => { localStorage.setItem("rapport_dark", darkMode ? "1" : "0"); }, [darkMode]); + useEffect(() => { localStorage.setItem("rapport_sidebar_collapsed", sidebarCollapsed ? "1" : "0"); }, [sidebarCollapsed]); + + // UI-Zoom: nur main-content, Sidebar bleibt unberührt + useEffect(() => { + localStorage.setItem("rapport_zoom", String(uiZoom)); + // Tauri: native WebView-Zoom entfernen falls gesetzt (Sidebar-Problem) + if (window.__TAURI_INTERNALS__) { + import("@tauri-apps/api/webviewWindow") + .then(({ getCurrentWebviewWindow }) => getCurrentWebviewWindow().setZoom(1)) + .catch(() => {}); + } + }, [uiZoom]); + + const zoomStep = 0.05; + const zoomIn = () => setUiZoom(z => Math.min(1.5, Math.round((z + zoomStep) * 100) / 100)); + const zoomOut = () => setUiZoom(z => Math.max(0.5, Math.round((z - zoomStep) * 100) / 100)); + + + // Navigation zu Protokoll von Projekt aus + useEffect(() => { + const handler = (e) => { + navigate("protokolle"); + window.__openProtokoll = e.detail?.id || null; + }; + window.addEventListener("openProtokoll", handler); + return () => window.removeEventListener("openProtokoll", handler); + }, []); + + // Auto-expand parent when navigating to a child + useEffect(() => { + NAV_ITEMS.forEach(item => { + if (item.children?.some(c => c.id === view)) { + setExpandedNav(prev => { const next = new Set(prev); next.add(item.id); return next; }); + } + }); + }, [view]); + + const save = useCallback((newData) => { + setData(newData); + try { localStorage.setItem(STORAGE_KEY, JSON.stringify(newData)); } catch {} + }, []); + + const update = useCallback((key, value) => { + save({ ...data, [key]: value }); + }, [data, save]); + + // Auto-überfällig + useEffect(() => { + const today = new Date().toISOString().slice(0, 10); + const updated = data.invoices.map(inv => + inv.status === "gesendet" && inv.dueDate && inv.dueDate < today + ? { ...inv, status: "überfällig" } : inv + ); + if (updated.some((inv, i) => inv.status !== data.invoices[i].status)) + save({ ...data, invoices: updated }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (isNewInstall && !data.settings.setupCompleted) { + return ; + } + + if (!localStorage.getItem("rapport_v0_5_migrated")) { + return ; + } + + if (!currentUser) { + return ; + } + + if (printContent) { + return setPrintContent(null)} settings={data.settings} />; + } + + return ( +
+ + + {/* Mobile Header */} +
+ +
RAPPORT
+
+ + {/* Sidebar */} +
+
+ {collapsed ? ( + + ) : ( + <> + + + + )} +
+ + {/* ── Vor / Zurück ── */} +
+ {[["goBack", "‹", goBack, navCanBack, "Zurück"], ["goForward", "›", goForward, navCanForward, "Vorwärts"]].map(([key, ch, fn, enabled, title]) => ( + + ))} +
+ + {!collapsed &&
} + + {/* Benutzer + Logout + Theme */} +
+ {!collapsed && ( +
+
+ {currentUserRecord?.avatar + ? + : userInitials} +
+
+
+ {currentUser.displayName || currentUser.username} +
+ {currentUser.role === "admin" &&
ADMIN
} +
+
+ )} +
+ + +
+
+
+ + {/* Main */} +
+ {view === "dashboard" && } + {view === "pinnwand" && } + {view === "projects" && !selectedProjectId && } + {view === "projects" && selectedProjectId && setSelectedProjectId(null)} setPrintContent={setPrintContent} modal={modal} setModal={setModal} currentUser={currentUser} />} + {view === "time" &&
+ + {showChangelog && (() => { + const CHANGELOGS = { + "0.5": { + items: [ + ["Anmeldesystem", "Benutzerverwaltung mit Rollen und Passwörtern. Jeder Mitarbeiter erhält einen eigenen Login. Berechtigungen steuern, welche Module sichtbar sind."], + ["Migration bestehender Daten", "Beim ersten Start mit einer bestehenden Datenbank erscheint ein Migrations-Assistent: Daten sichern, Admin-Konto einrichten — alle bisherigen Inhalte bleiben erhalten."], + ["Rechnungstypen: Akonto / Teilrechnung / Schluss", "Klare Trennung der Rechnungsarten mit unterschiedlicher steuerlicher Behandlung. Akonto ist erst bei der Schlussrechnung steuerrelevant; Teilrechnungen sind sofort wirksam."], + ["Neuer Rechnungsdialog", "Zweistufige Auswahl: zuerst Art der Rechnung (Akonto / Teilrechnung / Schlussrechnung), dann Berechnungsmethode (Stunden / % vom Budget / Fixer Betrag / SIA-Phase)."], + ["Akonto & Teilrechnung nach SIA-Phase", "Für Pauschal-Projekte können einzelne SIA-Phasen direkt verrechnet werden — bereits verrechnete Phasen werden als solche markiert."], + ["Aufwandsrechnungen erweitert", "Stundenprojekte unterstützen jetzt Akonto (Stunden bis heute, %, Fixbetrag) und Teilrechnung (Stunden auswählen, %, Fixbetrag, SIA-Phase)."], + ["Buchhaltung: Akonto-MwSt getrennt", "Akonto-Rechnungen werden in der Buchhaltung separat ausgewiesen — die MwSt wird erst bei der Schlussrechnung als steuerrelevant gezählt."], + ["Mitarbeiter: Intern & Absenzen", "Umbenennung zu «Intern / Absenzen». Neue Jahresübersicht mit Monatsvergleich und Vorjahr, Absenzkategorien-Matrix, sowie Auswertung interner Stunden ohne Projektbezug."], + ], + }, + "0.4": { + items: [ + ["Material Design 3", "Sidebar mit einklappbarem Icon-Modus und Material Symbols Rounded Icons. Buttons als Pill, Inputs und Cards mit mehr Radius, Tags als Chips, Modals mit Backdrop-Blur."], + ["Interne Projektbeteiligung", "Mitarbeitende können direkt im Projekt zugewiesen werden. In Protokollen erscheinen unter «Intern» nur noch die zugewiesenen Personen."], + ["Offerten im Budget", "Neben Rechnungen können jetzt auch Offerten in die Einnahmen-Planung des Bürobudgets einbezogen werden."], + ["Kategorien direkt auf der Seite", "Spesenarten und Ausgaben-Kategorien werden neu direkt auf der jeweiligen Seite verwaltet, nicht mehr in den Einstellungen."], + ], + }, + "0.3": { + items: [ + ["Visuelles Redesign", "Sidebar schwebt als eigenständiges Panel mit Radius und Schatten. Cards haben mehr Tiefe. Header kompakter, Abstände überarbeitet, Menüpunkte in Kapitälchen. Studio-Name in der Sidebar."], + ["Zoom", "Der UI-Zoom betrifft nur den Hauptinhalt — die Sidebar bleibt immer gleich gross und unverzerrt."], + ], + }, + "0.2": { + items: [ + ["Neue Module", "Lohnabrechnung, Bürobudget, Protokolle, Lieferscheine und Spesen (Mitarbeiter & intern) hinzugefügt."], + ["Zeiterfassung Wochenansicht", "Visuelles Zeitraster mit Drag & Drop — Einträge verschieben und skalieren, Wechsel zwischen Tag-, Wochen- und Monatsansicht."], + ["Ferienplanung", "Ferienanträge stellen, genehmigen und zurückziehen. Absenzverwaltung ausgebaut."], + ["Teilzeit", "Lohn wird proportional zum Pensum berechnet, pro Monat überschreibbar."], + ], + }, + "0.1": { + items: [ + ["Erster Release", "Projekte, Kunden, Mitarbeiterverwaltung, Zeiterfassung."], + ["Rechnungen & Offerten", "Rechnungen mit QR-Einzahlungsschein, Offerten nach SIA 102, manuell oder frei — konvertierbar zur Rechnung."], + ["Einstellungen", "Studio-Stammdaten, Stundensätze, Rollen, MwSt und Projektnummern-Format."], + ], + }, + }; + const versions = Object.keys(CHANGELOGS); + const current = CHANGELOGS[changelogVersion] || CHANGELOGS["0.5"]; + return ( +
+
+
+
CHANGELOG
+
+
Alpha {changelogVersion}
+
+
+ {versions.map(v => ( + + ))} +
+
+
+ {current.items.map(([title, desc]) => ( +
+
+
+
{title}
+
{desc}
+
+
+ ))} +
+
+ +
+
+
+ ); + })()} +
+ ); +} diff --git a/src/App.jsx.bak b/src/App.jsx.bak new file mode 100755 index 0000000..5b15ac2 --- /dev/null +++ b/src/App.jsx.bak @@ -0,0 +1,451 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { STORAGE_KEY, NAV_ITEMS, defaultData } from "./constants.js"; +import Dashboard from "./views/Dashboard.jsx"; +import { Projects, ProjectDetail } from "./views/Projects.jsx"; +import Time from "./views/Time.jsx"; +import { Spesen, InternalExpenses } from "./views/Spesen.jsx"; +import Protokolle from "./views/Protokolle.jsx"; +import Lieferscheine from "./views/Lieferscheine.jsx"; +import Buchhaltung from "./views/Buchhaltung.jsx"; +import Invoices from "./views/Invoices.jsx"; +import Quotes, { ConvertQuoteModal } from "./views/Quotes.jsx"; +import Personen from "./views/Personen.jsx"; +import Letters from "./views/Letters.jsx"; +import Settings from "./views/Settings.jsx"; +import StudioBudget from "./views/StudioBudget.jsx"; +import Loehne from "./views/Loehne.jsx"; +import Mitarbeiter from "./views/Mitarbeiter.jsx"; +import Dokumente from "./views/Dokumente.jsx"; +import { PrintView } from "./print/PrintComponents.jsx"; + +export default function App() { + const [data, setData] = useState(() => { + try { + const stored = localStorage.getItem(STORAGE_KEY); + if (stored) { + const parsed = JSON.parse(stored); + let merged = { ...defaultData, ...parsed, settings: { ...defaultData.settings, ...parsed.settings } }; + + // Migrate: clients[] + contacts[] → persons[] + if (!merged.persons && (merged.clients?.length || merged.contacts?.length)) { + const idMap = {}; + const persons = []; + const usedContactIds = new Set(); + for (const c of merged.clients || []) { + const linked = (merged.contacts || []).find(ct => ct.id === c.linkedContactId); + persons.push({ + ...c, + isAuftraggeber: true, + isPartner: !!linked, + type: c.type || linked?.type || "", + note: c.note || linked?.note || "", + honorarOffers: c.honorarOffers || linked?.honorarOffers || [], + contacts: c.contacts?.length ? c.contacts : (linked?.contacts || []), + linkedContactId: undefined, + linkedClientId: undefined, + }); + if (linked) { usedContactIds.add(linked.id); idMap[linked.id] = c.id; } + } + for (const ct of merged.contacts || []) { + if (usedContactIds.has(ct.id)) continue; + persons.push({ ...ct, isAuftraggeber: false, isPartner: true, linkedClientId: undefined }); + } + const remapProjects = (merged.projects || []).map(p => ({ + ...p, + projectContacts: (p.projectContacts || []).map(pc => ({ ...pc, contactId: idMap[pc.contactId] || pc.contactId })), + })); + const remapProtocols = (merged.protocols || []).map(p => ({ + ...p, + entries: (p.entries || []).map(e => ({ ...e, assignee: e.assignee ? (idMap[e.assignee] || e.assignee) : e.assignee })), + })); + merged = { ...merged, persons, projects: remapProjects, protocols: remapProtocols, clients: undefined, contacts: undefined }; + } + + // Migrate: projects linked to SIA/manual quotes should be pauschal (not stundensatz) + const allQuotes = merged.quotes || []; + const projects = (merged.projects || []).map(p => { + if ((p.billingType || p.type || "stundensatz") === "stundensatz" && (p.linkedQuotes || []).length > 0) { + const linkedQs = (p.linkedQuotes || []).map(lq => allQuotes.find(q => q.id === lq.quoteId)).filter(Boolean); + if (linkedQs.some(q => q.mode === "sia" || q.mode === "manual")) { + return { ...p, billingType: "pauschal", budget: p.budget || p.budgetAmount || 0 }; + } + } + return p; + }); + return { ...merged, projects }; + } + } catch {} + return defaultData; + }); + const [view, setView] = useState("dashboard"); + const [selectedProjectId, setSelectedProjectId] = useState(null); + const [modal, setModal] = useState(null); + const [printContent, setPrintContent] = useState(null); + const [darkMode, setDarkMode] = useState(() => localStorage.getItem("rapport_dark") === "1"); + const [whatsNewDismissed, setWhatsNewDismissed] = useState(() => localStorage.getItem("rapport_whats_new_v0_2_0") === "1"); + const [navOpen, setNavOpen] = useState(false); + const [expandedNav, setExpandedNav] = useState(new Set(["buchhaltung"])); + const [uiZoom, setUiZoom] = useState(() => parseFloat(localStorage.getItem("rapport_zoom") || "1")); + + // Persist dark mode + useEffect(() => { localStorage.setItem("rapport_dark", darkMode ? "1" : "0"); }, [darkMode]); + + // UI-Zoom via Tauri native API (kein CSS-Balken-Problem), Fallback auf document.body.style.zoom + useEffect(() => { + localStorage.setItem("rapport_zoom", String(uiZoom)); + const apply = async () => { + try { + if (window.__TAURI_INTERNALS__) { + const { getCurrentWebviewWindow } = await import("@tauri-apps/api/webviewWindow"); + await getCurrentWebviewWindow().setZoom(uiZoom); + } else { + document.body.style.zoom = uiZoom === 1 ? "" : String(uiZoom); + } + } catch { + document.body.style.zoom = uiZoom === 1 ? "" : String(uiZoom); + } + }; + apply(); + }, [uiZoom]); + + const zoomStep = 0.05; + const zoomIn = () => setUiZoom(z => Math.min(1.5, Math.round((z + zoomStep) * 100) / 100)); + const zoomOut = () => setUiZoom(z => Math.max(0.5, Math.round((z - zoomStep) * 100) / 100)); + + + // Navigation zu Protokoll von Projekt aus + useEffect(() => { + const handler = (e) => { + setView("protokolle"); + window.__openProtokoll = e.detail?.id || null; + }; + window.addEventListener("openProtokoll", handler); + return () => window.removeEventListener("openProtokoll", handler); + }, []); + + // Auto-expand parent when navigating to a child + useEffect(() => { + NAV_ITEMS.forEach(item => { + if (item.children?.some(c => c.id === view)) { + setExpandedNav(prev => { const next = new Set(prev); next.add(item.id); return next; }); + } + }); + }, [view]); + + const save = useCallback((newData) => { + setData(newData); + try { localStorage.setItem(STORAGE_KEY, JSON.stringify(newData)); } catch {} + }, []); + + const update = useCallback((key, value) => { + save({ ...data, [key]: value }); + }, [data, save]); + + // Auto-überfällig + useEffect(() => { + const today = new Date().toISOString().slice(0, 10); + const updated = data.invoices.map(inv => + inv.status === "gesendet" && inv.dueDate && inv.dueDate < today + ? { ...inv, status: "überfällig" } : inv + ); + if (updated.some((inv, i) => inv.status !== data.invoices[i].status)) + save({ ...data, invoices: updated }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (printContent) { + return setPrintContent(null)} settings={data.settings} />; + } + + return ( +
+ + + {/* Mobile Header */} +
+ +
RAPPORT
+
{NAV_ITEMS.find(n => n.id === view || (n.children||[]).some(c=>c.id===view))?.label || ""}
+
+ + {/* Sidebar */} +
+
+
+
RAPPORT
+
STUDIO ADMINISTRATION
+
+ +
+ + {/* Zoom-Steuerung */} +
+ + + +
+ +
+
ALPHA 0.2.1
+
+
+
+
AGPL-3.0
+
+ +
+
+
+
+ + {/* Main */} +
+ {view === "dashboard" && } + {view === "projects" && !selectedProjectId && } + {view === "projects" && selectedProjectId && setSelectedProjectId(null)} setPrintContent={setPrintContent} modal={modal} setModal={setModal} />} + {view === "time" &&
+ + {!whatsNewDismissed && ( +
+
+
+
NEUERUNGEN
+
Version 0.2.0
+
+
+ {[ + ["Wochenansicht", "Zeiterfassung mit Kalender-Ansicht, Einträge per Drag & Drop verschieben und skalieren"], + ["Tagessaldo", "Wochenkopf zeigt Soll/Ist-Differenz pro Tag — wie im Monatskalender"], + ["Eintrag kopieren", "Rechtsklick auf einen Eintrag → auf morgen duplizieren"], + ["Teilzeit & Pensum", "Lohn wird automatisch gemäss Pensum berechnet, pro Monat überschreibbar"], + ["Ferien zurückziehen", "Beantragte und genehmigte Ferien können jederzeit zurückgezogen werden"], + ].map(([title, desc]) => ( +
+
+
+
{title}
+
{desc}
+
+
+ ))} +
+
+
+
Datenbank-Neustart empfohlen
+
Aufgrund umfangreicher Neuerungen und fehlerhafter Teile im letzten Build wird empfohlen, unter Einstellungen → Datenbank löschen neu zu starten.
+
+
+
+
+ +
+
+
+ )} +
+ ); +} diff --git a/src/assets/hero.png b/src/assets/hero.png new file mode 100755 index 0000000000000000000000000000000000000000..02251f4b956c55af2d76fd0788124d7eee2b45eb GIT binary patch literal 13057 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 P00000NkvXXu0mjft=yBf literal 0 HcmV?d00001 diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100755 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/vite.svg b/src/assets/vite.svg new file mode 100755 index 0000000..5101b67 --- /dev/null +++ b/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/src/components/UI.jsx b/src/components/UI.jsx new file mode 100755 index 0000000..4a7dcf9 --- /dev/null +++ b/src/components/UI.jsx @@ -0,0 +1,469 @@ +import React, { useState, useEffect, useRef } from "react"; +import { STATUS_COLORS, STATUS_BG } from "../constants.js"; + +export function StatusBadge({ status }) { + const color = STATUS_COLORS[status] || "#888"; + const bg = STATUS_BG[status] || "#f5f5f5"; + return ( + {status} + ); +} + +export function StatusSelect({ value, options, onChange }) { + const color = STATUS_COLORS[value] || "#888"; + const bg = STATUS_BG[value] || "#f5f5f5"; + return ( + + ); +} + +export function Header({ title, action }) { + return ( +
+
+

{title}

+ {action} +
+
+ ); +} + +export function FormField({ label, children }) { + return ( +
+ + {children} +
+ ); +} + +export function Modal({ title, onClose, onSave, saveLabel, hideSave, children, wide, overflow }) { + return ( +
e.target === e.currentTarget && onClose()}> +
+

{title}

+ {children} +
+ + {!hideSave && } +
+
+
+ ); +} + +export function StudioLogo({ settings, size = 24 }) { + if (settings.logo) { + const h = settings.logoSize || 60; + return {settings.name}; + } + return
{settings.name}
; +} + +export function useConfirm() { + const [pending, setPending] = useState(null); + const askConfirm = (msg, confirmLabel = "Löschen") => + new Promise(resolve => setPending({ msg, confirmLabel, resolve })); + const ConfirmModalEl = pending ? ( +
+
+
{pending.msg}
+
+ + +
+
+
+ ) : null; + return { askConfirm, ConfirmModalEl }; +} + +export function DateInput({ value, onChange, style, ...props }) { + const toDE = (iso) => { + if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return ""; + return `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}`; + }; + const toISO = (de) => { + const m = de.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/); + if (!m) return null; + const iso = `${m[3]}-${m[2].padStart(2, "0")}-${m[1].padStart(2, "0")}`; + return isNaN(new Date(iso).getTime()) ? null : iso; + }; + const [text, setText] = React.useState(() => toDE(value)); + React.useEffect(() => { const de = toDE(value); if (de !== text) setText(de); }, [value]); + const handleChange = (e) => { + const digits = e.target.value.replace(/\D/g, "").slice(0, 8); + let fmt = ""; + if (digits.length <= 2) fmt = digits; + else if (digits.length <= 4) fmt = `${digits.slice(0, 2)}.${digits.slice(2)}`; + else fmt = `${digits.slice(0, 2)}.${digits.slice(2, 4)}.${digits.slice(4)}`; + setText(fmt); + const iso = toISO(fmt); + if (iso) onChange({ target: { value: iso } }); + }; + return ( + { if (!toISO(text) && value) setText(toDE(value)); }} + placeholder="TT.MM.JJJJ" + style={style} + {...props} + /> + ); +} + +export function RichEditor({ value, onChange, minHeight = 420, compact = false }) { + const editorRef = React.useRef(null); + const isInternalChange = React.useRef(false); + const lastValue = React.useRef(value); + const savedRange = React.useRef(null); + const colorInputRef = React.useRef(null); + const [colorValue, setColorValue] = React.useState("#000000"); + + // Only push content into DOM when value changes from outside (template load) + useEffect(() => { + if (!editorRef.current) return; + if (value !== lastValue.current && !isInternalChange.current) { + editorRef.current.innerHTML = value; + lastValue.current = value; + } + isInternalChange.current = false; + }, [value]); + + const saveSelection = () => { + const sel = window.getSelection(); + if (sel && sel.rangeCount > 0 && editorRef.current?.contains(sel.anchorNode)) { + savedRange.current = sel.getRangeAt(0).cloneRange(); + } + }; + + const restoreSelection = () => { + editorRef.current?.focus(); + if (!savedRange.current) { + // Place cursor at end if no saved range + const range = document.createRange(); + range.selectNodeContents(editorRef.current); + range.collapse(false); + const sel = window.getSelection(); + if (sel) { sel.removeAllRanges(); sel.addRange(range); } + return; + } + const sel = window.getSelection(); + if (sel) { sel.removeAllRanges(); sel.addRange(savedRange.current); } + }; + + const exec = (cmd, val = null) => { + restoreSelection(); + document.execCommand(cmd, false, val); + saveSelection(); + // Sync content after command + isInternalChange.current = true; + const html = editorRef.current?.innerHTML || ""; + lastValue.current = html; + onChange(html); + }; + + + + const TB = ({ cmd, val, title, style: s, children }) => ( + + ); + const Sep = () =>
; + + return ( +
+
+ B + I + U + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Font size */} + + + + + {/* Color */} + + { setColorValue(e.target.value); exec("foreColor", e.target.value); }} + style={{ position: "absolute", width: 0, height: 0, opacity: 0, pointerEvents: "none" }} + /> +
+ + {/* Editor */} +
{ + isInternalChange.current = true; + const html = editorRef.current?.innerHTML || ""; + lastValue.current = html; + onChange(html); + }} + onKeyUp={saveSelection} + onMouseUp={saveSelection} + onBlur={saveSelection} + onPaste={e => { + e.preventDefault(); + const text = e.clipboardData.getData("text/plain"); + restoreSelection(); + document.execCommand("insertText", false, text); + saveSelection(); + }} + style={{ + minHeight, padding: compact ? "8px 10px" : "20px 24px", outline: "none", + fontSize: compact ? 12 : 13, lineHeight: 1.8, color: "var(--text)", + background: "var(--surface)", + fontFamily: "'DM Mono', 'Courier New', monospace", + }} + /> +
+ ); +} + +export function CalendarPopup({ value, onChange, onClose, align = "left", showClear = true }) { + const [viewYM, setViewYM] = useState(() => { + const d = value ? new Date(value + "T00:00:00") : new Date(); + return { year: d.getFullYear(), month: d.getMonth() }; + }); + const todayStr = new Date().toISOString().slice(0, 10); + const { year, month } = viewYM; + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + const startWeekday = (firstDay.getDay() + 6) % 7; + const cells = []; + for (let i = 0; i < startWeekday; i++) cells.push(null); + for (let d = 1; d <= lastDay.getDate(); d++) { + cells.push(`${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`); + } + const prevMonth = () => { const d = new Date(year, month - 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); }; + const nextMonth = () => { const d = new Date(year, month + 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); }; + const select = (ds) => { onChange(ds); onClose(); }; + + return ( +
e.stopPropagation()} + > +
+ +
+ {firstDay.toLocaleDateString("de-CH", { month: "long", year: "numeric" })} +
+ +
+
+ {["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"].map(d => ( +
{d}
+ ))} +
+
+ {cells.map((ds, i) => { + if (!ds) return
; + const dow = new Date(ds + "T00:00:00").getDay(); + const isWeekend = dow === 0 || dow === 6; + const isSelected = ds === value; + const isToday = ds === todayStr; + return ( + + ); + })} +
+ {showClear && value && ( +
+ +
+ )} +
+ ); +} + +export function DatePicker({ value, onChange, style, placeholder, align = "left", ...props }) { + const [open, setOpen] = useState(false); + const wrapRef = useRef(null); + const toDE = (iso) => { + if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return ""; + return `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}`; + }; + useEffect(() => { + if (!open) return; + const close = (e) => { if (!wrapRef.current?.contains(e.target)) setOpen(false); }; + document.addEventListener("mousedown", close); + return () => document.removeEventListener("mousedown", close); + }, [open]); + return ( +
+ setOpen(o => !o)} + placeholder={placeholder || "TT.MM.JJJJ"} + style={{ cursor: "pointer", ...style }} + {...props} + /> + {open && ( + onChange({ target: { value: ds } })} + onClose={() => setOpen(false)} + align={align} + /> + )} +
+ ); +} + +export function NavArrows({ onPrev, onNext, disabledNext = false }) { + const btn = (onClick, disabled, children) => ( + + ); + return ( +
+ {btn(onPrev, false, "‹")} +
+ {btn(onNext, disabledNext, "›")} +
+ ); +} + +export function useCalendarNav() { + const [open, setOpen] = useState(false); + const ref = useRef(null); + useEffect(() => { + if (!open) return; + const close = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); }; + document.addEventListener("mousedown", close); + return () => document.removeEventListener("mousedown", close); + }, [open]); + return { open, setOpen, ref }; +} diff --git a/src/components/UI.jsx.bak b/src/components/UI.jsx.bak new file mode 100755 index 0000000..71786f0 --- /dev/null +++ b/src/components/UI.jsx.bak @@ -0,0 +1,444 @@ +import React, { useState, useEffect, useRef } from "react"; +import { STATUS_COLORS, STATUS_BG } from "../constants.js"; + +export function StatusBadge({ status }) { + const color = STATUS_COLORS[status] || "#888"; + const bg = STATUS_BG[status] || "#f5f5f5"; + return ( + {status} + ); +} + +export function StatusSelect({ value, options, onChange }) { + const color = STATUS_COLORS[value] || "#888"; + const bg = STATUS_BG[value] || "#f5f5f5"; + return ( + + ); +} + +export function Header({ title, action }) { + return ( +
+

{title}

+ {action} +
+ ); +} + +export function FormField({ label, children }) { + return ( +
+ + {children} +
+ ); +} + +export function Modal({ title, onClose, onSave, saveLabel, hideSave, children, wide, overflow }) { + return ( +
e.target === e.currentTarget && onClose()}> +
+

{title}

+ {children} +
+ + {!hideSave && } +
+
+
+ ); +} + +export function StudioLogo({ settings, size = 24 }) { + if (settings.logo) { + const h = settings.logoSize || 60; + return {settings.name}; + } + return
{settings.name}
; +} + +export function useConfirm() { + const [pending, setPending] = useState(null); + const askConfirm = (msg, confirmLabel = "Löschen") => + new Promise(resolve => setPending({ msg, confirmLabel, resolve })); + const ConfirmModalEl = pending ? ( +
+
+
{pending.msg}
+
+ + +
+
+
+ ) : null; + return { askConfirm, ConfirmModalEl }; +} + +export function DateInput({ value, onChange, style, ...props }) { + const toDE = (iso) => { + if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return ""; + return `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}`; + }; + const toISO = (de) => { + const m = de.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/); + if (!m) return null; + const iso = `${m[3]}-${m[2].padStart(2, "0")}-${m[1].padStart(2, "0")}`; + return isNaN(new Date(iso).getTime()) ? null : iso; + }; + const [text, setText] = React.useState(() => toDE(value)); + React.useEffect(() => { const de = toDE(value); if (de !== text) setText(de); }, [value]); + const handleChange = (e) => { + const digits = e.target.value.replace(/\D/g, "").slice(0, 8); + let fmt = ""; + if (digits.length <= 2) fmt = digits; + else if (digits.length <= 4) fmt = `${digits.slice(0, 2)}.${digits.slice(2)}`; + else fmt = `${digits.slice(0, 2)}.${digits.slice(2, 4)}.${digits.slice(4)}`; + setText(fmt); + const iso = toISO(fmt); + if (iso) onChange({ target: { value: iso } }); + }; + return ( + { if (!toISO(text) && value) setText(toDE(value)); }} + placeholder="TT.MM.JJJJ" + style={style} + {...props} + /> + ); +} + +export function RichEditor({ value, onChange, minHeight = 420, compact = false }) { + const editorRef = React.useRef(null); + const isInternalChange = React.useRef(false); + const lastValue = React.useRef(value); + const savedRange = React.useRef(null); + const colorInputRef = React.useRef(null); + const [colorValue, setColorValue] = React.useState("#000000"); + + // Only push content into DOM when value changes from outside (template load) + useEffect(() => { + if (!editorRef.current) return; + if (value !== lastValue.current && !isInternalChange.current) { + editorRef.current.innerHTML = value; + lastValue.current = value; + } + isInternalChange.current = false; + }, [value]); + + const saveSelection = () => { + const sel = window.getSelection(); + if (sel && sel.rangeCount > 0 && editorRef.current?.contains(sel.anchorNode)) { + savedRange.current = sel.getRangeAt(0).cloneRange(); + } + }; + + const restoreSelection = () => { + editorRef.current?.focus(); + if (!savedRange.current) { + // Place cursor at end if no saved range + const range = document.createRange(); + range.selectNodeContents(editorRef.current); + range.collapse(false); + const sel = window.getSelection(); + if (sel) { sel.removeAllRanges(); sel.addRange(range); } + return; + } + const sel = window.getSelection(); + if (sel) { sel.removeAllRanges(); sel.addRange(savedRange.current); } + }; + + const exec = (cmd, val = null) => { + restoreSelection(); + document.execCommand(cmd, false, val); + saveSelection(); + // Sync content after command + isInternalChange.current = true; + const html = editorRef.current?.innerHTML || ""; + lastValue.current = html; + onChange(html); + }; + + + + const TB = ({ cmd, val, title, style: s, children }) => ( + + ); + const Sep = () =>
; + + return ( +
+
+ B + I + U + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Font size */} + + + + + {/* Color */} + + { setColorValue(e.target.value); exec("foreColor", e.target.value); }} + style={{ position: "absolute", width: 0, height: 0, opacity: 0, pointerEvents: "none" }} + /> +
+ + {/* Editor */} +
{ + isInternalChange.current = true; + const html = editorRef.current?.innerHTML || ""; + lastValue.current = html; + onChange(html); + }} + onKeyUp={saveSelection} + onMouseUp={saveSelection} + onBlur={saveSelection} + onPaste={e => { + e.preventDefault(); + const text = e.clipboardData.getData("text/plain"); + restoreSelection(); + document.execCommand("insertText", false, text); + saveSelection(); + }} + style={{ + minHeight, padding: compact ? "8px 10px" : "20px 24px", outline: "none", + fontSize: compact ? 12 : 13, lineHeight: 1.8, color: "var(--text)", + background: "var(--surface)", + fontFamily: "'DM Mono', 'Courier New', monospace", + }} + /> +
+ ); +} + +export function CalendarPopup({ value, onChange, onClose, align = "left", showClear = true }) { + const [viewYM, setViewYM] = useState(() => { + const d = value ? new Date(value + "T00:00:00") : new Date(); + return { year: d.getFullYear(), month: d.getMonth() }; + }); + const todayStr = new Date().toISOString().slice(0, 10); + const { year, month } = viewYM; + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + const startWeekday = (firstDay.getDay() + 6) % 7; + const cells = []; + for (let i = 0; i < startWeekday; i++) cells.push(null); + for (let d = 1; d <= lastDay.getDate(); d++) { + cells.push(`${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`); + } + const prevMonth = () => { const d = new Date(year, month - 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); }; + const nextMonth = () => { const d = new Date(year, month + 1, 1); setViewYM({ year: d.getFullYear(), month: d.getMonth() }); }; + const select = (ds) => { onChange(ds); onClose(); }; + + return ( +
e.stopPropagation()} + > +
+ +
+ {firstDay.toLocaleDateString("de-CH", { month: "long", year: "numeric" })} +
+ +
+
+ {["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"].map(d => ( +
{d}
+ ))} +
+
+ {cells.map((ds, i) => { + if (!ds) return
; + const dow = new Date(ds + "T00:00:00").getDay(); + const isWeekend = dow === 0 || dow === 6; + const isSelected = ds === value; + const isToday = ds === todayStr; + return ( + + ); + })} +
+ {showClear && value && ( +
+ +
+ )} +
+ ); +} + +export function DatePicker({ value, onChange, style, placeholder, align = "left", ...props }) { + const [open, setOpen] = useState(false); + const wrapRef = useRef(null); + const toDE = (iso) => { + if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) return ""; + return `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}`; + }; + useEffect(() => { + if (!open) return; + const close = (e) => { if (!wrapRef.current?.contains(e.target)) setOpen(false); }; + document.addEventListener("mousedown", close); + return () => document.removeEventListener("mousedown", close); + }, [open]); + return ( +
+ setOpen(o => !o)} + placeholder={placeholder || "TT.MM.JJJJ"} + style={{ cursor: "pointer", ...style }} + {...props} + /> + {open && ( + onChange({ target: { value: ds } })} + onClose={() => setOpen(false)} + align={align} + /> + )} +
+ ); +} + +export function useCalendarNav() { + const [open, setOpen] = useState(false); + const ref = useRef(null); + useEffect(() => { + if (!open) return; + const close = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); }; + document.addEventListener("mousedown", close); + return () => document.removeEventListener("mousedown", close); + }, [open]); + return { open, setOpen, ref }; +} diff --git a/src/constants.js b/src/constants.js new file mode 100755 index 0000000..e7a2325 --- /dev/null +++ b/src/constants.js @@ -0,0 +1,252 @@ +// ─── CONSTANTS ────────────────────────────────────────────────── + +export const STORAGE_KEY = "studio_data_v1"; + +// SIA-Phasen nach SIA 102/103 (Architektur) +export const SIA_PHASES = [ + { id: "11", label: "11 Strategische Planung" }, + { id: "21", label: "21 Vorstudien" }, + { id: "22", label: "22 Machbarkeitsstudie" }, + { id: "31", label: "31 Vorprojekt" }, + { id: "32", label: "32 Bauprojekt" }, + { id: "33", label: "33 Bewilligungsverfahren" }, + { id: "41", label: "41 Ausschreibung" }, + { id: "51", label: "51 Ausführungsprojekt" }, + { id: "52", label: "52 Ausführung" }, + { id: "53", label: "53 Inbetriebnahme / Abschluss" }, +]; + +// SIA 102 Teilleistungen mit Standard-Prozentanteilen +export const SIA_PHASE_WEIGHTS = [ + { id: "31", label: "Vorprojekt", items: [ + { label: "Lösungsstudien / Grobschätzung", pct: 3 }, + { label: "Vorprojekt / Kostenschätzung", pct: 6 }, + ]}, + { id: "32", label: "Bauprojekt", items: [ + { label: "Bauprojekt", pct: 13 }, + { label: "Detailstudien", pct: 4 }, + { label: "Kostenvoranschlag", pct: 4 }, + ]}, + { id: "33", label: "Bewilligungsverfahren", items: [ + { label: "Bewilligungsverfahren", pct: 2.5 }, + ]}, + { id: "41", label: "Ausschreibung", items: [ + { label: "Ausschreibungspläne", pct: 10 }, + { label: "Ausschreibung / Offertvergleich", pct: 8 }, + ]}, + { id: "51", label: "Ausführungsplanung", items: [ + { label: "Ausführungspläne", pct: 15 }, + { label: "Werkverträge", pct: 1 }, + ]}, + { id: "52", label: "Ausführung", items: [ + { label: "Gestalterische Leitung", pct: 6 }, + { label: "Bauleitung / Kostenkontrolle", pct: 23 }, + ]}, + { id: "53", label: "Inbetriebnahme / Abschluss", items: [ + { label: "Inbetriebnahme", pct: 1 }, + { label: "Dokumentation", pct: 1 }, + { label: "Garantiearbeiten", pct: 1.5 }, + { label: "Schlussabrechnung", pct: 1 }, + ]}, +]; + +// Projekt-Typen +export const PROJECT_TYPES = [ + "Wettbewerb", + "Studienauftrag", + "Direktauftrag", + "Machbarkeitsstudie", + "Gutachten", + "Grafik", + "Sonstiges", +]; + +export const EXPENSE_CATEGORIES = [ + "Reise / Fahrt", "Drucken / Reprografie", "Modellbau / Material", + "Büromaterial", "Weiterbildung", + "Unterauftrag / Freelancer", "Verpflegung / Geschäftsessen", + "Sonstiges", +]; + +export const INTERNAL_EXPENSE_CATEGORIES = [ + "Miete / Raumkosten", "Software / Lizenzen", "Hardware / IT", + "Telefon / Internet", "Versicherung", "Steuern / Abgaben", + "Büromaterial", "Marketing / Werbung", "Weiterbildung", + "Unterauftrag / Freelancer", "Bankgebühren", "Sonstiges", +]; + +export const NAV_ITEMS = [ + { id: "dashboard", label: "Übersicht", icon: "grid_view" }, + { id: "pinnwand", label: "Pinnwand", icon: "campaign" }, + { id: "projects", label: "Projekte", icon: "work" }, + { id: "time", label: "Zeiterfassung", icon: "schedule" }, + { id: "quotes", label: "Offerten", icon: "request_quote" }, + { id: "buchhaltung", label: "Buchhaltung", icon: "account_balance", children: [ + { id: "invoices", label: "Rechnungen" }, + { id: "internal-expenses", label: "Ausgaben" }, + { id: "expenses", label: "Spesen" }, + { id: "loehne", label: "Löhne" }, + { id: "studio-budget", label: "Budget" }, + ]}, + { id: "dokumente", label: "Dokumente", icon: "folder", children: [ + { id: "protokolle", label: "Protokolle" }, + { id: "lieferscheine", label: "Lieferscheine" }, + { id: "letters", label: "Briefe" }, + ]}, + { id: "personen", label: "Personen", icon: "group" }, + { id: "mitarbeiter", label: "Mitarbeiter", icon: "badge" }, + { id: "settings", label: "Einstellungen", icon: "settings" }, +]; + +export const STATUS_COLORS = { + aktiv: "#2d6a4f", abgeschlossen: "#555", pausiert: "#b5621e", + entwurf: "#7a6a00", gesendet: "#1a4e8a", bezahlt: "#2d6a4f", überfällig: "#8a1a1a", + offen: "#7a6a00", angenommen: "#2d6a4f", abgelehnt: "#8a1a1a", abgelaufen: "#888", + genehmigt: "#1a4e8a", "auf nächsten Lohn": "#b5621e", ausbezahlt: "#2d6a4f", +}; + +export const STATUS_BG = { + aktiv: "#e8f5ee", abgeschlossen: "#f0f0ee", pausiert: "#fdf0e8", + entwurf: "#fffbe6", gesendet: "#e8f0fa", bezahlt: "#e8f5ee", überfällig: "#fdf2f2", + offen: "#fffbe6", angenommen: "#e8f5ee", abgelehnt: "#fdf2f2", abgelaufen: "#f2f2f2", + genehmigt: "#e8f0fa", "auf nächsten Lohn": "#fdf0e8", ausbezahlt: "#e8f5ee", +}; + +export const defaultData = { + settings: { + setupCompleted: false, + name: "Mein Studio", + address: "Musterstrasse 1\n8001 Zürich", + street: "", + zip: "", + city: "", + country: "CH", + email: "mail@studio.ch", + phone: "+41 79 000 00 00", + iban: "CH00 0000 0000 0000 0000 0", + ibanType: "qr", // "qr" | "normal" + mwst: "CHE-000.000.000 MWST", + mwstRate: 8.1, + defaultHourlyRate: 120, + autoPrint: false, + logoSize: 60, + expenseCategories: [...EXPENSE_CATEGORIES], + internalExpenseCategories: [...INTERNAL_EXPENSE_CATEGORIES], + projectNumberFormat: "YYYY/NN", + invoiceNumberFormat: "YYYY-NNN", + protokollNumberFormat: "YYYY-TT-NN", + protokollTypeAbbreviations: { + "Bausitzung": "BS", + "Planungssitzung": "PS", + "Baubesprechung": "BB", + "Jour fixe": "JF", + "Interne Sitzung": "IS", + "Kundensitzung": "KS", + "Abnahme": "AB", + "Sonstiges": "SO", + }, + pdfNameFormat: "{studio}_{typ}_{nummer}", + qrNewPage: true, + pageMarginTop: 20, + pageMarginBottom: 20, + pageMarginLeft: 20, + pageMarginRight: 20, + defaultWochenstunden: 35, + defaultFerienWochen: 5, + closedMonths: [], + blockMaiTag: true, + roles: [ + { id: "PL", label: "Projektleiter/in", rate: 140 }, + { id: "TS", label: "Technischer Support", rate: 120 }, + { id: "BL", label: "Bauleiter/in", rate: 135 }, + { id: "AS", label: "Administrativer Support", rate: 120 }, + ], + }, + persons: [], + projects: [], + timeEntries: [], + invoices: [], + quotes: [], + expenses: [], + internalExpenses: [], + deliveryNotes: [], + protocols: [], + employees: [], + feiertage: [], + absences: [], + ferienEntries: [], + absenzTypes: [], + lohnEntries: [], + uberstundenAbschluss: [], + dashboardTemplates: [ + { id: "tpl-admin", name: "Administrator", isPublic: true, layout: [ + { id: "dw-a1", cols: 4, minH: 0, widgets: ["kpi-projekte","kpi-stunden","kpi-ausstehend","kpi-umsatz"] }, + { id: "dw-a2", cols: 1, minH: 0, widgets: ["warnungen"] }, + { id: "dw-a3", cols: 2, minH: 0, widgets: ["aktive-projekte","unverrechnete-stunden"] }, + { id: "dw-a4", cols: 2, minH: 0, widgets: ["umsatz-sparkline","offene-offerten"] }, + { id: "dw-a5", cols: 1, minH: 0, widgets: ["letzte-zeiteintraege"] }, + ]}, + { id: "tpl-projektleiter", name: "Projektleiter", isPublic: true, layout: [ + { id: "dw-p1", cols: 2, minH: 0, widgets: ["kpi-projekte","kpi-stunden"] }, + { id: "dw-p2", cols: 1, minH: 0, widgets: ["warnungen"] }, + { id: "dw-p3", cols: 3, minH: 0, widgets: ["meine-projekte","team-auslastung","offene-offerten"] }, + { id: "dw-p4", cols: 1, minH: 0, widgets: ["letzte-zeiteintraege"] }, + ]}, + { id: "tpl-mitarbeiter", name: "Mitarbeiter", isPublic: true, layout: [ + { id: "dw-m1", cols: 3, minH: 0, widgets: ["kpi-stunden","ueberstunden","meine-ferien"] }, + { id: "dw-m2", cols: 2, minH: 0, widgets: ["meine-projekte","stunden-woche"] }, + { id: "dw-m3", cols: 1, minH: 0, widgets: ["meine-zeiteintraege"] }, + ]}, + ], + appRoles: [ + { id: "r-admin", name: "Administrator", permissions: null, dashboardTemplateId: "tpl-admin" }, + { id: "r-projektleiter", name: "Projektleiter", permissions: ["dashboard","projects","time","quotes","personen","mitarbeiter","settings"], dashboardTemplateId: "tpl-projektleiter" }, + { id: "r-mitarbeiter", name: "Mitarbeiter", permissions: ["dashboard","projects","time","personen","settings"], dashboardTemplateId: "tpl-mitarbeiter" }, + ], + users: [ + { id: "admin", username: "admin", password: "admin", role: "admin", displayName: "Administrator", appRoleId: "r-admin" }, + ], + blogPosts: [], + letterTemplates: [ + { id: "offer", name: "Offerte", body: "Sehr geehrte/r {{client}}\n\nGerne unterbreiten wir Ihnen die Offerte für das Projekt «{{project}}».\n\n[Leistungsumfang]\n\nHonorar: CHF [Betrag]\n\nWir freuen uns auf die Zusammenarbeit.\n\nFreundliche Grüsse" }, + { id: "reminder", name: "Zahlungserinnerung", body: "Sehr geehrte/r {{client}}\n\nBei einer Überprüfung unserer Buchhaltung stellen wir fest, dass die Rechnung [Nr.] vom [Datum] über CHF [Betrag] noch nicht beglichen ist.\n\nWir bitten Sie höflich, den offenen Betrag innert 10 Tagen zu überweisen.\n\nFreundliche Grüsse" }, + ], +}; + +export const PROTOKOLL_TYPES = ["Bausitzung", "Planungssitzung", "Baubesprechung", "Jour fixe", "Interne Sitzung", "Kundensitzung", "Abnahme", "Sonstiges"]; + +export const PROTOKOLL_ENTRY_TYPES = [ + { id: "beschluss", label: "Beschluss", color: "#1a4e8a", bg: "#e8f0fa", icon: "⬡" }, + { id: "info", label: "Info", color: "#2d6a4f", bg: "#e8f5ee", icon: "ℹ" }, + { id: "aufgabe", label: "Aufgabe", color: "#b5621e", bg: "#fdf0e8", icon: "◎" }, +]; + +export const DASHBOARD_WIDGETS = [ + { id: "kpi-projekte", label: "Aktive Projekte (KPI)", span: 3 }, + { id: "kpi-stunden", label: "Stunden diesen Monat (KPI)", span: 3 }, + { id: "kpi-ausstehend", label: "Ausstehend (KPI)", span: 3 }, + { id: "kpi-umsatz", label: "Jahresumsatz (KPI)", span: 3 }, + { id: "warnungen", label: "Warnungen", span: 12 }, + { id: "aktive-projekte", label: "Projektliste mit Budget", span: 4 }, + { id: "unverrechnete-stunden", label: "Unverrechnete Stunden", span: 4 }, + { id: "umsatz-sparkline", label: "Umsatz Sparkline", span: 4 }, + { id: "offene-offerten", label: "Offene Offerten", span: 4 }, + { id: "letzte-zeiteintraege", label: "Letzte Zeiteinträge", span: 12 }, + { id: "meine-zeiteintraege", label: "Meine Zeiteinträge", span: 12 }, + { id: "meine-projekte", label: "Meine Projekte", span: 6 }, + { id: "meine-ferien", label: "Ferienstand", span: 4 }, + { id: "ueberstunden", label: "Stundensaldo", span: 4 }, + { id: "stunden-woche", label: "Stunden pro Woche", span: 6 }, + { id: "team-auslastung", label: "Team-Auslastung", span: 6 }, + { id: "interner-blog", label: "Pinnwand", span: 6 }, +]; + +export const DEFAULT_ABSENZ_TYPES = [ + { id: "krankheit", label: "Krankheit", color: "#8a1a1a" }, + { id: "unfall", label: "Unfall", color: "#b5621e" }, + { id: "intern", label: "Intern", color: "#1a4e8a" }, + { id: "informatik", label: "Informatik", color: "#555" }, + { id: "rechnungswesen", label: "Rechnungswesen", color: "#7a6a00" }, + { id: "weiterbildung", label: "Weiterbildung", color: "#2d6a4f" }, + { id: "militaer", label: "Militär / Zivildienst", color: "#3d3d38" }, +]; diff --git a/src/index.css b/src/index.css new file mode 100755 index 0000000..3cb100e --- /dev/null +++ b/src/index.css @@ -0,0 +1,3 @@ +*, *::before, *::after { box-sizing: border-box; } +html, body { margin: 0; padding: 0; height: 100%; } +#root { height: 100%; } diff --git a/src/main.jsx b/src/main.jsx new file mode 100755 index 0000000..b9a1a6d --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/src/print/PrintComponents.jsx b/src/print/PrintComponents.jsx new file mode 100755 index 0000000..8976d9e --- /dev/null +++ b/src/print/PrintComponents.jsx @@ -0,0 +1,1686 @@ +import React, { useState, useEffect } from "react"; +import { SIA_PHASES, PROJECT_TYPES, STATUS_COLORS } from "../constants.js"; +import { calcSIAHours, calcManualHours, formatCHF, formatDate, formatHours, formatSenderAddress, isQRIban, generateQRReference, formatIban, buildPdfName } from "../utils.js"; +import { StudioLogo } from "../components/UI.jsx"; + +export +function PrintView({ content, onClose, settings }) { + const triggerPrint = async () => { + const pdfName = buildPdfName(settings?.pdfNameFormat, content, settings); + const prevTitle = document.title; + document.title = pdfName; + try { + if (window.__TAURI_INTERNALS__) { + const { getCurrentWebviewWindow } = await import("@tauri-apps/api/webviewWindow"); + await getCurrentWebviewWindow().print(); + } else { + window.print(); + } + } catch { + window.print(); + } finally { + setTimeout(() => { document.title = prevTitle; }, 2000); + } + }; + + useEffect(() => { + if (!settings.autoPrint) return; + const timer = setTimeout(() => triggerPrint(), 400); + return () => clearTimeout(timer); + }, [settings.autoPrint]); + + const mTop = settings?.pageMarginTop ?? 20; + const mBottom = settings?.pageMarginBottom ?? 20; + const mLeft = settings?.pageMarginLeft ?? 20; + const mRight = settings?.pageMarginRight ?? 20; + const isQrOnly = content.type === "qrbill"; + + return ( +
+ +
+ + +
+ +
+ {content.type === "invoice" && } + {content.type === "invoice+qr" && ( + <> + +
+ +
+ + )} + {content.type === "letter" && } + {content.type === "projectDetail" && } + {content.type === "projectsOverview" && } + {content.type === "qrbill" && } + {content.type === "quote" && } + {content.type === "buchhaltung" && } + {content.type === "lohn" && } + {content.type === "lieferschein" && } + {content.type === "studioBudget" && } + {content.type === "protokoll" && } + {content.type === "mitarbeiterOverview" && } + {content.type === "timeReport" && } +
+
+ ); +} + +export +function InvoicePrint({ inv, client, settings }) { + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
{settings.email} · {settings.phone}
+
+
+
RECHNUNG
+
Nr. {inv.number}
+
+
+ +
+
+
RECHNUNG AN
+
{client?.name || "—"}
+ {(() => { + const contact = inv.contactId ? (client?.contacts || []).find(ct => ct.id === inv.contactId) : null; + if (contact) return
z.H. {contact.name}{contact.position ? `, ${contact.position}` : ""}
; + return null; + })()} + {client?.street &&
{client.street}
} + {(client?.zip || client?.city) &&
{[client.zip, client.city].filter(Boolean).join(" ")}
} + {!client?.street && client?.address &&
{client.address}
} +
+
+
Datum: {formatDate(inv.date)}
+ {inv.dueDate &&
Fällig: {formatDate(inv.dueDate)}
} +
+
+ + + + + + + + {(inv.items || []).some(it => (it.discount || 0) > 0) && ( + + )} + + + + + {(inv.items || []).map((item, i) => { + const lineTotal = item.qty * item.price; + const lineDisc = (item.discount || 0) > 0 ? lineTotal * (item.discount / 100) : 0; + const hasAnyDiscount = (inv.items || []).some(it => (it.discount || 0) > 0); + return ( + + + + + {hasAnyDiscount && ( + + )} + + + ); + })} + +
BESCHREIBUNGMENGEPREISRABATTTOTAL
{item.desc}{item.qty}{formatCHF(item.price)} + {(item.discount || 0) > 0 ? `−${item.discount}%` : "—"} + {formatCHF(lineTotal - lineDisc)}
+ +
+
+ {(inv.globalDisc || 0) > 0 && <> +
Zwischentotal{formatCHF((inv.items || []).reduce((s, it) => { const l = it.qty * it.price; return s + l - ((it.discount||0) > 0 ? l*(it.discount/100) : 0); }, 0))}
+
{inv.discountLabel || "Rabatt"}−{formatCHF(inv.globalDisc)}
+ } + {inv.mwst && <> +
Netto{formatCHF(inv.sub)}
+
MWST {inv.mwstRate || settings.mwstRate}%{formatCHF(inv.tax)}
+ } +
+ Total{formatCHF(inv.total)} +
+
+
+ + {inv.notes &&
{inv.notes}
} + +
+
+
ZAHLUNG AUF
+
{settings.iban}
+
Referenz: {inv.number}
+
+
+
{settings.mwst}
+
+
+ + ); +} + +export +function LieferscheinPrint({ note, client, data, settings }) { + const project = note.projectId ? (data?.projects || []).find(p => p.id === note.projectId) : null; + const projectLabel = project?.name || note.projectManual || null; + const addr = note.deliveryAddress || client?.address || ""; + + return ( + <> + {/* Kopf */} +
+
+ +
{formatSenderAddress(settings)}
+
{settings.email} · {settings.phone}
+
+
+
LIEFERSCHEIN
+
{note.number || "—"}
+
Datum: {formatDate(note.date)}
+
+
+ + {/* Empfänger & Projektinfo */} +
+
+
LIEFERUNG AN
+
{client?.name || note.clientManual || "—"}
+ {client?.company &&
{client.company}
} + {addr &&
{addr}
} +
+ {projectLabel && ( +
+
PROJEKT
+
{projectLabel}
+ {project?.number &&
{project.number}
} +
+ )} +
+ + {/* Positionen */} + + + + + + + + + + + + + {(note.items || []).map((it, i) => ( + + + + + + + + + ))} + +
POS.BESCHREIBUNGMENGEEINHEITBEMERKUNGEMPFANGEN ✓
{i + 1}{it.desc || "—"}{it.qty}{it.unit}{it.note || ""} +
+
+ + {/* Notizen */} + {note.notes && ( +
+ {note.notes} +
+ )} + + {/* Unterschriften */} +
+
+
+ ÜBERGABE – {settings.name} +
+
Datum / Unterschrift
+
+
+
+ EMPFANG – {client?.name || note.clientManual || "Empfänger"} +
+
Datum / Unterschrift
+
+
+ + {/* Footer */} +
+
{settings.name} · {formatSenderAddress(settings).split("\n")[0]}
+
{note.number}
+
+ + ); +} + +export +function StudioBudgetPrint({ snapshot, settings }) { + const r = snapshot.results || {}; + const rateOk = (r.currentRate || 0) >= (r.zielHonorar || 0); + const b = snapshot.b || {}; + + const PRow = ({ label, value, bold, indent, color }) => ( +
+ {label} + {value} +
+ ); + + return ( + <> + {/* Kopf */} +
+
+ +
{formatSenderAddress(settings)}
+
+
+
BÜROBUDGET
+
{snapshot.name}
+
+ Erstellt: {snapshot.savedAt ? new Date(snapshot.savedAt).toLocaleDateString("de-CH", { day: "numeric", month: "long", year: "numeric" }) : "—"} +
+
+
+ +
+ + {/* Kostenstruktur */} +
+
KOSTENSTRUKTUR / JAHR
+ + + + +
+ Gesamtkosten + {formatCHF(r.gesamtKosten || 0)} +
+
+ + {/* Jahresstunden & Kernresultat */} +
+
STUNDENANALYSE
+ + +
+
+
+
+
+
SELBSTKOSTEN/H
+
{formatCHF(Math.round(r.selbstkosten || 0))}
+
+
+
ZIEL-HONORAR/H
+
{formatCHF(Math.round(r.zielHonorar || 0))}
+
inkl. {b.zielMarge || 25}% Marge
+
+
+
+
+ {rateOk ? "✓ Aktueller Ansatz ausreichend" : "⚠ Aktueller Ansatz zu tief"} +
+
+ Aktuell: {formatCHF(r.currentRate || 0)}/h · Ziel: {formatCHF(Math.round(r.zielHonorar || 0))}/h · Differenz: {rateOk ? "+" : ""}{formatCHF(Math.round((r.currentRate || 0) - (r.zielHonorar || 0)))} +
+
+
+
+ + {/* Personal-Detail */} + {(snapshot.empSnapshot || []).length > 0 && ( +
+
PERSONAL
+ + + + + + + + + + {snapshot.empSnapshot.filter(r => r.aktiv).map((r, i) => ( + + + + + + ))} + +
MitarbeiterJahreskostenJahresstunden
{r.name}{formatCHF(r.kosten)}{r.stunden}h
+
+ )} + + {/* Fixkosten-Detail */} + {(snapshot.fixSnapshot || []).length > 0 && ( +
+
FIXKOSTEN
+ + + + + + + + + {snapshot.fixSnapshot.map((r, i) => ( + + + + + ))} + +
PostenCHF/Jahr
{r.label}{formatCHF(r.amount)}
+
+ )} + + {/* Footer */} +
+
{settings.name}
+
Bürobudget · {snapshot.name}
+
+ + ); +} + +export +function ProtokollPrint({ protokoll, data, settings }) { + const p = protokoll; + const proj = data?.projects?.find(x => x.id === p.projectId); + const projLabel = proj?.name || p.projectManual || null; + const today = new Date().toLocaleDateString("de-CH", { day: "numeric", month: "long", year: "numeric" }); + + const statusLabels = { anwesend: "A", entschuldigt: "E", abwesend: "Ab", eingeladen: "Eingeladen" }; + const statusColors = { anwesend: "#2d6a4f", entschuldigt: "#b5621e", abwesend: "#8a1a1a", eingeladen: "#1a4e8a" }; + + const allTasks = (p.traktanden || []).flatMap(t => + (t.items || []).filter(it => it.type === "aufgabe") + .map(it => ({ ...it, tNr: t.nr, tTitle: t.title })) + ); + const allBeschluesse = (p.traktanden || []).flatMap(t => + (t.items || []).filter(it => it.type === "beschluss") + .map(it => ({ ...it, tNr: t.nr, tTitle: t.title })) + ); + + return ( + <> + {/* Kopf */} +
+
+ +
{formatSenderAddress(settings)}
+
+
+
PROTOKOLL
+
{p.nummer}
+
+
+ + {/* Titel & Meta */} +
+
{p.title || "Protokoll"}
+
+ {[ + { label: "TYP", value: p.type }, + { label: "DATUM", value: p.date ? `${formatDate(p.date)}${p.time ? `, ${p.time}${p.endTime ? `–${p.endTime}` : ""} Uhr` : ""}` : "—" }, + { label: "ORT", value: p.location || "—" }, + { label: "PROJEKT", value: projLabel || "—" }, + ].map(m => ( +
+
{m.label}
+
{m.value}
+
+ ))} +
+
+ + {/* Teilnehmer */} + {(p.participants || []).length > 0 && ( +
+
TEILNEHMER
+ + + + + + + + + + {(p.participants || []).map((tn, i) => ( + + + + + + ))} + +
NameFunktionStatus
{tn.name}{tn.role || "—"} + {statusLabels[tn.status] || tn.status} +
+
+ )} + + {/* Traktanden */} + {(p.traktanden || []).map(t => { + const hasContent = t.title || (t.items || []).length > 0; + if (!hasContent) return null; + return ( +
+
+ {t.nr} + {t.title || "—"} +
+ {(t.items || []).map((item, ii) => { + const icons = { info: "ℹ", beschluss: "✅", aufgabe: "📌" }; + const colors = { info: "#1a4e8a", beschluss: "#2d6a4f", aufgabe: "#b5621e" }; + return ( +
+
{icons[item.type]}
+
+
{item.text || "—"}
+ {item.type === "beschluss" && item.date && ( +
Beschluss vom {formatDate(item.date)}
+ )} + {item.type === "aufgabe" && ( +
+ {item.responsible && → {item.responsible}} + {item.dueDateType === "kw" ? (item.dueKW ? `KW ${item.dueKW}/${item.dueYear || ""}` : "—") : item.dueDate ? formatDate(item.dueDate) : "—"} + {item.status} +
+ )} +
+
+ ); + })} +
+ ); + })} + + {/* Aufgabenliste */} + {allTasks.length > 0 && ( +
+
AUFGABEN-ÜBERSICHT
+ + + + + + + + + + + {allTasks.map((t, i) => ( + + + + + + + ))} + +
AufgabeVerantwortlichFälligkeitStatus
+ {t.tNr}.{t.text || "—"} + {t.responsible || "—"} + {t.dueDateType === "kw" ? (t.dueKW ? `KW ${t.dueKW}/${t.dueYear || ""}` : "—") : t.dueDate ? formatDate(t.dueDate) : "—"} + {t.status}
+
+ )} + + {/* Nächste Sitzung */} + {(p.nextDate || p.verteiler) && ( +
+ {p.nextDate &&
Nächste Sitzung:{formatDate(p.nextDate)}
} + {p.verteiler &&
Verteiler:{p.verteiler}
} +
+ )} + + {/* Unterschriften */} +
+
+
PROTOKOLLFÜHRUNG
+
Datum / Unterschrift
+
+
+
GENEHMIGUNG
+
Datum / Unterschrift
+
+
+ + {/* Footer */} +
+
{settings.name} · {p.nummer}
+
Erstellt {today}{p.verteiler ? ` · Verteiler: ${p.verteiler}` : ""}
+
+ + ); +} + +export +function LetterPrint({ client, subject, body, isHtml, settings }) { + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
+
+
{settings.email}
+
{settings.phone}
+
+
+ +
+ {client ? (<> +
{client.name}
+ {client.company &&
{client.company}
} + {client.street &&
{client.street}
} + {(client.zip || client.city) &&
{[client.zip, client.city].filter(Boolean).join(" ")}
} + {!client.street && !client.city && client.address &&
{client.address}
} + ) :
[Empfänger]
} +
+ +
+ {settings.city || (settings.address || "").split("\n").pop().replace(/^\d{4,5}\s*/, "").trim() || "Zürich"}, {new Date().toLocaleDateString("de-CH", { day: "numeric", month: "long", year: "numeric" })} +
+ + {subject &&
{subject}
} + + + {isHtml + ?
+ :
{body}
+ } + +
{settings.name}
+ + ); +} + +export +function ProjectDetailPrint({ content, settings }) { + const { project, client, entries, phaseStats, unassignedMins, totalMinutes, totalAmount, billingType, invoices, data } = content; + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
+
+
PROJEKTREPORT
+
{new Date().toLocaleDateString("de-CH")}
+
+
+ +
+
{(project.category || "PROJEKT").toUpperCase()}
+
{project.name}
+ {client &&
{client.name}{client.company ? ` · ${client.company}` : ""}
} + {project.description &&
{project.description}
} +
+ +
+
STUNDEN TOTAL
{formatHours(totalMinutes)}
+
{billingType === "stundensatz" ? "AUFWAND" : "PAUSCHALE"}
{formatCHF(totalAmount)}
+
EINTRÄGE
{entries.length}
+
+ + {phaseStats.length > 0 && ( +
+
+ AUFWAND PRO SIA-PHASE · HAUPTAUFTRAG +
+ {phaseStats.map(ps => ( +
+
+ {ps.label} + {formatHours(ps.minutes)} · {ps.percent.toFixed(1)}% +
+
+
+
+
+ ))} + {unassignedMins > 0 &&
Ohne Phasen-Zuordnung: {formatHours(unassignedMins)}
} +
+ )} + + {(project.positions || []).filter(pos => { + const posEntries = entries.filter(e => e.positionId === pos.code); + return posEntries.length > 0 || (pos.enabledPhases || []).length > 0; + }).map(pos => { + const posEntries = entries.filter(e => e.positionId === pos.code); + const posMins = posEntries.reduce((s, e) => s + (e.minutes || 0), 0); + const allPhaseIds = [...new Set([...(pos.enabledPhases || []), ...posEntries.map(e => e.phaseId).filter(Boolean)])]; + const linkedQ = pos.quoteId ? (data?.quotes || []).find(q => q.id === pos.quoteId) : null; + return ( +
+
+ ↪ {pos.code}{pos.label ? ` · ${pos.label}` : ""}{linkedQ ? ` · ${linkedQ.number}` : ""} + {formatHours(posMins)} +
+ {allPhaseIds.length > 0 ? allPhaseIds.map(phId => { + const ph = SIA_PHASES.find(p => p.id === phId); + if (!ph) return null; + const phMins = posEntries.filter(e => e.phaseId === phId).reduce((s, e) => s + (e.minutes || 0), 0); + const pct = posMins > 0 ? (phMins / posMins) * 100 : 0; + return ( +
+
+ {ph.label} + {formatHours(phMins)} · {pct.toFixed(1)}% +
+
+
+
+
+ ); + }) : ( + posMins === 0 ? null :
Keine Phasen-Unterteilung · {formatHours(posMins)}
+ )} +
+ ); + })} + + {entries.length > 0 && ( +
+
ZEITEINTRÄGE
+ + + + + + + + + + + {entries.map(e => { + const phase = SIA_PHASES.find(p => p.id === e.phaseId); + return ( + + + + + + + ); + })} + +
DATUMPHASETÄTIGKEITDAUER
{formatDate(e.date)}{phase?.id || "—"}{e.description || "—"}{formatHours(e.minutes)}
+
+ )} + + {invoices && invoices.length > 0 && ( +
+
RECHNUNGEN
+ + + {invoices.map(inv => ( + + + + + + + ))} + +
{inv.number}{formatDate(inv.date)}{inv.status}{formatCHF(inv.total)}
+
+ )} + + ); +} + +export +function ProjectsOverviewPrint({ projects, data, settings }) { + const projectMinutes = (id) => data.timeEntries.filter(e => e.projectId === id).reduce((s, e) => s + (e.minutes || 0), 0); + const projectAmount = (p) => { + const bType = p.billingType || p.type; + if (bType === "stundensatz") return (projectMinutes(p.id) / 60) * p.hourlyRate; + return p.budget || 0; + }; + + const grouped = PROJECT_TYPES.map(cat => ({ + category: cat, + projects: projects.filter(p => (p.category || "Sonstiges") === cat), + })).filter(g => g.projects.length > 0); + + const uncategorized = projects.filter(p => !p.category); + if (uncategorized.length > 0) grouped.push({ category: "Ohne Kategorie", projects: uncategorized }); + + const totalMins = projects.reduce((s, p) => s + projectMinutes(p.id), 0); + const totalAmount = projects.reduce((s, p) => s + projectAmount(p), 0); + + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
+
+
PROJEKTÜBERSICHT
+
{new Date().toLocaleDateString("de-CH")}
+
+
+ +
+
Alle Projekte
+
{projects.length} Projekte · {formatHours(totalMins)} · {formatCHF(totalAmount)}
+
+ + {grouped.map(g => ( +
+
{g.category.toUpperCase()} — {g.projects.length}
+ + + + + + + + + + + + + + + + + + + {g.projects.map(p => { + const client = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === p.clientId); + return ( + + + + + + + + ); + })} + +
PROJEKTKUNDESTATUSSTUNDENBETRAG
{p.name}{client?.name || "—"}{p.status} + {formatHours(projectMinutes(p.id))} + {p.budgetHours > 0 && / {p.budgetHours}h} + {formatCHF(projectAmount(p))}
+
+ ))} + +
+ Total + {formatHours(totalMins)} · {formatCHF(totalAmount)} +
+ + ); +} + +export +function QRBillPrint({ inv, client, settings }) { + const [qrSvg, setQrSvg] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + + const loadSwissQRBill = () => new Promise((resolve, reject) => { + if (window.SwissQRBill) return resolve(window.SwissQRBill); + const existing = document.querySelector('script[data-swissqrbill]'); + if (existing) { + existing.addEventListener("load", () => resolve(window.SwissQRBill)); + existing.addEventListener("error", reject); + return; + } + const script = document.createElement("script"); + script.src = "https://cdn.jsdelivr.net/npm/swissqrbill@4/lib/browser/bundle/svg.min.js"; + script.dataset.swissqrbill = "true"; + script.onload = () => resolve(window.SwissQRBill); + script.onerror = () => { + // Fallback URL + const fallback = document.createElement("script"); + fallback.src = "https://cdn.jsdelivr.net/npm/swissqrbill/lib/browser/bundle/index.js"; + fallback.onload = () => resolve(window.SwissQRBill); + fallback.onerror = reject; + document.head.appendChild(fallback); + }; + document.head.appendChild(script); + }); + + (async () => { + try { + const lib = await loadSwissQRBill(); + if (cancelled) return; + if (!lib) throw new Error("swissqrbill-Bibliothek konnte nicht geladen werden"); + + // Daten vorbereiten + const ibanClean = (settings.iban || "").replace(/\s/g, "").toUpperCase(); + const hasQRIban = isQRIban(ibanClean); + const data = { + currency: "CHF", + amount: inv.total, + creditor: { + name: settings.name || "—", + address: settings.street || "—", + zip: settings.zip || "", + city: settings.city || "", + account: ibanClean, + country: settings.country || "CH", + }, + }; + if (client) { + data.debtor = { + name: client.company || client.name || "—", + address: client.street || "—", + zip: client.zip || "", + city: client.city || "", + country: client.country || "CH", + }; + } + if (hasQRIban) { + data.reference = generateQRReference(inv.number); + } + if (inv.notes || inv.number) { + data.message = `Rechnung ${inv.number}`; + } + + // SVG erstellen — je nach Exportstruktur unterschiedlich + const SVG = lib.SVG || lib.SwissQRBill || (lib.svg && lib.svg.SVG); + if (!SVG) throw new Error("SVG-Klasse nicht gefunden in swissqrbill"); + const qr = new SVG(data); + const svgElement = qr.element || qr.outerHTML || qr; + const svgString = typeof svgElement === "string" ? svgElement : svgElement.outerHTML; + + if (!cancelled) setQrSvg(svgString); + } catch (err) { + console.error("QR-Bill Fehler:", err); + if (!cancelled) setError(err.message || "Fehler beim Generieren der QR-Rechnung"); + } + })(); + + return () => { cancelled = true; }; + }, [inv, client, settings]); + + if (error) { + return ( +
+
Fehler beim Generieren
+
{error}
+
+ Mögliche Ursachen: fehlende Empfänger-Adresse (Strasse, PLZ, Ort), ungültige IBAN, oder fehlende Internetverbindung zum CDN. +
+
+ ); + } + + if (!qrSvg) { + return ( +
QR-Rechnung wird generiert…
+ ); + } + + return ( +
+ ); +} + +export +function QuotePrint({ quote, client, settings }) { + const taxRate = settings.mwstRate || 8.1; + const roles = quote.quoteRoles || settings.roles || []; + const siaCalc = quote.mode === "sia" && quote.sia ? calcSIAHours(quote.sia.baukosten, quote.sia.schwierigkeit, quote.sia.phases) : null; + const manCalc = quote.mode === "manual" ? calcManualHours(quote.manualPhases || [], roles) : null; + const stundenansatz = quote.sia?.stundenansatz || 0; + + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
{settings.email} · {settings.phone}
+
+
+
HONORAROFFERTE
+
Nr. {quote.number}
+
+
+ +
+
+
OFFERTE AN
+ {client ? ( + <> + {client.company &&
{client.company}
} +
{client.name || "—"}
+ {client.street &&
{client.street}
} + {(client.zip || client.city) &&
{[client.zip, client.city].filter(Boolean).join(" ")}
} + {!client.street && !client.city && client.address &&
{client.address}
} + + ) :
} +
+
+
Datum: {formatDate(quote.date)}
+ {quote.validUntil &&
Gültig bis: {formatDate(quote.validUntil)}
} +
+
+ + {quote.notes &&
{quote.notes}
} + + {/* SIA-Modus */} + {quote.mode === "sia" && siaCalc && ( + <> +
+ HONORARBERECHNUNG NACH SIA 102 +
+
+
+
Aufwandbestimmende Baukosten
+
{formatCHF(quote.sia.baukosten)}
+
+
+
Schwierigkeitsgrad n
+
{quote.sia.schwierigkeit}
+
+
+
Stundenansatz
+
CHF {stundenansatz}.–/h
+
+
+ + + + + + + + + + + + {siaCalc.phases.map(ph => ( + + + + + {ph.items.filter(it => it.enabled !== false && it.hours > 0).map((it, idx) => ( + + + + + + + ))} + + + + + + + ))} + +
TEILLEISTUNG%STUNDENHONORAR
+ Phase {ph.id} · {ph.label} +
{it.label}{it.pct}%{formatHours(Math.round(it.hours * 60))}{formatCHF(it.hours * stundenansatz)}
Total Phase {ph.id}{formatHours(Math.round(ph.hours * 60))}{formatCHF(ph.hours * stundenansatz)}
+ + )} + + {/* Manueller Modus */} + {quote.mode === "manual" && manCalc && ( + <> +
+ HONORARSCHÄTZUNG STUNDENAUFWAND +
+
+ {roles.map(r => ( +
{r.id} {r.label} — CHF {r.rate}.–/h
+ ))} +
+ + + + + {roles.map(r => ( + + ))} + + + + + + {manCalc.phases.filter(p => p.totalHours > 0).map(ph => ( + + + {roles.map(r => { + const h = ph.roleDetails.find(rd => rd.id === r.id)?.hours || 0; + return ; + })} + + + + ))} + +
PHASE{r.id}StdHonorar
{ph.label}{h || "—"}{ph.totalHours}{formatCHF(ph.totalAmount)}
+ + )} + + {/* Freier Modus */} + {quote.mode === "free" && (quote.freeItems || []).length > 0 && ( + <> +
+ LEISTUNGEN / POSITIONEN +
+ + + + + + + + + + + {(quote.freeItems || []).map((it, idx) => ( + + + + + + + ))} + +
BESCHREIBUNGMENGEPREISTOTAL
{it.desc || "—"}{it.qty}{formatCHF(it.price)}{formatCHF(it.qty * it.price)}
+ + )} + + {/* Total */} +
+
+
+ Netto + {formatCHF(quote.sub)} +
+ {quote.mwst && ( +
+ MWST {taxRate}% + {formatCHF(quote.tax)} +
+ )} +
+ Offertsumme + {formatCHF(quote.total)} +
+
+
+ +
+ Diese Offerte ist unverbindlich und {quote.validUntil ? `gültig bis ${formatDate(quote.validUntil)}` : "zeitlich unbegrenzt gültig"}. + {quote.mode !== "free" && " Honorar gemäss SIA-Ordnung 102."} Änderungen am Auftragsumfang können zu einer Anpassung führen. +
+ + ); +} + +export +function LohnPrint({ entry, emp, data, monatLabel, settings }) { + const spesen = (data.expenses || []).filter(e => e.lohnEntryId === entry.id); + // Immer den gespeicherten Snapshot verwenden — nie live emp-Werte + const s = entry.saetzeSnapshot || emp; + + const LRow = ({ label, betrag, satz, bold, sub, color, topBorder }) => ( + + {label} + {satz || ""} + {formatCHF(betrag)} + + ); + + return ( +
+ {/* Header: Arbeitgeber links, Arbeitnehmer rechts */} +
+
+ +
+ {formatSenderAddress(settings).split("\n").map((l,i) =>
{l}
)} + {settings.email &&
{settings.email}
} +
+
+
+
LOHNABRECHNUNG
+
{entry.empSnapshot?.name || emp.name}
+ {emp.role &&
{emp.role}
} + {emp.personalNr &&
Personal-Nr. {emp.personalNr}
} + {emp.ahvNr &&
AHV-Nr. {emp.ahvNr}
} + {emp.adresse &&
{emp.adresse}
} + {emp.ort &&
{emp.ort}
} +
+
+ + {/* Periode */} +
+
+
PERIODE
+
{monatLabel}
+
+
+
ABRECHNUNGSDATUM
+
{new Date(entry.createdAt).toLocaleDateString("de-CH")}
+
+ {emp.eintrittsdatum && ( +
+
EINTRITTSDATUM
+
{formatDate(emp.eintrittsdatum)}
+
+ )} +
+
PENSUM
+
{s.pensum || 100}%
+
+
+ + {/* Lohn-Tabelle */} + + + + + + + + + + + {(s.pensum || 100) < 100 && entry.bruttoBase != null && entry.bruttoBase !== entry.brutto && ( + + )} + {entry.dreizehnter > 0 && } + {entry.bonusBetrag > 0 && } + + + {/* Spacer */} + + + + + + + + {entry.qst > 0 && } + + + + {spesen.length > 0 && <> + + {spesen.map(s => )} + } + + + +
POSITIONSATZBETRAG CHF
ABZÜGE ARBEITNEHMER
SPESENERSTATTUNG
+ + {/* Überweisungsdetails */} + {emp.lohnIban && ( +
+
ÜBERWEISUNG AUF
+
{formatIban(emp.lohnIban)}
+ {emp.name &&
{emp.name}{emp.ort ? ` · ${emp.ort}` : ""}
} +
+ )} + + {/* Arbeitgeber-Anteile (informativ, klein) */} +
+
ARBEITGEBERANTEILE (informativ)
+
+ {[ + { label: "AHV/IV/EO", val: Math.round(entry.bruttoTotal * (s.ahvSatz ?? 5.3) / 100 * 100)/100 }, + { label: "ALV", val: Math.round(entry.bruttoTotal * (s.alvSatz ?? 1.1) / 100 * 100)/100 }, + { label: "BVG/PK (AG)", val: Math.round(entry.bruttoTotal * (s.bvgSatz ?? 8.0) / 100 * 100)/100 }, + { label: "UVG BU", val: Math.round(entry.bruttoTotal * 0.5 / 100 * 100)/100 }, + ].map(r => ( +
+
{r.label}
+
{formatCHF(r.val)}
+
+ ))} +
+
+ +
+ Lohnabrechnung gemäss OR Art. 323b · {settings.name}{settings.mwst ? ` · ${settings.mwst}` : ""} +
+
+ ); +} + +export +function BuchhaltungPrint({ data, filterYear, settings }) { + const mwstRate = settings.mwstRate || 8.1; + const invoices = [...data.invoices] + .filter(i => !filterYear || (i.date || "").startsWith(filterYear)) + .sort((a, b) => (a.date || "").localeCompare(b.date || "")); + const expenses = [...(data.expenses || [])] + .filter(e => !filterYear || (e.date || "").startsWith(filterYear)) + .sort((a, b) => (a.date || "").localeCompare(b.date || "")); + const loehne = [...(data.lohnEntries || [])] + .filter(l => !filterYear || l.monat.startsWith(filterYear)) + .sort((a, b) => a.monat.localeCompare(b.monat)); + + const totalInvoicedNet = invoices.reduce((s, i) => s + (i.sub || 0), 0); + const totalInvoicedTax = invoices.reduce((s, i) => s + (i.tax || 0), 0); + const totalExpBrutto = expenses.reduce((s, e) => s + (e.amount || 0), 0); + const totalExpNet = expenses.reduce((s, e) => { const net = e.inclMwst ? e.amount / (1 + (e.mwstRate || 0) / 100) : e.amount; return s + net; }, 0); + const totalExpTax = totalExpBrutto - totalExpNet; + const totalLoehne = loehne.reduce((s, l) => s + (l.auszahlung || 0), 0); + const totalAusgaben = totalExpNet + totalLoehne; + + const thStyle = { textAlign: "left", padding: "6px 0", fontSize: 8, letterSpacing: "0.1em", color: "#888", fontWeight: 500, borderBottom: "1px solid #1a1a18" }; + const thR = { ...thStyle, textAlign: "right" }; + const tdStyle = { padding: "5px 0", fontSize: 9, borderBottom: "1px solid #f0f0f0" }; + const tdR = { ...tdStyle, textAlign: "right" }; + + return ( + <> + {/* Header */} +
+
+ +
{formatSenderAddress(settings)}
+
+
+
BUCHHALTUNGSÜBERSICHT
+
{filterYear || "Alle Jahre"}
+
{new Date().toLocaleDateString("de-CH")}
+
+
+ + {/* Zusammenfassung */} +
+
+
EINNAHMEN
+ {[ + { label: "Umsatz (Netto)", value: totalInvoicedNet }, + { label: `MWST ${mwstRate}%`, value: totalInvoicedTax, small: true }, + { label: "Umsatz (Brutto)", value: totalInvoicedNet + totalInvoicedTax, bold: true }, + ].map((r, i) => ( +
+ {r.label} + {formatCHF(r.value)} +
+ ))} +
+
+
AUSGABEN & ERGEBNIS
+ {[ + { label: "Spesen / Ausgaben (Netto)", value: totalExpNet }, + { label: "Vorsteuer", value: totalExpTax, small: true }, + { label: `Personalaufwand / Löhne (${loehne.length})`, value: totalLoehne }, + { label: "Ergebnis (Netto)", value: totalInvoicedNet - totalAusgaben, bold: true }, + { label: "MWST-Schuld", value: totalInvoicedTax - totalExpTax, bold: true, small: true }, + ].map((r, i) => ( +
+ {r.label} + {formatCHF(r.value)} +
+ ))} +
+
+ + {/* Rechnungen */} +
+
+ RECHNUNGEN ({invoices.length}) +
+ + + + + + + + + + + + + + + {invoices.map(inv => { + const client = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === inv.clientId); + const desc = (inv.items || []).map(it => it.desc).filter(Boolean).join(", "); + return ( + + + + + + + + + + + ); + })} + + + + + + + + + + +
NR.DATUMKUNDEBESCHREIBUNGNETTOMWSTTOTALSTATUS
{inv.number}{formatDate(inv.date)}{client?.name || "—"}{desc || "—"}{formatCHF(inv.sub)}{inv.mwst ? formatCHF(inv.tax) : "—"}{formatCHF(inv.total)}{inv.status}
Total{formatCHF(totalInvoicedNet)}{formatCHF(totalInvoicedTax)}{formatCHF(totalInvoicedNet + totalInvoicedTax)}
+
+ + {/* Spesen */} +
+
+ SPESEN / AUSGABEN ({expenses.length}) +
+ + + + + + + + + + + + + + {expenses.map(e => { + const proj = data.projects.find(p => p.id === e.projectId); + const net = e.inclMwst ? e.amount / (1 + (e.mwstRate || 0) / 100) : e.amount; + const tax = e.amount - net; + return ( + + + + + + + + + + ); + })} + + + + + + + + + +
DATUMKATEGORIEPROJEKTBESCHREIBUNGNETTOVORSTEUERBRUTTO
{formatDate(e.date)}{e.category}{proj?.name || "—"}{e.description || "—"}{formatCHF(net)}{e.mwstRate > 0 ? formatCHF(tax) : "—"}{formatCHF(e.amount)}
Total{formatCHF(totalExpNet)}{formatCHF(totalExpTax)}{formatCHF(totalExpBrutto)}
+
+ + {/* Personalaufwand / Löhne */} + {loehne.length > 0 && ( +
+
+ PERSONALAUFWAND / LÖHNE ({loehne.length}) +
+ + + + + + + + + + + + + + {loehne.map(l => ( + + + + + + + + + + ))} + + + + + + + + + +
MONATMITARBEITERBRUTTOABZÜGE ANNETTOSPESENAUSZAHLUNG
{l.monat}{l.empSnapshot?.name || "—"}{formatCHF(l.bruttoTotal)}{formatCHF(l.totalAbzuege)}{formatCHF(l.netto)}{l.spesenTotal > 0 ? formatCHF(l.spesenTotal) : "—"}{formatCHF(l.auszahlung)}
Total Auszahlungen{formatCHF(totalLoehne)}
+
+ )} + +
+ {settings.name} · {settings.mwst} · Erstellt am {new Date().toLocaleDateString("de-CH")} +
+ + ); +} + +function MitarbeiterOverviewPrint({ employees, settings }) { + const active = employees.filter(e => e.status !== "inaktiv"); + const inactive = employees.filter(e => e.status === "inaktiv"); + + const Row = ({ label, value }) => value ? ( +
+ {label} + {value} +
+ ) : null; + + const EmpCard = ({ emp }) => ( +
+
+
+
{emp.name}
+ {emp.role &&
{emp.role}
} +
+ {emp.personalNr &&
#{emp.personalNr}
} +
+ + + + + +
+ ); + + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
+
+
MITARBEITERÜBERSICHT
+
{new Date().toLocaleDateString("de-CH")}
+
+
+ +
+
Mitarbeiter
+
{employees.length} Mitarbeitende · {active.length} aktiv
+
+ + {active.length > 0 && ( +
+
AKTIV — {active.length}
+
+ {active.map(e => )} +
+
+ )} + + {inactive.length > 0 && ( +
+
INAKTIV — {inactive.length}
+
+ {inactive.map(e => )} +
+
+ )} + + ); +} + +function TimeReportPrint({ employee, entries, month, data, settings }) { + const monthEntries = entries.filter(e => e.date.startsWith(month)) + .sort((a, b) => a.date.localeCompare(b.date) || (a.startTime || "").localeCompare(b.startTime || "")); + + const projects = data.projects || []; + const getProj = (id) => projects.find(p => p.id === id); + + const totalMins = monthEntries.reduce((s, e) => s + (e.minutes || 0), 0); + + const byProject = {}; + monthEntries.forEach(e => { + const k = e.projectId || "__none__"; + if (!byProject[k]) byProject[k] = { proj: getProj(e.projectId), mins: 0 }; + byProject[k].mins += e.minutes || 0; + }); + + const monthLabel = new Date(month + "-01").toLocaleDateString("de-CH", { month: "long", year: "numeric" }); + + return ( + <> +
+
+ +
{formatSenderAddress(settings)}
+
+
+
STUNDENRAPPORT
+
{new Date().toLocaleDateString("de-CH")}
+
+
+ +
+
{employee?.name}
+
{monthLabel} · {formatHours(totalMins)}
+
+ + {/* Zusammenfassung */} +
+
ZUSAMMENFASSUNG PRO PROJEKT
+ {Object.values(byProject).sort((a, b) => b.mins - a.mins).map(({ proj, mins }) => ( +
+ {proj ? `${proj.number ? proj.number + " " : ""}${proj.name}` : "Kein Projekt"} + {formatHours(mins)} +
+ ))} +
+ Total{formatHours(totalMins)} +
+
+ + {/* Detailliste */} +
EINZELEINTRÄGE
+ + + + {["Datum", "Projekt", "Zeit", "Stunden", "Notiz"].map(h => ( + + ))} + + + + {monthEntries.map(e => { + const proj = getProj(e.projectId); + return ( + + + + + + + + ); + })} + +
{h}
{formatDate(e.date)}{proj ? `${proj.number ? proj.number + " " : ""}${proj.name}` : "—"}{e.startTime && e.endTime ? `${e.startTime}–${e.endTime}` : "—"}{formatHours(e.minutes || 0)}{e.note || ""}
+ + {monthEntries.length === 0 && ( +
Keine Einträge für diesen Monat
+ )} + + ); +} diff --git a/src/utils.js b/src/utils.js new file mode 100755 index 0000000..7e2aba1 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,540 @@ +// ─── UTILS ────────────────────────────────────────────────── + +import { DEFAULT_ABSENZ_TYPES } from "./constants.js"; + +// SIA-Honorar-Formel: p = Z1 + Z2 / ∛B +export function calcSIAHours(baukosten, schwierigkeit, phasen) { + if (!baukosten || baukosten <= 0) return { p: 0, total: 0, phases: [] }; + const cbrtB = Math.cbrt(baukosten); + const p = 0.062 + 10.58 / cbrtB; + const results = phasen.map(ph => { + const items = ph.items.map(it => { + if (it.enabled === false) return { ...it, hours: 0 }; + const r = it.r ?? 1; + const hours = baukosten * (p / 100) * schwierigkeit * (it.pct / 100) * r; + return { ...it, hours: Math.round(hours * 10) / 10 }; + }); + const phaseHours = items.reduce((s, it) => s + it.hours, 0); + return { ...ph, items, hours: phaseHours }; + }); + const total = results.reduce((s, ph) => s + ph.hours, 0); + return { p: Math.round(p * 1000) / 1000, cbrtB, total, phases: results }; +} + +// Manuelle Aufwandschätzung: Stunden pro Rolle × Stundensatz +export function calcManualHours(phases, roles) { + const results = phases.filter(ph => ph.enabled).map(ph => { + const roleDetails = (roles || []).map(r => ({ + ...r, hours: ph.hoursByRole?.[r.id] || 0, + })); + const totalHours = roleDetails.reduce((s, r) => s + r.hours, 0); + const totalAmount = roleDetails.reduce((s, r) => s + r.hours * r.rate, 0); + return { ...ph, roleDetails, totalHours, totalAmount }; + }); + return { + phases: results, + totalHours: results.reduce((s, p) => s + p.totalHours, 0), + totalAmount: results.reduce((s, p) => s + p.totalAmount, 0), + }; +} + +// Berechnet Budget aus linkedQuotes-Array (Migration von sourceQuoteId) +export function migrateLinkedQuotes(project) { + if (project.linkedQuotes) return project.linkedQuotes; + if (project.sourceQuoteId) return [{ quoteId: project.sourceQuoteId, role: "Hauptofferte" }]; + return []; +} + +export function deriveQuoteBudget(linkedQuotes, allQuotes, settingsRoles) { + const quotes = (linkedQuotes || []).map(lq => allQuotes.find(q => q.id === lq.quoteId)).filter(Boolean); + let totalHours = 0; + let totalAmount = 0; + const phaseMap = {}; // phaseId -> hours (summed) + const enabledSet = new Set(); // phases enabled in quotes even with 0 hours + + quotes.forEach(q => { + const roles = q.quoteRoles || settingsRoles || []; + if (q.mode === "sia") { + const calc = calcSIAHours(q.sia?.baukosten, q.sia?.schwierigkeit, q.sia?.phases || []); + totalHours += calc.total || 0; + totalAmount += (calc.total || 0) * (q.sia?.stundenansatz || 0); + (calc.phases || []).forEach(ph => { + if (ph.hours > 0) phaseMap[ph.id] = (phaseMap[ph.id] || 0) + ph.hours; + }); + } else if (q.mode === "manual") { + const calc = calcManualHours(q.manualPhases || [], roles); + totalHours += calc.totalHours || 0; + totalAmount += calc.totalAmount || 0; + (q.manualPhases || []).filter(ph => ph.enabled).forEach(ph => { + enabledSet.add(ph.id); + const h = roles.reduce((s, r) => s + (ph.hoursByRole?.[r.id] || 0), 0); + if (h > 0) phaseMap[ph.id] = (phaseMap[ph.id] || 0) + h; + }); + } else if (q.mode === "free") { + totalAmount += (q.freeItems || []).reduce((s, it) => s + (it.qty * it.price), 0); + } + }); + + const phasesBudget = Object.entries(phaseMap).map(([id, hours]) => ({ id, hours: Math.round(hours * 10) / 10 })); + const enabledPhases = [...new Set([...phasesBudget.map(p => p.id), ...enabledSet])]; + return { + budgetHours: Math.round(totalHours * 10) / 10, + budgetAmount: Math.round(totalAmount), + phasesBudget, + enabledPhases, + hasFreeQuotes: quotes.some(q => q.mode === "free"), + hasHourQuotes: quotes.some(q => q.mode === "sia" || q.mode === "manual"), + }; +} + +export function generateId() { + return Date.now().toString(36) + Math.random().toString(36).slice(2, 6); +} + +export function formatCHF(amount) { + return new Intl.NumberFormat("de-CH", { style: "currency", currency: "CHF" }).format(amount || 0); +} + +export function formatDate(dateStr) { + if (!dateStr) return "—"; + return new Date(dateStr).toLocaleDateString("de-CH"); +} + +// Schweizer 5-Rappen-Rundung +export function roundCHF(amount) { + return Math.round((amount || 0) * 20) / 20; +} + +// Absender-Adresse aus strukturierten Feldern bauen; Fallback auf altes Freitext-Feld +export function formatSenderAddress(settings) { + const parts = []; + if (settings.street) parts.push(settings.street); + const line2 = [settings.zip, settings.city].filter(Boolean).join(" "); + if (line2) parts.push(line2); + if (parts.length > 0) return parts.join("\n"); + return settings.address || ""; +} + +// ─── QR-BILL HELPERS ────────────────────────────────────────── + +// Prüft ob IBAN eine QR-IBAN ist (IID im Bereich 30000-31999) +export function isQRIban(iban) { + const clean = (iban || "").replace(/\s/g, "").toUpperCase(); + if (!clean.startsWith("CH") && !clean.startsWith("LI")) return false; + const iid = parseInt(clean.slice(4, 9)); + return iid >= 30000 && iid <= 31999; +} + +// IBAN-Formatierung mit Leerzeichen alle 4 Stellen +export function formatIban(iban) { + const clean = (iban || "").replace(/\s/g, "").toUpperCase(); + return clean.match(/.{1,4}/g)?.join(" ") || ""; +} + +// Modulo-10-Rekursiv Prüfziffer (für QR-Referenz) +export function mod10(input) { + const table = [[0,9,4,6,8,2,7,1,3,5],[9,4,6,8,2,7,1,3,5,0],[4,6,8,2,7,1,3,5,0,9],[6,8,2,7,1,3,5,0,9,4],[8,2,7,1,3,5,0,9,4,6],[2,7,1,3,5,0,9,4,6,8],[7,1,3,5,0,9,4,6,8,2],[1,3,5,0,9,4,6,8,2,7],[3,5,0,9,4,6,8,2,7,1],[5,0,9,4,6,8,2,7,1,3]]; + let carry = 0; + for (const ch of input) { + const digit = parseInt(ch); + if (isNaN(digit)) continue; + carry = table[carry][digit]; + } + return ((10 - carry) % 10).toString(); +} + +// Generiert 27-stellige QR-Referenz aus Rechnungsnummer +export function generateQRReference(invoiceNumber) { + // Nur Ziffern extrahieren, links mit Nullen auf 26 Stellen auffüllen, dann Prüfziffer + const digits = (invoiceNumber || "").replace(/\D/g, "").padStart(26, "0").slice(-26); + return digits + mod10(digits); +} + +// Formatiert Referenz in 5er-Blöcken von rechts +export function formatReference(ref) { + const clean = (ref || "").replace(/\s/g, ""); + const reversed = clean.split("").reverse().join(""); + const blocks = reversed.match(/.{1,5}/g) || []; + return blocks.map(b => b.split("").reverse().join("")).reverse().join(" "); +} + +export function formatHours(minutes) { + const h = Math.floor((minutes || 0) / 60); + const m = (minutes || 0) % 60; + return `${h}h${m > 0 ? " " + m + "m" : ""}`; +} + +// Formatiert Projektnummer nach konfigurierbarem Format +// Platzhalter: YYYY=2025, YY=25, NN=01..99 +export function applyProjectNumberFormat(fmt, seq) { + const now = new Date(); + const yyyy = String(now.getFullYear()); + const yy = yyyy.slice(2); + const nn = String(seq).padStart(2, "0"); + return (fmt || "YYYY/NN").replace(/YYYY/g, yyyy).replace(/YY/g, yy).replace(/NN/g, nn); +} + +// Parst die laufende Nummer aus einer gespeicherten Projektnummer anhand des Formats +export function parseSeqFromNumber(num, fmt) { + if (!num || !fmt) return null; + const now = new Date(); + const yyyy = String(now.getFullYear()); + const yy = yyyy.slice(2); + // Escape regex special chars, then replace placeholders with capture groups + const pattern = (fmt || "YYYY/NN") + .replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&") + .replace(/YYYY/g, yyyy) + .replace(/YY/g, yy) + .replace(/NN/g, "(\\d+)"); + const match = num.match(new RegExp("^" + pattern + "$")); + return match ? parseInt(match[1]) : null; +} + +export function exportBuchhaltungCSV(data, year = "") { + const sep = ";"; + const q = (s) => `"${String(s || "").replace(/"/g, '""')}"`; + const mwstRate = data.settings.mwstRate || 8.1; + const rows = []; + + // Einnahmen + rows.push(["EINNAHMEN", "", "", "", "", "", "", ""].map(q).join(sep)); + rows.push(["Datum", "Rechnungs-Nr.", "Kunde", "Beschreibung", "Netto CHF", "MWST-Satz %", "MWST CHF", "Brutto CHF"].map(q).join(sep)); + const paidInvoices = [...data.invoices].filter(i => !year || (i.date || "").startsWith(year)).sort((a, b) => (a.date || "").localeCompare(b.date || "")); + paidInvoices.forEach(inv => { + const client = (data.persons||[]).find(c => c.id === inv.clientId); + const desc = (inv.items || []).map(it => it.desc).filter(Boolean).join(", "); + const taxRate = inv.mwst ? mwstRate : 0; + rows.push([inv.date, inv.number, client?.name || "", desc, (inv.sub || 0).toFixed(2), taxRate, (inv.tax || 0).toFixed(2), (inv.total || 0).toFixed(2)].map(q).join(sep)); + }); + const totalNet = paidInvoices.reduce((s, i) => s + (i.sub || 0), 0); + const totalTax = paidInvoices.reduce((s, i) => s + (i.tax || 0), 0); + const totalGross = paidInvoices.reduce((s, i) => s + (i.total || 0), 0); + rows.push(["", "", "", "TOTAL", totalNet.toFixed(2), "", totalTax.toFixed(2), totalGross.toFixed(2)].map(q).join(sep)); + rows.push([""].join(sep)); + + // Ausgaben + rows.push(["SPESEN (MITARBEITERBEZOGEN)", "", "", "", "", "", "", ""].map(q).join(sep)); + rows.push(["Datum", "Kategorie", "Projekt", "Beschreibung", "Netto CHF", "MWST-Satz %", "MWST CHF", "Brutto CHF"].map(q).join(sep)); + const sortedExp = [...(data.expenses || [])].filter(e => !year || (e.date || "").startsWith(year)).sort((a, b) => (a.date || "").localeCompare(b.date || "")); + sortedExp.forEach(exp => { + const proj = data.projects.find(p => p.id === exp.projectId); + const net = exp.inclMwst ? (exp.amount / (1 + (exp.mwstRate || 0) / 100)) : exp.amount; + const taxAmt = exp.amount - net; + rows.push([exp.date, exp.category, proj?.name || "", exp.description, net.toFixed(2), exp.mwstRate || 0, taxAmt.toFixed(2), exp.amount.toFixed(2)].map(q).join(sep)); + }); + const expTotal = sortedExp.reduce((s, e) => s + (e.amount || 0), 0); + const expTax = sortedExp.reduce((s, e) => { const net = e.inclMwst ? (e.amount / (1 + (e.mwstRate || 0) / 100)) : e.amount; return s + (e.amount - net); }, 0); + rows.push(["", "", "", "TOTAL", (expTotal - expTax).toFixed(2), "", expTax.toFixed(2), expTotal.toFixed(2)].map(q).join(sep)); + rows.push([""].join(sep)); + + // Interne Ausgaben + rows.push(["INTERNE AUSGABEN", "", "", "", "", "", "", ""].map(q).join(sep)); + rows.push(["Datum", "Kategorie", "Beschreibung", "Wiederkehrend", "Netto CHF", "MWST-Satz %", "MWST CHF", "Brutto CHF"].map(q).join(sep)); + const sortedIntExp = [...(data.internalExpenses || [])].filter(e => !year || (e.date || "").startsWith(year)).sort((a, b) => (a.date || "").localeCompare(b.date || "")); + sortedIntExp.forEach(exp => { + const net = exp.inclMwst ? (exp.amount / (1 + (exp.mwstRate || 0) / 100)) : exp.amount; + const taxAmt = exp.amount - net; + rows.push([exp.date, exp.category, exp.description, exp.recurring ? (exp.recurringInterval || "monatlich") : "", net.toFixed(2), exp.mwstRate || 0, taxAmt.toFixed(2), exp.amount.toFixed(2)].map(q).join(sep)); + }); + const intExpTotal = sortedIntExp.reduce((s, e) => s + (e.amount || 0), 0); + const intExpTax = sortedIntExp.reduce((s, e) => { const net = e.inclMwst ? (e.amount / (1 + (e.mwstRate || 0) / 100)) : e.amount; return s + (e.amount - net); }, 0); + rows.push(["", "", "", "TOTAL", (intExpTotal - intExpTax).toFixed(2), "", intExpTax.toFixed(2), intExpTotal.toFixed(2)].map(q).join(sep)); + rows.push([""].join(sep)); + + // Personalaufwand (Löhne) + const sortedLoehne = [...(data.lohnEntries || [])].filter(l => !year || l.monat.startsWith(year)).sort((a, b) => a.monat.localeCompare(b.monat)); + if (sortedLoehne.length > 0) { + rows.push(["PERSONALAUFWAND / LÖHNE", "", "", "", "", "", "", "", ""].map(q).join(sep)); + rows.push(["Monat", "Mitarbeiter", "Brutto", "Abzüge AN", "Netto", "Spesen", "Auszahlung AN", "PK AG-Anteil", "Gesamtlohnkosten"].map(q).join(sep)); + sortedLoehne.forEach(l => { + const name = l.empSnapshot?.name || ""; + const bvgAG = l.bvgAG || 0; + const gesamt = (l.auszahlung || 0) + bvgAG; + rows.push([l.monat, name, (l.bruttoTotal || 0).toFixed(2), (l.totalAbzuege || 0).toFixed(2), (l.netto || 0).toFixed(2), (l.spesenTotal || 0).toFixed(2), (l.auszahlung || 0).toFixed(2), bvgAG.toFixed(2), gesamt.toFixed(2)].map(q).join(sep)); + }); + const lohnTotal = sortedLoehne.reduce((s, l) => s + (l.auszahlung || 0) + (l.bvgAG || 0), 0); + rows.push(["", "", "", "", "", "", "", "TOTAL", lohnTotal.toFixed(2)].map(q).join(sep)); + rows.push([""].join(sep)); + } + + // Zusammenfassung + const lohnTotalAll = sortedLoehne.reduce((s, l) => s + (l.auszahlung || 0) + (l.bvgAG || 0), 0); + rows.push(["ZUSAMMENFASSUNG", "", "", "", "", "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "Einnahmen (Netto)", totalNet.toFixed(2), "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "Spesen (Netto)", (expTotal - expTax).toFixed(2), "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "Interne Ausgaben (Netto)", (intExpTotal - intExpTax).toFixed(2), "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "Personalaufwand (Löhne)", lohnTotalAll.toFixed(2), "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "Ergebnis (Netto)", (totalNet - (expTotal - expTax) - (intExpTotal - intExpTax) - lohnTotalAll).toFixed(2), "", "", ""].map(q).join(sep)); + rows.push(["", "", "", "MWST auf Einnahmen", "", "", totalTax.toFixed(2), ""].map(q).join(sep)); + rows.push(["", "", "", "Vorsteuer (Spesen + Ausgaben)", "", "", (expTax + intExpTax).toFixed(2), ""].map(q).join(sep)); + rows.push(["", "", "", "MWST-Schuld", "", "", (totalTax - expTax - intExpTax).toFixed(2), ""].map(q).join(sep)); + + const bom = ""; + const blob = new Blob([bom + rows.join("\n")], { type: "text/csv;charset=utf-8;" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `buchhaltung-${year || "gesamt"}.csv`; + a.click(); + URL.revokeObjectURL(url); +} + +export function buildReminderLetter(inv, nr, sentDate, clients, settings) { + const client = clients.find(c => c.id === inv.clientId); + const existingReminders = inv.reminders || []; + const daysPast = Math.floor((new Date() - new Date(inv.dueDate)) / 86400000); + const intro = nr === 1 + ? `Bei einer Überprüfung unserer Buchhaltung stellen wir fest, dass die Rechnung Nr. ${inv.number} vom ${formatDate(inv.date)} über ${formatCHF(inv.total)} seit ${daysPast} Tagen (Fälligkeit: ${formatDate(inv.dueDate)}) noch nicht beglichen ist.\n\nWir bitten Sie höflich, den offenen Betrag innert 10 Tagen zu überweisen.` + : nr === 2 + ? `Leider mussten wir feststellen, dass unsere Zahlungserinnerung vom ${formatDate(existingReminders[0]?.sentDate || existingReminders[0]?.date)} bezüglich Rechnung Nr. ${inv.number} über ${formatCHF(inv.total)} bisher ohne Reaktion geblieben ist.\n\nWir fordern Sie hiermit auf, den ausstehenden Betrag innert 7 Tagen zu begleichen.` + : `Trotz unserer Zahlungserinnerungen vom ${existingReminders.map(r => formatDate(r.sentDate || r.date)).join(" und ")} ist die Rechnung Nr. ${inv.number} über ${formatCHF(inv.total)} nach wie vor unbeglichen.\n\nWir sehen uns gezwungen, bei weiterem Ausbleiben der Zahlung innerhalb von 5 Tagen rechtliche Schritte einzuleiten.`; + const body = `Sehr geehrte/r ${client?.name || "[Kunde]"}\n\n${intro}\n\nIBAN: ${settings.iban}\nReferenz: ${inv.number}\n\nFreundliche Grüsse\n${settings.name}`; + const subject = nr === 1 ? `Zahlungserinnerung – Rechnung Nr. ${inv.number}` : `${nr}. Mahnung – Rechnung Nr. ${inv.number}`; + return { client, subject, body }; +} + +export function getKW(dateStr) { + if (!dateStr) return "—"; + const d = new Date(dateStr); + const jan4 = new Date(d.getFullYear(), 0, 4); + const startOfWeek = new Date(jan4); + startOfWeek.setDate(jan4.getDate() - ((jan4.getDay() + 6) % 7)); + const kw = Math.ceil(((d - startOfWeek) / 86400000 + 1) / 7); + return `KW ${kw}`; +} + +export function linkedClientForNote(n, data) { + if (n.clientId) return (data.persons||[]).find(c => c.id === n.clientId) || null; + return n.clientManual ? { name: n.clientManual, address: n.deliveryAddress || "" } : null; +} + +export function getWeekNumber(date) { + const d = new Date(date); + d.setHours(0, 0, 0, 0); + d.setDate(d.getDate() + 3 - ((d.getDay() + 6) % 7)); + const week1 = new Date(d.getFullYear(), 0, 4); + return Math.round(((d - week1) / 86400000 + ((week1.getDay() + 6) % 7) - 2) / 7) + 1; +} + +export function formatKW(dateStr) { + if (!dateStr) return "—"; + return `KW ${getWeekNumber(dateStr)} / ${new Date(dateStr).getFullYear()}`; +} + +// Generiert nächste Protokollnummer (legacy, nicht mehr direkt genutzt) +export function nextProtoNumber(protocols, projectNumber) { + const prefix = projectNumber ? `${projectNumber}-P` : "P"; + const existing = (protocols || []).map(p => { + const m = (p.nummer || p.number || "").match(/(\d+)$/); + return m ? parseInt(m[1]) : 0; + }); + const max = existing.length ? Math.max(...existing) : 0; + return `${prefix}${String(max + 1).padStart(2, "0")}`; +} + +// Nächste Sequenznummer aus bestehenden Protokollnummern ableiten +// Ignoriert Jahr-artige Zahlen (4-stellig, 2000–2099) +export function nextProtoSeq(protocols) { + let max = 0; + (protocols || []).forEach(p => { + const groups = (p.nummer || "").match(/\d+/g) || []; + groups.forEach(n => { + const num = parseInt(n); + if (n.length <= 3 || !(num >= 2000 && num <= 2099)) { + if (num > max) max = num; + } + }); + }); + return max + 1; +} + +// Wendet konfigurierbares Protokollnummer-Format an +// Platzhalter: YYYY YY MM DD PP(Projektnr.) TT(Typkürzel) NN/NNN(Sequenz) +export function applyProtoNumberFormat(fmt, { date, projectNumber, seq, typKuerzel }) { + const d = date ? new Date(date + "T12:00:00") : new Date(); + const yyyy = String(d.getFullYear()); + const yy = yyyy.slice(2); + const mm = String(d.getMonth() + 1).padStart(2, "0"); + const dd = String(d.getDate()).padStart(2, "0"); + // Normalize separators in project number, then strip a leading year segment + // so PP can be combined with YYYY/YY without producing a double year. + const ppNorm = (projectNumber || "") + .replace(/[\/\s.]/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); + const pp4 = ppNorm.replace(/^\d{4}-/, ""); + const pp2 = ppNorm.replace(/^\d{2}-/, ""); + const ppStripped = pp4 !== ppNorm ? pp4 : pp2 !== ppNorm ? pp2 : ppNorm; + const pp = ppStripped || ppNorm || "P"; + const tt = typKuerzel || "SO"; + const tokens = { + YYYY: yyyy, YY: yy, MM: mm, DD: dd, + PPP: ppNorm || "P", PP: pp, TT: tt, + NNN: String(seq).padStart(3, "0"), + NN: String(seq).padStart(2, "0"), + }; + return (fmt || "PP-TT-NN").replace(/YYYY|YY|NNN|NN|MM|DD|PPP|PP|TT/g, m => tokens[m] ?? m); +} + +// Convert plain text (legacy templates) to HTML +export function textToHtml(text) { + if (!text) return ""; + if (text.trim().startsWith("<")) return text; // already HTML + return text + .split("\n\n") + .map(para => `

${para.replace(/\n/g, "
")}

`) + .join(""); +} + +// Convert HTML back to plain text for print (fallback) +export function htmlToText(html) { + const div = document.createElement("div"); + div.innerHTML = html; + return div.innerText || div.textContent || ""; +} + +export function getFeiertageForYear(feiertage, year) { + return (feiertage || []).filter(f => { + if (f.repeatsYearly) return true; + return f.date.startsWith(String(year)); + }).map(f => { + if (f.repeatsYearly) return { ...f, date: `${year}-${f.date.slice(5, 10)}` }; + return f; + }); +} + +export function getAbsenzTypes(data) { + const custom = data.absenzTypes || []; + const overrideMap = new Map(custom.map(t => [t.id, t])); + const defaultIds = new Set(DEFAULT_ABSENZ_TYPES.map(t => t.id)); + const defaults = DEFAULT_ABSENZ_TYPES + .map(t => overrideMap.get(t.id) || t) + .filter(t => !overrideMap.get(t.id)?.deleted); + const newCustom = custom.filter(t => !defaultIds.has(t.id) && !t.deleted); + return [...defaults, ...newCustom]; +} + +export function getWorkdaysInMonth(year, month, feiertage) { + // month: 0-based; use ISO string to avoid local-midnight timezone offset + const days = []; + const monthStr = `${year}-${String(month + 1).padStart(2, "0")}`; + const d = new Date(`${monthStr}-01`); + while (d.toISOString().slice(0, 7) === monthStr) { + const ds = d.toISOString().slice(0, 10); + const dow = d.getDay(); + if (dow !== 0 && dow !== 6) { + const ft = (feiertage || []).find(f => f.date === ds); + days.push({ date: ds, feiertag: ft || null }); + } + d.setDate(d.getDate() + 1); + } + return days; +} + +export function getSollStunden(employee, date, feiertage) { + // Returns Soll-Stunden for a given workday + const pensum = (employee.pensum || 100) / 100; + const wochenstunden = (employee.wochenstunden || 35); + const tagessoll = (wochenstunden * pensum) / 5; + const ft = (feiertage || []).find(f => f.date === date); + if (ft) return tagessoll + (ft.stundenDelta || 0); // e.g. -1 for Halbfeiertag, 0 for full + return tagessoll; +} + +// ─── LOHNBERECHNUNG HELPER ────────────────────────────────────── +export function calcLohn(emp, monat, spesen, bonus) { + const pensumFactor = (emp.pensum || 100) / 100; + const bruttoBase = emp.monatslohn || 0; + const brutto = Math.round(bruttoBase * pensumFactor * 100) / 100; + // 13. Monatslohn: 1/12 pro Monat + const dreizehnter = emp.dreizehnterLohn ? Math.round(brutto / 12 * 100) / 100 : 0; + const bonusBetrag = Math.round((bonus || 0) * 100) / 100; + const bruttoTotal = brutto + dreizehnter + bonusBetrag; // Bonus ist AHV-pflichtig + + const ahv = Math.round(bruttoTotal * ((emp.ahvSatz ?? 5.3) / 100) * 100) / 100; + const alv = Math.round(bruttoTotal * ((emp.alvSatz ?? 1.1) / 100) * 100) / 100; + const bvg = Math.round(bruttoTotal * ((emp.bvgSatz ?? 8.0) / 100) * 100) / 100; + const nbu = Math.round(bruttoTotal * ((emp.nbuSatz ?? 1.5) / 100) * 100) / 100; + const ktg = Math.round(bruttoTotal * ((emp.ktgSatz ?? 0.5) / 100) * 100) / 100; + const qst = emp.quellensteuerPflichtig + ? Math.round(bruttoTotal * ((emp.quellensteuerSatz ?? 10) / 100) * 100) / 100 : 0; + const bvgAG = Math.round(bruttoTotal * ((emp.pkAGSatz ?? 8.0) / 100) * 100) / 100; + + const totalAbzuege = ahv + alv + bvg + nbu + ktg + qst; + const netto = Math.round((bruttoTotal - totalAbzuege) * 100) / 100; + const spesenTotal = Math.round((spesen || []).reduce((s, e) => s + (e.amount || 0), 0) * 100) / 100; + const auszahlung = Math.round((netto + spesenTotal) * 100) / 100; + + return { brutto, bruttoBase, dreizehnter, bonusBetrag, bruttoTotal, ahv, alv, bvg, nbu, ktg, qst, totalAbzuege, netto, spesenTotal, auszahlung, bvgAG }; +} + +// ─── Dashboard layout helpers ────────────────────────────────────────────────── + +const KPI_IDS = ["kpi-projekte","kpi-stunden","kpi-ausstehend","kpi-umsatz"]; +const MID_IDS = ["aktive-projekte","unverrechnete-stunden","umsatz-sparkline","offene-offerten"]; +const FULL_IDS = ["warnungen","letzte-zeiteintraege","meine-zeiteintraege"]; + +export function widgetsToRows(widgetIds) { + const uid = () => Math.random().toString(36).slice(2, 8); + const kpi = widgetIds.filter(w => KPI_IDS.includes(w)); + const mid = widgetIds.filter(w => MID_IDS.includes(w)); + const full = widgetIds.filter(w => FULL_IDS.includes(w)); + const rows = []; + if (kpi.length) rows.push({ id: uid(), cols: Math.min(4, Math.max(2, kpi.length)), minH: 0, widgets: kpi }); + for (let i = 0; i < mid.length; i += 3) { + const chunk = mid.slice(i, i + 3); + rows.push({ id: uid(), cols: Math.max(2, chunk.length), minH: 0, widgets: chunk }); + } + full.forEach(w => rows.push({ id: uid(), cols: 1, minH: 0, widgets: [w] })); + return rows; +} + +export function migrateDashboardLayout(val) { + if (!val || !Array.isArray(val) || val.length === 0) return null; + if (typeof val[0] === "object" && "widgets" in val[0]) return val; + return widgetsToRows(val); +} + +// PDF-Dateiname aus Format und Content ableiten +export function buildPdfName(format, content, settings) { + const studio = (settings?.name || "RAPPORT").replace(/\s+/g, "-"); + const typeLabels = { + "invoice": "Rechnung", "invoice+qr": "Rechnung", "qrbill": "QR-Rechnung", + "quote": "Offerte", "lieferschein": "Lieferschein", "protokoll": "Protokoll", + "lohn": "Lohnabrechnung", "letter": "Brief", "projectDetail": "Projekt", + "projectsOverview": "Projekte", "buchhaltung": "Buchhaltung", "studioBudget": "Budget", + }; + const typ = typeLabels[content?.type] || content?.type || "Dokument"; + let nummer = ""; + let kunde = ""; + let datum = new Date().toISOString().slice(0, 10); + if (content?.inv) { + nummer = content.inv.number || ""; + datum = content.inv.date || datum; + kunde = content.client?.company || content.client?.name || ""; + } else if (content?.quote) { + nummer = content.quote.number || ""; + datum = content.quote.date || datum; + kunde = content.client?.company || content.client?.name || ""; + } else if (content?.note) { + nummer = content.note.number || ""; + kunde = content.client?.company || content.client?.name || ""; + } else if (content?.protokoll) { + datum = content.protokoll.date || datum; + nummer = content.protokoll.number || ""; + } else if (content?.emp) { + kunde = content.emp.name || ""; + nummer = content.monatLabel || ""; + } else if (content?.filterYear) { + nummer = String(content.filterYear); + } + const sanitize = (s) => (s || "").replace(/[^a-zA-Z0-9äöüÄÖÜ_\-\.]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); + const fmt = format || "{studio}_{typ}_{nummer}"; + const result = fmt + .replace("{studio}", sanitize(studio)) + .replace("{typ}", sanitize(typ)) + .replace("{nummer}", sanitize(nummer)) + .replace("{kunde}", sanitize(kunde)) + .replace("{datum}", sanitize(datum)); + return result.replace(/-+/g, "-").replace(/^-|-$/g, "") || "RAPPORT"; +} diff --git a/src/views/Buchhaltung.jsx b/src/views/Buchhaltung.jsx new file mode 100755 index 0000000..f294418 --- /dev/null +++ b/src/views/Buchhaltung.jsx @@ -0,0 +1,374 @@ +import React, { useState } from "react"; +import { formatCHF, formatDate, exportBuchhaltungCSV } from "../utils.js"; +import { Header, StatusBadge } from "../components/UI.jsx"; +import { MahnModal } from "./Protokolle.jsx"; +import { ReceiptViewer } from "./Spesen.jsx"; + +export default +function Buchhaltung({ data, update, setView, setPrintContent }) { + const mwstRate = data.settings.mwstRate || 8.1; + const currentYear = new Date().getFullYear().toString(); + const [filterYear, setFilterYear] = useState(currentYear); + + const availableYears = Array.from(new Set([ + ...data.invoices.map(i => (i.date || "").slice(0, 4)), + ...(data.expenses || []).map(e => (e.date || "").slice(0, 4)), + ].filter(Boolean))).sort().reverse(); + if (!availableYears.includes(currentYear)) availableYears.unshift(currentYear); + + // Gefilterte Daten + const invoices = data.invoices.filter(i => !filterYear || (i.date || "").startsWith(filterYear)); + const expenses = (data.expenses || []).filter(e => !filterYear || (e.date || "").startsWith(filterYear)); + const lohnEntries = (data.lohnEntries || []).filter(l => !filterYear || l.monat.startsWith(filterYear)); + + // Einnahmen + const totalInvoiced = invoices.reduce((s, i) => s + (i.sub || 0), 0); + const totalTax = invoices.reduce((s, i) => s + (i.tax || 0), 0); + // Akonto-MwSt ist erst bei Schlussrechnung steuerrelevant — separat ausweisen + const akontoInvoices = invoices.filter(i => i.invoiceKind === "akonto"); + const akontoTax = akontoInvoices.reduce((s, i) => s + (i.tax || 0), 0); + const akontoSub = akontoInvoices.reduce((s, i) => s + (i.sub || 0), 0); + const taxWithoutAkonto = totalTax - akontoTax; + const totalPaid = invoices.filter(i => i.status === "bezahlt").reduce((s, i) => s + (i.total || 0), 0); + const totalOpen = invoices.filter(i => i.status === "gesendet" || i.status === "entwurf").reduce((s, i) => s + (i.total || 0), 0); + const totalOverdue = invoices.filter(i => i.status === "überfällig").reduce((s, i) => s + (i.total || 0), 0); + const totalDraftSub = invoices.filter(i => i.status === "entwurf").reduce((s, i) => s + (i.sub || 0), 0); + const totalBilledSub = totalInvoiced - totalDraftSub; + + // Ausgaben Spesen + const totalExpBrutto = expenses.reduce((s, e) => s + (e.amount || 0), 0); + const totalExpNet = expenses.reduce((s, e) => { const net = e.inclMwst ? e.amount / (1 + (e.mwstRate || 0) / 100) : e.amount; return s + net; }, 0); + const totalExpTax = totalExpBrutto - totalExpNet; + + // Interne Ausgaben + const internalExpenses = (data.internalExpenses || []).filter(e => !filterYear || (e.date || "").startsWith(filterYear)); + const totalIntExpBrutto = internalExpenses.reduce((s, e) => s + (e.amount || 0), 0); + const totalIntExpNet = internalExpenses.reduce((s, e) => { const net = e.inclMwst ? e.amount / (1 + (e.mwstRate || 0) / 100) : e.amount; return s + net; }, 0); + const totalIntExpTax = totalIntExpBrutto - totalIntExpNet; + + // Personalaufwand (abgeschlossene Lohnabrechnungen — Auszahlung an MA + AG-Abgaben) + const totalLoehne = lohnEntries.reduce((s, l) => s + (l.auszahlung || 0), 0); + const totalLoehneAGAbgaben = lohnEntries.reduce((s, l) => s + (l.bvgAG || 0), 0); + const totalLoehneGesamt = totalLoehne + totalLoehneAGAbgaben; + const totalLoehneAnzahl = lohnEntries.length; + + const totalAusgaben = totalExpNet + totalIntExpNet + totalLoehneGesamt; + const result = totalInvoiced - totalAusgaben; + + // Überfällige Rechnungen für Mahnwesen + const today = new Date().toISOString().slice(0, 10); + const [mahnModal, setMahnModal] = useState(null); + const [mahnMode, setMahnMode] = useState("new"); + const [mahnSentDate, setMahnSentDate] = useState(new Date().toISOString().slice(0, 10)); + const [receiptView, setReceiptView] = useState(null); + + const overdueInvoices = data.invoices.filter(i => + (i.status === "gesendet" || i.status === "überfällig") && i.dueDate && i.dueDate < today + ).sort((a, b) => (a.dueDate || "").localeCompare(b.dueDate || "")); + + const sendReminder = (inv) => { + const reminders = inv.reminders || []; + setMahnMode(reminders.length === 0 ? "new" : "reprint"); + setMahnSentDate(new Date().toISOString().slice(0, 10)); + setMahnModal({ inv }); + }; + + return ( +
+
+ + + +
+ } /> + + {/* KPI-Karten */} +
+ {[ + { label: "UMSATZ NETTO", value: formatCHF(totalInvoiced), sub: totalDraftSub > 0 ? `${invoices.length} Rechnungen — davon ${formatCHF(totalDraftSub)} erwartet` : `${invoices.length} Rechnungen`, color: "#2d6a4f" }, + { label: "DAVON BEZAHLT", value: formatCHF(totalPaid), sub: "eingegangen", color: "#2d6a4f" }, + { label: "OFFEN / ÜBERFÄLLIG", value: formatCHF(totalOpen + totalOverdue), sub: `${overdueInvoices.length} überfällig`, color: totalOverdue > 0 ? "#8a1a1a" : "#7a6a00" }, + { label: "AUSGABEN TOTAL", value: formatCHF(totalAusgaben), sub: `Spesen + ${totalLoehneAnzahl} Lohnabrechnungen (inkl. AG-Abgaben)`, color: "#555" }, + ].map(c => ( +
+
{c.label}
+
{c.value}
+
{c.sub}
+
+ ))} +
+ +
+ {/* Ergebnis-Übersicht */} +
+
JAHRESERGEBNIS {filterYear || "GESAMT"}
+ {[ + { label: "Einnahmen (Netto)", value: totalInvoiced, bold: false }, + totalDraftSub > 0 && { label: "→ Davon fakturiert", value: totalBilledSub, note: true }, + totalDraftSub > 0 && { label: "→ Davon erwartet (Entwürfe)", value: totalDraftSub, note: true, expected: true }, + { label: "Spesen (Netto)", value: -totalExpNet, bold: false }, + { label: "Interne Ausgaben (Netto)", value: -totalIntExpNet, bold: false }, + { label: "Personalaufwand (Löhne)", value: -totalLoehne, bold: false }, + totalLoehneAGAbgaben > 0 && { label: "→ AG-Sozialabgaben (PK/BVG)", value: -totalLoehneAGAbgaben, note: true }, + { label: "Ergebnis vor MWST", value: result, bold: true, sep: true }, + { label: `MWST auf Einnahmen (${mwstRate}%, excl. Akonto)`, value: taxWithoutAkonto, bold: false, small: true }, + akontoTax > 0 && { label: `↳ Akonto-MWST ausstehend (bei Schlussrechn.)`, value: akontoTax, bold: false, small: true, pending: true }, + { label: "Vorsteuer (Spesen + Ausgaben)", value: -(totalExpTax + totalIntExpTax), bold: false, small: true }, + { label: "MWST-Schuld (excl. Akonto)", value: taxWithoutAkonto - totalExpTax - totalIntExpTax, bold: true, small: true }, + ].filter(Boolean).map((row, i) => ( +
+ + {row.label} + {row.expected && noch nicht fakturiert} + {row.pending && ausstehend} + + + {formatCHF(row.value)} + +
+ ))} +
+ + {/* Monatsumsatz */} +
+
MONATSUMSATZ {filterYear || new Date().getFullYear()}
+ {(() => { + const year = filterYear || String(new Date().getFullYear()); + const months = ["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"]; + const monthData = months.map((label, i) => { + const key = `${year}-${String(i + 1).padStart(2, "0")}`; + const invs = data.invoices.filter(inv => (inv.date || "").startsWith(key)); + const paid = invs.filter(inv => inv.status === "bezahlt").reduce((s, inv) => s + (inv.sub || 0), 0); + const open = invs.filter(inv => inv.status === "gesendet" || inv.status === "überfällig").reduce((s, inv) => s + (inv.sub || 0), 0); + const draft = invs.filter(inv => inv.status === "entwurf").reduce((s, inv) => s + (inv.sub || 0), 0); + return { label, key, paid, open, draft, total: paid + open + draft }; + }); + const maxVal = Math.max(...monthData.map(m => m.total), 1); + const yearTotal = monthData.reduce((s, m) => s + m.total, 0); + const currentMonth = new Date().toISOString().slice(0, 7); + return ( + <> +
+ Total {formatCHF(yearTotal)} · {data.invoices.filter(i => (i.date||"").startsWith(year)).length} Rechnungen +
+
+ {monthData.map(m => ( +
+
+ {m.total === 0 ? ( +
+ ) : ( + <> + {m.draft > 0 &&
} + {m.open > 0 &&
} + {m.paid > 0 &&
} + + )} +
+
+ ))} +
+
+ {monthData.map(m => ( +
{m.label}
+ ))} +
+
+ {[ + { color: "#2d6a4f", label: "Bezahlt" }, + { color: "#b07848", label: "Ausstehend" }, + { color: "#ccc", label: "Entwurf" }, + ].map(l => ( +
+
+ {l.label} +
+ ))} +
+ + ); + })()} +
+
+ + {/* Mahnwesen */} +
+
+ MAHNWESEN — ÜBERFÄLLIGE RECHNUNGEN + {overdueInvoices.length === 0 && ✓ Keine überfälligen Rechnungen} +
+ {overdueInvoices.length > 0 && ( + + + + + + {overdueInvoices.map(inv => { + const client = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === inv.clientId); + const daysPast = Math.floor((new Date() - new Date(inv.dueDate)) / 86400000); + const reminders = inv.reminders || []; + const nextNr = reminders.length + 1; + const mahnLabel = nextNr === 1 ? "Zahlungserinnerung" : `${nextNr}. Mahnung`; + const mahnColor = nextNr >= 3 ? "#8a1a1a" : nextNr === 2 ? "#b5621e" : "#7a6a00"; + return ( + + + + + + + + + ); + })} + +
Nr.KundeFällig seitMahnungenBetrag
{inv.number}{client?.name || "—"} + 30 ? "#8a1a1a" : "#b5621e", fontWeight: 500 }}> + {formatDate(inv.dueDate)} ({daysPast} Tage) + + + {reminders.length === 0 ? ( + Keine + ) : ( +
+ {reminders.map((r, i) => ( + + {i === 0 ? "Erinnerung" : `${i + 1}. Mahnung`} · {formatDate(r.date)} + + ))} +
+ )} +
{formatCHF(inv.total)} + +
+ )} +
+ + {/* Letzte Rechnungen */} +
+
+
LETZTE RECHNUNGEN
+ +
+ + + + {[...data.invoices].sort((a, b) => (b.date || "").localeCompare(a.date || "")).slice(0, 6).map(inv => { + const client = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === inv.clientId); + return ( + + + + + + + + ); + })} + +
Nr.KundeDatumBetragStatus
{inv.number}{client?.name || "—"}{formatDate(inv.date)}{formatCHF(inv.total)}
+
+ + {/* Spesen & Belege */} + {expenses.length > 0 && ( +
+
+
+ SPESEN {filterYear || ""} + + {expenses.filter(e => e.receiptData).length} von {expenses.length} mit Beleg + +
+ +
+ + + + + + + + + + + + + + {[...expenses].sort((a, b) => (b.date || "").localeCompare(a.date || "")).map(e => { + const emp = (data.employees || []).find(em => em.id === e.employeeId); + const expStatus = e.status || "offen"; + const statusColors = { offen: "#b07848", genehmigt: "#2d6a4f", "auf nächsten Lohn": "#1a4e8a", ausbezahlt: "#2d6a4f" }; + return ( + + + + + + + + + + ); + })} + + + + + + + + +
DatumKategorieBeschreibungMitarbeiterBruttoBelegStatus
{formatDate(e.date)}{e.category}{e.description || "—"}{emp?.name || "—"}{formatCHF(e.amount)} + {e.receiptData ? ( + + ) : ( + + )} + + + {expStatus.charAt(0).toUpperCase() + expStatus.slice(1)} + +
{expenses.length} Einträge{formatCHF(totalExpBrutto)}
+
+ )} + + {/* Mahnung-Dialog */} + {mahnModal && ( + setMahnModal(null)} + mahnMode={mahnMode} + setMahnMode={setMahnMode} + mahnSentDate={mahnSentDate} + setMahnSentDate={setMahnSentDate} + /> + )} + setReceiptView(null)} /> +
+ ); +} diff --git a/src/views/Clients.jsx b/src/views/Clients.jsx new file mode 100755 index 0000000..bdffdf4 --- /dev/null +++ b/src/views/Clients.jsx @@ -0,0 +1,452 @@ +import React, { useState } from "react"; +import { generateId } from "../utils.js"; +import { Header, Modal, FormField, useConfirm } from "../components/UI.jsx"; + +export default +function Clients({ data, update, modal, setModal, setView }) { + const clients = data.clients || []; + const { askConfirm, ConfirmModalEl } = useConfirm(); + + const [selectedId, setSelectedId] = useState(() => { + const id = window.__navToClient || null; + window.__navToClient = null; + return id; + }); + const [search, setSearch] = useState(""); + const [groupBy, setGroupBy] = useState("alpha"); + const [contactModal, setContactModal] = useState(null); + const [contactForm, setContactForm] = useState({ name: "", position: "", email: "", phone: "" }); + const [showHauptPicker, setShowHauptPicker] = useState(false); + + const emptyForm = { + name: "", street: "", zip: "", city: "", country: "CH", + email: "", phone: "", website: "", + contacts: [], + _contactName: "", _contactPosition: "", + }; + const [form, setForm] = useState(emptyForm); + + const selectedClient = clients.find(c => c.id === selectedId) || null; + + // ── Client speichern ── + const save = () => { + if (!form.name.trim()) return; + const { _contactName, _contactPosition, ...clientData } = form; + let contacts = clientData.contacts || []; + if (_contactName.trim() && !modal?.id) { + contacts = [{ id: generateId(), name: _contactName.trim(), position: _contactPosition.trim(), email: "", phone: "" }]; + } + const client = { ...clientData, contacts, id: modal?.id || generateId() }; + update("clients", modal?.id ? clients.map(c => c.id === modal.id ? client : c) : [...clients, client]); + setModal(null); + }; + + const openNew = () => { setForm(emptyForm); setModal({ type: "client" }); }; + const openEdit = (c) => { + setForm({ ...emptyForm, ...c, _contactName: "", _contactPosition: "" }); + setModal({ type: "client", id: c.id }); + }; + const del = async (id) => { + if (await askConfirm("Kunde löschen? Alle zugehörigen Projekte verlieren die Kundenzuordnung.")) { + update("clients", clients.filter(c => c.id !== id)); + if (selectedId === id) setSelectedId(null); + } + }; + + // ── Kontakt speichern ── + const saveContact = () => { + if (!contactForm.name.trim()) return; + const client = clients.find(c => c.id === contactModal.clientId); + if (!client) return; + const contacts = client.contacts || []; + const updated = contactModal.contactId + ? contacts.map(ct => ct.id === contactModal.contactId ? { ...ct, ...contactForm } : ct) + : [...contacts, { ...contactForm, id: generateId() }]; + update("clients", clients.map(c => c.id === client.id ? { ...c, contacts: updated } : c)); + setContactModal(null); + }; + const delContact = async (clientId, contactId) => { + if (await askConfirm("Kontaktperson löschen?")) { + const client = clients.find(c => c.id === clientId); + update("clients", clients.map(c => c.id === clientId ? { ...c, contacts: (c.contacts || []).filter(ct => ct.id !== contactId) } : c)); + } + }; + + // ── Detail-Ansicht ── + if (selectedId && selectedClient) { + const projs = (data.projects || []).filter(p => p.clientId === selectedId).sort((a, b) => (b.startDate || "").localeCompare(a.startDate || "")); + const invoices = (data.invoices || []).filter(i => i.clientId === selectedId).sort((a, b) => (b.date || "").localeCompare(a.date || "")); + const quotes = (data.quotes || []).filter(q => q.clientId === selectedId).sort((a, b) => (b.date || "").localeCompare(a.date || "")); + const contacts = selectedClient.contacts || []; + const hauptkontakt = contacts[0] || null; + const addressLine = [selectedClient.street, [selectedClient.zip, selectedClient.city].filter(Boolean).join(" ")].filter(Boolean).join(", "); + + const navTo = (view) => { window.__navClientId = selectedId; setView(view); }; + + const formatCHF = (v) => v != null ? `CHF ${Number(v).toLocaleString("de-CH", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "—"; + const fmtDate = (s) => s ? new Date(s).toLocaleDateString("de-CH") : "—"; + + return ( +
+ {ConfirmModalEl} + + +
+
+

{selectedClient.name}

+ {addressLine &&
{addressLine}
} +
+ +
+ +
+ {/* Firmeninfo */} +
+
FIRMENINFO
+ {[ + { label: "E-Mail", value: selectedClient.email, href: `mailto:${selectedClient.email}` }, + { label: "Telefon", value: selectedClient.phone }, + { label: "Website", value: selectedClient.website, href: selectedClient.website?.startsWith("http") ? selectedClient.website : selectedClient.website ? `https://${selectedClient.website}` : null }, + { label: "Adresse", value: addressLine || null }, + ].filter(r => r.value).map(({ label, value, href }) => ( +
+ {label} + {href ? {value} : {value}} +
+ ))} + {contacts.length > 0 && ( +
+
+
HAUPTKONTAKT
+ {contacts.length > 1 && ( + + )} +
+ {showHauptPicker ? ( +
+ {contacts.map((ct, i) => ( + + ))} +
+ ) : hauptkontakt ? ( + <> +
{hauptkontakt.name}
+ {hauptkontakt.position &&
{hauptkontakt.position}
} +
+ {hauptkontakt.email && {hauptkontakt.email}} + {hauptkontakt.phone && {hauptkontakt.phone}} +
+ + ) : null} +
+ )} +
+ + {/* Ansprechpartner */} +
+
0 ? "1px solid #ece8e2" : "none" }}> +
ANSPRECHPARTNER ({contacts.length})
+ +
+ {contacts.length === 0 ? ( +
Noch keine Ansprechpartner erfasst.
+ ) : ( + contacts.map((ct, i) => ( +
+
+
+
+ {ct.name} + {i === 0 && HAUPT} +
+ {ct.position &&
{ct.position}
} +
+ {ct.email && {ct.email}} + {ct.phone && {ct.phone}} +
+
+
+ + +
+
+
+ )) + )} +
+
+ + {/* Projekte */} +
+
0 ? "1px solid #ece8e2" : "none" }}> + PROJEKTE ({projs.length}) + {projs.length > 0 && } +
+ {projs.length === 0 + ?
Noch keine Projekte.
+ : <> + + + + {projs.slice(0, 5).map(p => ( + + + + + + + ))} + +
ProjektKategorieStatusBudget
{p.name}{p.number && {p.number}}{p.category || "—"}{p.status}{p.budget > 0 ? formatCHF(p.budget) : "—"}
+ {projs.length > 5 &&
+{projs.length - 5} weitere —
} + + } +
+ + {/* Rechnungen */} +
+
0 ? "1px solid #ece8e2" : "none" }}> + RECHNUNGEN ({invoices.length}) + {invoices.length > 0 && } +
+ {invoices.length === 0 + ?
Noch keine Rechnungen.
+ : <> + + + + {invoices.slice(0, 5).map(inv => { + const proj = inv.projectId ? (data.projects || []).find(p => p.id === inv.projectId) : null; + return ( + + + + + + + + ); + })} + +
Nr.DatumProjektStatusBetrag
{inv.number}{fmtDate(inv.date)}{proj?.name || "—"}{inv.status}{formatCHF(inv.total)}
+ {invoices.length > 5 &&
+{invoices.length - 5} weitere —
} + + } +
+ + {/* Offerten */} +
+
0 ? "1px solid #ece8e2" : "none" }}> + OFFERTEN ({quotes.length}) + {quotes.length > 0 && } +
+ {quotes.length === 0 + ?
Noch keine Offerten.
+ : <> + + + + {quotes.slice(0, 5).map(q => ( + + + + + + + + ))} + +
Nr.DatumModusStatusHonorar
{q.number}{fmtDate(q.date)}{q.mode === "sia" ? "SIA 102" : q.mode === "manual" ? "Aufwand" : "Frei"}{q.status || "—"}{formatCHF(q.total)}
+ {quotes.length > 5 &&
+{quotes.length - 5} weitere —
} + + } +
+ + {/* Kontakt-Modal */} + {contactModal && ( + setContactModal(null)} onSave={saveContact}> +
+ setContactForm({ ...contactForm, name: e.target.value })} autoFocus /> + setContactForm({ ...contactForm, position: e.target.value })} placeholder="z.B. Geschäftsführer, Bauleiter…" /> +
+
+ setContactForm({ ...contactForm, email: e.target.value })} /> + setContactForm({ ...contactForm, phone: e.target.value })} /> +
+
+ )} + + {/* Client-Edit-Modal */} + {modal?.type === "client" && modal.id && ( + setModal(null)} onSave={save} wide> + {clientFormFields(form, setForm)} + + )} +
+ ); + } + + // ── Listen-Ansicht ── + const filteredClients = clients.filter(c => { + if (!search) return true; + const q = search.toLowerCase(); + return [c.name, c.city, c.email, c.street, ...(c.contacts || []).map(ct => ct.name)].some(v => v?.toLowerCase().includes(q)); + }); + + const clientGroups = (() => { + if (groupBy === "none") return [{ key: "_all", label: null, items: filteredClients }]; + if (groupBy === "alpha") { + const g = {}; + [...filteredClients].sort((a, b) => a.name.localeCompare(b.name, "de")) + .forEach(c => { const k = c.name[0]?.toUpperCase() || "#"; (g[k] = g[k] || []).push(c); }); + return Object.entries(g).sort((a, b) => a[0].localeCompare(b[0])).map(([k, items]) => ({ key: k, label: k, items })); + } + if (groupBy === "city") { + const g = {}; + [...filteredClients].sort((a, b) => a.name.localeCompare(b.name, "de")) + .forEach(c => { const k = c.city || "Ohne Ort"; (g[k] = g[k] || []).push(c); }); + return Object.entries(g).sort((a, b) => a[0].localeCompare(b[0])).map(([k, items]) => ({ key: k, label: k, items })); + } + })(); + + const ClientTable = ({ items }) => ( +
+ + + + + + + + + + + + + {items.length === 0 && } + {items.map(c => { + const projs = (data.projects || []).filter(p => p.clientId === c.id).length; + const cts = c.contacts || []; + const hauptkontakt = cts[0]; + const city = [c.zip, c.city].filter(Boolean).join(" "); + return ( + setSelectedId(c.id)}> + + + + + + + + ); + })} + +
FirmennameAdresseHauptkontaktKontakteProjekte
Keine Treffer
+ {c.name} + {c.email &&
{c.email}
} +
+ {c.street &&
{c.street}
} + {city &&
{city}
} +
+ {hauptkontakt ? ( + <> +
{hauptkontakt.name}
+ {hauptkontakt.position &&
{hauptkontakt.position}
} + + ) : } +
{cts.length || "—"}{projs || "—"} e.stopPropagation()}> + + +
+
+ ); + + return ( +
+ {ConfirmModalEl} +
+ Neuer Kunde} /> + +
+ setSearch(e.target.value)} + style={{ flex: "1 1 200px", maxWidth: 300, fontSize: 12 }} /> + +
+ + {clients.length === 0 ? ( +
Noch keine Kunden erfasst.
+ ) : filteredClients.length === 0 ? ( +
Keine Treffer
+ ) : clientGroups.map(group => ( +
+ {group.label && ( +
+ {group.label.toUpperCase()} {group.items.length} +
+ )} + +
+ ))} + + {modal?.type === "client" && ( + setModal(null)} onSave={save} wide> + {clientFormFields(form, setForm, !modal.id)} + + )} +
+ ); +} + +function clientFormFields(form, setForm, isNew = false) { + return ( + <> + + setForm({ ...form, name: e.target.value })} autoFocus placeholder="z.B. Müller Immobilien AG" /> + +
+ setForm({ ...form, street: e.target.value })} placeholder="Bahnhofstrasse 1" /> + setForm({ ...form, zip: e.target.value })} style={{ maxWidth: 100 }} /> + setForm({ ...form, city: e.target.value })} /> + setForm({ ...form, country: e.target.value.toUpperCase() })} maxLength={2} style={{ maxWidth: 70 }} /> +
+
+ setForm({ ...form, email: e.target.value })} /> + setForm({ ...form, phone: e.target.value })} /> + setForm({ ...form, website: e.target.value })} placeholder="www.beispiel.ch" /> +
+ + {isNew && ( + <> +
+ HAUPTKONTAKT (optional) +
+
+ + setForm({ ...form, _contactName: e.target.value })} placeholder="z.B. Hans Müller" /> + + + setForm({ ...form, _contactPosition: e.target.value })} placeholder="z.B. Geschäftsführer" /> + +
+
Weitere Ansprechpartner können in der Kundendetailseite hinzugefügt werden.
+ + )} + + ); +} diff --git a/src/views/Contacts.jsx b/src/views/Contacts.jsx new file mode 100755 index 0000000..a12eefa --- /dev/null +++ b/src/views/Contacts.jsx @@ -0,0 +1,456 @@ +import React, { useState } from "react"; +import { generateId } from "../utils.js"; +import { Header, Modal, FormField, useConfirm , DateInput } from "../components/UI.jsx"; + +const CONTACT_TYPES = [ + "Elektroplaner", "HLKSE-Planer", "Statiker", "Tragwerksplaner", + "Kostenplaner", "Landschaftsarchitekt", "Bauphysiker", + "Vermessungsingenieur", "Brandschutzspezialist", "Geologe", + "Generalunternehmer", "Fachplaner", "Sonstiges", +]; + +const fmtCHF = (v) => v != null ? `CHF ${Number(v).toLocaleString("de-CH", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "—"; +const fmtDate = (s) => s ? new Date(s).toLocaleDateString("de-CH") : "—"; + +export default +function Contacts({ data, update }) { + const contacts = data.contacts || []; + const { askConfirm, ConfirmModalEl } = useConfirm(); + + const [selectedId, setSelectedId] = useState(() => { + const id = window.__navToContact || null; + window.__navToContact = null; + return id; + }); + const [search, setSearch] = useState(""); + const [typeFilter, setTypeFilter] = useState(""); + const [groupBy, setGroupBy] = useState("alpha"); + + const emptyFirm = { + name: "", type: "", street: "", zip: "", city: "", email: "", phone: "", website: "", note: "", + contacts: [], honorarOffers: [], + _personName: "", _personPosition: "", + }; + const [firmModal, setFirmModal] = useState(null); + const [firmForm, setFirmForm] = useState(emptyFirm); + + const [personModal, setPersonModal] = useState(null); + const [personForm, setPersonForm] = useState({ name: "", position: "", email: "", phone: "" }); + + const [honorarModal, setHonorarModal] = useState(null); + const [honorarForm, setHonorarForm] = useState({ date: "", amount: "", phase: "", description: "", note: "" }); + + const selectedContact = contacts.find(c => c.id === selectedId) || null; + + // ── Firm CRUD ── + const saveFirm = () => { + if (!firmForm.name.trim()) return; + const { _personName, _personPosition, ...firmData } = firmForm; + let persons = firmData.contacts || []; + if (_personName.trim() && !firmModal?.id) { + persons = [{ id: generateId(), name: _personName.trim(), position: _personPosition.trim(), email: "", phone: "" }]; + } + const firm = { ...firmData, contacts: persons, id: firmModal?.id || generateId() }; + update("contacts", firmModal?.id ? contacts.map(c => c.id === firmModal.id ? firm : c) : [...contacts, firm]); + setFirmModal(null); + }; + const openNew = () => { setFirmForm(emptyFirm); setFirmModal({}); }; + const openEdit = (c) => { setFirmForm({ ...emptyFirm, ...c, _personName: "", _personPosition: "" }); setFirmModal({ id: c.id }); }; + const delFirm = async (id) => { + if (await askConfirm("Kontakt löschen?")) { + update("contacts", contacts.filter(c => c.id !== id)); + if (selectedId === id) setSelectedId(null); + } + }; + + // ── Person CRUD ── + const savePerson = () => { + if (!personForm.name.trim()) return; + const firm = contacts.find(c => c.id === personModal.contactId); + if (!firm) return; + const persons = firm.contacts || []; + const updated = personModal.personId + ? persons.map(p => p.id === personModal.personId ? { ...p, ...personForm } : p) + : [...persons, { ...personForm, id: generateId() }]; + update("contacts", contacts.map(c => c.id === firm.id ? { ...c, contacts: updated } : c)); + setPersonModal(null); + }; + const delPerson = async (contactId, personId) => { + if (await askConfirm("Person löschen?")) { + update("contacts", contacts.map(c => c.id === contactId + ? { ...c, contacts: (c.contacts || []).filter(p => p.id !== personId) } : c)); + } + }; + + // ── Honorar CRUD ── + const saveHonorar = () => { + const firm = contacts.find(c => c.id === honorarModal.contactId); + if (!firm) return; + const offers = firm.honorarOffers || []; + const offer = { id: honorarModal.offerId || generateId(), date: honorarForm.date, amount: parseFloat(honorarForm.amount) || 0, phase: honorarForm.phase, description: honorarForm.description, note: honorarForm.note }; + const updated = honorarModal.offerId ? offers.map(o => o.id === honorarModal.offerId ? offer : o) : [...offers, offer]; + update("contacts", contacts.map(c => c.id === firm.id ? { ...c, honorarOffers: updated } : c)); + setHonorarModal(null); + }; + const delHonorar = async (contactId, offerId) => { + if (await askConfirm("Honorarangebot löschen?")) { + update("contacts", contacts.map(c => c.id === contactId + ? { ...c, honorarOffers: (c.honorarOffers || []).filter(o => o.id !== offerId) } : c)); + } + }; + + // ── Form fields (shared new/edit) ── + const firmFormFields = (isNew) => ( + <> +
+ + setFirmForm(f => ({ ...f, name: e.target.value }))} autoFocus placeholder="z.B. Elektroplaner AG" /> + + + + +
+
+ setFirmForm(f => ({ ...f, street: e.target.value }))} /> + setFirmForm(f => ({ ...f, zip: e.target.value }))} style={{ maxWidth: 90 }} /> + setFirmForm(f => ({ ...f, city: e.target.value }))} /> +
+
+ setFirmForm(f => ({ ...f, email: e.target.value }))} /> + setFirmForm(f => ({ ...f, phone: e.target.value }))} /> + setFirmForm(f => ({ ...f, website: e.target.value }))} placeholder="www.beispiel.ch" /> +
+ setFirmForm(f => ({ ...f, note: e.target.value }))} /> + {isNew && ( + <> +
+ HAUPTKONTAKT (optional) +
+
+ + setFirmForm(f => ({ ...f, _personName: e.target.value }))} placeholder="z.B. Max Muster" /> + + + setFirmForm(f => ({ ...f, _personPosition: e.target.value }))} placeholder="z.B. Projektleiter" /> + +
+
Weitere Personen können in der Detailansicht hinzugefügt werden.
+ + )} + + ); + + // ── Detail view ── + if (selectedId && selectedContact) { + const persons = selectedContact.contacts || []; + const offers = selectedContact.honorarOffers || []; + const hauptperson = persons[0] || null; + const linkedProjects = (data.projects || []).filter(p => (p.projectContacts || []).some(pc => pc.contactId === selectedId)); + const addressLine = [selectedContact.street, [selectedContact.zip, selectedContact.city].filter(Boolean).join(" ")].filter(Boolean).join(", "); + + return ( +
+ {ConfirmModalEl} + + +
+
+ {selectedContact.type &&
{selectedContact.type.toUpperCase()}
} +

{selectedContact.name}

+ {addressLine &&
{addressLine}
} +
+
+ + +
+
+ +
+ {/* Firmeninfo */} +
+
FIRMENINFO
+ {[ + { label: "E-Mail", value: selectedContact.email, href: selectedContact.email ? `mailto:${selectedContact.email}` : null }, + { label: "Telefon", value: selectedContact.phone }, + { label: "Website", value: selectedContact.website, href: selectedContact.website ? (selectedContact.website.startsWith("http") ? selectedContact.website : `https://${selectedContact.website}`) : null }, + { label: "Adresse", value: addressLine || null }, + ].filter(r => r.value).map(({ label, value, href }) => ( +
+ {label} + {href ? {value} : {value}} +
+ ))} + {selectedContact.note &&
{selectedContact.note}
} + {persons.length > 0 && hauptperson && ( +
+
HAUPTKONTAKT
+
{hauptperson.name}
+ {hauptperson.position &&
{hauptperson.position}
} +
+ {hauptperson.email && {hauptperson.email}} + {hauptperson.phone && {hauptperson.phone}} +
+
+ )} +
+ + {/* Ansprechpartner */} +
+
0 ? "1px solid #ece8e2" : "none" }}> +
ANSPRECHPARTNER ({persons.length})
+ +
+ {persons.length === 0 + ?
Noch keine Ansprechpartner erfasst.
+ : persons.map((p, i) => ( +
+
+
+
+ {p.name} + {i === 0 && HAUPT} +
+ {p.position &&
{p.position}
} +
+ {p.email && {p.email}} + {p.phone && {p.phone}} +
+
+
+ + +
+
+
+ )) + } +
+
+ + {/* Honorar-Angebote */} +
+
0 ? "1px solid #ece8e2" : "none" }}> +
HONORAR-ANGEBOTE ({offers.length})
+ +
+ {offers.length === 0 + ?
Noch keine Honorar-Angebote erfasst.
+ : ( + + + + {[...offers].sort((a, b) => (b.date || "").localeCompare(a.date || "")).map(o => ( + + + + + + + + ))} + + {offers.length > 1 && ( + + + + + + + )} +
DatumBeschriebPhaseBetrag
{fmtDate(o.date)} +
{o.description || }
+ {o.note &&
{o.note}
} +
{o.phase || "—"}{fmtCHF(o.amount)} + + +
Total{fmtCHF(offers.reduce((s, o) => s + (parseFloat(o.amount) || 0), 0))} +
+ ) + } +
+ + {/* Beteiligt an */} + {linkedProjects.length > 0 && ( +
+
BETEILIGT AN ({linkedProjects.length})
+ + + + {linkedProjects.map(proj => { + const client = (data.clients || []).find(c => c.id === proj.clientId); + return ( + + + + + + ); + })} + +
ProjektKundeStatus
{proj.number ? {proj.number} : null}{proj.name}{client?.name || "—"}{proj.status}
+
+ )} + + {/* Person modal */} + {personModal && ( + setPersonModal(null)} onSave={savePerson}> +
+ setPersonForm(f => ({ ...f, name: e.target.value }))} autoFocus /> + setPersonForm(f => ({ ...f, position: e.target.value }))} placeholder="z.B. Projektleiter" /> +
+
+ setPersonForm(f => ({ ...f, email: e.target.value }))} /> + setPersonForm(f => ({ ...f, phone: e.target.value }))} /> +
+
+ )} + + {/* Honorar modal */} + {honorarModal && ( + setHonorarModal(null)} onSave={saveHonorar}> +
+ setHonorarForm(f => ({ ...f, date: e.target.value }))} /> + setHonorarForm(f => ({ ...f, amount: e.target.value }))} placeholder="0" /> +
+ setHonorarForm(f => ({ ...f, description: e.target.value }))} placeholder="z.B. Elektroplanung Rohbau" /> + setHonorarForm(f => ({ ...f, phase: e.target.value }))} placeholder="z.B. Phase 31–33" /> + setHonorarForm(f => ({ ...f, note: e.target.value }))} /> +
+ )} + + {/* Edit modal */} + {firmModal && ( + setFirmModal(null)} onSave={saveFirm} wide> + {firmFormFields(false)} + + )} +
+ ); + } + + // ── List view ── + const allTypes = [...new Set(contacts.map(c => c.type).filter(Boolean))].sort(); + const filtered = contacts + .filter(c => + (!typeFilter || c.type === typeFilter) && + (!search || c.name.toLowerCase().includes(search.toLowerCase()) || + (c.type || "").toLowerCase().includes(search.toLowerCase()) || + (c.contacts || []).some(p => p.name.toLowerCase().includes(search.toLowerCase()))) + ) + .sort((a, b) => a.name.localeCompare(b.name, "de")); + + const contactGroups = (() => { + if (groupBy === "none") return [{ key: "_all", label: null, items: filtered }]; + if (groupBy === "alpha") { + const g = {}; + filtered.forEach(c => { const k = c.name[0]?.toUpperCase() || "#"; (g[k] = g[k] || []).push(c); }); + return Object.entries(g).sort((a, b) => a[0].localeCompare(b[0])).map(([k, items]) => ({ key: k, label: k, items })); + } + if (groupBy === "type") { + const g = {}; + filtered.forEach(c => { const k = c.type || "Ohne Typ"; (g[k] = g[k] || []).push(c); }); + return Object.entries(g).sort((a, b) => a[0].localeCompare(b[0])).map(([k, items]) => ({ key: k, label: k, items })); + } + })(); + + const ContactTable = ({ items }) => ( +
+ + + + + + + + + + + + + + {items.length === 0 && } + {items.map(c => { + const persons = c.contacts || []; + const haupt = persons[0]; + const city = [c.zip, c.city].filter(Boolean).join(" "); + const projCount = (data.projects || []).filter(p => (p.projectContacts || []).some(pc => pc.contactId === c.id)).length; + return ( + setSelectedId(c.id)}> + + + + + + + + + ); + })} + +
FirmaTypAdresseHauptkontaktPersonenProjekte
Keine Treffer
+ {c.name} + {c.email &&
{c.email}
} +
{c.type || } + {c.street &&
{c.street}
} + {city &&
{city}
} +
+ {haupt ? ( + <> +
{haupt.name}
+ {haupt.position &&
{haupt.position}
} + + ) : } +
{persons.length || "—"} 0 ? "#1a4e8a" : "#ccc", fontWeight: projCount > 0 ? 600 : 400 }}>{projCount || "—"} e.stopPropagation()}> + + +
+
+ ); + + return ( +
+ {ConfirmModalEl} +
+ Neuer Kontakt} /> + +
+ setSearch(e.target.value)} placeholder="Suchen…" + style={{ flex: "1 1 200px", maxWidth: 300, fontSize: 12 }} /> + {allTypes.length > 0 && ( + + )} + +
+ + {contacts.length === 0 ? ( +
Noch keine Kontakte erfasst.
+ ) : filtered.length === 0 ? ( +
Keine Treffer
+ ) : contactGroups.map(group => ( +
+ {group.label && ( +
+ {group.label.toUpperCase()} {group.items.length} +
+ )} + +
+ ))} + + {firmModal && ( + setFirmModal(null)} onSave={saveFirm} wide> + {firmFormFields(!firmModal.id)} + + )} +
+ ); +} diff --git a/src/views/Dashboard.jsx b/src/views/Dashboard.jsx new file mode 100755 index 0000000..5b4c0fd --- /dev/null +++ b/src/views/Dashboard.jsx @@ -0,0 +1,762 @@ +import React, { useState, useRef, useEffect } from "react"; +import { SIA_PHASES, DASHBOARD_WIDGETS } from "../constants.js"; +import { formatCHF, formatDate, formatHours, migrateDashboardLayout, widgetsToRows, generateId } from "../utils.js"; + +const HEIGHT_OPTS = [ + { v: 0, l: "Auto" }, + { v: 160, l: "S" }, + { v: 280, l: "M" }, + { v: 420, l: "L" }, +]; + +function deepCloneLayout(layout) { + return (layout || []).map(r => ({ ...r, widgets: [...r.widgets] })); +} + +export default function Dashboard({ data, setView, currentUser, saveAll }) { + const today = new Date().toISOString().slice(0, 10); + const thisMonth = today.slice(0, 7); + const thisYear = today.slice(0, 4); + const lastMonth = (() => { const d = new Date(); d.setMonth(d.getMonth() - 1); return d.toISOString().slice(0, 7); })(); + + // ─── Layout resolution ───────────────────────────────────────────── + const myUser = (data.users || []).find(u => u.id === currentUser?.id); + const myRole = (data.appRoles || []).find(r => r.id === (currentUser?.appRoleId || myUser?.appRoleId)); + const myTpl = (data.dashboardTemplates || []).find(t => t.id === myRole?.dashboardTemplateId); + const roleLayout = myTpl + ? migrateDashboardLayout(myTpl.layout) + : migrateDashboardLayout(myRole?.dashboardWidgets) // fallback for old data + || widgetsToRows(DASHBOARD_WIDGETS.map(w => w.id)); + const savedLayout = myUser?.dashboardWidgets ? migrateDashboardLayout(myUser.dashboardWidgets) : null; + + const [editMode, setEditMode] = useState(false); + const [layout, setLayout] = useState([]); + const [dragOver, setDragOver] = useState(null); + const [addPopoverRowId, setAddPopoverRowId] = useState(null); + const [saveTemplateOpen, setSaveTemplateOpen] = useState(false); + const [newPublicName, setNewPublicName] = useState(""); + const [newPrivateName, setNewPrivateName] = useState(""); + const dragRef = useRef(null); + + const activeLayout = editMode ? layout : (savedLayout || roleLayout); + + // ─── Data ────────────────────────────────────────────────────────── + const activeProjects = data.projects.filter(p => p.status === "aktiv"); + const projMins = id => data.timeEntries.filter(e => e.projectId === id).reduce((s, e) => s + (e.minutes || 0), 0); + const monthMins = data.timeEntries.filter(e => (e.date||"").startsWith(thisMonth)).reduce((s,e)=>s+(e.minutes||0),0); + const lastMoMins = data.timeEntries.filter(e => (e.date||"").startsWith(lastMonth)).reduce((s,e)=>s+(e.minutes||0),0); + const myEmpId = currentUser?.employeeId; + const myMonthMins = data.timeEntries.filter(e => (e.date||"").startsWith(thisMonth) && e.employeeId===myEmpId).reduce((s,e)=>s+(e.minutes||0),0); + const recentTime = [...data.timeEntries].sort((a,b)=>(b.date||"").localeCompare(a.date||"")).slice(0,6); + const myRecentTime = [...data.timeEntries].filter(e=>e.employeeId===myEmpId).sort((a,b)=>(b.date||"").localeCompare(a.date||"")).slice(0,6); + const openInvoices = data.invoices.filter(i => i.status==="gesendet"||i.status==="überfällig"); + const overdueInvoices = data.invoices.filter(i => i.status==="überfällig"); + const openAmount = openInvoices.reduce((s,i)=>s+(i.total||0),0); + const paidThisYear = data.invoices.filter(i=>i.status==="bezahlt"&&(i.date||"").startsWith(thisYear)).reduce((s,i)=>s+(i.sub||0),0); + const pendingQuotes = (data.quotes||[]).filter(q=>q.status==="gesendet"); + const expiredQuotes = (data.quotes||[]).filter(q=>q.status==="gesendet"&&q.validUntil&&q.validUntil{ + const mins = data.timeEntries.filter(e=>e.projectId===p.id&&!e.invoiceId).reduce((s,e)=>s+(e.minutes||0),0); + return {...p, unbilledMins:mins, unbilledAmt:(mins/60)*(p.hourlyRate||0)}; + }).filter(p=>p.unbilledMins>0&&(p.billingType||p.type)==="stundensatz").sort((a,b)=>b.unbilledMins-a.unbilledMins); + const totalUnbilled = unbilledProjects.reduce((s,p)=>s+p.unbilledMins,0); + const last6Months = Array.from({length:6},(_,i)=>{const d=new Date();d.setMonth(d.getMonth()-(5-i));return d.toISOString().slice(0,7);}); + const monthlyRevenue = last6Months.map(m=>({m,paid:data.invoices.filter(i=>i.status==="bezahlt"&&(i.date||"").startsWith(m)).reduce((s,i)=>s+(i.sub||0),0)})); + const maxRev = Math.max(...monthlyRevenue.map(m=>m.paid),1); + + // ─── Permission ──────────────────────────────────────────────────── + const canSaveTemplate = !myRole || myRole.permissions === null || (myRole.permissions||[]).includes("dashboard-vorlage"); + + // ─── Edit mode ───────────────────────────────────────────────────── + const enterEdit = () => { setLayout(deepCloneLayout(savedLayout || roleLayout)); setEditMode(true); }; + const cancelEdit = () => { setEditMode(false); setAddPopoverRowId(null); setSaveTemplateOpen(false); setNewPublicName(""); setNewPrivateName(""); }; + const saveEdit = () => { + if (currentUser && saveAll) { + const users = (data.users||[]).map(u => u.id===currentUser.id ? {...u, dashboardWidgets: layout} : u); + saveAll({ ...data, users }); + } + setEditMode(false); setAddPopoverRowId(null); setSaveTemplateOpen(false); setNewPublicName(""); setNewPrivateName(""); + }; + const loadTemplate = tplId => { + const tpl = (data.dashboardTemplates||[]).find(t=>t.id===tplId); + if (tpl?.layout) setLayout(deepCloneLayout(migrateDashboardLayout(tpl.layout))); + }; + const saveAsTemplate = (tplId) => { + if (!saveAll) return; + const dashboardTemplates = (data.dashboardTemplates||[]).map(t => t.id===tplId ? {...t, layout} : t); + saveAll({ ...data, dashboardTemplates }); + setSaveTemplateOpen(false); + }; + const createTemplate = (name, isPublic) => { + if (!name.trim() || !saveAll) return; + const tpl = { id: generateId(), name: name.trim(), isPublic, layout, ...(!isPublic ? { createdBy: currentUser?.id } : {}) }; + saveAll({ ...data, dashboardTemplates: [...(data.dashboardTemplates||[]), tpl] }); + setSaveTemplateOpen(false); + if (isPublic) setNewPublicName(""); else setNewPrivateName(""); + }; + // Add widget to row, moving it out of any other row it's already in + const addWidgetExclusive = (rowId, wid) => { + setLayout(l => l.map(r => { + if (r.id === rowId) return { ...r, widgets: r.widgets.includes(wid) ? r.widgets : [...r.widgets, wid] }; + return { ...r, widgets: r.widgets.filter(w => w !== wid) }; + })); + setAddPopoverRowId(null); + }; + // Close popovers on outside click + useEffect(() => { + if (!addPopoverRowId && !saveTemplateOpen) return; + const close = e => { if (!e.target.closest("[data-popover]")) { setAddPopoverRowId(null); setSaveTemplateOpen(false); } }; + document.addEventListener("mousedown", close); + return () => document.removeEventListener("mousedown", close); + }, [addPopoverRowId, saveTemplateOpen]); + + // ─── Row operations ──────────────────────────────────────────────── + const updateRow = (rowId, patch) => setLayout(l => l.map(r => r.id===rowId ? {...r,...patch} : r)); + const addRow = (afterId) => { + const row = { id: generateId(), cols: 2, minH: 0, widgets: [] }; + setLayout(l => { + const i = l.findIndex(r=>r.id===afterId); + const next = [...l]; + next.splice(i+1, 0, row); + return next; + }); + }; + const deleteRow = rowId => setLayout(l => l.filter(r=>r.id!==rowId)); + const moveRow = (rowId, dir) => setLayout(l => { + const i = l.findIndex(r=>r.id===rowId); + const j = i + dir; + if (j<0||j>=l.length) return l; + const next=[...l]; + [next[i],next[j]]=[next[j],next[i]]; + return next; + }); + const addWidgetToRow = (rowId, wid) => + setLayout(l => l.map(r => r.id===rowId ? {...r, widgets:[...r.widgets,wid]} : r)); + const removeWidgetFromRow = (rowId, wid) => + setLayout(l => l.map(r => r.id===rowId ? {...r, widgets:r.widgets.filter(w=>w!==wid)} : r)); + + // ─── Drag & Drop ─────────────────────────────────────────────────── + const handleDragStart = (fromRowId, widgetId) => { + dragRef.current = { fromRowId, widgetId }; + }; + const handleDragEnd = () => { + dragRef.current = null; + setDragOver(null); + }; + const handleDrop = (toRowId, beforeWidgetId) => { + const src = dragRef.current; + if (!src) return; + const { fromRowId, widgetId } = src; + setLayout(l => { + const next = deepCloneLayout(l); + const fromRow = next.find(r=>r.id===fromRowId); + const toRow = next.find(r=>r.id===toRowId); + if (!fromRow||!toRow) return l; + fromRow.widgets = fromRow.widgets.filter(w=>w!==widgetId); + if (beforeWidgetId) { + const idx = toRow.widgets.indexOf(beforeWidgetId); + toRow.widgets.splice(idx<0 ? toRow.widgets.length : idx, 0, widgetId); + } else { + if (!toRow.widgets.includes(widgetId)) toRow.widgets.push(widgetId); + } + return next; + }); + dragRef.current = null; + setDragOver(null); + }; + + // ─── Styles ──────────────────────────────────────────────────────── + const ctrlBtn = "pill"; + const activeCtrlBtn = "pill active"; + + // ─── Widget content renderers ────────────────────────────────────── + const wContent = { + "kpi-projekte": () => p.status==="abgeschlossen").length} abgeschlossen`} />, + "kpi-stunden": () => 0?`Vormonat: ${formatHours(lastMoMins)}`:undefined} />, + "kpi-ausstehend": () => 0?"#8a1a1a":"#7a6a00"} go="invoices" setView={!editMode?setView:undefined} sub={overdueInvoices.length>0?`${overdueInvoices.length} überfällig`:`${openInvoices.length} gesendet`} />, + "kpi-umsatz": () => , + "warnungen": () => { + const has = overdueInvoices.length>0||expiredQuotes.length>0; + if (!editMode&&!has) return null; + return has ? ( +
+ {overdueInvoices.length>0&&
setView("invoices"):undefined} style={{flex:1,minWidth:180,padding:"12px 16px",background:"#fff3f3",border:"1.5px solid #e0b0b0",borderRadius:8,cursor:editMode?"default":"pointer",display:"flex",alignItems:"center",gap:12}}> +
+
{overdueInvoices.length} überfällige Rechnung{overdueInvoices.length>1?"en":""}
{formatCHF(overdueInvoices.reduce((s,i)=>s+i.total,0))} ausstehend
+
} + {expiredQuotes.length>0&&
setView("quotes"):undefined} style={{flex:1,minWidth:180,padding:"12px 16px",background:"#fffbe8",border:"1.5px solid #e0d090",borderRadius:8,cursor:editMode?"default":"pointer",display:"flex",alignItems:"center",gap:12}}> +
+
{expiredQuotes.length} Offerte{expiredQuotes.length>1?"n":""} abgelaufen
Gültigkeit überschritten
+
} +
+ ) :
Warnungen (keine aktuellen)
; + }, + "aktive-projekte": () => ( +
+
+
AKTIVE PROJEKTE
+ +
+ {activeProjects.length===0?
Keine aktiven Projekte
:activeProjects.slice(0,6).map(p=>{ + const used=projMins(p.id),budget=p.budgetHours||0,pct=budget>0?Math.min((used/60)/budget,1):0,over=budget>0&&(used/60)>budget; + const cl=(data.persons||[]).filter(x=>x.isAuftraggeber).find(c=>c.id===p.clientId); + return (
+
+
{p.name}
{cl&&
{cl.name}
}
+
{formatHours(used)}{budget>0?` / ${budget}h`:""}
+
+ {budget>0&&
0.8?"#b5621e":"#2d6a4f",borderRadius:2,transition:"width 0.3s"}}/>
} +
); + })} +
+ ), + "unverrechnete-stunden": () => ( +
+
+
UNVERRECHNETE STUNDEN
+ +
+ {totalUnbilled===0?
✓ Alles verrechnet
:<> +
{formatHours(totalUnbilled)}
+
≈ {formatCHF(unbilledProjects.reduce((s,p)=>s+p.unbilledAmt,0))}
+ {unbilledProjects.slice(0,5).map(p=>
{p.name}{formatHours(p.unbilledMins)}
)} + } +
+ ), + "umsatz-sparkline": () => ( +
+
UMSATZ LETZTE 6 MONATE
+
+ {monthlyRevenue.map(({m,paid})=>( +
+
0?`${Math.max((paid/maxRev)*54,4)}px`:"2px",background:m===thisMonth?"#b07848":paid>0?"#2d6a4f":"var(--border2)",borderRadius:"2px 2px 0 0",transition:"height 0.3s"}} title={formatCHF(paid)}/> +
{new Date(m+"-01").toLocaleString("de-CH",{month:"short"})}
+
+ ))} +
+
+ ), + "offene-offerten": () => ( +
+
+
OFFENE OFFERTEN
+ +
+ {pendingQuotes.length===0?
Keine pendenten Offerten
:pendingQuotes.slice(0,5).map(q=>{ + const cl=(data.persons||[]).filter(p=>p.isAuftraggeber).find(c=>c.id===q.clientId); + const expired=q.validUntil&&q.validUntil +
{q.number}
{cl&&
{cl.name}
}
+
{formatCHF(q.total)}
{expired&&
abgelaufen
}
+
); + })} +
+ ), + "letzte-zeiteintraege": () => ( +
+
+
LETZTE ZEITEINTRÄGE
+ +
+ +
+ ), + "meine-zeiteintraege": () => ( +
+
+
MEINE ZEITEINTRÄGE
+ +
+ +
+ ), + + "meine-projekte": () => { + const myProjects = (data.projects||[]).filter(p=>p.status==="aktiv"&&(p.internalMembers||[]).includes(myEmpId)); + return ( +
+
+
MEINE PROJEKTE
+ +
+ {myProjects.length===0 + ?
Keinen Projekten zugewiesen
+ : myProjects.map(p=>{ + const myMins=data.timeEntries.filter(e=>e.projectId===p.id&&e.employeeId===myEmpId).reduce((s,e)=>s+(e.minutes||0),0); + const cl=(data.persons||[]).find(c=>c.id===p.clientId); + return ( +
+
+
+
{p.name}
+ {cl&&
{cl.name}
} +
+
{formatHours(myMins)}
+
+
+ ); + }) + } +
+ ); + }, + + "meine-ferien": () => { + const myEmp=(data.employees||[]).find(e=>e.id===myEmpId); + if(!myEmpId||!myEmp) return
Kein Mitarbeiterprofil verknüpft
; + const anspruchTage=(myEmp.ferienWochen||5)*5; + const approvedEntries=(data.ferienEntries||[]).filter(f=>f.employeeId===myEmpId&&(f.status==="approved"||!f.status)&&(f.dateFrom||"").startsWith(thisYear)); + const countWorkdays=(from,to)=>{ + let n=0;const d=new Date(from);const end=new Date(to); + while(d<=end){const dow=d.getDay();if(dow!==0&&dow!==6)n++;d.setDate(d.getDate()+1);} + return n; + }; + const bezogenTage=approvedEntries.reduce((s,f)=>s+countWorkdays(f.dateFrom,f.dateTo),0); + const restTage=anspruchTage-bezogenTage; + const pct=Math.min(bezogenTage/anspruchTage,1); + const upcoming=(data.ferienEntries||[]).filter(f=>f.employeeId===myEmpId&&(f.status==="approved"||!f.status)&&f.dateFrom>today).slice(0,2); + return ( +
+
FERIENSTAND {thisYear}
+
+
+
{restTage}
+
Verbleibend
+
+
+
{bezogenTage}
+
Bezogen
+
+
+
{anspruchTage}
+
Anspruch
+
+
+
+
+
+ {upcoming.length>0&&<> +
NÄCHSTE FERIEN
+ {upcoming.map(f=>
{formatDate(f.dateFrom)} – {formatDate(f.dateTo)}
)} + } +
+ ); + }, + + "ueberstunden": () => { + const myEmp=(data.employees||[]).find(e=>e.id===myEmpId); + if(!myEmpId||!myEmp) return
Kein Mitarbeiterprofil verknüpft
; + const pensum=(myEmp.pensum||100)/100; + const tagessollH=((myEmp.wochenstunden||35)*pensum)/5; + const startOfYear=`${thisYear}-01-01`; + const fts=data.feiertage||[]; + // Respect eintrittsdatum: only count from when the employee actually started + const effectiveYearStart=myEmp.eintrittsdatum&&myEmp.eintrittsdatum>startOfYear?myEmp.eintrittsdatum:startOfYear; + const todayD=new Date(today); + let workdays=0;const d=new Date(effectiveYearStart); + while(d<=todayD){const dow=d.getDay();const ds=d.toISOString().slice(0,10);const ft=fts.find(f=>f.date===ds);const isFt=ft&&(ft.stundenDelta===0||ft.stundenDelta===null||ft.stundenDelta===undefined);if(dow!==0&&dow!==6&&!isFt)workdays++;d.setDate(d.getDate()+1);} + const sollMin=workdays*tagessollH*60; + const istMin=data.timeEntries.filter(e=>e.employeeId===myEmpId&&(e.date||"")>=effectiveYearStart&&(e.date||"")<=today).reduce((s,e)=>s+(e.minutes||0),0); + const deltaMin=istMin-sollMin; + const isPos=deltaMin>=0; + // This month — also respect eintrittsdatum + const effectiveMonthStart=myEmp.eintrittsdatum&&myEmp.eintrittsdatum>`${thisMonth}-01`?myEmp.eintrittsdatum:`${thisMonth}-01`; + const sollMonthMin=(() => { + let wd=0;const me=new Date(new Date(`${thisMonth}-01`).getFullYear(),new Date(`${thisMonth}-01`).getMonth()+1,0); + const end=mef.date===ds);const isFt=ft&&(ft.stundenDelta===0||ft.stundenDelta===null||ft.stundenDelta===undefined);if(dow!==0&&dow!==6&&!isFt)wd++;dd.setDate(dd.getDate()+1);} + return wd*tagessollH*60; + })(); + const istMonthMin=data.timeEntries.filter(e=>e.employeeId===myEmpId&&(e.date||"").startsWith(thisMonth)).reduce((s,e)=>s+(e.minutes||0),0); + const deltaMonth=istMonthMin-sollMonthMin; + return ( +
+
STUNDENSALDO
+
+
JAHRESSALDO {thisYear}
+
+ {isPos?"+":""}{formatHours(Math.abs(deltaMin))} + {isPos?"Überstunden":"Minusstunden"} +
+
{formatHours(istMin)} von {formatHours(sollMin)} Soll
+
+
+
DIESER MONAT
+
=0?"#2d6a4f":"#8a1a1a"}}> + {deltaMonth>=0?"+":""}{formatHours(Math.abs(deltaMonth))} +
+
{formatHours(istMonthMin)} von {formatHours(sollMonthMin)} Soll
+
+
+ ); + }, + + "stunden-woche": () => { + const myEmp=(data.employees||[]).find(e=>e.id===myEmpId); + const pensum=(myEmp?.pensum||100)/100; + const sollH=(myEmp?.wochenstunden||35)*pensum; + const getMonday=(dateStr)=>{const d=new Date(dateStr);const day=d.getDay();d.setDate(d.getDate()-(day===0?6:day-1));return d;}; + const monday=getMonday(today); + const weeks=Array.from({length:5},(_,i)=>{ + const mon=new Date(monday);mon.setDate(mon.getDate()-(4-i)*7); + const sun=new Date(mon);sun.setDate(sun.getDate()+6); + const monStr=mon.toISOString().slice(0,10); + const sunStr=sun.toISOString().slice(0,10); + const isCurrent=i===4; + const mins=(myEmpId?data.timeEntries.filter(e=>e.employeeId===myEmpId&&e.date>=monStr&&e.date<=sunStr):data.timeEntries.filter(e=>e.date>=monStr&&e.date<=sunStr)).reduce((s,e)=>s+(e.minutes||0),0); + const kw=(() => { const d2=new Date(mon);d2.setHours(0,0,0,0);d2.setDate(d2.getDate()+3-(d2.getDay()||7)+1); const w1=new Date(d2.getFullYear(),0,4);return 1+Math.round(((d2-w1)/86400000+((w1.getDay()||7)-1))/7); })(); + return {kw,mins,isCurrent}; + }); + const maxMins=Math.max(...weeks.map(w=>w.mins),sollH*60,1); + const sollPct=(sollH*60)/maxMins; + return ( +
+
STUNDEN PRO WOCHE
+
+
+ {weeks.map(({kw,mins,isCurrent})=>{ + const pct=mins/maxMins; + const over=mins>sollH*60; + return ( +
+
{mins>0?formatHours(mins):""}
+
0?4:1)}px`,background:isCurrent?(over?"#2d6a4f":"#b07848"):over?"#2d6a4f33":"var(--border2)",borderRadius:"3px 3px 0 0",transition:"height 0.3s"}}/> +
KW{kw}
+
+ ); + })} +
+
+ — Soll: {sollH}h / Woche +
+
+ ); + }, + + "interner-blog": () => { + const posts = (data.blogPosts || []); + const recent = [...posts].sort((a,b) => { + if (a.pinned !== b.pinned) return a.pinned ? -1 : 1; + return b.createdAt.localeCompare(a.createdAt); + }).slice(0, 3); + const getMonday = d => { const dd=new Date(d); dd.setDate(dd.getDate()-(dd.getDay()===0?6:dd.getDay()-1)); return dd; }; + const weekStart = getMonday(new Date(today)); + const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate()+6); + const feiertageWeek = (data.feiertage||[]).filter(f=>f.date>=weekStart.toISOString().slice(0,10)&&f.date<=weekEnd.toISOString().slice(0,10)); + const TYPE_COLOR = { beitrag:"#1a4e8a", ankuendigung:"#b5621e", event:"#2d6a4f" }; + const TYPE_LABEL = { beitrag:"Beitrag", ankuendigung:"Ankündigung", event:"Event" }; + return ( +
+
+
PINNWAND
+ +
+ {feiertageWeek.length>0&&( +
+ 🎉 + Feiertag diese Woche: {feiertageWeek.map(f=>f.name).join(", ")} +
+ )} + {recent.length===0 + ?
Keine Beiträge
+ : recent.map(p=>( +
+
+ {(TYPE_LABEL[p.type]||"").toUpperCase()} + {p.pinned&&📌} +
+ {p.title&&
{p.title}
} +
{p.body}
+
{p.authorName} · {new Date(p.createdAt).toLocaleDateString("de-CH")}
+
+ )) + } +
+ ); + }, + + "team-auslastung": () => { + const activeEmps=(data.employees||[]).filter(e=>e.aktiv!==false); + const pensum=e=>(e.pensum||100)/100; + const sollH=e=>((e.wochenstunden||35)*pensum(e))/5*(() => { + let wd=0;const d=new Date(`${thisMonth}-01`);const end=new Date(d.getFullYear(),d.getMonth()+1,0);const todayD=new Date(today); + const cap=end{ + const istMin=data.timeEntries.filter(t=>t.employeeId===e.id&&(t.date||"").startsWith(thisMonth)).reduce((s,t)=>s+(t.minutes||0),0); + const sollMin=sollH(e)*60; + const pct=sollMin>0?Math.min(istMin/sollMin,1.5):0; + return{...e,istMin,sollMin,pct}; + }).sort((a,b)=>b.istMin-a.istMin); + return ( +
+
TEAM-AUSLASTUNG {new Date().toLocaleString("de-CH",{month:"long"}).toUpperCase()}
+ {empData.length===0 + ?
Keine Mitarbeitenden
+ : empData.map(e=>{ + const over=e.pct>1; + return ( +
+
+
{e.name}
+
{formatHours(e.istMin)}{e.sollMin>0?` / ${formatHours(e.sollMin)}`:""}
+
+
+
0.8?"#b07848":"var(--border3)",borderRadius:2,transition:"width 0.3s"}}/> +
+
+ ); + }) + } +
+ ); + }, + }; + + // ─── Row renderer ────────────────────────────────────────────────── + const renderRow = (row, rowIdx) => { + const isDragOverRow = dragOver?.rowId === row.id && dragOver?.before === null; + const content = wContent[row.id] ? null : null; // widget lookup happens below + + return ( +
+ {/* Row toolbar */} + {editMode && ( +
+ SPALTEN + {[1,2,3,4].map(n=>( + + ))} + HÖHE + {HEIGHT_OPTS.map(opt=>( + + ))} +
+ + {addPopoverRowId===row.id&&( +
+ {DASHBOARD_WIDGETS.map(d=>{ + const inThis=row.widgets.includes(d.id); + const inOther=!inThis&&layout.some(r=>r.id!==row.id&&r.widgets.includes(d.id)); + return ( + + ); + })} +
+ )} +
+
+ {rowIdx>0&&} + {rowIdxmoveRow(row.id,1)} className={ctrlBtn}>↓} + + +
+
+ )} + + {/* Row grid */} +
{e.preventDefault();setDragOver({rowId:row.id,before:null});}:undefined} + onDrop={editMode?e=>{e.preventDefault();handleDrop(row.id,null);}:undefined} + > + {row.widgets.map(wid=>{ + const content = wContent[wid]; + if (!content) return null; + const rendered = content(); + if (rendered===null&&!editMode) return null; + const isBefore = dragOver?.rowId===row.id&&dragOver?.before===wid; + const isDragging = dragRef.current?.widgetId===wid; + return ( +
handleDragStart(row.id,wid):undefined} + onDragEnd={editMode?handleDragEnd:undefined} + onDragOver={editMode?e=>{e.preventDefault();e.stopPropagation();setDragOver({rowId:row.id,before:wid});}:undefined} + onDrop={editMode?e=>{e.preventDefault();e.stopPropagation();handleDrop(row.id,wid);}:undefined} + style={{ + position:"relative", + height:"100%", + opacity:isDragging?0.35:1, + boxShadow:isBefore?"inset 3px 0 0 var(--text)":undefined, + borderRadius:10, + cursor:editMode?"grab":"default", + transition:"opacity 0.15s", + }} + > + {rendered===null?
{DASHBOARD_WIDGETS.find(d=>d.id===wid)?.label}
:rendered} + {editMode&&( + + )} +
+ ); + })} + + {/* Empty slot drop target */} + {editMode&&( +
{e.preventDefault();setDragOver({rowId:row.id,before:null});}} + onDrop={e=>{e.preventDefault();handleDrop(row.id,null);}} + style={{minHeight:80,border:"1.5px dashed var(--border3)",borderRadius:10,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text5)",fontSize:13}} + > + ablegen +
+ )} +
+
+ ); + }; + + // ─── Render ──────────────────────────────────────────────────────── + return ( +
+ {/* Header */} +
+
+

+ {data.settings.name||"Studio"} +

+
+ {new Date().toLocaleDateString("de-CH",{weekday:"long",day:"numeric",month:"long",year:"numeric"}).toUpperCase()} +
+
+
+ {editMode?( + <> + +
+ + {saveTemplateOpen&&( +
+ {canSaveTemplate&&(<> +
ÖFFENTLICHE VORLAGE
+ {(data.dashboardTemplates||[]).filter(t=>t.isPublic).map(t=>( + + ))} +
+
+ setNewPublicName(e.target.value)} placeholder="Neue öffentliche Vorlage…" + onKeyDown={e=>e.key==="Enter"&&createTemplate(newPublicName,true)} + style={{flex:1,height:26,border:"1px solid var(--border)",borderRadius:4,padding:"0 8px",fontSize:11,background:"var(--surface)",color:"var(--text)",fontFamily:"inherit",outline:"none"}} /> + +
+
+
+ )} +
PERSÖNLICHE VORLAGE
+ {(data.dashboardTemplates||[]).filter(t=>!t.isPublic&&t.createdBy===currentUser?.id).map(t=>( + + ))} +
+
+ setNewPrivateName(e.target.value)} placeholder="Neue persönliche Vorlage…" + onKeyDown={e=>e.key==="Enter"&&createTemplate(newPrivateName,false)} + style={{flex:1,height:26,border:"1px solid var(--border)",borderRadius:4,padding:"0 8px",fontSize:11,background:"var(--surface)",color:"var(--text)",fontFamily:"inherit",outline:"none"}} /> + +
+
+
+ )} +
+ + + + ):( + + )} +
+
+ + {/* Edit banner */} + {editMode&&( +
+ Dashboard anpassen — Spaltenanzahl und Höhe pro Zeile wählen. Widgets per Drag & Drop verschieben oder mit × entfernen. +
+ )} + + {/* Rows */} + {activeLayout.map((row,idx) => renderRow(row,idx))} + + {/* Edit mode: add first row / add row at bottom */} + {editMode&&( +
+ +
+ )} +
+ ); +} + +function KpiCard({label,value,sub,color,go,setView}) { + return ( +
setView(go):undefined} + style={{borderTop:`3px solid ${color||"var(--border)"}`,cursor:go&&setView?"pointer":"default",transition:"transform 0.15s",height:"100%",boxSizing:"border-box"}} + onMouseEnter={go&&setView?e=>{e.currentTarget.style.transform="translateY(-2px)";}:undefined} + onMouseLeave={go&&setView?e=>{e.currentTarget.style.transform="";}:undefined} + > +
{label}
+
{value}
+ {sub&&
{sub}
} +
+ ); +} + +function TimeTable({entries,data}) { + if (!entries.length) return
Noch keine Zeiteinträge
; + return ( + + + + {entries.map(e=>{ + const proj=data.projects.find(p=>p.id===e.projectId); + const phase=SIA_PHASES.find(ph=>ph.id===e.phaseId); + return ( + + + + + ); + })} + +
DatumProjektBeschreibungDauer
{formatDate(e.date)}
{proj?.name||"—"}
{phase&&
Phase {phase.id}
}
{e.description||"—"}{formatHours(e.minutes)}
+ ); +} diff --git a/src/views/Dashboard.jsx.bak b/src/views/Dashboard.jsx.bak new file mode 100755 index 0000000..888abb2 --- /dev/null +++ b/src/views/Dashboard.jsx.bak @@ -0,0 +1,252 @@ +import React from "react"; +import { SIA_PHASES } from "../constants.js"; +import { formatCHF, formatDate, formatHours } from "../utils.js"; + +export default function Dashboard({ data, setView }) { + const today = new Date().toISOString().slice(0, 10); + const thisMonth = today.slice(0, 7); + const thisYear = today.slice(0, 4); + const lastMonth = (() => { const d = new Date(); d.setMonth(d.getMonth() - 1); return d.toISOString().slice(0, 7); })(); + + // Projekte + const activeProjects = data.projects.filter(p => p.status === "aktiv"); + const projectMinutes = (id) => data.timeEntries.filter(e => e.projectId === id).reduce((s, e) => s + (e.minutes || 0), 0); + + // Zeit + const monthMinutes = data.timeEntries.filter(e => (e.date || "").startsWith(thisMonth)).reduce((s, e) => s + (e.minutes || 0), 0); + const lastMonthMinutes = data.timeEntries.filter(e => (e.date || "").startsWith(lastMonth)).reduce((s, e) => s + (e.minutes || 0), 0); + const recentTime = [...data.timeEntries].sort((a, b) => (b.date || "").localeCompare(a.date || "")).slice(0, 6); + + // Rechnungen + const openInvoices = data.invoices.filter(i => i.status === "gesendet" || i.status === "überfällig"); + const overdueInvoices = data.invoices.filter(i => i.status === "überfällig"); + const openAmount = openInvoices.reduce((s, i) => s + (i.total || 0), 0); + const paidThisYear = data.invoices.filter(i => i.status === "bezahlt" && (i.date || "").startsWith(thisYear)).reduce((s, i) => s + (i.sub || 0), 0); + + // Offerten + const pendingQuotes = (data.quotes || []).filter(q => q.status === "gesendet"); + const expiredQuotes = (data.quotes || []).filter(q => q.status === "gesendet" && q.validUntil && q.validUntil < today); + + // Unverrechnete Stunden + const unbilledProjects = activeProjects + .map(p => { + const mins = data.timeEntries.filter(e => e.projectId === p.id && !e.invoiceId).reduce((s, e) => s + (e.minutes || 0), 0); + return { ...p, unbilledMins: mins, unbilledAmount: (mins / 60) * (p.hourlyRate || 0) }; + }) + .filter(p => p.unbilledMins > 0 && (p.billingType || p.type) === "stundensatz") + .sort((a, b) => b.unbilledMins - a.unbilledMins); + const totalUnbilledMins = unbilledProjects.reduce((s, p) => s + p.unbilledMins, 0); + + // Monats-Umsatz für Sparkline (letzten 6 Monate) + const last6Months = Array.from({ length: 6 }, (_, i) => { + const d = new Date(); d.setMonth(d.getMonth() - (5 - i)); + return d.toISOString().slice(0, 7); + }); + const monthlyRevenue = last6Months.map(m => ({ + m, paid: data.invoices.filter(i => i.status === "bezahlt" && (i.date || "").startsWith(m)).reduce((s, i) => s + (i.sub || 0), 0), + })); + const maxRevMonth = Math.max(...monthlyRevenue.map(m => m.paid), 1); + + const Card = ({ label, value, sub, color, go, children }) => ( +
setView(go) : undefined} + style={{ borderTop: `3px solid ${color || "var(--border)"}`, cursor: go ? "pointer" : "default", transition: "transform 0.15s" }} + onMouseEnter={go ? e => { e.currentTarget.style.transform = "translateY(-2px)"; } : undefined} + onMouseLeave={go ? e => { e.currentTarget.style.transform = ""; } : undefined}> +
{label}
+ {value !== undefined &&
{value}
} + {sub &&
{sub}
} + {children} +
+ ); + + return ( +
+ {/* Header */} +
+

+ {data.settings.name || "Studio"} +

+
+ {new Date().toLocaleDateString("de-CH", { weekday: "long", day: "numeric", month: "long", year: "numeric" }).toUpperCase()} +
+
+ + {/* KPI Cards */} +
+ p.status === "abgeschlossen").length} abgeschlossen`} /> + 0 ? `Vormonat: ${formatHours(lastMonthMinutes)}` : "Noch keine Vormonatsdaten"} /> + 0 ? "#8a1a1a" : "#7a6a00"} go="invoices" + sub={overdueInvoices.length > 0 ? `${overdueInvoices.length} überfällig` : `${openInvoices.length} gesendet`} /> + +
+ + {/* Warnungen */} + {(overdueInvoices.length > 0 || expiredQuotes.length > 0) && ( +
+ {overdueInvoices.length > 0 && ( +
setView("invoices")} style={{ flex: 1, minWidth: 200, padding: "12px 16px", background: "#fff3f3", border: "1.5px solid #e0b0b0", borderRadius: 8, cursor: "pointer", display: "flex", alignItems: "center", gap: 12 }}> +
+
+
{overdueInvoices.length} überfällige Rechnung{overdueInvoices.length > 1 ? "en" : ""}
+
{formatCHF(overdueInvoices.reduce((s, i) => s + i.total, 0))} ausstehend
+
+
+ )} + {expiredQuotes.length > 0 && ( +
setView("quotes")} style={{ flex: 1, minWidth: 200, padding: "12px 16px", background: "#fffbe8", border: "1.5px solid #e0d090", borderRadius: 8, cursor: "pointer", display: "flex", alignItems: "center", gap: 12 }}> +
+
+
{expiredQuotes.length} Offerte{expiredQuotes.length > 1 ? "n" : ""} abgelaufen
+
Gültigkeit überschritten
+
+
+ )} +
+ )} + + {/* Hauptbereich: 3 Spalten */} +
+ + {/* Aktive Projekte mit Budget */} +
+
+
AKTIVE PROJEKTE
+ +
+ {activeProjects.length === 0 ? ( +
Keine aktiven Projekte
+ ) : activeProjects.slice(0, 6).map(p => { + const used = projectMinutes(p.id); + const budget = p.budgetHours || 0; + const pct = budget > 0 ? Math.min((used / 60) / budget, 1) : 0; + const overBudget = budget > 0 && (used / 60) > budget; + const client = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === p.clientId); + return ( +
+
+
+
{p.name}
+ {client &&
{client.name}
} +
+
+ {formatHours(used)}{budget > 0 ? ` / ${budget}h` : ""} +
+
+ {budget > 0 && ( +
+
0.8 ? "#b5621e" : "#2d6a4f", borderRadius: 2, transition: "width 0.3s" }} /> +
+ )} +
+ ); + })} +
+ + {/* Unverrechnete Stunden */} +
+
+
UNVERRECHNETE STUNDEN
+ +
+ {totalUnbilledMins === 0 ? ( +
✓ Alles verrechnet
+ ) : ( + <> +
{formatHours(totalUnbilledMins)}
+
≈ {formatCHF(unbilledProjects.reduce((s, p) => s + p.unbilledAmount, 0))}
+ {unbilledProjects.slice(0, 5).map(p => ( +
+ {p.name} + {formatHours(p.unbilledMins)} +
+ ))} + + )} +
+ + {/* Monatsumsatz Sparkline + Offerte */} +
+
+
UMSATZ LETZTE 6 MONATE
+
+ {monthlyRevenue.map(({ m, paid }) => ( +
+
0 ? `${Math.max((paid / maxRevMonth) * 54, 4)}px` : "2px", background: m === thisMonth ? "#d4a85a" : paid > 0 ? "#2d6a4f" : "var(--border2)", borderRadius: "2px 2px 0 0", transition: "height 0.3s" }} title={formatCHF(paid)} /> +
+ {new Date(m + "-01").toLocaleString("de-CH", { month: "short" })} +
+
+ ))} +
+
+ +
+
+
OFFENE OFFERTEN
+ +
+ {pendingQuotes.length === 0 ? ( +
Keine pendenten Offerten
+ ) : pendingQuotes.slice(0, 4).map(q => { + const cl = ((data.persons||[]).filter(p=>p.isAuftraggeber)).find(c => c.id === q.clientId); + const expired = q.validUntil && q.validUntil < today; + return ( +
+
+
{q.number}
+ {cl &&
{cl.name}
} +
+
+
{formatCHF(q.total)}
+ {expired &&
abgelaufen
} +
+
+ ); + })} +
+
+
+ + {/* Untere Zeile: Letzte Zeiteinträge */} +
+
+
LETZTE ZEITEINTRÄGE
+ +
+ {recentTime.length === 0 ? ( +
Noch keine Zeiteinträge
+ ) : ( + + + + + + + + {recentTime.map(e => { + const proj = data.projects.find(p => p.id === e.projectId); + const phase = SIA_PHASES.find(ph => ph.id === e.phaseId); + return ( + + + + + + + ); + })} + +
DatumProjektBeschreibungDauer
{formatDate(e.date)} +
{proj?.name || "—"}
+ {phase &&
Phase {phase.id}
} +
{e.description || "—"}{formatHours(e.minutes)}
+ )} +
+
+ ); +} diff --git a/src/views/Dokumente.jsx b/src/views/Dokumente.jsx new file mode 100755 index 0000000..5fa3e1f --- /dev/null +++ b/src/views/Dokumente.jsx @@ -0,0 +1,194 @@ +import React from "react"; +import { PROTOKOLL_TYPES } from "../constants.js"; +import { formatDate } from "../utils.js"; +import { Header } from "../components/UI.jsx"; + +export default function Dokumente({ data, setView }) { + const protocols = (data.protocols || []).sort((a, b) => (b.date || "").localeCompare(a.date || "")); + const deliveryNotes = (data.deliveryNotes || []).sort((a, b) => (b.date || "").localeCompare(a.date || "")); + const letterTemplates = data.letterTemplates || []; + + const recentProtos = protocols.slice(0, 6); + const recentNotes = deliveryNotes.slice(0, 5); + + const protoByType = PROTOKOLL_TYPES.map(t => ({ + type: t, + count: protocols.filter(p => p.type === t).length, + })).filter(r => r.count > 0).sort((a, b) => b.count - a.count); + const maxTypeCount = protoByType[0]?.count || 1; + + const getClient = (n) => { + if (n.clientId) return (data.persons||[]).filter(p=>p.isAuftraggeber).find(c => c.id === n.clientId)?.name || "—"; + if (n.projectId) { + const proj = data.projects?.find(p => p.id === n.projectId); + if (proj?.clientId) return (data.persons||[]).filter(p=>p.isAuftraggeber).find(c => c.id === proj.clientId)?.name || "—"; + } + return "—"; + }; + + const getProject = (n) => { + if (!n.projectId) return null; + return data.projects?.find(p => p.id === n.projectId)?.name || null; + }; + + const SectionCard = ({ title, count, action, onAction, children, accent }) => ( +
+
+
+ {title} + {count > 0 && ( + {count} + )} +
+ +
+ {children} +
+ ); + + return ( +
+
+ + {/* KPI-Zeile */} +
+ {[ + { label: "Protokolle", count: protocols.length, sub: `${recentProtos.length > 0 ? formatDate(recentProtos[0]?.date) : "—"} zuletzt`, view: "protokolle", color: "#2d6a4f", bg: "#e8f5ee" }, + { label: "Lieferscheine", count: deliveryNotes.length, sub: `${recentNotes.length > 0 ? formatDate(recentNotes[0]?.date) : "—"} zuletzt`, view: "lieferscheine", color: "#1a4e8a", bg: "#e8f0fa" }, + { label: "Briefvorlagen", count: letterTemplates.length, sub: "Vorlagen", view: "letters", color: "#7a3e8a", bg: "#f3eafa" }, + ].map(({ label, count, sub, view: v, color, bg }) => ( +
setView(v)}> +
{label.toUpperCase()}
+
{count}
+
{sub}
+
+ → Öffnen +
+
+ ))} +
+ +
+ + {/* Linke Spalte */} +
+ {/* Letzte Protokolle */} + setView("protokolle")} accent="#e8f5ee"> + {recentProtos.length === 0 ? ( +
Noch keine Protokolle erfasst.
+ ) : ( + + + + + + + + + + + + {recentProtos.map(p => { + const proj = getProject(p); + return ( + + + + + + + + ); + })} + +
DatumTypTitelProjektEinträge
{formatDate(p.date)} + {p.type || "—"} + {p.title || }{proj || }{(p.entries || []).length}
+ )} +
+ + {/* Letzte Lieferscheine */} + setView("lieferscheine")} accent="#e8f0fa"> + {recentNotes.length === 0 ? ( +
Noch keine Lieferscheine erfasst.
+ ) : ( + + + + + + + + + + + + {recentNotes.map(n => ( + + + + + + + + ))} + +
Nr.DatumKundeProjektPositionen
{n.number || "—"}{formatDate(n.date)}{getClient(n)}{getProject(n) || }{(n.items || []).length}
+ )} +
+
+ + {/* Rechte Spalte */} +
+ {/* Protokoll-Typen */} + {protoByType.length > 0 && ( +
+
PROTOKOLLE NACH TYP
+ {protoByType.map(({ type, count }) => { + const pct = (count / maxTypeCount) * 100; + return ( +
+
+ {type} + {count} +
+
+
+
+
+ ); + })} +
+ )} + + {/* Briefvorlagen */} +
+
0 ? "1px solid #ece8e2" : "none" }}> + BRIEFVORLAGEN + +
+ {letterTemplates.length === 0 ? ( +
Noch keine Briefvorlagen erstellt.
+ ) : ( +
+ {letterTemplates.map(t => ( +
+ {t.name || "Unbenannt"} + + {t.body ? `${t.body.replace(/<[^>]+>/g, "").slice(0, 40)}…` : "—"} + +
+ ))} +
+ )} +
+
+
+
+ ); +} diff --git a/src/views/Invoices.jsx b/src/views/Invoices.jsx new file mode 100755 index 0000000..7996700 --- /dev/null +++ b/src/views/Invoices.jsx @@ -0,0 +1,1467 @@ +import React, { useState, useEffect } from "react"; +import { SIA_PHASES } from "../constants.js"; +import { generateId, formatCHF, formatDate, formatHours, roundCHF, isQRIban, generateQRReference, formatReference } from "../utils.js"; +import { Header, Modal, FormField, StatusBadge, StatusSelect, useConfirm , DateInput } from "../components/UI.jsx"; +import { MahnModal } from "./Protokolle.jsx"; + +export default +function Invoices({ data, update, saveAll, modal, setModal, setPrintContent, setView }) { + const invoices = data.invoices || []; + const clients = (data.persons || []).filter(p => p.isAuftraggeber); + const [form, setForm] = useState({ number: "", clientId: "", contactId: "", projectId: "", date: new Date().toISOString().slice(0, 10), dueDate: "", items: [{ id: generateId(), desc: "", qty: 1, price: 0 }], mwst: true, notes: "", status: "entwurf" }); + const [filter, setFilter] = useState(() => { const cid = window.__navClientId || ""; window.__navClientId = null; return { status: "", clientId: cid, year: "", search: "" }; }); + const [groupBy, setGroupBy] = useState("date"); + const [sort, setSort] = useState({ col: "date", dir: -1 }); + const toggleSort = (col) => setSort(s => ({ col, dir: s.col === col ? -s.dir : -1 })); + const SortTh = ({ col, children, style }) => ( + toggleSort(col)} style={{ cursor: "pointer", userSelect: "none", whiteSpace: "nowrap", ...style }}> + {children} {sort.col === col ? (sort.dir === 1 ? "▲" : "▼") : "⇅"} + + ); + + const nextNumber = () => { + const fmt = data.settings.invoiceNumberFormat || "YYYY-NNN"; + const now = new Date(); + const yyyy = String(now.getFullYear()); + const yy = yyyy.slice(2); + // Build regex to extract the sequence number from existing invoice numbers + const pattern = fmt + .replace(/[-/\^$*+?.()|[\]{}]/g, "\\$&") + .replace(/YYYY/g, yyyy).replace(/YY/g, yy) + .replace(/N+/, "(\\d+)"); + const rx = new RegExp("^" + pattern + "$"); + const nums = invoices.map(i => { + const m = (i.number || "").match(rx); + return m ? parseInt(m[1]) : null; + }).filter(n => n !== null); + const nextSeq = nums.length ? Math.max(...nums) + 1 : 1; + const padLen = (fmt.match(/N+/) || ["NNN"])[0].length; + return fmt + .replace(/YYYY/g, yyyy).replace(/YY/g, yy) + .replace(/N+/, String(nextSeq).padStart(padLen, "0")); + }; + + const openNew = () => { + const due = new Date(); due.setDate(due.getDate() + 30); + setForm({ number: nextNumber(), clientId: "", projectId: "", date: new Date().toISOString().slice(0, 10), dueDate: due.toISOString().slice(0, 10), items: [{ id: generateId(), desc: "", qty: 1, price: 0 }], mwst: true, mwstRate: data.settings.mwstRate, notes: "Zahlbar innert 30 Tagen netto.", status: "entwurf" }); + setModal({ type: "invoice" }); + }; + + const editingId = modal?.id || null; + + const calcTotal = (items, mwst, rate, discountType, discountValue) => { + const sub = (items || []).reduce((s, i) => { + const line = i.qty * i.price; + const disc = (i.discount || 0) > 0 ? line * ((i.discount || 0) / 100) : 0; + return s + line - disc; + }, 0); + const globalDisc = discountType === "percent" ? sub * ((discountValue || 0) / 100) + : discountType === "amount" ? (discountValue || 0) : 0; + const subAfterDisc = sub - globalDisc; + const tax = mwst ? subAfterDisc * (rate / 100) : 0; + const total = roundCHF(subAfterDisc + tax); + return { sub, globalDisc, subAfterDisc, tax, total }; + }; + + const calcLineTotal = (item) => { + const line = (item.qty || 0) * (item.price || 0); + return line * (1 - ((item.discount || 0) / 100)); + }; + + // Offene Zeiteinträge + die bereits zu dieser Rechnung gehören (beim Bearbeiten) + const openEntriesForProject = (projectId) => { + if (!projectId) return []; + return data.timeEntries + .filter(e => e.projectId === projectId && (!e.invoiceId || e.invoiceId === editingId)) + .sort((a, b) => (a.date || "").localeCompare(b.date || "")); + }; + + const [sendModal, setSendModal] = useState(null); + const [newInvModal, setNewInvModal] = useState(false); + const [ni, setNi] = useState({ tab: "projekt", projectId: "", quoteId: "", mode: "teilrechnung", pct: 30, amt: 0, phaseId: "" }); + + useEffect(() => { + if (modal?.type === "newInvoice" && modal.quoteId) { + setNi({ tab: "offerte", quoteId: modal.quoteId, mode: "schluss", pct: 30, amt: 0 }); + setNewInvModal(true); + setModal(null); + } + }, [modal?.type, modal?.quoteId]); + + // ── Akonto-Planer ────────────────────────────────────────────── + const defaultStartDate = () => { + const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() + 1); + return d.toISOString().slice(0, 10); + }; + const emptyAp = { projectId: "", clientId: "", totalAmt: 0, mode: "interval", intervalMonths: 4, count: 4, startDate: defaultStartDate(), manualRows: [] }; + const [akontoModal, setAkontoModal] = useState(false); + const [ap, setAp] = useState(emptyAp); + + const apRows = (() => { + if (ap.mode === "interval") { + const start = new Date(ap.startDate || new Date()); + const perInv = ap.count > 0 ? Math.round((ap.totalAmt / ap.count) * 100) / 100 : 0; + return Array.from({ length: Math.max(1, Math.min(ap.count, 24)) }, (_, i) => { + const d = new Date(start); + d.setMonth(d.getMonth() + i * (ap.intervalMonths || 1)); + return { id: String(i), date: d.toISOString().slice(0, 10), amt: perInv }; + }); + } + return ap.manualRows; + })(); + + const generateSequentialNumbers = (count) => { + const fmt = data.settings.invoiceNumberFormat || "YYYY-NNN"; + const now = new Date(); + const yyyy = String(now.getFullYear()); const yy = yyyy.slice(2); + const escaped = fmt.replace(/[-/\^$*+?.()|[\]{}]/g, "\\$&").replace(/YYYY/g, yyyy).replace(/YY/g, yy).replace(/N+/, "(\\d+)"); + const rx = new RegExp("^" + escaped + "$"); + const nums = invoices.map(i => { const m = (i.number || "").match(rx); return m ? parseInt(m[1]) : null; }).filter(n => n !== null); + let nextSeq = nums.length ? Math.max(...nums) + 1 : 1; + const padLen = (fmt.match(/N+/) || ["NNN"])[0].length; + return Array.from({ length: count }, () => { + const n = fmt.replace(/YYYY/g, yyyy).replace(/YY/g, yy).replace(/N+/, String(nextSeq).padStart(padLen, "0")); + nextSeq++; + return n; + }); + }; + + const createAkontoInvoices = () => { + const rows = apRows.filter(r => r.date && r.amt > 0); + if (rows.length === 0) return; + const proj = data.projects.find(p => p.id === ap.projectId); + const numbers = generateSequentialNumbers(rows.length); + const newInvoices = rows.map((row, i) => { + const due = new Date(row.date); due.setDate(due.getDate() + 30); + const { sub, tax, total, subAfterDisc, globalDisc } = calcTotal( + [{ id: generateId(), desc: `Akontorechnung – ${proj?.name || ""}`, qty: 1, price: row.amt, discount: 0 }], + true, data.settings.mwstRate, "none", 0 + ); + return { + id: generateId(), number: numbers[i], date: row.date, + dueDate: due.toISOString().slice(0, 10), + clientId: ap.clientId || proj?.clientId || "", + projectId: ap.projectId, invoiceKind: "akonto", + items: [{ id: generateId(), desc: `Akontorechnung – ${proj?.name || ""}`, qty: 1, price: row.amt, discount: 0 }], + mwst: true, mwstRate: data.settings.mwstRate, + notes: "Zahlbar innert 30 Tagen netto.", + status: "entwurf", discountType: "none", discountValue: 0, + sub, tax, total, subAfterDisc, globalDisc, + createdAt: new Date().toISOString(), + }; + }); + update("invoices", [...invoices, ...newInvoices]); + setAkontoModal(false); + setAp(emptyAp); + }; + + const confirmNewInvoice = () => { + const todayStr = new Date().toISOString().slice(0, 10); + const due = new Date(); due.setDate(due.getDate() + 30); + const base = { + number: nextNumber(), date: todayStr, dueDate: due.toISOString().slice(0, 10), + mwst: true, mwstRate: data.settings.mwstRate, + notes: "Zahlbar innert 30 Tagen netto.", status: "entwurf", + discountType: "none", discountValue: 0, discountLabel: "Rabatt", + }; + + if (ni.tab === "frei") { + setForm({ ...base, clientId: "", projectId: "", entrySelections: {}, items: [{ id: generateId(), desc: "", qty: 1, price: 0, discount: 0 }] }); + } else if (ni.tab === "projekt") { + const proj = data.projects.find(p => p.id === ni.projectId); + if (!proj) return; + const bType = proj.billingType || proj.type; + const projBudget = proj.budget || proj.budgetAmount || 0; + if (ni.mode === "teilrechnung") { + const entries = openEntriesForProject(proj.id); + const entrySelections = {}; + entries.forEach(e => { entrySelections[e.id] = { selected: true, billedMinutes: e.minutes }; }); + const hours = Math.round(entries.reduce((s, e) => s + e.minutes, 0) / 60 * 100) / 100; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections, invoiceKind: "teilrechnung", + items: [{ id: generateId(), desc: `Teilrechnung – Architektur-/Grafikleistungen – ${proj.name}`, qty: hours, price: proj.hourlyRate || 0, discount: 0 }] }); + } else if (ni.mode === "teilrechnung-percent") { + const amt = projBudget * (ni.pct / 100); + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "teilrechnung", + items: [{ id: generateId(), desc: `Teilrechnung – ${proj.name} (${ni.pct.toFixed(1)}%)`, qty: 1, price: Math.round(amt * 100) / 100, discount: 0 }] }); + } else if (ni.mode === "teilrechnung-amount") { + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "teilrechnung", + items: [{ id: generateId(), desc: `Teilrechnung – ${proj.name}`, qty: 1, price: ni.amt, discount: 0 }] }); + } else if (ni.mode === "akonto-percent") { + const amt = projBudget * (ni.pct / 100); + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "akonto", + items: [{ id: generateId(), desc: `Akontorechnung – ${proj.name} (${ni.pct.toFixed(1)}%)`, qty: 1, price: Math.round(amt * 100) / 100, discount: 0 }] }); + } else if (ni.mode === "akonto-amount") { + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "akonto", + items: [{ id: generateId(), desc: `Akontorechnung – ${proj.name}`, qty: 1, price: ni.amt, discount: 0 }] }); + } else if (ni.mode === "akonto-stunden") { + const entries = openEntriesForProject(proj.id).filter(e => (e.date || "") <= todayStr); + const entrySelections = {}; + entries.forEach(e => { entrySelections[e.id] = { selected: true, billedMinutes: e.minutes }; }); + const hours = Math.round(entries.reduce((s, e) => s + e.minutes, 0) / 60 * 100) / 100; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections, invoiceKind: "akonto", + items: [{ id: generateId(), desc: `Akontorechnung – ${proj.name}`, qty: hours, price: proj.hourlyRate || 0, discount: 0 }] }); + } else if (ni.mode === "phase") { + const ph = (proj.phasesBudget || []).find(p => p.id === ni.phaseId); + const phInfo = SIA_PHASES.find(p => p.id === ni.phaseId); + const amt = Math.round((ph?.hours || 0) * (proj.hourlyRate || 0) * 100) / 100; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "teilrechnung", + items: [{ id: generateId(), desc: `Teilrechnung ${phInfo?.label || ni.phaseId} – ${proj.name}`, qty: 1, price: amt, discount: 0 }] }); + } else if (ni.mode === "akonto-phase") { + const ph = (proj.phasesBudget || []).find(p => p.id === ni.phaseId); + const phInfo = SIA_PHASES.find(p => p.id === ni.phaseId); + const amt = Math.round((ph?.hours || 0) * (proj.hourlyRate || 0) * 100) / 100; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "akonto", + items: [{ id: generateId(), desc: `Akontorechnung ${phInfo?.label || ni.phaseId} – ${proj.name}`, qty: 1, price: amt, discount: 0 }] }); + } else { + // schluss + if (bType === "stundensatz") { + const entries = openEntriesForProject(proj.id).filter(e => (e.date || "") <= todayStr); + const entrySelections = {}; + entries.forEach(e => { entrySelections[e.id] = { selected: true, billedMinutes: e.minutes }; }); + const hours = Math.round(entries.reduce((s, e) => s + e.minutes, 0) / 60 * 100) / 100; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections, invoiceKind: "schluss", + items: [{ id: generateId(), desc: `Schlussrechnung – ${proj.name}`, qty: hours, price: proj.hourlyRate || 0, discount: 0 }] }); + } else { + // Pauschal-Schluss: Gesamthonorar ausweisen, bisherige Akontozahlungen abziehen + const akontoInvs = invoices.filter(i => i.projectId === proj.id && i.invoiceKind === "akonto" && i.status !== "entwurf"); + const akontoTotal = akontoInvs.reduce((s, i) => s + (i.subAfterDisc ?? i.sub ?? 0), 0); + const schlussItems = [ + { id: generateId(), desc: `Pauschalhonorar – ${proj.name}`, qty: 1, price: projBudget, discount: 0 }, + ...(akontoTotal > 0 ? [{ id: generateId(), desc: `Abzgl. geleistete Akontozahlungen (${akontoInvs.map(i => i.number).filter(Boolean).join(", ")})`, qty: 1, price: -akontoTotal, discount: 0 }] : []), + ]; + const notes = akontoTotal > 0 + ? `Schlussrechnung gemäss Honorarvereinbarung.\nBisherige Akontozahlungen:\n${akontoInvs.map(i => ` – ${i.number}: CHF ${(i.subAfterDisc ?? i.sub ?? 0).toFixed(2)}`).join("\n")}\n\nZahlbar innert 30 Tagen netto.` + : "Zahlbar innert 30 Tagen netto."; + setForm({ ...base, clientId: proj.clientId || "", projectId: proj.id, entrySelections: {}, invoiceKind: "schluss", items: schlussItems, notes }); + } + } + } else if (ni.tab === "offerte") { + const q = (data.quotes || []).find(x => x.id === ni.quoteId); + if (!q) return; + const existing = (invoices).filter(i => i.quoteId === q.id); + const totalInvoiced = existing.reduce((s, i) => s + (i.sub || 0), 0); + const remaining = Math.max(0, (q.sub || 0) - totalInvoiced); + let items = [], invoiceKind = "akonto"; + if (ni.mode === "schluss") { + invoiceKind = "schluss"; + const akontoInvs = existing.filter(i => i.invoiceKind === "akonto" && i.status !== "entwurf"); + const akontoTotal = akontoInvs.reduce((s, i) => s + (i.subAfterDisc ?? i.sub ?? 0), 0); + items = [ + { id: generateId(), desc: `Honorar gemäss Offerte ${q.number}`, qty: 1, price: q.sub || 0, discount: 0 }, + ...(akontoTotal > 0 ? [{ id: generateId(), desc: `Abzgl. geleistete Akontozahlungen (${akontoInvs.map(i => i.number).filter(Boolean).join(", ")})`, qty: 1, price: -akontoTotal, discount: 0 }] : []), + ]; + } else if (ni.mode === "teilrechnung-percent") { + invoiceKind = "teilrechnung"; + const amt = (q.sub || 0) * (ni.pct / 100); + items = [{ id: generateId(), desc: `Teilrechnung gemäss Offerte ${q.number} (${ni.pct.toFixed(1)}%)`, qty: 1, price: Math.round(amt * 100) / 100, discount: 0 }]; + } else if (ni.mode === "teilrechnung-amount") { + invoiceKind = "teilrechnung"; + items = [{ id: generateId(), desc: `Teilrechnung gemäss Offerte ${q.number}`, qty: 1, price: ni.amt, discount: 0 }]; + } else if (ni.mode === "akonto-percent") { + const amt = (q.sub || 0) * (ni.pct / 100); + items = [{ id: generateId(), desc: `Akontorechnung gemäss Offerte ${q.number} (${ni.pct.toFixed(1)}%)`, qty: 1, price: Math.round(amt * 100) / 100, discount: 0 }]; + } else { + items = [{ id: generateId(), desc: `Akontorechnung gemäss Offerte ${q.number}`, qty: 1, price: ni.amt, discount: 0 }]; + } + let notes = `Gemäss Offerte ${q.number}. Zahlbar innert 30 Tagen netto.`; + if (invoiceKind === "schluss" && existing.filter(i => i.invoiceKind === "akonto").length > 0) { + const akontoInvs = existing.filter(i => i.invoiceKind === "akonto" && i.status !== "entwurf"); + notes = `Schlussrechnung gemäss Offerte ${q.number}.\nBisherige Akontozahlungen:\n${akontoInvs.map(i => ` – ${i.number}: CHF ${(i.subAfterDisc ?? i.sub ?? 0).toFixed(2)}`).join("\n")}\n\nZahlbar innert 30 Tagen netto.`; + } + setForm({ ...base, clientId: q.clientId || "", projectId: q.projectId || "", quoteId: q.id, entrySelections: {}, invoiceKind, items, notes }); + } + setNewInvModal(false); + setModal({ type: "invoice" }); + }; + + const save = (statusOverride) => { + if (!form.clientId) { + alert("Bitte einen Kunden auswählen."); + return; + } + const { sub, globalDisc, subAfterDisc, tax, total } = calcTotal(form.items, form.mwst, form.mwstRate ?? data.settings.mwstRate, form.discountType, form.discountValue); + const invoiceId = editingId || generateId(); + const status = statusOverride || form.status || "entwurf"; + const inv = { ...form, id: invoiceId, sub, globalDisc, subAfterDisc, tax, total, mwstRate: form.mwstRate ?? data.settings.mwstRate, status }; + delete inv.entrySelections; + + const selectedIds = Object.entries(form.entrySelections || {}) + .filter(([_, sel]) => sel.selected) + .map(([id]) => id); + + const updatedEntries = data.timeEntries.map(e => { + if (e.invoiceId === editingId) { + return selectedIds.includes(e.id) ? { ...e, invoiceId } : { ...e, invoiceId: null }; + } + if (selectedIds.includes(e.id)) return { ...e, invoiceId }; + return e; + }); + + const updatedInvoices = editingId + ? invoices.map(i => i.id === editingId ? { ...i, ...inv } : i) + : [...invoices, { ...inv, createdAt: new Date().toISOString() }]; + + saveAll({ ...data, invoices: updatedInvoices, timeEntries: updatedEntries }); + setModal(null); + if (!editingId && !statusOverride) setSendModal(inv); + }; + + const openEdit = (inv) => { + const linked = data.timeEntries.filter(e => e.invoiceId === inv.id); + const entrySelections = {}; + linked.forEach(e => { entrySelections[e.id] = { selected: true, billedMinutes: e.minutes }; }); + setForm({ + discountType: "none", discountValue: 0, discountLabel: "Rabatt", + ...inv, + items: (inv.items || []).map(it => ({ discount: 0, ...it })), + entrySelections, + }); + setModal({ type: "invoice", id: inv.id }); + }; + + const del = async (id) => { + if (!(await askConfirm("Rechnung löschen? Zugehörige Zeiteinträge werden wieder als offen markiert."))) return; + const updatedEntries = data.timeEntries.map(e => e.invoiceId === id ? { ...e, invoiceId: null } : e); + saveAll({ ...data, invoices: invoices.filter(i => i.id !== id), timeEntries: updatedEntries }); + }; + const setStatus = (id, status) => update("invoices", invoices.map(i => i.id === id ? { ...i, status } : i)); + + const addItem = () => setForm({ ...form, items: [...form.items, { id: generateId(), desc: "", qty: 1, price: 0, discount: 0 }] }); + const removeItem = (idx) => setForm({ ...form, items: form.items.filter((_, i) => i !== idx) }); + const updateItem = (idx, key, val) => setForm({ ...form, items: form.items.map((it, i) => i === idx ? { ...it, [key]: val } : it) }); + const [openDropdown, setOpenDropdown] = useState(null); + const [dropdownData, setDropdownData] = useState(null); + const [mahnModal, setMahnModal] = useState(null); + const [mahnMode, setMahnMode] = useState("new"); + const [mahnSentDate, setMahnSentDate] = useState(new Date().toISOString().slice(0, 10)); + const { askConfirm, ConfirmModalEl } = useConfirm(); + + const openMahnung = (inv) => { + setMahnMode((inv.reminders || []).length === 0 ? "new" : "reprint-0"); + setMahnSentDate(new Date().toISOString().slice(0, 10)); + setMahnModal({ inv }); + }; + + const toggleEntrySelection = (entryId, entry) => { + const current = form.entrySelections?.[entryId]; + const newSelections = { ...form.entrySelections }; + if (current?.selected) { + newSelections[entryId] = { ...current, selected: false }; + } else { + newSelections[entryId] = { selected: true, billedMinutes: current?.billedMinutes ?? entry.minutes }; + } + setForm(f => ({ ...f, entrySelections: newSelections })); + }; + + const updateBilledMinutes = (entryId, minutes) => { + const newSelections = { ...form.entrySelections }; + newSelections[entryId] = { ...(newSelections[entryId] || { selected: true }), billedMinutes: Math.max(0, minutes) }; + setForm(f => ({ ...f, entrySelections: newSelections })); + }; + + const prefillFromProject = (projectId) => { + if (!projectId) { setForm(f => ({ ...f, projectId: "", entrySelections: {} })); return; } + const proj = data.projects.find(p => p.id === projectId); + if (!proj) return; + const bType = proj.billingType || proj.type; + const openEntries = openEntriesForProject(projectId); + if (bType === "stundensatz") { + const entrySelections = {}; + openEntries.forEach(e => { entrySelections[e.id] = { selected: true, billedMinutes: e.minutes }; }); + const totalMins = openEntries.reduce((s, e) => s + e.minutes, 0); + const hours = Math.round(totalMins / 60 * 100) / 100; + setForm(f => ({ + ...f, projectId, clientId: proj.clientId || f.clientId, entrySelections, + items: hours > 0 + ? [{ id: generateId(), desc: `Architektur-/Grafikleistungen – ${proj.name}`, qty: hours, price: proj.hourlyRate, discount: 0 }] + : [{ id: generateId(), desc: "", qty: 1, price: 0, discount: 0 }] + })); + } else if (bType === "pauschal") { + setForm(f => ({ ...f, projectId, clientId: proj.clientId || f.clientId, entrySelections: {}, + items: [{ id: generateId(), desc: `Pauschalhonorar – ${proj.name}`, qty: 1, price: proj.budget, discount: 0 }] })); + } else { + setForm(f => ({ ...f, projectId, clientId: proj.clientId || f.clientId, entrySelections: {} })); + } + }; + + useEffect(() => { + if (!openDropdown) return; + const close = () => { setOpenDropdown(null); setDropdownData(null); }; + document.addEventListener("click", close); + return () => document.removeEventListener("click", close); + }, [openDropdown]); + + useEffect(() => { + if (!form.projectId) return; + const proj = data.projects.find(p => p.id === form.projectId); + if (!proj || (proj.billingType || proj.type) !== "stundensatz") return; + const totalBilledMins = Object.values(form.entrySelections || {}) + .filter(s => s.selected) + .reduce((sum, s) => sum + (s.billedMinutes || 0), 0); + const hours = Math.round(totalBilledMins / 60 * 100) / 100; + setForm(f => { + const existing = f.items[0] || {}; + if (existing.qty === hours && existing.price === proj.hourlyRate) return f; + const newItems = [...f.items]; + newItems[0] = { id: existing.id || generateId(), desc: existing.desc || `Architektur-/Grafikleistungen – ${proj.name}`, qty: hours, price: proj.hourlyRate, discount: existing.discount || 0 }; + return { ...f, items: newItems }; + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [form.entrySelections, form.projectId]); + + const { sub, globalDisc, subAfterDisc, tax, total } = calcTotal(form.items, form.mwst, form.mwstRate ?? data.settings.mwstRate, form.discountType, form.discountValue); + + // Verfügbare Jahre aus Rechnungen sammeln + const availableYears = Array.from(new Set(invoices.map(i => (i.date || "").slice(0, 4)).filter(Boolean))).sort().reverse(); + + // Filter-Matching + const matchesFilter = (inv) => { + if (filter.status && inv.status !== filter.status) return false; + if (filter.clientId && inv.clientId !== filter.clientId) return false; + if (filter.year && !(inv.date || "").startsWith(filter.year)) return false; + if (filter.search) { + const q = filter.search.toLowerCase(); + const client = clients.find(c => c.id === inv.clientId); + const haystack = [ + inv.number, + client?.name, + client?.company, + inv.notes, + ...(inv.items || []).map(it => it.desc) + ].filter(Boolean).join(" ").toLowerCase(); + if (!haystack.includes(q)) return false; + } + return true; + }; + + const filtered = [...invoices].filter(matchesFilter).sort((a, b) => { + let va, vb; + if (sort.col === "number") { va = a.number || ""; vb = b.number || ""; } + else if (sort.col === "date") { va = a.date || ""; vb = b.date || ""; } + else if (sort.col === "dueDate") { va = a.dueDate || ""; vb = b.dueDate || ""; } + else if (sort.col === "client") { va = clients.find(c => c.id === a.clientId)?.name || ""; vb = clients.find(c => c.id === b.clientId)?.name || ""; } + else if (sort.col === "total") { va = a.total || 0; vb = b.total || 0; } + else if (sort.col === "status") { va = a.status || ""; vb = b.status || ""; } + else { va = a.date || ""; vb = b.date || ""; } + return typeof va === "number" ? (va - vb) * sort.dir : va.localeCompare(vb) * sort.dir; + }); + const filteredTotal = filtered.reduce((s, i) => s + (i.total || 0), 0); + const filteredOpen = filtered.filter(i => i.status === "gesendet" || i.status === "überfällig").reduce((s, i) => s + (i.total || 0), 0); + const filteredOverdue = filtered.filter(i => i.status === "überfällig").reduce((s, i) => s + (i.total || 0), 0); + const filteredPaid = filtered.filter(i => i.status === "bezahlt").reduce((s, i) => s + (i.total || 0), 0); + + // Unverrechnete Stunden über alle aktiven Stundensatz-Projekte (global) + const unbilledProjects = data.projects + .filter(p => (p.billingType || p.type) === "stundensatz" && p.status === "aktiv") + .map(p => { + const mins = data.timeEntries.filter(e => e.projectId === p.id && !e.invoiceId).reduce((s, e) => s + (e.minutes || 0), 0); + const amount = (mins / 60) * (p.hourlyRate || 0); + return { ...p, mins, amount }; + }) + .filter(p => p.mins > 0) + .sort((a, b) => b.mins - a.mins); + const totalUnbilledMins = unbilledProjects.reduce((s, p) => s + p.mins, 0); + const totalUnbilledAmount = unbilledProjects.reduce((s, p) => s + p.amount, 0); + + // Gruppieren + const groupedInvoices = (() => { + if (groupBy === "date") { + const months = {}; + filtered.forEach(inv => { + const key = (inv.date || "").slice(0, 7); + if (!months[key]) months[key] = []; + months[key].push(inv); + }); + return Object.entries(months).sort((a, b) => b[0].localeCompare(a[0])).map(([key, items]) => ({ + key, label: key ? new Date(key + "-01").toLocaleDateString("de-CH", { month: "long", year: "numeric" }) : "Ohne Datum", items, + })); + } + if (groupBy === "client") { + const clients = {}; + filtered.forEach(inv => { + const cl = clients.find(c => c.id === inv.clientId); + const key = inv.clientId || "__none__"; + const label = cl?.name || "Kein Kunde"; + if (!clients[key]) clients[key] = { label, items: [] }; + clients[key].items.push(inv); + }); + return Object.entries(clients).sort((a, b) => a[1].label.localeCompare(b[1].label)).map(([key, val]) => ({ key, label: val.label, items: val.items })); + } + if (groupBy === "status") { + const statuses = {}; + filtered.forEach(inv => { + const key = inv.status || "unbekannt"; + if (!statuses[key]) statuses[key] = []; + statuses[key].push(inv); + }); + return Object.entries(statuses).sort((a, b) => a[0].localeCompare(b[0])).map(([key, items]) => ({ key, label: key.charAt(0).toUpperCase() + key.slice(1), items })); + } + return [{ key: "all", label: "", items: filtered }]; + })(); + + return ( +
+ {ConfirmModalEl} +
+ +
+
+ + +
+ } /> + + {/* KPI-Cards */} +
+
+
BEZAHLT
+
{formatCHF(filteredPaid)}
+
{filtered.filter(i => i.status === "bezahlt").length} Rechnung(en)
+
+
0 ? "3px solid #8a1a1a" : "3px solid #7a6a00" }}> +
AUSSTEHEND
+
0 ? "#8a1a1a" : "#7a6a00" }}>{formatCHF(filteredOpen)}
+
+ {filteredOverdue > 0 ? davon {formatCHF(filteredOverdue)} überfällig : `${filtered.filter(i => i.status === "gesendet" || i.status === "überfällig").length} Rechnung(en)`} +
+
+
0 ? "3px solid #b5621e" : "3px solid #aaa" }}> +
UNVERRECHNETE STUNDEN
+
0 ? "#b5621e" : "#aaa" }}>{formatHours(totalUnbilledMins)}
+
{totalUnbilledAmount > 0 ? `≈ ${formatCHF(totalUnbilledAmount)}` : "Alle verrechnet ✓"}
+
+
+
PROJEKTE MIT PENDENZEN
+ {unbilledProjects.length === 0 ? ( +
Keine offenen Stunden
+ ) : ( + <> +
{unbilledProjects.length} Projekt{unbilledProjects.length !== 1 ? "e" : ""}
+ {unbilledProjects.slice(0, 4).map(p => ( +
+
+ {p.name} + {formatHours(p.mins)} +
+
+
+
+
+ ))} + + )} +
+
+ +
+ setFilter({ ...filter, search: e.target.value })} style={{ minWidth: 220 }} /> + + + + {(filter.status || filter.clientId || filter.year || filter.search) && ( + + )} +
+ +
+ GRUPPIEREN: + {[{ id: "none", label: "Keine" }, { id: "date", label: "Monat" }, { id: "client", label: "Kunde" }, { id: "status", label: "Status" }].map(g => ( + + ))} +
+
{filtered.length} {filtered.length === 1 ? "Rechnung" : "Rechnungen"} · {formatCHF(filteredTotal)}
+ {filteredOpen > 0 &&
davon offen: {formatCHF(filteredOpen)}
} +
+
+ +
+ + Nr.KundeDatumFälligBetragStatus + + {filtered.length === 0 && } + {groupedInvoices.map(group => ( + + {groupBy !== "none" && group.label && ( + + + + )} + {group.items.map(inv => { + const client = clients.find(c => c.id === inv.clientId); + const kindLabel = inv.invoiceKind === "akonto" ? "Akonto" : inv.invoiceKind === "teilrechnung" ? "Teilrechnung" : inv.invoiceKind === "schluss" ? "Schluss" : inv.invoiceKind === "voll" ? "Vollrechnung" : "—"; + const kindColor = inv.invoiceKind === "akonto" ? "#7a6a00" : inv.invoiceKind === "teilrechnung" ? "#2d5a8e" : inv.invoiceKind === "schluss" ? "#1a4e8a" : "transparent"; + return ( + + + + + + + + + + + ); + })} + + ))} + +
Art
{invoices.length === 0 ? "Noch keine Rechnungen" : "Keine Treffer"}
+ {group.label} + + {group.items.length} · {formatCHF(group.items.reduce((s, i) => s + (i.total || 0), 0))} + +
+ {inv.number} + {(inv.reminders || []).length > 0 && ( +
+ {(inv.reminders || []).length === 1 ? "Erinnerung" : `${(inv.reminders || []).length}× Mahnung`} · {formatDate((inv.reminders || []).at(-1)?.date)} +
+ )} +
{client?.name || "—"} + {inv.invoiceKind && inv.invoiceKind !== "voll" + ? {kindLabel} + : } + {formatDate(inv.date)}{formatDate(inv.dueDate)}{formatCHF(inv.total)} + setStatus(inv.id, v)} /> + + {inv.status === "überfällig" && ( + + )} +
+ + +
+ + +
+
+ + {openDropdown && dropdownData && ( +
e.stopPropagation()} + > + {[ + { label: "Rechnung + QR", type: "invoice+qr" }, + { label: "Nur Rechnung", type: "invoice" }, + { label: "Nur QR", type: "qrbill" }, + ].map(opt => ( + + ))} +
+ )} + + {mahnModal && ( + setMahnModal(null)} + mahnMode={mahnMode} + setMahnMode={setMahnMode} + mahnSentDate={mahnSentDate} + setMahnSentDate={setMahnSentDate} + /> + )} + + {modal?.type === "invoice" && ( + setModal(null)} onSave={() => save()} wide> +
+ setForm({ ...form, number: e.target.value })} /> + setForm({ ...form, date: e.target.value })} /> + setForm({ ...form, dueDate: e.target.value })} /> +
+
+ + + + {form.clientId && (() => { + const cl = clients.find(c => c.id === form.clientId); + const contacts = cl?.contacts || []; + if (contacts.length === 0) return null; + return ( + + + + ); + })()} + + + +
+ + {/* Offene Zeiteinträge des Projekts */} + {(() => { + if (!form.projectId) return null; + const proj = data.projects.find(p => p.id === form.projectId); + if (!proj) return null; + const bType = proj.billingType || proj.type; + if (bType !== "stundensatz") return null; + const openEntries = openEntriesForProject(form.projectId); + if (openEntries.length === 0) return ( +
+ Keine offenen Zeiteinträge für dieses Projekt. +
+ ); + const totalErfasst = openEntries.reduce((s, e) => s + e.minutes, 0); + const totalVerrechnet = Object.entries(form.entrySelections || {}) + .filter(([id, s]) => s.selected && openEntries.some(e => e.id === id)) + .reduce((s, [_, sel]) => s + (sel.billedMinutes || 0), 0); + const diff = totalErfasst - totalVerrechnet; + const allSelected = openEntries.every(e => form.entrySelections?.[e.id]?.selected); + const toggleAll = () => { + const newSel = { ...form.entrySelections }; + if (allSelected) { + openEntries.forEach(e => { newSel[e.id] = { ...newSel[e.id], selected: false }; }); + } else { + openEntries.forEach(e => { newSel[e.id] = { selected: true, billedMinutes: newSel[e.id]?.billedMinutes ?? e.minutes }; }); + } + setForm(f => ({ ...f, entrySelections: newSel })); + }; + return ( +
+
+ +
+ Erfasst {formatHours(totalErfasst)} · Verrechnet {formatHours(totalVerrechnet)} + {diff > 0 && Nicht verrechnet: {formatHours(diff)}} +
+
+
+ + + + + + + + + + + + + {openEntries.map(e => { + const sel = form.entrySelections?.[e.id]; + const selected = sel?.selected; + const billedMinutes = selected ? (sel?.billedMinutes ?? e.minutes) : 0; + const hoursBilled = Math.round((billedMinutes / 60) * 100) / 100; + const phase = SIA_PHASES.find(p => p.id === e.phaseId); + const pos = (proj?.positions || []).find(p => p.code === e.positionId); + return ( + + + + + + + + + ); + })} + +
+ + DatumPhaseTätigkeitErfasstVerrechnet
+ toggleEntrySelection(e.id, e)} style={{ width: "auto", cursor: "pointer" }} /> + {formatDate(e.date)} + {phase?.id || "—"} + {pos && {pos.code}} + {e.description || "—"}{formatHours(e.minutes)} + {selected ? ( + updateBilledMinutes(e.id, Math.round(+ev.target.value * 60))} + style={{ width: 70, height: 26, fontSize: 11, textAlign: "right", padding: "2px 6px" }} /> + ) : } + {selected && h} +
+
+
+ ); + })()} + +
+
+ + +
+
+
Beschreibung
+
Menge
+
Preis
+
Rabatt %
+
Total
+
+
+ {form.items.map((item, idx) => { + const lineTotal = calcLineTotal(item); + const hasDiscount = (item.discount || 0) > 0; + return ( +
+ updateItem(idx, "desc", e.target.value)} style={{ flex: 3 }} /> + updateItem(idx, "qty", +e.target.value)} style={{ width: 70, textAlign: "right" }} /> + updateItem(idx, "price", +e.target.value)} style={{ width: 90, textAlign: "right" }} /> + updateItem(idx, "discount", +e.target.value)} style={{ width: 60, textAlign: "right", background: hasDiscount ? "#fff8ed" : undefined }} /> +
+ {hasDiscount &&
{formatCHF(item.qty * item.price)}
} +
{formatCHF(lineTotal)}
+
+ +
+ ); + })} +
+ + {/* Gesamt-Rabatt */} +
+
+ + + {form.discountType && form.discountType !== "none" && ( + <> + setForm({ ...form, discountValue: +e.target.value })} style={{ width: 90, textAlign: "right" }} /> + setForm({ ...form, discountLabel: e.target.value })} style={{ flex: 1, minWidth: 180 }} /> + + )} +
+
+ +
+
+ + {form.mwst && ( +
+ setForm({ ...form, mwstRate: +e.target.value })} style={{ width: 60, fontSize: 12, height: 28 }} /> + % +
+ )} +
+
+
Zwischentotal {formatCHF(sub)}
+ {globalDisc > 0 &&
{form.discountLabel || "Rabatt"} −{formatCHF(globalDisc)}
} + {globalDisc > 0 &&
Nach Rabatt {formatCHF(subAfterDisc)}
} + {form.mwst &&
MWST {formatCHF(tax)}
} +
Total {formatCHF(total)}
+
+
+ +