diff --git a/dashboard/package.json b/dashboard/package.json index 55fd69c..378db80 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -19,7 +19,10 @@ }, "dependencies": { "@electron-toolkit/preload": "^3.0.1", - "@electron-toolkit/utils": "^4.0.0" + "@electron-toolkit/utils": "^4.0.0", + "react-icons": "^5.5.0", + "react-router-dom": "^7.7.0", + "sass": "^1.89.2" }, "devDependencies": { "@electron-toolkit/eslint-config": "^2.0.0", diff --git a/dashboard/pnpm-lock.yaml b/dashboard/pnpm-lock.yaml index 544ef21..036c9f1 100644 --- a/dashboard/pnpm-lock.yaml +++ b/dashboard/pnpm-lock.yaml @@ -14,6 +14,15 @@ importers: '@electron-toolkit/utils': specifier: ^4.0.0 version: 4.0.0(electron@35.7.2) + react-icons: + specifier: ^5.5.0 + version: 5.5.0(react@19.1.0) + react-router-dom: + specifier: ^7.7.0 + version: 7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + sass: + specifier: ^1.89.2 + version: 1.89.2 devDependencies: '@electron-toolkit/eslint-config': specifier: ^2.0.0 @@ -23,7 +32,7 @@ importers: version: 3.0.0(eslint@9.31.0)(prettier@3.6.2) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.7.0(vite@6.3.5(@types/node@24.0.14)) + version: 4.7.0(vite@6.3.5(@types/node@24.0.14)(sass@1.89.2)) electron: specifier: ^35.1.5 version: 35.7.2 @@ -32,7 +41,7 @@ importers: version: 25.1.8(electron-builder-squirrel-windows@25.1.8) electron-vite: specifier: ^3.1.0 - version: 3.1.0(vite@6.3.5(@types/node@24.0.14)) + version: 3.1.0(vite@6.3.5(@types/node@24.0.14)(sass@1.89.2)) eslint: specifier: ^9.24.0 version: 9.31.0 @@ -56,7 +65,7 @@ importers: version: 19.1.0(react@19.1.0) vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@24.0.14) + version: 6.3.5(@types/node@24.0.14)(sass@1.89.2) packages: @@ -467,6 +476,88 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -823,6 +914,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + browserslist@4.25.1: resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -883,6 +978,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -960,6 +1059,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -1032,6 +1135,11 @@ packages: delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -1293,6 +1401,10 @@ packages: filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1506,6 +1618,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immutable@5.1.3: + resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -1611,6 +1726,10 @@ packages: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -1802,6 +1921,10 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -1908,6 +2031,9 @@ packages: node-addon-api@1.7.2: resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-api-version@0.2.1: resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} @@ -2036,6 +2162,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -2103,6 +2233,11 @@ packages: peerDependencies: react: ^19.1.0 + react-icons@5.5.0: + resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} + peerDependencies: + react: '*' + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -2110,6 +2245,23 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-router-dom@7.7.0: + resolution: {integrity: sha512-wwGS19VkNBkneVh9/YD0pK3IsjWxQUVMDD6drlG7eJpo1rXBtctBqDyBm/k+oKHRAm1x9XWT3JFC82QI9YOXXA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.7.0: + resolution: {integrity: sha512-3FUYSwlvB/5wRJVTL/aavqHmfUKe0+Xm9MllkYgGo9eDwNdkvwlJGjpPxono1kCycLt6AnDTgjmXvK3/B4QGuw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.1.0: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} @@ -2128,6 +2280,10 @@ packages: readdir-glob@1.1.3: resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -2204,6 +2360,11 @@ packages: sanitize-filename@1.6.3: resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + sass@1.89.2: + resolution: {integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==} + engines: {node: '>=14.0.0'} + hasBin: true + sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} @@ -2229,6 +2390,9 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2401,6 +2565,10 @@ packages: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} @@ -3007,6 +3175,67 @@ snapshots: mkdirp: 1.0.4 rimraf: 3.0.2 + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + '@pkgjs/parseargs@0.11.0': optional: true @@ -3156,7 +3385,7 @@ snapshots: '@types/node': 22.16.4 optional: true - '@vitejs/plugin-react@4.7.0(vite@6.3.5(@types/node@24.0.14))': + '@vitejs/plugin-react@4.7.0(vite@6.3.5(@types/node@24.0.14)(sass@1.89.2))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) @@ -3164,7 +3393,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.5(@types/node@24.0.14) + vite: 6.3.5(@types/node@24.0.14)(sass@1.89.2) transitivePeerDependencies: - supports-color @@ -3408,6 +3637,11 @@ snapshots: dependencies: balanced-match: 1.0.2 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + optional: true + browserslist@4.25.1: dependencies: caniuse-lite: 1.0.30001727 @@ -3515,6 +3749,10 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@2.0.0: {} chromium-pickle-js@0.2.0: {} @@ -3581,6 +3819,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie@1.0.2: {} + core-util-is@1.0.2: optional: true @@ -3654,6 +3894,9 @@ snapshots: delegates@1.0.0: {} + detect-libc@1.0.3: + optional: true + detect-libc@2.0.4: {} detect-node@2.1.0: @@ -3755,7 +3998,7 @@ snapshots: electron-to-chromium@1.5.187: {} - electron-vite@3.1.0(vite@6.3.5(@types/node@24.0.14)): + electron-vite@3.1.0(vite@6.3.5(@types/node@24.0.14)(sass@1.89.2)): dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.0) @@ -3763,7 +4006,7 @@ snapshots: esbuild: 0.25.6 magic-string: 0.30.17 picocolors: 1.1.1 - vite: 6.3.5(@types/node@24.0.14) + vite: 6.3.5(@types/node@24.0.14)(sass@1.89.2) transitivePeerDependencies: - supports-color @@ -4078,6 +4321,11 @@ snapshots: dependencies: minimatch: 5.1.6 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + optional: true + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4348,6 +4596,8 @@ snapshots: ignore@5.3.2: {} + immutable@5.1.3: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -4453,6 +4703,9 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-number@7.0.0: + optional: true + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -4653,6 +4906,12 @@ snapshots: math-intrinsics@1.1.0: {} + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + optional: true + mime-db@1.52.0: {} mime-types@2.1.35: @@ -4739,6 +4998,9 @@ snapshots: node-addon-api@1.7.2: optional: true + node-addon-api@7.1.1: + optional: true + node-api-version@0.2.1: dependencies: semver: 7.7.2 @@ -4887,6 +5149,9 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.1: + optional: true + picomatch@4.0.3: {} plist@3.1.0: @@ -4942,10 +5207,28 @@ snapshots: react: 19.1.0 scheduler: 0.26.0 + react-icons@5.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + react-is@16.13.1: {} react-refresh@0.17.0: {} + react-router-dom@7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-router: 7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + + react-router@7.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + cookie: 1.0.2 + react: 19.1.0 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.0(react@19.1.0) + react@19.1.0: {} read-binary-file-arch@1.0.6: @@ -4974,6 +5257,8 @@ snapshots: dependencies: minimatch: 5.1.6 + readdirp@4.1.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -5090,6 +5375,14 @@ snapshots: dependencies: truncate-utf8-bytes: 1.0.2 + sass@1.89.2: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + sax@1.4.1: {} scheduler@0.26.0: {} @@ -5108,6 +5401,8 @@ snapshots: set-blocking@2.0.0: {} + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5339,6 +5634,11 @@ snapshots: tmp@0.2.3: {} + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + optional: true + truncate-utf8-bytes@1.0.2: dependencies: utf8-byte-length: 1.0.5 @@ -5429,7 +5729,7 @@ snapshots: extsprintf: 1.4.1 optional: true - vite@6.3.5(@types/node@24.0.14): + vite@6.3.5(@types/node@24.0.14)(sass@1.89.2): dependencies: esbuild: 0.25.6 fdir: 6.4.6(picomatch@4.0.3) @@ -5440,6 +5740,7 @@ snapshots: optionalDependencies: '@types/node': 24.0.14 fsevents: 2.3.3 + sass: 1.89.2 wcwidth@1.0.1: dependencies: diff --git a/dashboard/src/renderer/index.html b/dashboard/src/renderer/index.html index 0022e5e..d9a8c51 100644 --- a/dashboard/src/renderer/index.html +++ b/dashboard/src/renderer/index.html @@ -5,7 +5,7 @@ OpenWall diff --git a/dashboard/src/renderer/src/App.jsx b/dashboard/src/renderer/src/App.jsx index 8ff24e0..d171581 100644 --- a/dashboard/src/renderer/src/App.jsx +++ b/dashboard/src/renderer/src/App.jsx @@ -1,9 +1,38 @@ +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' +import Header from './common/Header' +import Calendar from './pages/Calendar' +import Shopping from './pages/Shopping' +import Notes from './pages/Notes' +import Search from './pages/Search' + +// Configuration +const BACKGROUND_IMAGE_URL = 'https://cdn.pixabay.com/photo/2018/11/19/03/26/iceland-3824494_1280.jpg' + +const APP_BACKGROUND_STYLE = { + backgroundImage: `url(${BACKGROUND_IMAGE_URL})`, + backgroundSize: 'cover', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundAttachment: 'fixed', + minHeight: '100vh' +} + const App = () => { return ( - <> -

Not implemented yet

- + +
+
+
+ + } /> + } /> + } /> + } /> + +
+
+
) } -export default App; \ No newline at end of file +export default App \ No newline at end of file diff --git a/dashboard/src/renderer/src/common/Header/Header.jsx b/dashboard/src/renderer/src/common/Header/Header.jsx new file mode 100644 index 0000000..38252de --- /dev/null +++ b/dashboard/src/renderer/src/common/Header/Header.jsx @@ -0,0 +1,119 @@ +import { useState, useEffect } from 'react' +import { useNavigate, useLocation } from 'react-router-dom' +import { FiCalendar, FiShoppingBag, FiBookOpen, FiSearch } from 'react-icons/fi' +import './styles.sass' + +// Static color configuration +const HEADER_COLORS = { + primary: 'rgba(76, 175, 160, 0.25)', + secondary: 'rgba(34, 139, 156, 0.35)', + tertiary: 'rgba(21, 94, 117, 0.4)', + accent: 'rgba(147, 197, 253, 0.3)' +} + +// Icon-specific colors for better differentiation +const ICON_COLORS = { + calendar: '#FF6B6B', // Red + shopping: '#4ECDC4', // Teal + notes: '#45B7D1', // Blue + search: '#FFA726' // Orange +} + +const Header = () => { + const [currentTime, setCurrentTime] = useState(new Date()) + const navigate = useNavigate() + const location = useLocation() + + useEffect(() => { + const timer = setInterval(() => { + setCurrentTime(new Date()) + }, 1000) + + return () => clearInterval(timer) + }, []) + + const formatTime = (date) => { + return date.toLocaleTimeString('de-DE', { + hour: '2-digit', + minute: '2-digit' + }) + } + + const getCurrentMonth = (date) => { + return date.toLocaleDateString('de-DE', { month: 'long' }) + } + + const navigationItems = [ + { id: 'calendar', icon: FiCalendar, label: 'Kalender', path: '/' }, + { id: 'shopping', icon: FiShoppingBag, label: 'Einkaufen', path: '/shopping' }, + { id: 'notes', icon: FiBookOpen, label: 'Notizen', path: '/notes' }, + { id: 'search', icon: FiSearch, label: 'Suchen', path: '/search' } + ] + + const getActiveIcon = () => { + const currentPath = location.pathname + const activeItem = navigationItems.find(item => item.path === currentPath) + return activeItem ? activeItem.id : 'calendar' + } + + const handleNavigation = (path) => { + navigate(path) + } + + const headerStyle = { + background: `linear-gradient(135deg, ${HEADER_COLORS.primary}, ${HEADER_COLORS.secondary}, ${HEADER_COLORS.tertiary})`, + borderColor: HEADER_COLORS.accent + } + + const buttonStyle = { + background: `linear-gradient(135deg, ${HEADER_COLORS.accent}, ${HEADER_COLORS.primary})`, + borderColor: HEADER_COLORS.accent, + color: '#ffffff', + boxShadow: `0 8px 32px ${HEADER_COLORS.tertiary}, inset 0 1px 0 ${HEADER_COLORS.accent}` + } + + const activeButtonStyle = { + background: `linear-gradient(135deg, ${HEADER_COLORS.primary}, ${HEADER_COLORS.secondary})`, + borderColor: HEADER_COLORS.primary, + color: '#ffffff', + boxShadow: `0 12px 40px ${HEADER_COLORS.primary}, inset 0 2px 0 ${HEADER_COLORS.accent}` + } + + return ( +
+ +
+ ) +} + +export default Header \ No newline at end of file diff --git a/dashboard/src/renderer/src/common/Header/index.js b/dashboard/src/renderer/src/common/Header/index.js new file mode 100644 index 0000000..a99a897 --- /dev/null +++ b/dashboard/src/renderer/src/common/Header/index.js @@ -0,0 +1 @@ +export { default } from './Header' \ No newline at end of file diff --git a/dashboard/src/renderer/src/common/Header/styles.sass b/dashboard/src/renderer/src/common/Header/styles.sass new file mode 100644 index 0000000..1fab696 --- /dev/null +++ b/dashboard/src/renderer/src/common/Header/styles.sass @@ -0,0 +1,161 @@ +// Header Component - Dynamic Color Extraction from Background +.header + position: fixed + top: 0.5rem + left: 0.5rem + right: 0.5rem + z-index: 1000 + padding: 1rem 2rem + backdrop-filter: blur(80px) saturate(180%) + border-radius: 24px + border: 1px solid + box-shadow: 0 20px 80px rgba(0, 0, 0, 0.15), 0 8px 32px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.4) + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) + + &:hover + backdrop-filter: blur(100px) saturate(200%) + box-shadow: 0 24px 96px rgba(0, 0, 0, 0.25), 0 12px 48px rgba(0, 0, 0, 0.15), inset 0 2px 0 rgba(255, 255, 255, 0.5) + transform: translateY(-1px) + + &__nav + display: flex + justify-content: space-between + align-items: center + max-width: 100% + margin: 0 auto + + &__left + display: flex + flex-direction: column + align-items: flex-start + gap: 0.125rem + + &__month + font-size: 1.5rem + font-weight: 700 + color: rgba(255, 255, 255, 0.95) + letter-spacing: -0.02em + text-shadow: 0 2px 8px rgba(21, 94, 117, 0.6), 0 1px 2px rgba(0, 0, 0, 0.3) + line-height: 1.1 + + &__time + font-size: 2.25rem + font-weight: 800 + color: #ffffff + font-variant-numeric: tabular-nums + text-shadow: 0 3px 12px rgba(21, 94, 117, 0.8), 0 1px 4px rgba(0, 0, 0, 0.4) + line-height: 0.9 + letter-spacing: -0.05em + + &__right + display: flex + align-items: center + gap: 1rem + + &__nav-item + display: flex + align-items: center + justify-content: center + width: 56px + height: 56px + border: none + border-radius: 18px + cursor: pointer + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) + backdrop-filter: blur(40px) + border: 1px solid + font-size: 1.375rem + position: relative + overflow: hidden + + // Allow custom icon colors + svg + transition: all 0.3s ease + + &::before + content: '' + position: absolute + top: 0 + left: 0 + right: 0 + bottom: 0 + opacity: 0 + transition: opacity 0.3s ease + border-radius: 18px + + &:hover + transform: translateY(-3px) scale(1.08) + + svg + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4)) !important + + &::before + opacity: 1 + + &:active + transform: translateY(-1px) scale(1.03) + + &--active + border: 1px solid + + svg + filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5)) !important + + &::before + opacity: 1 + + &:hover + transform: translateY(-3px) scale(1.08) + +// Responsive Design +@media (max-width: 768px) + .header + top: 0.375rem + left: 0.375rem + right: 0.375rem + padding: 0.875rem 1.75rem + border-radius: 20px + + &__left + gap: 0.0625rem + + &__month + font-size: 1.25rem + + &__time + font-size: 1.875rem + + &__right + gap: 0.875rem + + &__nav-item + width: 52px + height: 52px + border-radius: 16px + font-size: 1.25rem + +@media (max-width: 480px) + .header + top: 0.25rem + left: 0.25rem + right: 0.25rem + padding: 0.75rem 1.5rem + border-radius: 18px + + &__left + gap: 0.0625rem + + &__month + font-size: 1.125rem + + &__time + font-size: 1.625rem + + &__right + gap: 0.75rem + + &__nav-item + width: 48px + height: 48px + border-radius: 14px + font-size: 1.125rem \ No newline at end of file diff --git a/dashboard/src/renderer/src/index.sass b/dashboard/src/renderer/src/index.sass new file mode 100644 index 0000000..e4c5e6f --- /dev/null +++ b/dashboard/src/renderer/src/index.sass @@ -0,0 +1,71 @@ +// Global Styles - Light Mode with Waterfall Background +// Reset and base styles +* + margin: 0 + padding: 0 + box-sizing: border-box + +html, body + height: 100vh + width: 100vw + overflow: hidden + +body + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif + background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.3)), url('https://cdn.pixabay.com/photo/2024/07/16/23/33/waterfall-8900207_1280.png') + background-size: cover + background-position: center + background-attachment: fixed + color: #1e293b + font-weight: 400 + letter-spacing: -0.01em + line-height: 1.5 + -webkit-font-smoothing: antialiased + -moz-osx-font-smoothing: grayscale + +#root + height: 100vh + width: 100vw + display: flex + flex-direction: column + +// App Layout Styles +.app + height: 100vh + width: 100vw + display: flex + flex-direction: column + + &__main + flex: 1 + padding-top: 5rem + display: flex + align-items: center + justify-content: center + + &__content + text-align: center + backdrop-filter: blur(40px) saturate(180%) + background: rgba(255, 255, 255, 0.25) + padding: 4rem + border-radius: 32px + border: 1px solid rgba(255, 255, 255, 0.3) + box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1), 0 8px 32px rgba(0, 0, 0, 0.05), inset 0 1px 0 rgba(255, 255, 255, 0.4) + max-width: 600px + margin: 0 auto + + h1 + font-size: 3rem + font-weight: 800 + margin-bottom: 1.5rem + background: linear-gradient(135deg, #1e293b, #475569, #0f766e) + -webkit-background-clip: text + -webkit-text-fill-color: transparent + background-clip: text + line-height: 1.2 + + p + font-size: 1.25rem + color: rgba(30, 41, 59, 0.8) + font-weight: 500 + line-height: 1.6 \ No newline at end of file diff --git a/dashboard/src/renderer/src/main.jsx b/dashboard/src/renderer/src/main.jsx index 4ac475c..e290eef 100644 --- a/dashboard/src/renderer/src/main.jsx +++ b/dashboard/src/renderer/src/main.jsx @@ -1,5 +1,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import './index.sass' import App from './App' createRoot(document.getElementById('root')).render( diff --git a/dashboard/src/renderer/src/pages/Calendar.jsx b/dashboard/src/renderer/src/pages/Calendar.jsx new file mode 100644 index 0000000..33269bb --- /dev/null +++ b/dashboard/src/renderer/src/pages/Calendar.jsx @@ -0,0 +1,9 @@ +const Calendar = () => { + return ( +
+

Kalender

+
+ ) +} + +export default Calendar diff --git a/dashboard/src/renderer/src/pages/Notes.jsx b/dashboard/src/renderer/src/pages/Notes.jsx new file mode 100644 index 0000000..4fe36d1 --- /dev/null +++ b/dashboard/src/renderer/src/pages/Notes.jsx @@ -0,0 +1,203 @@ +import { useRef, useEffect, useState } from 'react' +import { FiEdit3, FiTrash, FiChevronDown } from 'react-icons/fi' +import { TbEraser } from 'react-icons/tb' +import './Notes.sass' + +const Notes = () => { + const canvasRef = useRef(null) + const [isDrawing, setIsDrawing] = useState(false) + const [tool, setTool] = useState('pen') // 'pen' or 'eraser' + const [penColor, setPenColor] = useState('#2d3748') + const [showColorPicker, setShowColorPicker] = useState(false) + + const colors = [ + '#2d3748', // Dark gray + '#000000', // Black + '#e53e3e', // Red + '#3182ce', // Blue + '#38a169', // Green + '#d69e2e', // Yellow + '#805ad5', // Purple + '#dd6b20', // Orange + '#e91e63', // Pink + '#00acc1' // Cyan + ] + + useEffect(() => { + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + + // Set canvas size + const resizeCanvas = () => { + const container = canvas.parentElement + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) + + canvas.width = container.clientWidth + canvas.height = container.clientHeight + + // Set drawing properties + ctx.lineCap = 'round' + ctx.lineJoin = 'round' + ctx.imageSmoothingEnabled = true + + // Restore canvas content after resize + ctx.putImageData(imageData, 0, 0) + + // Load saved canvas data + loadCanvasFromStorage() + } + + resizeCanvas() + window.addEventListener('resize', resizeCanvas) + + return () => window.removeEventListener('resize', resizeCanvas) + }, []) + + const saveCanvasToStorage = () => { + const canvas = canvasRef.current + const dataURL = canvas.toDataURL() + localStorage.setItem('notes-canvas', dataURL) + } + + const loadCanvasFromStorage = () => { + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + const savedData = localStorage.getItem('notes-canvas') + + if (savedData) { + const img = new Image() + img.onload = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.drawImage(img, 0, 0) + } + img.src = savedData + } + } + + const startDrawing = (e) => { + setIsDrawing(true) + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + const rect = canvas.getBoundingClientRect() + + const x = e.clientX - rect.left + const y = e.clientY - rect.top + + ctx.beginPath() + ctx.moveTo(x, y) + } + + const draw = (e) => { + if (!isDrawing) return + + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + const rect = canvas.getBoundingClientRect() + + const x = e.clientX - rect.left + const y = e.clientY - rect.top + + if (tool === 'pen') { + ctx.globalCompositeOperation = 'source-over' + ctx.strokeStyle = penColor + ctx.lineWidth = 3 + ctx.lineTo(x, y) + ctx.stroke() + } else if (tool === 'eraser') { + ctx.globalCompositeOperation = 'destination-out' + ctx.lineWidth = 40 // Increased eraser size + ctx.lineTo(x, y) + ctx.stroke() + } + } + + const stopDrawing = () => { + setIsDrawing(false) + // Save canvas state after drawing + saveCanvasToStorage() + } + + const clearCanvas = () => { + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + ctx.clearRect(0, 0, canvas.width, canvas.height) + // Clear saved state + localStorage.removeItem('notes-canvas') + } + + return ( +
+
+ {/* Toolbar */} +
+
+ + + {showColorPicker && ( +
+
+ {colors.map((color) => ( +
+
+ )} +
+ + + + +
+ + {/* Canvas Container */} +
+ +
+
+
+ ) +} + +export default Notes diff --git a/dashboard/src/renderer/src/pages/Notes.sass b/dashboard/src/renderer/src/pages/Notes.sass new file mode 100644 index 0000000..776a910 --- /dev/null +++ b/dashboard/src/renderer/src/pages/Notes.sass @@ -0,0 +1,249 @@ +// Notes Page - Drawing Canvas with Glassmorphism (Matching Search Page Structure) +.notes-page + padding: 2rem 0.75rem 0.75rem 0.75rem + height: calc(100vh - 6rem) + width: 100% + +.notes-container + position: relative + width: 100% + height: 100% + backdrop-filter: blur(60px) saturate(200%) + background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.2)) + border-radius: 28px + border: 1px solid rgba(255, 255, 255, 0.5) + box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1), 0 8px 32px rgba(0, 0, 0, 0.05), inset 0 2px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(0, 0, 0, 0.1) + padding: 1.5rem + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) + overflow: hidden + + &:hover + backdrop-filter: blur(80px) saturate(220%) + background: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.3)) + box-shadow: 0 20px 80px rgba(0, 0, 0, 0.15), 0 10px 40px rgba(0, 0, 0, 0.08), inset 0 2px 0 rgba(255, 255, 255, 0.7) + transform: translateY(-2px) + +.notes-toolbar + position: absolute + bottom: 1rem + left: 50% + transform: translateX(-50%) + z-index: 10 + display: flex + align-items: center + gap: 0.75rem + padding: 0.75rem 1rem + backdrop-filter: blur(40px) saturate(180%) + background: rgba(255, 255, 255, 0.2) + border-radius: 16px + border: 1px solid rgba(255, 255, 255, 0.3) + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.4) + +.pen-tool-group + position: relative + display: flex + align-items: center + gap: 0.25rem + +.color-picker-button + display: flex + align-items: center + justify-content: center + width: 24px + height: 44px + border: none + border-radius: 0 14px 14px 0 + border: 1px solid rgba(255, 255, 255, 0.4) + border-left: none + cursor: pointer + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) + font-size: 0.875rem + color: white + + &:hover + transform: translateY(-2px) + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15) + +.color-picker-popover + position: absolute + bottom: calc(100% + 0.5rem) + left: 0 + backdrop-filter: blur(40px) saturate(180%) + background: rgba(255, 255, 255, 0.25) + border-radius: 16px + border: 1px solid rgba(255, 255, 255, 0.3) + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.4) + padding: 0.75rem + z-index: 20 + +.color-grid + display: grid + grid-template-columns: repeat(5, 1fr) + gap: 0.5rem + +.color-option + width: 32px + height: 32px + border: 2px solid rgba(255, 255, 255, 0.3) + border-radius: 12px + cursor: pointer + transition: all 0.2s ease + position: relative + + &:hover + transform: scale(1.1) + border-color: rgba(255, 255, 255, 0.6) + + &.active + transform: scale(1.15) + border-color: rgba(255, 255, 255, 0.8) + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2) + + &::after + content: '✓' + position: absolute + top: 50% + left: 50% + transform: translate(-50%, -50%) + color: white + font-size: 0.875rem + font-weight: bold + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8) + +.toolbar-section + display: flex + align-items: center + gap: 0.75rem + +.tool-button + display: flex + align-items: center + justify-content: center + width: 44px + height: 44px + border: none + border-radius: 14px + background: rgba(255, 255, 255, 0.3) + backdrop-filter: blur(20px) + border: 1px solid rgba(255, 255, 255, 0.4) + color: rgba(50, 50, 50, 0.8) + cursor: pointer + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) + font-size: 1.125rem + + &:hover + background: rgba(255, 255, 255, 0.5) + color: rgba(50, 50, 50, 1) + transform: translateY(-2px) + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15) + + &.active + background: rgba(255, 255, 255, 0.6) + color: rgba(50, 50, 50, 1) + border-color: rgba(255, 255, 255, 0.6) + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2) + + &.clear-button + background: rgba(239, 68, 68, 0.3) + border-color: rgba(239, 68, 68, 0.4) + color: rgba(50, 50, 50, 0.8) + + &:hover + background: rgba(239, 68, 68, 0.5) + color: rgba(50, 50, 50, 1) + transform: translateY(-2px) + box-shadow: 0 8px 24px rgba(239, 68, 68, 0.2) + + // Special styling for pen tool in group + .pen-tool-group &:first-child + border-radius: 14px 0 0 14px + border-right: none + +.canvas-container + width: 100% + height: 100% + border-radius: 20px + background: rgba(255, 255, 255, 0.9) + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5) + overflow: hidden + +.drawing-canvas + width: 100% + height: 100% + cursor: crosshair + display: block + background: #ffffff + border-radius: 20px + + &.eraser-mode + cursor: url('data:image/svg+xml;utf8,') 10 10, auto + +// Responsive Design +@media (max-width: 768px) + .notes-page + padding: 1.5rem 0.5rem 0.5rem 0.5rem + + .notes-container + border-radius: 24px + padding: 1.25rem + + .canvas-container + border-radius: 16px + + .drawing-canvas + border-radius: 16px + + .notes-toolbar + bottom: 0.75rem + padding: 0.625rem 0.875rem + gap: 0.625rem + + .tool-button + width: 40px + height: 40px + font-size: 1rem + + .color-picker-button + width: 20px + height: 40px + + .color-option + width: 28px + height: 28px + +@media (max-width: 480px) + .notes-page + padding: 1rem 0.375rem 0.375rem 0.375rem + + .notes-container + border-radius: 20px + padding: 1rem + + .canvas-container + border-radius: 12px + + .drawing-canvas + border-radius: 12px + + .notes-toolbar + bottom: 0.5rem + padding: 0.5rem 0.75rem + gap: 0.5rem + border-radius: 14px + + .tool-button + width: 36px + height: 36px + border-radius: 12px + font-size: 0.875rem + + .color-picker-button + width: 18px + height: 36px + + .color-option + width: 24px + height: 24px + + .color-grid + grid-template-columns: repeat(4, 1fr) diff --git a/dashboard/src/renderer/src/pages/Search.jsx b/dashboard/src/renderer/src/pages/Search.jsx new file mode 100644 index 0000000..997d1c7 --- /dev/null +++ b/dashboard/src/renderer/src/pages/Search.jsx @@ -0,0 +1,20 @@ +import './Search.sass' + +const Search = () => { + return ( +
+
+
+