From 7be0d691cc2a9b914e53e33ce483f99476dc57dc Mon Sep 17 00:00:00 2001 From: Karn-x7 Date: Sun, 12 Jan 2025 01:25:48 +0530 Subject: [PATCH 1/2] added customizer/compressor --- frontend/.prettierrc | 12 +- frontend/index.html | 1 - frontend/package-lock.json | 776 ++++++++++++++++-- frontend/package.json | 7 +- frontend/postcss.config.js | 6 +- frontend/src-tauri/Cargo.lock | 2 +- frontend/src-tauri/Cargo.toml | 2 +- frontend/src-tauri/tauri.conf.json | 12 +- frontend/src/App.css | 56 +- .../src/components/AITagging/AIgallery.tsx | 15 +- frontend/src/components/Album/AlbumList.tsx | 2 +- .../Album/ImageManagementDialog.tsx | 94 ++- .../LoadingScreen/LoadingScreen.tsx | 32 +- frontend/src/components/Media/MediaCard.tsx | 35 +- frontend/src/components/Media/MediaView.tsx | 82 +- .../src/components/Media/SortningControls.tsx | 2 +- .../components/Navigation/Navbar/Navbar.tsx | 65 +- .../Navigation/Sidebar/CustomizationPopup.tsx | 212 +++++ .../Navigation/Sidebar/ImageCompressor.tsx | 269 ++++++ .../components/Navigation/Sidebar/Sidebar.tsx | 223 +++-- .../components/Navigation/Sidebar/styles.ts | 63 ++ frontend/src/components/ui/button.tsx | 16 +- frontend/src/pages/Setupscreen/Setup.tsx | 5 +- frontend/tailwind.config.cjs | 70 +- frontend/tailwind.config.js | 176 ++-- 25 files changed, 1812 insertions(+), 423 deletions(-) create mode 100644 frontend/src/components/Navigation/Sidebar/CustomizationPopup.tsx create mode 100644 frontend/src/components/Navigation/Sidebar/ImageCompressor.tsx create mode 100644 frontend/src/components/Navigation/Sidebar/styles.ts diff --git a/frontend/.prettierrc b/frontend/.prettierrc index 59b6c78b..2bb6a340 100644 --- a/frontend/.prettierrc +++ b/frontend/.prettierrc @@ -1,7 +1,7 @@ { - "semi": true, - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "all", - "plugins": ["prettier-plugin-tailwindcss"] - } \ No newline at end of file + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all", + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/frontend/index.html b/frontend/index.html index bf3975be..ff93803b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,7 +5,6 @@ Tauri + React + Typescript - diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 252560ce..4390ad69 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,16 +17,19 @@ "@tauri-apps/plugin-dialog": "^2.0.0-beta.5", "@tauri-apps/plugin-fs": "^2.0.0-beta.3", "@tauri-apps/plugin-shell": "^2.0.0-beta.4", - "axios": "^1.7.2", + "axios": "^1.7.9", + "browser-image-compression": "^2.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "ldrs": "^1.0.2", "lucide-react": "^0.400.0", + "openai": "^4.77.3", "react": "^18.2.0", "react-colorful": "^5.6.1", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-easy-crop": "^5.2.0", "react-icons": "^5.4.0", "react-router-dom": "^6.24.1", "tailwind-merge": "^2.3.0", @@ -37,6 +40,8 @@ "@types/node": "^20.14.9", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", @@ -3875,12 +3880,21 @@ "version": "20.16.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz", "integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==", - "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -3922,37 +3936,147 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", + "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/type-utils": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { @@ -3960,6 +4084,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3987,30 +4112,131 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", + "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@typescript-eslint/scope-manager": { @@ -4031,30 +4257,154 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", + "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/utils": "8.19.1", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^2.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@typescript-eslint/types": { @@ -4212,6 +4562,18 @@ "vite": "^4.2.0 || ^5.0.0" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -4233,6 +4595,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -4561,9 +4935,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -4703,6 +5077,15 @@ "node": ">=8" } }, + "node_modules/browser-image-compression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/browser-image-compression/-/browser-image-compression-2.0.2.tgz", + "integrity": "sha512-pBLlQyUf6yB8SmmngrcOw3EoS4RpQ1BcylI3T9Yqn7+4nrQTXJD4sJDe5ODnJdrvNMaio5OicFo75rDyJD2Ucw==", + "license": "MIT", + "dependencies": { + "uzip": "0.20201231.0" + } + }, "node_modules/browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", @@ -5493,6 +5876,110 @@ "eslint": "^8.0.0" } }, + "node_modules/eslint-config-react-app/node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-react-app/node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-react-app/node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-react-app/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -5998,6 +6485,15 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6171,6 +6667,25 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -6482,6 +6997,15 @@ "react-is": "^16.7.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -7275,7 +7799,6 @@ "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/mz": { @@ -7317,7 +7840,47 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } }, "node_modules/node-releases": { "version": "2.0.18", @@ -7345,6 +7908,12 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==", + "license": "BSD-3-Clause" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7474,6 +8043,47 @@ "wrappy": "1" } }, + "node_modules/openai": { + "version": "4.77.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.77.3.tgz", + "integrity": "sha512-wLDy4+KWHz31HRFMW2+9KQuVuT2QWhs0z94w1Gm1h2Ut9vIHr9/rHZggbykZEfyiaJRVgw8ZS9K6AylDWzvPYw==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.70", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.70.tgz", + "integrity": "sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8031,6 +8641,20 @@ "react": "^18.3.1" } }, + "node_modules/react-easy-crop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-5.2.0.tgz", + "integrity": "sha512-gjb7jN+WnwfgpbNUI2jSwyoIxF1sJ0PVSNVgEysAgF1rj8AqR75fqmdvqZ6PFVgEX3rT1G4HJELesiQXr2ZvAg==", + "license": "MIT", + "dependencies": { + "normalize-wheel": "^1.0.1", + "tslib": "^2.0.1" + }, + "peerDependencies": { + "react": ">=16.4.0", + "react-dom": ">=16.4.0" + } + }, "node_modules/react-icons": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz", @@ -8965,6 +9589,25 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -9124,6 +9767,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9151,7 +9795,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -9283,6 +9926,12 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uzip": { + "version": "0.20201231.0", + "resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz", + "integrity": "sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==", + "license": "MIT" + }, "node_modules/vite": { "version": "5.4.8", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", @@ -9373,6 +10022,31 @@ "fsevents": "~2.3.2" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index a6af0937..2931c932 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,16 +24,19 @@ "@tauri-apps/plugin-dialog": "^2.0.0-beta.5", "@tauri-apps/plugin-fs": "^2.0.0-beta.3", "@tauri-apps/plugin-shell": "^2.0.0-beta.4", - "axios": "^1.7.2", + "axios": "^1.7.9", + "browser-image-compression": "^2.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "ldrs": "^1.0.2", "lucide-react": "^0.400.0", + "openai": "^4.77.3", "react": "^18.2.0", "react-colorful": "^5.6.1", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-easy-crop": "^5.2.0", "react-icons": "^5.4.0", "react-router-dom": "^6.24.1", "tailwind-merge": "^2.3.0", @@ -44,6 +47,8 @@ "@types/node": "^20.14.9", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 0486115b..8e53f9d1 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -1,7 +1,7 @@ -const postcssConfig = { +const postcssConfig = { plugins: { tailwindcss: {}, autoprefixer: {}, }, -} -export default postcssConfig \ No newline at end of file +}; +export default postcssConfig; diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock index 768ad00c..7f34ef97 100644 --- a/frontend/src-tauri/Cargo.lock +++ b/frontend/src-tauri/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Pictopy" diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index 09b38712..b58f82a6 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" tauri-build = { version = "2.0.0-beta", features = [] } [dependencies] -tauri = { version = "2.0.0-beta", features = [ "protocol-asset"] } +tauri = { version = "2.0.0-beta", features = ["protocol-asset"] } walkdir = "2.3" serde_json = "1" anyhow = "1.0" diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index 6eae9883..c9aa1bd0 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -23,11 +23,9 @@ "plugins": { "updater": { "active": true, - "endpoints": [ - "https://server.com//api/v1/tauri/update" - ], + "endpoints": ["https://server.com//api/v1/tauri/update"], "dialog": true, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEI3ODc5QjNDMERGMzlCMUEKUldRYW0vTU5QSnVIdHplYktOV3hKKzdmSGd6ZVN3eTg4Q2ExbmVTbk4yN0pMWjZLYXl1M1ZzN3AK" + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEI3QzQyQUVCMEZBQ0FEQQpSV1RheXZxd3JrSjhDMk9ENllaUm1TcGVSeHdkbTQ4d0QrUjBXVEE0a21LL2RoRkZ2MXB6K1BuRQo= " } }, "app": { @@ -43,12 +41,10 @@ ], "security": { "assetProtocol": { - "scope": [ - "**" - ], + "scope": ["**"], "enable": true }, "csp": null } } -} \ No newline at end of file +} diff --git a/frontend/src/App.css b/frontend/src/App.css index a146e422..2653e16a 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -2,10 +2,10 @@ @tailwind components; @tailwind utilities; - @layer base { - :root { - --background: 0 0% 100%; - --foreground: 0 0% 0%; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 0%; --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; @@ -32,39 +32,38 @@ --input: 214.3 31.8% 91.4%; --ring: 222.2 84% 4.9%; - --radius: 0.5rem; - } + --radius: 0.5rem; + } - .dark { - --background: 221, 39%, 11%; - --foreground: 0 0% 100%; + .dark { + --background: 221, 39%, 11%; + --foreground: 0 0% 100%; - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 212.7 26.8% 83.9%; - } - + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } } @layer base { @@ -75,4 +74,3 @@ @apply bg-background text-foreground; } } - diff --git a/frontend/src/components/AITagging/AIgallery.tsx b/frontend/src/components/AITagging/AIgallery.tsx index be350197..27c9f3c6 100644 --- a/frontend/src/components/AITagging/AIgallery.tsx +++ b/frontend/src/components/AITagging/AIgallery.tsx @@ -8,11 +8,13 @@ import PaginationControls from '../ui/PaginationControls'; import { usePictoQuery } from '@/hooks/useQueryExtensio'; import { getAllImageObjects } from '../../../api/api-functions/images'; -export default function AIGallery({ - title, - type, -}: MediaGalleryProps) { // Removed folderPath - const { successData: mediaItems = [], isLoading: loading, isError } = usePictoQuery({ +export default function AIGallery({ title, type }: MediaGalleryProps) { + // Removed folderPath + const { + successData: mediaItems = [], + isLoading: loading, + isError, + } = usePictoQuery({ queryFn: getAllImageObjects, queryKey: ['ai-tagging-images', 'ai'], }); @@ -29,7 +31,7 @@ export default function AIGallery({ const filteredMediaItems = useMemo(() => { return filterTag ? mediaItems.filter((mediaItem: any) => - mediaItem.tags?.includes(filterTag) + mediaItem.tags?.includes(filterTag), ) : mediaItems; }, [filterTag, mediaItems]); @@ -111,4 +113,3 @@ export default function AIGallery({ ); } - diff --git a/frontend/src/components/Album/AlbumList.tsx b/frontend/src/components/Album/AlbumList.tsx index 8bae74a7..3557870c 100644 --- a/frontend/src/components/Album/AlbumList.tsx +++ b/frontend/src/components/Album/AlbumList.tsx @@ -5,7 +5,7 @@ import AlbumCard from './AlbumCard'; const AlbumList: React.FC = ({ albums, - + onAlbumClick, onEditAlbum, onDeleteAlbum, diff --git a/frontend/src/components/Album/ImageManagementDialog.tsx b/frontend/src/components/Album/ImageManagementDialog.tsx index 41832094..8df38f94 100644 --- a/frontend/src/components/Album/ImageManagementDialog.tsx +++ b/frontend/src/components/Album/ImageManagementDialog.tsx @@ -1,5 +1,9 @@ import React, { useState, useEffect } from 'react'; -import { useViewAlbum, useRemoveImageFromAlbum } from '../../hooks/AlbumService'; +import { + useViewAlbum, + useRemoveImageFromAlbum, +} from '../../services/AlbumService'; + import { Button } from '@/components/ui/button'; import { Dialog, @@ -19,6 +23,42 @@ interface ImageManagementDialogProps { onError: (title: string, error: unknown) => void; } +const ImageGrid: React.FC<{ + images: string[]; + albumName: string; + onRemove: (image: string) => void; + isRemoving: boolean; +}> = ({ images, albumName, onRemove, isRemoving }) => { + const getImageName = (path: string) => path.split('\\').pop() || path; + + return ( +
+ {images.map((image, index) => { + const src = convertFileSrc(image); + return ( +
+ {`Album + +
+ {getImageName(image)} +
+
+ ); + })} +
+ ); +}; + const ImageManagementDialog: React.FC = ({ albumName, onClose, @@ -36,7 +76,9 @@ const ImageManagementDialog: React.FC = ({ useEffect(() => { if (albumName) { - viewAlbum(albumName).catch((err: Error) => onError('Error loading album', err)); + viewAlbum(albumName).catch((err: Error) => + onError('Error loading album', err), + ); } }, [albumName, viewAlbum, onError]); @@ -52,26 +94,30 @@ const ImageManagementDialog: React.FC = ({ } }; - const getImageName = (path: string) => { - return path.split('\\').pop() || path; - }; + if (!albumName) { + return null; + } if (viewError) { return
Error loading album: {viewError.message}
; } if (isViewingAlbum) { - return
Loading...
; + return ( +
+ Loading Album... +
+ ); } if (showImageSelection) { return ( setShowImageSelection(false)} onSuccess={() => { setShowImageSelection(false); - viewAlbum(albumName || ''); + viewAlbum(albumName); onSuccess(); }} onError={onError} @@ -90,30 +136,12 @@ const ImageManagementDialog: React.FC = ({ Add Images to Album -
- {viewedAlbum?.image_paths?.map((image: string, index: number) => { - const srcc = convertFileSrc(image); - return ( -
- {`Album - -
- {getImageName(image)} -
-
- ); - })} -
+ @@ -122,4 +150,4 @@ const ImageManagementDialog: React.FC = ({ ); }; -export default ImageManagementDialog; \ No newline at end of file +export default ImageManagementDialog; diff --git a/frontend/src/components/LoadingScreen/LoadingScreen.tsx b/frontend/src/components/LoadingScreen/LoadingScreen.tsx index a5979f82..16399c2a 100644 --- a/frontend/src/components/LoadingScreen/LoadingScreen.tsx +++ b/frontend/src/components/LoadingScreen/LoadingScreen.tsx @@ -1,14 +1,26 @@ import React from 'react'; export const LoadingScreen: React.FC = () => { - return( -
-
- -
-
- ) + return ( +
+
+ +
+
+ ); }; diff --git a/frontend/src/components/Media/MediaCard.tsx b/frontend/src/components/Media/MediaCard.tsx index 74468db9..8b5ec154 100644 --- a/frontend/src/components/Media/MediaCard.tsx +++ b/frontend/src/components/Media/MediaCard.tsx @@ -1,4 +1,3 @@ - import React, { useState, useRef } from 'react'; import { MediaCardProps } from '@/types/Media'; import { Play, Volume2, VolumeX, Loader2 } from 'lucide-react'; @@ -9,7 +8,7 @@ export default function MediaCard({ item, type }: MediaCardProps) { const [isError, setIsError] = useState(false); const [isMuted, setIsMuted] = useState(true); const videoRef = useRef(null); - + const handleLoadComplete = () => { setIsLoading(false); setIsError(false); @@ -39,7 +38,7 @@ export default function MediaCard({ item, type }: MediaCardProps) { }; return ( -

Failed to load media

-
- {/* Main Content */}
{ @@ -202,7 +206,7 @@ const MediaView: React.FC = ({ onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} - className="relative h-full w-full flex items-center justify-center overflow-hidden" + className="relative flex h-full w-full items-center justify-center overflow-hidden" > = ({ }} /> - {/* Image Controls */}
@@ -284,8 +286,8 @@ const MediaView: React.FC = ({ } cursor-pointer transition-transform hover:scale-105`} > {isFavorite(media) && ( -
- +
+
)} {type === 'image' ? ( @@ -309,4 +311,4 @@ const MediaView: React.FC = ({ ); }; -export default MediaView; \ No newline at end of file +export default MediaView; diff --git a/frontend/src/components/Media/SortningControls.tsx b/frontend/src/components/Media/SortningControls.tsx index fe30bb96..0958a0ef 100644 --- a/frontend/src/components/Media/SortningControls.tsx +++ b/frontend/src/components/Media/SortningControls.tsx @@ -70,4 +70,4 @@ const SortingControls: React.FC = ({ ); }; -export default SortingControls \ No newline at end of file +export default SortingControls; diff --git a/frontend/src/components/Navigation/Navbar/Navbar.tsx b/frontend/src/components/Navigation/Navbar/Navbar.tsx index 9e6e9f1a..7e9c7afc 100644 --- a/frontend/src/components/Navigation/Navbar/Navbar.tsx +++ b/frontend/src/components/Navigation/Navbar/Navbar.tsx @@ -20,18 +20,21 @@ export function Navbar({ title, onNameChange }: NavbarProps) { } }, []); - const handleNameSubmit = useCallback((e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - const inputValue = (e.target as HTMLInputElement).value.trim(); - if (inputValue) { - setName(inputValue); - setShowPlaceholder(false); - setIsEditing(false); - localStorage.setItem('pictopy-username', inputValue); - onNameChange?.(inputValue); + const handleNameSubmit = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + const inputValue = (e.target as HTMLInputElement).value.trim(); + if (inputValue) { + setName(inputValue); + setShowPlaceholder(false); + setIsEditing(false); + localStorage.setItem('pictopy-username', inputValue); + onNameChange?.(inputValue); + } } - } - }, [onNameChange]); + }, + [onNameChange], + ); const handleNameClick = useCallback(() => { if (!isEditing) { @@ -39,30 +42,32 @@ export function Navbar({ title, onNameChange }: NavbarProps) { } }, [isEditing]); - // Handle blur event - const handleBlur = useCallback((e: React.FocusEvent) => { - const inputValue = e.target.value.trim(); - if (inputValue) { - setName(inputValue); - setShowPlaceholder(false); - localStorage.setItem('pictopy-username', inputValue); - onNameChange?.(inputValue); - } - setIsEditing(false); - }, [onNameChange]); + const handleBlur = useCallback( + (e: React.FocusEvent) => { + const inputValue = e.target.value.trim(); + if (inputValue) { + setName(inputValue); + setShowPlaceholder(false); + localStorage.setItem('pictopy-username', inputValue); + onNameChange?.(inputValue); + } + setIsEditing(false); + }, + [onNameChange], + ); return (
-
+
{/* Logo Section */}
PictoPy Logo - + PictoPy
@@ -71,7 +76,7 @@ export function Navbar({ title, onNameChange }: NavbarProps) { {/* Welcome Section and Theme Toggle */}
- + Welcome{' '} {isEditing || showPlaceholder ? ( @@ -81,14 +86,14 @@ export function Navbar({ title, onNameChange }: NavbarProps) { defaultValue={name} onKeyDown={handleNameSubmit} onBlur={handleBlur} - className="ml-2 px-2 py-1 bg-white/10 rounded-md border border-white/20 text-white placeholder-white/50 focus:outline-none focus:border-yellow-300 transition-colors duration-200 w-32" + className="ml-2 w-32 rounded-md border border-white/20 bg-white/10 px-2 py-1 text-white placeholder-white/50 transition-colors duration-200 focus:border-yellow-300 focus:outline-none" autoFocus aria-label="Enter your name" /> ) : ( + )} + {styles.backgroundVideo && ( + + )} + + )} +
+ ); + + return ( +
+ {styles.backgroundVideo && ( +
+ ); +} + +export default CustomizationPopup; diff --git a/frontend/src/components/Navigation/Sidebar/ImageCompressor.tsx b/frontend/src/components/Navigation/Sidebar/ImageCompressor.tsx new file mode 100644 index 00000000..e5fd4735 --- /dev/null +++ b/frontend/src/components/Navigation/Sidebar/ImageCompressor.tsx @@ -0,0 +1,269 @@ +import React, { useState, useCallback } from 'react'; +import { Upload, Download, Trash2, RefreshCw } from 'lucide-react'; + +interface CompressedImage { + id: string; + originalFile: File; + originalSize: number; + compressedSize: number; + compressedBlob: Blob; + previewUrl: string; +} + +const ImageCompressor: React.FC = () => { + const [compressedImages, setCompressedImages] = useState( + [], + ); + const [isCompressing, setIsCompressing] = useState(false); + const [compressionLevel, setCompressionLevel] = useState(0.7); + const [maxWidth, setMaxWidth] = useState(1920); + const [maxHeight, setMaxHeight] = useState(1080); + + const compressImage = useCallback( + async (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (event) => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d')!; + + let width = img.width; + let height = img.height; + + if (width > maxWidth) { + height *= maxWidth / width; + width = maxWidth; + } + + if (height > maxHeight) { + width *= maxHeight / height; + height = maxHeight; + } + + canvas.width = width; + canvas.height = height; + + ctx.drawImage(img, 0, 0, width, height); + + canvas.toBlob( + (blob) => { + if (blob) { + const compressedImage: CompressedImage = { + id: Math.random().toString(36).substr(2, 9), + originalFile: file, + originalSize: file.size, + compressedSize: blob.size, + compressedBlob: blob, + previewUrl: URL.createObjectURL(blob), + }; + resolve(compressedImage); + } else { + reject('Failed to compress image'); + } + }, + 'image/jpeg', + compressionLevel, + ); + }; + img.onerror = () => reject('Image load failed'); + img.src = event.target?.result as string; + }; + reader.onerror = () => reject('File reading failed'); + reader.readAsDataURL(file); + }); + }, + [compressionLevel, maxWidth, maxHeight], + ); + + const handleFileUpload = async ( + event: React.ChangeEvent, + ) => { + const files = event.target.files; + if (files) { + setIsCompressing(true); + const compressedFiles = await Promise.all( + Array.from(files).map((file) => + compressImage(file).catch((err) => { + console.error('Compression failed:', err); + return null; + }), + ), + ); + setCompressedImages((prev) => [ + ...prev, + ...compressedFiles.filter((file) => file !== null), + ]); + setIsCompressing(false); + } + }; + + const handleDownload = (image: CompressedImage) => { + const url = URL.createObjectURL(image.compressedBlob); + const a = document.createElement('a'); + a.href = url; + a.download = `compressed_${image.originalFile.name}`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + + const handleRemove = (id: string) => { + setCompressedImages((prev) => prev.filter((img) => img.id !== id)); + }; + + const handleRecompress = async (image: CompressedImage) => { + setIsCompressing(true); + const recompressedImage = await compressImage(image.originalFile); + setCompressedImages((prev) => + prev.map((img) => (img.id === image.id ? recompressedImage : img)), + ); + setIsCompressing(false); + }; + + return ( +
+

Image Compressor

+
+
+ + setCompressionLevel(parseFloat(e.target.value))} + className="w-full" + /> +
+
+ + setMaxWidth(parseInt(e.target.value))} + className="w-full" + /> +
+
+ + setMaxHeight(parseInt(e.target.value))} + className="w-full" + /> +
+
+
+ + +
+ {isCompressing &&

Compressing images...

} +
    + {compressedImages.map((image) => ( +
  • +
    + + {image.originalFile.name} + +
    + + + +
    +
    +
    + Preview +
    +

    + Original: {(image.originalSize / 1024).toFixed(2)} KB +

    +

    + Compressed: {(image.compressedSize / 1024).toFixed(2)} KB +

    +

    + Saved:{' '} + {((image.originalSize - image.compressedSize) / 1024).toFixed( + 2, + )}{' '} + KB ( + {( + ((image.originalSize - image.compressedSize) / + image.originalSize) * + 100 + ).toFixed(2)} + %) +

    +
    +
    +
  • + ))} +
+
+ ); +}; + +export default ImageCompressor; diff --git a/frontend/src/components/Navigation/Sidebar/Sidebar.tsx b/frontend/src/components/Navigation/Sidebar/Sidebar.tsx index a05a779d..d5950010 100644 --- a/frontend/src/components/Navigation/Sidebar/Sidebar.tsx +++ b/frontend/src/components/Navigation/Sidebar/Sidebar.tsx @@ -1,65 +1,192 @@ +import React, { useState, useEffect, useCallback } from 'react'; import { Link, useLocation } from 'react-router-dom'; -import { Home, Sparkles, Video, Images, Settings } from 'lucide-react'; -import { useState } from 'react'; +import { + Home, + Sparkles, + Video, + Images, + Settings, + Palette, + FileArchiveIcon as FileCompress, + X, +} from 'lucide-react'; +import CustomizationPopup from './CustomizationPopup'; +import ImageCompressor from './ImageCompressor'; +import { defaultStyles, CustomStyles } from './styles'; function Sidebar() { const location = useLocation(); const [isExpanded, setIsExpanded] = useState(false); + const [showCustomize, setShowCustomize] = useState(false); + const [showImageCompressor, setShowImageCompressor] = useState(false); + const [styles, setStyles] = useState(defaultStyles); + const [hoveredItem, setHoveredItem] = useState(null); const isActive = (path: string) => location.pathname === path; - const handleMouseEnter = () => setIsExpanded(true); - const handleMouseLeave = () => setIsExpanded(false); + useEffect(() => { + document.body.style.backgroundColor = styles.uiBackgroundColor; + }, [styles.uiBackgroundColor]); - const linkClasses = (path: string) => { - const baseClasses = - 'group flex flex-col items-center gap-2 p-3 rounded-xl transition-all duration-200'; - const activeClasses = isActive(path) - ? 'bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100' - : 'text-gray-500 dark:text-gray-300'; - return `${baseClasses} ${activeClasses}`; - }; + const handleKeyDown = useCallback((event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + (event.target as HTMLElement).click(); + } + }, []); - const iconClasses = - 'h-5 w-5 transition-transform duration-200 ease-out group-hover:scale-110'; + const sidebarStyle = { + background: styles.bgColor, + color: styles.textColor, + borderColor: styles.borderColor, + borderRadius: `${styles.borderRadius}px`, + backgroundSize: 'cover', + fontFamily: styles.fontFamily, + fontSize: `${styles.fontSize}px`, + width: isExpanded + ? `${styles.expandedWidth}px` + : `${styles.sidebarWidth}px`, + '--bg-active': styles.activeBackgroundColor, + '--text-active': styles.activeTextColor, + '--bg-hover': styles.hoverBackgroundColor, + } as React.CSSProperties; + + const navItems = [ + { path: '/home', label: 'Home', Icon: Home }, + { path: '/ai-tagging', label: 'AI Tagging', Icon: Sparkles }, + { path: '/videos', label: 'Videos', Icon: Video }, + { path: '/albums', label: 'Albums', Icon: Images }, + { path: '/settings', label: 'Settings', Icon: Settings }, + ]; return ( -
-
- {[{ path: '/home', label: 'Home', Icon: Home }, - { path: '/ai-tagging', label: 'AI Tagging', Icon: Sparkles }, - { path: '/videos', label: 'Videos', Icon: Video }, - { path: '/albums', label: 'Albums', Icon: Images }, - { path: '/settings', label: 'Settings', Icon: Settings }, - ].map(({ path, label, Icon }) => ( - - - + {styles.backgroundVideo && ( + <> +
+ +
+
+ + )} +
+
-
+ + {showCustomize && ( +
+
+ setShowCustomize(false)} + /> +
+
+ )} + + {showImageCompressor && ( +
+
+
+

Image Compressor

+ +
+ +
+
+ )} + ); } diff --git a/frontend/src/components/Navigation/Sidebar/styles.ts b/frontend/src/components/Navigation/Sidebar/styles.ts new file mode 100644 index 00000000..99fb5d61 --- /dev/null +++ b/frontend/src/components/Navigation/Sidebar/styles.ts @@ -0,0 +1,63 @@ +export interface CustomStyles { + bgColor: string; + textColor: string; + borderColor: string; + iconSize: number; + sidebarWidth: number; + borderRadius: number; + fontFamily: string; + fontSize: number; + hoverBackgroundColor: string; + activeBackgroundColor: string; + activeTextColor: string; + iconColor: string; + uiBackgroundColor: string; + backgroundImage: string; + backgroundVideo: string; +} + +export const defaultStyles: CustomStyles = { + bgColor: '#1f2937', + textColor: '#f3f4f6', + borderColor: '#374151', + iconSize: 20, + sidebarWidth: 128, + borderRadius: 8, + fontFamily: 'SF Pro Display, sans-serif', + fontSize: 14, + hoverBackgroundColor: '#374151', + activeBackgroundColor: '#4b5563', + activeTextColor: '#ffffff', + iconColor: '#9ca3af', + uiBackgroundColor: '#111827', + backgroundImage: '', + backgroundVideo: '', +}; + +export const presetThemes = { + dark: { ...defaultStyles }, + light: { + ...defaultStyles, + bgColor: '#ffffff', + textColor: '#333333', + borderColor: '#e5e7eb', + hoverBackgroundColor: '#f3f4f6', + activeBackgroundColor: '#e5e7eb', + activeTextColor: '#000000', + iconColor: '#4b5563', + uiBackgroundColor: '#f0f2f5', + fontFamily: 'Inter, sans-serif', + }, + blue: { + ...defaultStyles, + bgColor: '#e0f2fe', + textColor: '#0c4a6e', + borderColor: '#7dd3fc', + hoverBackgroundColor: '#bae6fd', + activeBackgroundColor: '#7dd3fc', + activeTextColor: '#0c4a6e', + iconColor: '#0369a1', + uiBackgroundColor: '#f0f9ff', + fontFamily: 'Roboto, sans-serif', + }, +}; diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx index eb7c1ef3..5777a53c 100644 --- a/frontend/src/components/ui/button.tsx +++ b/frontend/src/components/ui/button.tsx @@ -9,11 +9,16 @@ const buttonVariants = cva( { variants: { variant: { - default: 'bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80 focus:ring-primary dark:bg-primary-dark dark:text-primary-foreground-dark dark:hover:bg-primary-dark/90 dark:active:bg-primary-dark/80', - destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80 focus:ring-destructive dark:bg-destructive-dark dark:text-destructive-foreground-dark dark:hover:bg-destructive-dark/90 dark:active:bg-destructive-dark/80', - outline: 'border border-input hover:bg-accent hover:text-accent-foreground active:bg-accent/90 focus:ring-accent dark:bg-accent-dark dark:text-accent-foreground-dark dark:border-input-dark', - secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70 focus:ring-secondary dark:bg-secondary-dark dark:text-secondary-foreground-dark dark:hover:bg-secondary-dark/80 dark:active:bg-secondary-dark/70', - ghost: 'hover:bg-accent hover:text-accent-foreground active:bg-accent/90 focus:ring-accent dark:hover:bg-accent-dark dark:text-accent-foreground-dark', + default: + 'bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80 focus:ring-primary dark:bg-primary-dark dark:text-primary-foreground-dark dark:hover:bg-primary-dark/90 dark:active:bg-primary-dark/80', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80 focus:ring-destructive dark:bg-destructive-dark dark:text-destructive-foreground-dark dark:hover:bg-destructive-dark/90 dark:active:bg-destructive-dark/80', + outline: + 'border border-input hover:bg-accent hover:text-accent-foreground active:bg-accent/90 focus:ring-accent dark:bg-accent-dark dark:text-accent-foreground-dark dark:border-input-dark', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70 focus:ring-secondary dark:bg-secondary-dark dark:text-secondary-foreground-dark dark:hover:bg-secondary-dark/80 dark:active:bg-secondary-dark/70', + ghost: + 'hover:bg-accent hover:text-accent-foreground active:bg-accent/90 focus:ring-accent dark:hover:bg-accent-dark dark:text-accent-foreground-dark', link: 'text-primary underline-offset-4 hover:underline active:text-primary/80 focus:ring-primary dark:text-primary-dark dark:hover:underline', }, size: { @@ -51,4 +56,3 @@ const Button = React.forwardRef( Button.displayName = 'Button'; export { Button, buttonVariants }; - diff --git a/frontend/src/pages/Setupscreen/Setup.tsx b/frontend/src/pages/Setupscreen/Setup.tsx index 12351575..265b75cf 100644 --- a/frontend/src/pages/Setupscreen/Setup.tsx +++ b/frontend/src/pages/Setupscreen/Setup.tsx @@ -5,11 +5,10 @@ import { LoadingScreen } from '@/components/LoadingScreen/LoadingScreen'; export const InitialPage: React.FC = () => { const { loading, handleFolderPathChange } = useInitialPageController(); - - + if (loading) { return ; } - + return ; }; diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index 0a0ebfa6..fe12db56 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -1,77 +1,77 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: ["class"], + darkMode: ['class'], content: [ './pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}', './app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}', ], - prefix: "", + prefix: '', theme: { container: { center: true, - padding: "2rem", + padding: '2rem', screens: { - "2xl": "1400px", + '2xl': '1400px', }, }, extend: { colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', }, secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', }, destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', }, muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', }, accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', }, popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', }, card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', }, }, borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', }, keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, }, }, animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [require('tailwindcss-animate')], }; diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 7ab2522c..272285c9 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,102 +1,94 @@ /** @type {import('tailwindcss').Config} */ -module.exports = { - darkMode: ["class"], // Enable dark mode - content: [ - './pages/**/*.{ts,tsx}', - './components/**/*.{ts,tsx}', - './app/**/*.{ts,tsx}', - './src/**/*.{ts,tsx}', - ], - prefix: "", - theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, +import tailwindcssAnimate from 'tailwindcss-animate'; + +export const darkMode = ['class']; +export const content = [ + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', +]; +export const prefix = ''; +export const theme = { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', }, - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - // Custom gradient colors for buttons - gradientFrom: "#6366F1", // Indigo - gradientVia: "#8B5CF6", // Purple - gradientTo: "#EC4899", // Pink - // Dark mode-specific gradients - gradientFromDark: "#4F46E5", - gradientViaDark: "#7C3AED", - gradientToDark: "#BE185D", + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', }, - boxShadow: { - lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)", - xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)", - darkLg: "0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3)", + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', }, - keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, - }, - // Smooth hover animation - "button-hover": { - "0%": { transform: "scale(1)", boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)" }, - "100%": { transform: "scale(1.05)", boxShadow: "0 6px 10px rgba(0, 0, 0, 0.2)" }, - }, - // Reverse hover for dark mode - "button-hover-dark": { - "0%": { transform: "scale(1)", boxShadow: "0 4px 6px rgba(255, 255, 255, 0.1)" }, - "100%": { transform: "scale(1.05)", boxShadow: "0 6px 10px rgba(255, 255, 255, 0.15)" }, - }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - "button-hover": "button-hover 0.3s ease-in-out", - "button-hover-dark": "button-hover-dark 0.3s ease-in-out", + // Custom gradient colors for buttons + gradientFrom: '#6366F1', // Indigo + gradientVia: '#8B5CF6', // Purple + gradientTo: '#EC4899', // Pink + // Dark mode-specific gradients + gradientFromDark: '#4F46E5', + gradientViaDark: '#7C3AED', + gradientToDark: '#BE185D', + }, + boxShadow: { + lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', + xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', + darkLg: + '0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3)', + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + // Smooth hover animation + 'button-hover': 'button-hover 0.3s ease-in-out', + 'button-hover-dark': 'button-hover-dark 0.3s ease-in-out', }, }, - plugins: [require("tailwindcss-animate")], }; +export const plugins = [tailwindcssAnimate]; From 3c3024a53112353145073cb7c7b57b18d3931580 Mon Sep 17 00:00:00 2001 From: ASHUTOSH SINGH Date: Fri, 17 Jan 2025 04:44:39 +0530 Subject: [PATCH 2/2] Update tauri.conf.json --- frontend/src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index 67261d53..ff972536 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -28,7 +28,7 @@ "active": true, "endpoints": ["https://server.com//api/v1/tauri/update"], "dialog": true, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEI3QzQyQUVCMEZBQ0FEQQpSV1RheXZxd3JrSjhDMk9ENllaUm1TcGVSeHdkbTQ4d0QrUjBXVEE0a21LL2RoRkZ2MXB6K1BuRQo= " + "pubkey": " " } }, "app": {