diff --git a/package-lock.json b/package-lock.json index bd1bebf..dd65c25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "@tiptap/starter-kit": "^2.5.9", "@transistorsoft/capacitor-background-fetch": "^6.0.1", "@types/chrome": "^0.0.263", + "@uiw/react-color": "^2.5.1", "adm-zip": "^0.5.16", "asmcrypto.js": "2.3.2", "axios": "^1.7.7", @@ -5900,6 +5901,399 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiw/color-convert": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.5.1.tgz", + "integrity": "sha512-p+P8Ho0Z1AbUprES0hcLEDAaXbGH92TmjckkRQZ5S7HcyQ+9ZXlSsDFILjFbYu/okVjx5VG59T57Dx84lv9AWA==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0" + } + }, + "node_modules/@uiw/react-color": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color/-/react-color-2.5.1.tgz", + "integrity": "sha512-u6Kj7rdhsMOls2KItpHLkG8WTghDS2jYBucLeOLLJXJDs25TuEBI9d1o939og8cUJtTwBrowWFFU63a1kGsciA==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1", + "@uiw/react-color-block": "2.5.1", + "@uiw/react-color-chrome": "2.5.1", + "@uiw/react-color-circle": "2.5.1", + "@uiw/react-color-colorful": "2.5.1", + "@uiw/react-color-compact": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-editable-input-hsla": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1", + "@uiw/react-color-github": "2.5.1", + "@uiw/react-color-hue": "2.5.1", + "@uiw/react-color-material": "2.5.1", + "@uiw/react-color-name": "2.5.1", + "@uiw/react-color-saturation": "2.5.1", + "@uiw/react-color-shade-slider": "2.5.1", + "@uiw/react-color-sketch": "2.5.1", + "@uiw/react-color-slider": "2.5.1", + "@uiw/react-color-swatch": "2.5.1", + "@uiw/react-color-wheel": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-alpha": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-alpha/-/react-color-alpha-2.5.1.tgz", + "integrity": "sha512-hPsIgsnuOQrqinXt3Gt+87fHudbUvvPW+TpvRY0HS9v4ptFu5UsCc/7DPTVKTaL+p+0oaA6eTbziLzPLRLzgsQ==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-drag-event-interactive": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-block": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-block/-/react-color-block-2.5.1.tgz", + "integrity": "sha512-qvubiV0z0P3OxpNt6o1UQ3CVsjVBY1/n/oz6Gzzxx9YPqSClI04AtFjwOQxF7M17SYqXv+88y77gfEfPIqk5+A==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-swatch": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-chrome": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-chrome/-/react-color-chrome-2.5.1.tgz", + "integrity": "sha512-m/CyRaWgmkW5aQTQ8AZwyvopYm+bhvX06uS+ezQjXDYDtjLvq7RbM0JLLNIOyMXke964R58fhoX4G06ZWd8ycA==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-editable-input-hsla": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1", + "@uiw/react-color-github": "2.5.1", + "@uiw/react-color-hue": "2.5.1", + "@uiw/react-color-saturation": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-circle": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-circle/-/react-color-circle-2.5.1.tgz", + "integrity": "sha512-+8zb/Ork1Q5f2bq0jN+GF7OyqY+2ZDYGrdZovN3EBZLMmERbg6TM2+1gTweeFsdiEM/gpteupJpwKpO1aBCocg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-swatch": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-colorful": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-colorful/-/react-color-colorful-2.5.1.tgz", + "integrity": "sha512-Y/8Y2Kman6IZQpgs4tPTGPuTNr3fJIJxf4f13jll6xuaOsVZeDq9q+DlMErggL+5ICtaBr8gG+w68nCiY+QqKg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1", + "@uiw/react-color-hue": "2.5.1", + "@uiw/react-color-saturation": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-compact": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-compact/-/react-color-compact-2.5.1.tgz", + "integrity": "sha512-5jHJcXEkjMwcghzCgSBU2rPMVjuuaJ7B6IxypNkafRQ4FkW/6bP9WpPkzcNXCZ/gPvSJ1OMQ+Y600mdO78qG5Q==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1", + "@uiw/react-color-swatch": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input/-/react-color-editable-input-2.5.1.tgz", + "integrity": "sha512-0kr5vQJGPln8LObXwfI2YLiHFz2DW3Atgi51JXlrZUyyaVujXRgMTAc1fz/1RQR6cU2A4bweFaCQljcTsv+Cdg==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input-hsla": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input-hsla/-/react-color-editable-input-hsla-2.5.1.tgz", + "integrity": "sha512-gmnXB6JrYFAd8VN/EfNDJaTdkFHAnUxjzcsQjQyOEr046jDjWgEc/5o2uE1LwIvoJNg9Lo6LYsr37LnFWwsiLw==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input-rgba": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input-rgba/-/react-color-editable-input-rgba-2.5.1.tgz", + "integrity": "sha512-rk6OxL9lTdRI45aNe3GbUghvaELk4knkEf0gvF/mPHxoeE+nNphSrO5gHm3HhoDOgaplp81VP3q4gUwcdjBzvw==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-github": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-github/-/react-color-github-2.5.1.tgz", + "integrity": "sha512-t05rIy2ifReiVnjv3x+IVlJH7wvwtZugMeouDa/1Y7jIGZswO0zw3zMxz7qfHrzf5NVYWjmEF8QCj85ngv9brg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-swatch": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-hue": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-hue/-/react-color-hue-2.5.1.tgz", + "integrity": "sha512-o7mjZhm+U4gHxaBXFxjPINeE3jWfiZAl7RUFqwn4PDZC8wvhU5hEKgJUvcXzErYro0ZYrE1fC/wUHRpI+vcEBg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-material": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-material/-/react-color-material-2.5.1.tgz", + "integrity": "sha512-iPB4YfKVTNO1lSIQ16DMdDurDKvGTjv6Qwi/nq47yE3nnhB0YbOFwb/IZbWBS1sCTPx1an7dM2IZ+hYoYcjrXg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-name": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-name/-/react-color-name-2.5.1.tgz", + "integrity": "sha512-JFb6DFz9kF2jI42MS/vtXZu1XzIrzcSIOqCwVkYWCQnSxOM9h+vd4pv2Yi1oy7IPgaadXUDkrGQSAvEkXU593Q==", + "dependencies": { + "colors-named": "^1.0.1", + "colors-named-hex": "^1.0.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0" + } + }, + "node_modules/@uiw/react-color-saturation": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-saturation/-/react-color-saturation-2.5.1.tgz", + "integrity": "sha512-mQ6eGmn6dUXfScQrb5tP0TBGCpZWzrQuYOAiwK9u31IJaxFwD1NNAzkiienWe4MQkA5zmgz7Ol6FEdLN8K+vGw==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-drag-event-interactive": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-shade-slider": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-shade-slider/-/react-color-shade-slider-2.5.1.tgz", + "integrity": "sha512-hrscAmqmy/Od/usUPETaEuvsNRhUGvNArl73d7HK6e6FjbRFPDBq40LkvjETe8BJMbxrBXTMo6dK7DO08lYq9g==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-sketch": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-sketch/-/react-color-sketch-2.5.1.tgz", + "integrity": "sha512-eQgAnlSZvqoTt6frZa/j+tFdaIBEFneIdxEUfidD8hwvyu5OR/WLHnDy/4fYAxhehDp9Ej8eS3ZsCgPACBMOtA==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1", + "@uiw/react-color-editable-input": "2.5.1", + "@uiw/react-color-editable-input-rgba": "2.5.1", + "@uiw/react-color-hue": "2.5.1", + "@uiw/react-color-saturation": "2.5.1", + "@uiw/react-color-swatch": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-slider": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-slider/-/react-color-slider-2.5.1.tgz", + "integrity": "sha512-2yluI0Akp6UMXTeAJ4CEjL8flhIFpn3xUPsFXbQmBSzMYJygleVFmwhMye8LSA2PCe3UdaqA2cWXxWsTL0FbIg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-color-alpha": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-swatch": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-swatch/-/react-color-swatch-2.5.1.tgz", + "integrity": "sha512-EQ7UEzxdohfsdpXmcEWNmK/uiznZovEKo6+j3OLrSU5pZGO7pxjR9sQMlscikvd8Mu1Mm3U0E6bJseo2acD4Lg==", + "dependencies": { + "@uiw/color-convert": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-wheel": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-wheel/-/react-color-wheel-2.5.1.tgz", + "integrity": "sha512-e3tDwDoC2T7zTapRRm/QxcOJ7IWJwNCoxZ/f97RL1Ib3gAN/k67H1bkR9TK7euRCUxGy031guxTgdKO9v19XFg==", + "dependencies": { + "@uiw/color-convert": "2.5.1", + "@uiw/react-drag-event-interactive": "2.5.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-drag-event-interactive": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@uiw/react-drag-event-interactive/-/react-drag-event-interactive-2.5.1.tgz", + "integrity": "sha512-GNxhxk5L4O5Gpi20A/BG5sO0GNBNwtNWJidJsJu3pgHUBErN4rhqTDXXu3BQTz5C8yOG5D02Y6Zq/6yu6ckImw==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -7774,6 +8168,28 @@ "color-support": "bin.js" } }, + "node_modules/colors-named": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/colors-named/-/colors-named-1.0.2.tgz", + "integrity": "sha512-2ANq2r393PV9njYUD66UdfBcxR1slMqRA3QRTWgCx49JoCJ+kOhyfbQYxKJbPZQIhZUcNjVOs5AlyY1WwXec3w==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/colors-named-hex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/colors-named-hex/-/colors-named-hex-1.0.2.tgz", + "integrity": "sha512-k6kq1e1pUCQvSVwIaGFq2l0LrkAPQZWyeuZn1Z8nOiYSEZiKoFj4qx690h2Kd34DFl9Me0gKS6MUwAMBJj8nuA==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", diff --git a/package.json b/package.json index 3c92ad4..3594023 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@tiptap/starter-kit": "^2.5.9", "@transistorsoft/capacitor-background-fetch": "^6.0.1", "@types/chrome": "^0.0.263", + "@uiw/react-color": "^2.5.1", "adm-zip": "^0.5.16", "asmcrypto.js": "2.3.2", "axios": "^1.7.7", diff --git a/src/App.tsx b/src/App.tsx index b3d11d0..d31f4d7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,14 +30,12 @@ import { CountdownCircleTimer } from 'react-countdown-circle-timer'; import Logo1Dark from './assets/svgs/Logo1Dark.svg'; import RefreshIcon from '@mui/icons-material/Refresh'; import DownloadIcon from '@mui/icons-material/Download'; -import Copy from './assets/svgs/Copy.svg'; import ltcLogo from './assets/ltc.png'; import PersonSearchIcon from '@mui/icons-material/PersonSearch'; import qortLogo from './assets/qort.png'; import { CopyToClipboard } from 'react-copy-to-clipboard'; import { Return } from './assets/Icons/Return.tsx'; import WarningIcon from '@mui/icons-material/Warning'; -import Success from './assets/svgs/Success.svg'; import './utils/seedPhrase/RandomSentenceGenerator'; import EngineeringIcon from '@mui/icons-material/Engineering'; import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet'; @@ -137,6 +135,8 @@ import ThemeSelector from './components/Theme/ThemeSelector.tsx'; import { useTranslation } from 'react-i18next'; import LanguageSelector from './components/Language/LanguageSelector.tsx'; import { DownloadWallet } from './components/Auth/DownloadWallet.tsx'; +import { CopyIcon } from './assets/Icons/CopyIcon.tsx'; +import { SuccessIcon } from './assets/Icons/SuccessIcon.tsx'; type extStates = | 'not-authenticated' @@ -1297,7 +1297,8 @@ function App() { {rawWallet?.ltcAddress?.slice(0, 6)}... - {rawWallet?.ltcAddress?.slice(-4)} + {rawWallet?.ltcAddress?.slice(-4)}{' '} + @@ -1362,7 +1363,8 @@ function App() { {rawWallet?.address0?.slice(0, 6)}... - {rawWallet?.address0?.slice(-4)} + {rawWallet?.address0?.slice(-4)}{' '} + @@ -1471,6 +1473,7 @@ function App() { sx={{ height: '100%', justifyContent: 'space-between', + borderLeft: `1px solid ${theme.palette.border.subtle}`, }} > - + @@ -1548,7 +1555,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1558,7 +1565,11 @@ function App() { }, }} > - + @@ -1588,7 +1599,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1598,7 +1609,11 @@ function App() { }, }} > - + @@ -1628,7 +1643,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1638,7 +1653,11 @@ function App() { }, }} > - + @@ -1665,7 +1684,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1680,7 +1699,10 @@ function App() { setIsOpenDrawerProfile(true); }} > - + @@ -1776,7 +1798,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1786,7 +1808,11 @@ function App() { }, }} > - + @@ -1821,7 +1847,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1831,7 +1857,11 @@ function App() { }, }} > - + )} @@ -1863,7 +1893,7 @@ function App() { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -1873,7 +1903,11 @@ function App() { }, }} > - + @@ -2164,10 +2198,10 @@ function App() { defaultChecked={messageQortalRequest?.checkbox1?.value} sx={{ '&.Mui-checked': { - color: 'white', // Customize the color when checked + color: theme.palette.text.secondary, // Customize the color when checked }, '& .MuiSvgIcon-root': { - color: 'white', + color: theme.palette.text.secondary, }, }} /> @@ -2897,7 +2931,7 @@ function App() { {walletToBeDownloaded && ( <> - + - + - + - + )} {showScrollDownButton && !showScrollButton && ( - + )} {enableMentions && (hasSecretKey || isPrivate === false) && ( diff --git a/src/components/Chat/ChatOptions.tsx b/src/components/Chat/ChatOptions.tsx index e95fa5b..4f92f53 100644 --- a/src/components/Chat/ChatOptions.tsx +++ b/src/components/Chat/ChatOptions.tsx @@ -24,7 +24,7 @@ import { AppsSearchLeft, AppsSearchRight, } from '../Apps/Apps-styles'; -import IconSearch from '../../assets/svgs/Search.svg'; + import IconClearInput from '../../assets/svgs/ClearInput.svg'; import { CellMeasurerCache } from 'react-virtualized'; import { getBaseApiReact } from '../../App'; @@ -358,14 +358,14 @@ export const ChatOptions = ({ return ( - + setSearchValue(e.target.value)} @@ -576,7 +580,7 @@ export const ChatOptions = ({ 0 && (!lastMentionTimestamp || lastMentionTimestamp < mentionList[0]?.timestamp) - ? 'var(--unread)' - : 'white', + ? theme.palette.other.unread + : theme.palette.text.primary, }} /> @@ -767,7 +771,6 @@ const ShowMessage = ({ message, goToMessage, messages }) => { sx={{ fontWight: 600, fontFamily: 'Inter', - color: 'cadetBlue', }} > {message?.senderName} diff --git a/src/components/Chat/GroupAnnouncements.tsx b/src/components/Chat/GroupAnnouncements.tsx index 7f22d76..71e1613 100644 --- a/src/components/Chat/GroupAnnouncements.tsx +++ b/src/components/Chat/GroupAnnouncements.tsx @@ -674,7 +674,7 @@ export const GroupAnnouncements = ({ }} style={{ alignSelf: 'center', - background: 'var(--danger)', + background: theme.palette.other.danger, cursor: isSending ? 'default' : 'pointer', flexShrink: 0, fontSize: '14px', diff --git a/src/components/Chat/MessageItem.tsx b/src/components/Chat/MessageItem.tsx index a40fca8..0b23e3f 100644 --- a/src/components/Chat/MessageItem.tsx +++ b/src/components/Chat/MessageItem.tsx @@ -248,7 +248,6 @@ export const MessageItem = React.memo( sx={{ fontWight: 600, fontFamily: 'Inter', - color: 'cadetBlue', }} > {message?.senderName || message?.sender} @@ -304,7 +303,7 @@ export const MessageItem = React.memo( { return ( { > { + const theme = useTheme(); const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useRecoilState( isDisabledEditorEnterAtom ); @@ -483,12 +484,16 @@ export default ({ }, []); return ( -
-
+
); }; diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 491e1f7..84df599 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -1,35 +1,46 @@ import React, { useState, useRef, useMemo, useEffect } from 'react'; -import { ListItemIcon, Menu, MenuItem, Typography, styled } from '@mui/material'; +import { + ListItemIcon, + Menu, + MenuItem, + Typography, + styled, + useTheme, +} from '@mui/material'; import MailOutlineIcon from '@mui/icons-material/MailOutline'; import NotificationsOffIcon from '@mui/icons-material/NotificationsOff'; import { executeEvent } from '../utils/events'; const CustomStyledMenu = styled(Menu)(({ theme }) => ({ - '& .MuiPaper-root': { - backgroundColor: '#f9f9f9', - borderRadius: '12px', - padding: theme.spacing(1), - boxShadow: '0 5px 15px rgba(0, 0, 0, 0.2)', + '& .MuiPaper-root': { + // backgroundColor: '#f9f9f9', + borderRadius: '12px', + padding: theme.spacing(1), + boxShadow: '0 5px 15px rgba(0, 0, 0, 0.2)', + }, + '& .MuiMenuItem-root': { + fontSize: '14px', // Smaller font size for the menu item text + // color: '#444', + transition: '0.3s background-color', + '&:hover': { + backgroundColor: theme.palette.action.hover, // Explicit hover state }, - '& .MuiMenuItem-root': { - fontSize: '14px', // Smaller font size for the menu item text - color: '#444', - transition: '0.3s background-color', - '&:hover': { - backgroundColor: '#f0f0f0', // Explicit hover state - }, - - }, - })); + }, +})); -export const ContextMenu = ({ children, groupId, getUserSettings, mutedGroups }) => { +export const ContextMenu = ({ + children, + groupId, + getUserSettings, + mutedGroups, +}) => { const [menuPosition, setMenuPosition] = useState(null); const longPressTimeout = useRef(null); const preventClick = useRef(false); // Flag to prevent click after long-press or right-click - - const isMuted = useMemo(()=> { - return mutedGroups.includes(groupId) - }, [mutedGroups, groupId]) + const theme = useTheme(); + const isMuted = useMemo(() => { + return mutedGroups.includes(groupId); + }, [mutedGroups, groupId]); // Handle right-click (context menu) for desktop const handleContextMenu = (event) => { @@ -67,56 +78,52 @@ export const ContextMenu = ({ children, groupId, getUserSettings, mutedGroups }) } }; - - - const handleSetGroupMute = ()=> { + const handleSetGroupMute = () => { try { - let value = [...mutedGroups] - if(isMuted){ - value = value.filter((group)=> group !== groupId) - } else { - value.push(groupId) - } - window.sendMessage("addUserSettings", { + let value = [...mutedGroups]; + if (isMuted) { + value = value.filter((group) => group !== groupId); + } else { + value.push(groupId); + } + window + .sendMessage('addUserSettings', { keyValue: { key: 'mutedGroups', value, }, }) - .then((response) => { - if (response?.error) { - console.error("Error adding user settings:", response.error); - } else { - console.log("User settings added successfully"); - } - }) - .catch((error) => { - console.error("Failed to add user settings:", error.message || "An error occurred"); - }); - - setTimeout(() => { - getUserSettings() - }, 400); + .then((response) => { + if (response?.error) { + console.error('Error adding user settings:', response.error); + } else { + console.log('User settings added successfully'); + } + }) + .catch((error) => { + console.error( + 'Failed to add user settings:', + error.message || 'An error occurred' + ); + }); - } catch (error) { - - } - } - - + setTimeout(() => { + getUserSettings(); + }, 400); + } catch (error) {} + }; const handleClose = (e) => { e.preventDefault(); - e.stopPropagation(); + e.stopPropagation(); setMenuPosition(null); }; return (
{children} @@ -131,35 +138,48 @@ export const ContextMenu = ({ children, groupId, getUserSettings, mutedGroups }) ? { top: menuPosition.mouseY, left: menuPosition.mouseX } : undefined } - onClick={(e)=> { - e.stopPropagation(); - }} + onClick={(e) => { + e.stopPropagation(); + }} > - { - handleClose(e) - executeEvent("markAsRead", { - groupId - }); - }}> + { + handleClose(e); + executeEvent('markAsRead', { + groupId, + }); + }} + > - + Mark As Read - { - - handleClose(e) - handleSetGroupMute() - - }}> + { + handleClose(e); + handleSetGroupMute(); + }} + > - + - + {isMuted ? 'Unmute ' : 'Mute '}Push Notifications @@ -167,5 +187,3 @@ export const ContextMenu = ({ children, groupId, getUserSettings, mutedGroups })
); }; - - diff --git a/src/components/ContextMenuPinnedApps.tsx b/src/components/ContextMenuPinnedApps.tsx index 7dad268..3e2c2be 100644 --- a/src/components/ContextMenuPinnedApps.tsx +++ b/src/components/ContextMenuPinnedApps.tsx @@ -5,6 +5,7 @@ import { MenuItem, Typography, styled, + useTheme, } from '@mui/material'; import PushPinIcon from '@mui/icons-material/PushPin'; import { saveToLocalStorage } from './Apps/AppsNavBarDesktop'; @@ -13,7 +14,6 @@ import { sortablePinnedAppsAtom } from '../atoms/global'; const CustomStyledMenu = styled(Menu)(({ theme }) => ({ '& .MuiPaper-root': { - backgroundColor: '#f9f9f9', borderRadius: '12px', padding: theme.spacing(1), boxShadow: '0 5px 15px rgba(0, 0, 0, 0.2)', @@ -23,7 +23,7 @@ const CustomStyledMenu = styled(Menu)(({ theme }) => ({ color: '#444', transition: '0.3s background-color', '&:hover': { - backgroundColor: '#f0f0f0', + backgroundColor: theme.palette.action.hover, }, }, })); @@ -37,6 +37,7 @@ export const ContextMenuPinnedApps = ({ children, app, isMine }) => { const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState( sortablePinnedAppsAtom ); + const theme = useTheme(); const handleContextMenu = (event) => { if (isMine) return; @@ -170,9 +171,14 @@ export const ContextMenuPinnedApps = ({ children, app, isMine }) => { }} > - + - + Unpin app diff --git a/src/components/Desktop/DesktopFooter.tsx b/src/components/Desktop/DesktopFooter.tsx index 47a8181..3bef9cc 100644 --- a/src/components/Desktop/DesktopFooter.tsx +++ b/src/components/Desktop/DesktopFooter.tsx @@ -122,7 +122,7 @@ export const DesktopFooter = ({ height={30} color={ hasUnreadGroups - ? 'var(--danger)' + ? theme.palette.other.danger : isGroups ? theme.palette.text.primary : theme.palette.text.secondary @@ -141,7 +141,7 @@ export const DesktopFooter = ({ height={30} color={ hasUnreadDirects - ? 'var(--danger)' + ? theme.palette.other.danger : isDirects ? theme.palette.text.primary : theme.palette.text.secondary diff --git a/src/components/Desktop/DesktopHeader.tsx b/src/components/Desktop/DesktopHeader.tsx index d04a803..0b6cff8 100644 --- a/src/components/Desktop/DesktopHeader.tsx +++ b/src/components/Desktop/DesktopHeader.tsx @@ -104,14 +104,14 @@ export const DesktopHeader = ({ {isPrivate && ( )} {isPrivate === false && ( )} @@ -155,7 +155,7 @@ export const DesktopHeader = ({ width={20} color={ isUnread - ? 'var(--unread)' + ? theme.palette.other.unread : isAnnouncement ? theme.palette.text.primary : theme.palette.text.secondary @@ -183,7 +183,7 @@ export const DesktopHeader = ({ width={20} color={ isUnreadChat - ? 'var(--unread)' + ? theme.palette.other.unread : isChat ? theme.palette.text.primary : theme.palette.text.secondary diff --git a/src/components/DesktopSideBar.tsx b/src/components/DesktopSideBar.tsx index 06e54e8..616a128 100644 --- a/src/components/DesktopSideBar.tsx +++ b/src/components/DesktopSideBar.tsx @@ -1,6 +1,5 @@ import { Box, ButtonBase, useTheme } from '@mui/material'; import { HomeIcon } from '../assets/Icons/HomeIcon'; -import { MessagingIcon } from '../assets/Icons/MessagingIcon'; import { Save } from './Save/Save'; import { IconWrapper } from './Desktop/DesktopFooter'; import { useRecoilState } from 'recoil'; @@ -9,6 +8,7 @@ import { AppsIcon } from '../assets/Icons/AppsIcon'; import ThemeSelector from './Theme/ThemeSelector'; import { CoreSyncStatus } from './CoreSyncStatus'; import LanguageSelector from './Language/LanguageSelector'; +import { MessagingIconFilled } from '../assets/Icons/MessagingIconFilled'; export const DesktopSideBar = ({ goToHome, @@ -40,6 +40,8 @@ export const DesktopSideBar = ({ gap: '25px', height: '100vh', width: '60px', + backgroundColor: theme.palette.background.surface, + borderRight: `1px solid ${theme.palette.border.subtle}`, }} > - { + resourceData, + resourceDetails, + owner, + refresh, + openExternal, + external, + isLoadingParent, + errorMsg, + encryptionType, + selectedGroupId, +}) => { + const [isOpen, setIsOpen] = useState(true); + const { downloadResource } = useContext(MyContext); + const theme = useTheme(); - const [isOpen, setIsOpen] = useState(true); - const { downloadResource } = useContext(MyContext); - - const saveToDisk = async ()=> { - const { name, service, identifier } = resourceData; - - const url = `${getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}`; - fetch(url) - .then(response => response.blob()) - .then(async blob => { - await saveFileToDiskGeneric(blob, resourceData?.fileName) - }) - .catch(error => { - console.error("Error fetching the video:", error); - }); - } - - const saveToDiskEncrypted = async ()=> { - let blobUrl + const saveToDisk = async () => { + const { name, service, identifier } = resourceData; + + const url = `${getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}`; + fetch(url) + .then((response) => response.blob()) + .then(async (blob) => { + await saveFileToDiskGeneric(blob, resourceData?.fileName); + }) + .catch((error) => { + console.error('Error fetching the video:', error); + }); + }; + + const saveToDiskEncrypted = async () => { + let blobUrl; + try { + const { name, service, identifier, key } = resourceData; + + const url = `${getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}?encoding=base64`; + const res = await fetch(url); + const data = await res.text(); + let decryptedData; try { - const { name, service, identifier,key } = resourceData; - - const url = `${getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}?encoding=base64`; - const res = await fetch(url) - const data = await res.text(); - let decryptedData - try { - if(key && encryptionType === 'private'){ - decryptedData = await window.sendMessage( - "DECRYPT_DATA_WITH_SHARING_KEY", - - { - encryptedData: data, - key: decodeURIComponent(key), - } - - ); - } - if(encryptionType === 'group'){ - decryptedData = await window.sendMessage( - "DECRYPT_QORTAL_GROUP_DATA", - - { - data64: data, - groupId: selectedGroupId, - } - - ); - } - } catch (error) { - throw new Error('Unable to decrypt') + if (key && encryptionType === 'private') { + decryptedData = await window.sendMessage( + 'DECRYPT_DATA_WITH_SHARING_KEY', + + { + encryptedData: data, + key: decodeURIComponent(key), + } + ); + } + if (encryptionType === 'group') { + decryptedData = await window.sendMessage( + 'DECRYPT_QORTAL_GROUP_DATA', + + { + data64: data, + groupId: selectedGroupId, + } + ); } - - if (!decryptedData || decryptedData?.error) throw new Error("Could not decrypt data"); - blobUrl = base64ToBlobUrl(decryptedData, resourceData?.mimeType) - const response = await fetch(blobUrl); - const blob = await response.blob(); - await saveFileToDiskGeneric(blob, resourceData?.fileName) - } catch (error) { - console.error(error) - } finally { - if(blobUrl){ - URL.revokeObjectURL(blobUrl); - } - + throw new Error('Unable to decrypt'); + } + + if (!decryptedData || decryptedData?.error) + throw new Error('Could not decrypt data'); + blobUrl = base64ToBlobUrl(decryptedData, resourceData?.mimeType); + const response = await fetch(blobUrl); + const blob = await response.blob(); + await saveFileToDiskGeneric(blob, resourceData?.fileName); + } catch (error) { + console.error(error); + } finally { + if (blobUrl) { + URL.revokeObjectURL(blobUrl); } } - return ( - + - - + ATTACHMENT embed + + + + - ATTACHMENT embed - - + + {external && ( - - {external && ( - - - - )} -
-
- - - Created by {decodeIfEncoded(owner)} - - - {encryptionType === 'private' ? "ENCRYPTED" : encryptionType === 'group' ? 'GROUP ENCRYPTED' : "Not encrypted"} - - - - - - - {isLoadingParent && isOpen && ( - - {" "} - {" "} - )} - {errorMsg && ( - + + + + Created by {decodeIfEncoded(owner)} + + + {encryptionType === 'private' + ? 'ENCRYPTED' + : encryptionType === 'group' + ? 'GROUP ENCRYPTED' + : 'Not encrypted'} + + + + + {isLoadingParent && isOpen && ( + + {' '} + {' '} + + )} + {errorMsg && ( + + {' '} + - {" "} + {errorMsg} + {' '} + + )} + + + + + {resourceData?.fileName && ( + <> - {errorMsg} - {" "} - + {resourceData?.fileName} + + + )} - - - - - {resourceData?.fileName && ( + { + if (resourceDetails?.status?.status === 'READY') { + if (encryptionType) { + saveToDiskEncrypted(); + return; + } + saveToDisk(); + return; + } + downloadResource(resourceData); + }} + > + + + {resourceDetails?.status?.status === 'DOWNLOADED' + ? 'BUILDING' + : resourceDetails?.status?.status} + + {!resourceDetails && ( <> - {resourceData?.fileName} - + + Download File )} - { - if(resourceDetails?.status?.status === 'READY'){ - if(encryptionType){ - saveToDiskEncrypted() - return - } - saveToDisk() - return - } - downloadResource(resourceData) - }}> - - - {resourceDetails?.status?.status === 'DOWNLOADED' ? 'BUILDING' : resourceDetails?.status?.status} - {!resourceDetails && ( - <> - - Download File - - - )} - {resourceDetails && resourceDetails?.status?.status !== 'READY' && resourceDetails?.status?.status !== 'FAILED_TO_DOWNLOAD' && ( - <> - - Downloading: {resourceDetails?.status?.percentLoaded || '0'}% - - - )} - {resourceDetails && resourceDetails?.status?.status === 'READY' && ( - <> - - Save to Disk - - - )} - - - - - - - - - ); - }; \ No newline at end of file + {resourceDetails && + resourceDetails?.status?.status !== 'READY' && + resourceDetails?.status?.status !== 'FAILED_TO_DOWNLOAD' && ( + <> + + + Downloading:{' '} + {resourceDetails?.status?.percentLoaded || '0'}% + + + )} + {resourceDetails && + resourceDetails?.status?.status === 'READY' && ( + <> + + Save to Disk + + )} + + + +
+ + ); +}; diff --git a/src/components/Embeds/ImageEmbed.tsx b/src/components/Embeds/ImageEmbed.tsx index f1cc859..ec25e25 100644 --- a/src/components/Embeds/ImageEmbed.tsx +++ b/src/components/Embeds/ImageEmbed.tsx @@ -1,265 +1,266 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState } from 'react'; import { Card, CardContent, Typography, - Box, ButtonBase, Divider, Dialog, IconButton, + useTheme, +} from '@mui/material'; -} from "@mui/material"; - -import RefreshIcon from "@mui/icons-material/Refresh"; -import OpenInNewIcon from "@mui/icons-material/OpenInNew"; -import { CustomLoader } from "../../common/CustomLoader"; -import ImageIcon from "@mui/icons-material/Image"; -import CloseIcon from "@mui/icons-material/Close"; -import { decodeIfEncoded } from "../../utils/decode"; +import RefreshIcon from '@mui/icons-material/Refresh'; +import OpenInNewIcon from '@mui/icons-material/OpenInNew'; +import { CustomLoader } from '../../common/CustomLoader'; +import ImageIcon from '@mui/icons-material/Image'; +import CloseIcon from '@mui/icons-material/Close'; +import { decodeIfEncoded } from '../../utils/decode'; export const ImageCard = ({ - image, - fetchImage, - owner, - refresh, - openExternal, - external, - isLoadingParent, - errorMsg, - encryptionType, - }) => { - const [isOpen, setIsOpen] = useState(true); - const [height, setHeight] = useState('400px') - useEffect(() => { - if (isOpen) { - fetchImage(); - } - }, [isOpen]); - - // useEffect(()=> { - // if(errorMsg){ - // setHeight('300px') - // } - // }, [errorMsg]) - - return ( - { + const theme = useTheme(); + const [isOpen, setIsOpen] = useState(true); + const [height, setHeight] = useState('400px'); + useEffect(() => { + if (isOpen) { + fetchImage(); + } + }, [isOpen]); + + // useEffect(()=> { + // if(errorMsg){ + // setHeight('300px') + // } + // }, [errorMsg]) + + return ( + + - - + IMAGE embed + + + + - IMAGE embed - - + + {external && ( - - {external && ( - - - - )} + )} + + + + + Created by {decodeIfEncoded(owner)} + + + {encryptionType === 'private' + ? 'ENCRYPTED' + : encryptionType === 'group' + ? 'GROUP ENCRYPTED' + : 'Not encrypted'} + + + + + {isLoadingParent && isOpen && ( + + {' '} + {' '} - - - - Created by {decodeIfEncoded(owner)} - - - {encryptionType === 'private' ? "ENCRYPTED" : encryptionType === 'group' ? 'GROUP ENCRYPTED' : "Not encrypted"} - - - - - - {isLoadingParent && isOpen && ( - - {" "} - {" "} - - )} - {errorMsg && ( - - {" "} - - {errorMsg} - {" "} - - )} - - - - - - - - - ); - }; + {errorMsg} + {' '} +
+ )} +
- export function ImageViewer({ src, alt = "" }) { - const [isFullscreen, setIsFullscreen] = useState(false); - - const handleOpenFullscreen = () => setIsFullscreen(true); - const handleCloseFullscreen = () => setIsFullscreen(false); - - return ( - <> - {/* Image in container */} + + + + + + + ); +}; + +export function ImageViewer({ src, alt = '' }) { + const [isFullscreen, setIsFullscreen] = useState(false); + + const handleOpenFullscreen = () => setIsFullscreen(true); + const handleCloseFullscreen = () => setIsFullscreen(false); + const theme = useTheme(); + return ( + <> + {/* Image in container */} + + {alt} + + + {/* Fullscreen Viewer */} + + {/* Close Button */} + + + + + {/* Fullscreen Image */} {alt} - - {/* Fullscreen Viewer */} - - - {/* Close Button */} - - - - - {/* Fullscreen Image */} - {alt} - - - - ); - } \ No newline at end of file + + + ); +} diff --git a/src/components/Embeds/PollEmbed.tsx b/src/components/Embeds/PollEmbed.tsx index 65e5983..8ca2fd4 100644 --- a/src/components/Embeds/PollEmbed.tsx +++ b/src/components/Embeds/PollEmbed.tsx @@ -12,6 +12,7 @@ import { Box, ButtonBase, Divider, + useTheme, } from '@mui/material'; import { getNameInfo } from '../Group/Group'; import PollIcon from '@mui/icons-material/Poll'; @@ -37,6 +38,7 @@ export const PollCard = ({ const [isOpen, setIsOpen] = useState(false); const { show, userInfo } = useContext(MyContext); const [isLoadingSubmit, setIsLoadingSubmit] = useState(false); + const theme = useTheme(); const handleVote = async () => { const fee = await getFee('VOTE_ON_POLL'); @@ -103,7 +105,7 @@ export const PollCard = ({ return ( @@ -124,7 +126,7 @@ export const PollCard = ({ > POLL embed @@ -141,7 +143,7 @@ export const PollCard = ({ onClick={refresh} sx={{ fontSize: '24px', - color: 'white', + color: theme.palette.text.primary, }} /> @@ -151,7 +153,7 @@ export const PollCard = ({ onClick={openExternal} sx={{ fontSize: '24px', - color: 'white', + color: theme.palette.text.primary, }} /> @@ -186,9 +188,6 @@ export const PollCard = ({ - - - { - goToChat(); - handleClose(); - }} - > - - - - - - { - goToAnnouncements(); - handleClose(); - }} - > - - - - - - { - setGroupSection('forum'); - handleClose(); - }} - > - - - - - - { - setOpenManageMembers(true); - handleClose(); - }} - > - - - - - - -
- ); -}; diff --git a/src/components/Group/HomeDesktop.tsx b/src/components/Group/HomeDesktop.tsx index d0f2459..83f8828 100644 --- a/src/components/Group/HomeDesktop.tsx +++ b/src/components/Group/HomeDesktop.tsx @@ -242,27 +242,6 @@ export const HomeDesktop = ({ )}
- - - {/* - - */} -
); diff --git a/src/components/Group/ListOfGroupPromotions.tsx b/src/components/Group/ListOfGroupPromotions.tsx index 35ac442..598f828 100644 --- a/src/components/Group/ListOfGroupPromotions.tsx +++ b/src/components/Group/ListOfGroupPromotions.tsx @@ -21,6 +21,7 @@ import { Select, TextField, Typography, + useTheme, } from '@mui/material'; import { LoadingButton } from '@mui/lab'; import LockIcon from '@mui/icons-material/Lock'; @@ -47,6 +48,7 @@ import { useVirtualizer } from '@tanstack/react-virtual'; import ErrorBoundary from '../../common/ErrorBoundary'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import { getFee } from '../../background'; export const requestQueuePromos = new RequestQueueWithPromise(20); export function utf8ToBase64(inputString: string): string { @@ -90,7 +92,7 @@ export const ListOfGroupPromotions = () => { const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false); const [isLoadingPublish, setIsLoadingPublish] = useState(false); const { show, setTxList } = useContext(MyContext); - + const theme = useTheme(); const listRef = useRef(); const rowVirtualizer = useVirtualizer({ count: promotions.length, @@ -673,7 +675,7 @@ export const ListOfGroupPromotions = () => { { sx={{ fontWight: 600, fontFamily: 'Inter', - color: 'cadetBlue', }} > {promotion?.name} @@ -698,7 +699,6 @@ export const ListOfGroupPromotions = () => { sx={{ fontWight: 600, fontFamily: 'Inter', - color: 'cadetBlue', }} > {promotion?.groupName} @@ -717,14 +717,14 @@ export const ListOfGroupPromotions = () => { {promotion?.isOpen === false && ( )} {promotion?.isOpen === true && ( )} @@ -746,7 +746,6 @@ export const ListOfGroupPromotions = () => { sx={{ fontWight: 600, fontFamily: 'Inter', - color: 'cadetBlue', }} > {promotion?.data} @@ -768,7 +767,7 @@ export const ListOfGroupPromotions = () => { } sx={{ fontSize: '12px', - color: 'white', + color: theme.palette.text.primary, }} > Join Group: {` ${promotion?.groupName}`} @@ -848,10 +847,10 @@ export const ListOfGroupPromotions = () => { multiline={true} sx={{ '& .MuiFormLabel-root': { - color: 'white', + color: theme.palette.text.primary, }, '& .MuiFormLabel-root.Mui-focused': { - color: 'white', + color: theme.palette.text.primary, }, }} /> diff --git a/src/components/Group/ListOfMembers.tsx b/src/components/Group/ListOfMembers.tsx index 0f227f8..fb45945 100644 --- a/src/components/Group/ListOfMembers.tsx +++ b/src/components/Group/ListOfMembers.tsx @@ -7,6 +7,7 @@ import { ListItemText, Popover, Typography, + useTheme, } from '@mui/material'; import { useRef, useState } from 'react'; import { @@ -39,7 +40,7 @@ const ListOfMembers = ({ const [isLoadingBan, setIsLoadingBan] = useState(false); const [isLoadingMakeAdmin, setIsLoadingMakeAdmin] = useState(false); const [isLoadingRemoveAdmin, setIsLoadingRemoveAdmin] = useState(false); - + const theme = useTheme(); const listRef = useRef(); const handlePopoverOpen = (event, index) => { @@ -354,7 +355,7 @@ const ListOfMembers = ({ {member?.isAdmin && ( diff --git a/src/components/Group/ManageMembers.tsx b/src/components/Group/ManageMembers.tsx index 05d30aa..eba8de3 100644 --- a/src/components/Group/ManageMembers.tsx +++ b/src/components/Group/ManageMembers.tsx @@ -13,7 +13,7 @@ import { InviteMember } from './InviteMember'; import { ListOfInvites } from './ListOfInvites'; import { ListOfBans } from './ListOfBans'; import { ListOfJoinRequests } from './ListOfJoinRequests'; -import { Box, ButtonBase, Card, Tab, Tabs } from '@mui/material'; +import { Box, ButtonBase, Card, Tab, Tabs, useTheme } from '@mui/material'; import { CustomizedSnackbars } from '../Snackbar/Snackbar'; import { MyContext, getBaseApiReact } from '../../App'; import { getGroupMembers, getNames } from './Group'; @@ -60,6 +60,7 @@ export const ManageMembers = ({ const handleChange = (event: React.SyntheticEvent, newValue: number) => { setValue(newValue); }; + const theme = useTheme(); const { show, setTxList } = React.useContext(MyContext); const handleClose = () => { @@ -172,9 +173,14 @@ export const ManageMembers = ({ onClose={handleClose} TransitionComponent={Transition} > - + - + Manage Members { {isExpanded ? ( @@ -165,7 +167,9 @@ export const QMailMessages = ({ userName, userAddress }) => { ) : ( @@ -262,26 +266,26 @@ export const QMailMessages = ({ userName, userAddress }) => { isLessThanOneWeekOld(mail?.created) ? ( ) : !lastEnteredTimestamp ? ( ) : lastEnteredTimestamp < mail?.created && isLessThanOneWeekOld(mail?.created) ? ( ) : ( )} diff --git a/src/components/Group/Settings.tsx b/src/components/Group/Settings.tsx index 4af646b..3ac9a2e 100644 --- a/src/components/Group/Settings.tsx +++ b/src/components/Group/Settings.tsx @@ -1,4 +1,12 @@ -import { forwardRef, Fragment, ReactElement, Ref, useEffect } from 'react'; +import { + ChangeEvent, + forwardRef, + Fragment, + ReactElement, + Ref, + useEffect, + useState, +} from 'react'; import Dialog from '@mui/material/Dialog'; import AppBar from '@mui/material/AppBar'; import Toolbar from '@mui/material/Toolbar'; @@ -10,6 +18,7 @@ import { TransitionProps } from '@mui/material/transitions'; import { Box, FormControlLabel, Switch, styled, useTheme } from '@mui/material'; import { enabledDevModeAtom } from '../../atoms/global'; import { useRecoilState } from 'recoil'; +import ThemeManager from '../Theme/ThemeManager'; const LocalNodeSwitch = styled(Switch)(({ theme }) => ({ padding: 8, @@ -54,12 +63,12 @@ const Transition = forwardRef(function Transition( }); export const Settings = ({ address, open, setOpen }) => { - const [checked, setChecked] = React.useState(false); + const [checked, setChecked] = useState(false); const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom); const theme = useTheme(); - const handleChange = (event: React.ChangeEvent) => { + const handleChange = (event: ChangeEvent) => { setChecked(event.target.checked); window .sendMessage('addUserSettings', { @@ -123,9 +132,7 @@ export const Settings = ({ address, open, setOpen }) => { onClose={handleClose} TransitionComponent={Transition} > - + General Settings @@ -144,7 +151,6 @@ export const Settings = ({ address, open, setOpen }) => { { /> {window?.electronAPI && ( { label="Enable dev mode" /> )} + diff --git a/src/components/Group/UserListOfInvites.tsx b/src/components/Group/UserListOfInvites.tsx index 58efd9a..c6bb8d3 100644 --- a/src/components/Group/UserListOfInvites.tsx +++ b/src/components/Group/UserListOfInvites.tsx @@ -5,6 +5,7 @@ import { ListItemText, Popover, Typography, + useTheme, } from '@mui/material'; import { useContext, useEffect, useRef, useState } from 'react'; import { @@ -54,7 +55,7 @@ export const UserListOfInvites = ({ const { txList, setTxList, show } = useContext(MyContext); const [invites, setInvites] = useState([]); const [isLoading, setIsLoading] = useState(false); - + const theme = useTheme(); const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open const listRef = useRef(); @@ -205,14 +206,14 @@ export const UserListOfInvites = ({ {invite?.isOpen === false && ( )} {invite?.isOpen === true && ( )} diff --git a/src/components/Group/WalletsAppWrapper.tsx b/src/components/Group/WalletsAppWrapper.tsx index c569425..82e6660 100644 --- a/src/components/Group/WalletsAppWrapper.tsx +++ b/src/components/Group/WalletsAppWrapper.tsx @@ -1,4 +1,4 @@ -import { Box, ButtonBase, Divider, Typography } from '@mui/material'; +import { Box, ButtonBase, Divider, Typography, useTheme } from '@mui/material'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import CloseIcon from '@mui/icons-material/Close'; import AppViewerContainer from '../Apps/AppViewerContainer'; @@ -25,7 +25,7 @@ export const WalletsAppWrapper = () => { service: 'APP', path: 'qortal?authOnMount=true', }); - + const theme = useTheme(); const isDisableBackButton = useMemo(() => { if (selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false; @@ -62,7 +62,7 @@ export const WalletsAppWrapper = () => { position: 'fixed', height: '100vh', width: '100vw', - backgroundColor: '#27282c', // TODO: set color theme + backgroundColor: theme.palette.background.paper, // TODO: set color theme zIndex: 100, bottom: 0, right: 0, @@ -92,7 +92,7 @@ export const WalletsAppWrapper = () => { diff --git a/src/components/Home/QortPrice.tsx b/src/components/Home/QortPrice.tsx index 2f118c1..ec74b11 100644 --- a/src/components/Home/QortPrice.tsx +++ b/src/components/Home/QortPrice.tsx @@ -116,7 +116,7 @@ export const QortPrice = () => { > + Based on the latest 20 trades } @@ -127,7 +127,7 @@ export const QortPrice = () => { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -156,7 +156,7 @@ export const QortPrice = () => { {!ltcPerQort ? ( - + ) : ( { {!supply ? ( - + ) : ( { + {lastBlock?.timestamp && formatDate(lastBlock?.timestamp)} } @@ -211,7 +211,7 @@ export const QortPrice = () => { tooltip: { sx: { color: theme.palette.text.primary, - backgroundColor: theme.palette.background.default, + backgroundColor: theme.palette.background.paper, }, }, arrow: { @@ -240,7 +240,7 @@ export const QortPrice = () => { {!lastBlock?.height ? ( - + ) : ( { + const theme = useTheme(); return ( diff --git a/src/components/Minting/Minting.tsx b/src/components/Minting/Minting.tsx index 4c98fa1..552d39c 100644 --- a/src/components/Minting/Minting.tsx +++ b/src/components/Minting/Minting.tsx @@ -638,14 +638,14 @@ export const Minting = ({ }} disabled={mintingAccounts?.length > 1} sx={{ - backgroundColor: 'var(--green)', + backgroundColor: theme.palette.other.positive, color: 'black', fontWeight: 'bold', opacity: 0.7, maxWidth: '90%', width: '200px', '&:hover': { - backgroundColor: 'var(--green)', + backgroundColor: theme.palette.other.positive, color: 'black', opacity: 1, }, @@ -702,14 +702,14 @@ export const Minting = ({ - - - - ) -} + + + + + + + ); +}; diff --git a/src/components/Save/Save.tsx b/src/components/Save/Save.tsx index 413b9a5..a19efd2 100644 --- a/src/components/Save/Save.tsx +++ b/src/components/Save/Save.tsx @@ -321,12 +321,12 @@ export const Save = ({ isDesktop, disableWidth, myName }) => { }} variant="contained" sx={{ - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', fontWeight: 'bold', opacity: 0.7, '&:hover': { - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', opacity: 1, }, @@ -393,12 +393,12 @@ export const Save = ({ isDesktop, disableWidth, myName }) => { { onClick={revertChanges} variant="contained" sx={{ - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', fontWeight: 'bold', opacity: 0.7, '&:hover': { - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', opacity: 1, }, @@ -503,12 +503,12 @@ export const Save = ({ isDesktop, disableWidth, myName }) => { onClick={saveToQdn} variant="contained" sx={{ - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', fontWeight: 'bold', opacity: 0.7, '&:hover': { - backgroundColor: 'var(--danger)', + backgroundColor: theme.palette.other.danger, color: 'black', opacity: 1, }, diff --git a/src/components/Theme/ThemeContext.tsx b/src/components/Theme/ThemeContext.tsx index d2e7048..0f24b4a 100644 --- a/src/components/Theme/ThemeContext.tsx +++ b/src/components/Theme/ThemeContext.tsx @@ -6,57 +6,129 @@ import { useEffect, useCallback, } from 'react'; -import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles'; -import { darkTheme } from '../../styles/theme-dark'; -import { lightTheme } from '../../styles/theme-light'; +import { + ThemeProvider as MuiThemeProvider, + createTheme, +} from '@mui/material/styles'; +import { lightThemeOptions } from '../../styles/theme-light'; +import { darkThemeOptions } from '../../styles/theme-dark'; + +const defaultTheme = { + id: 'default', + name: 'Default Theme', + light: lightThemeOptions.palette, + dark: darkThemeOptions.palette, +}; const ThemeContext = createContext({ themeMode: 'light', toggleTheme: () => {}, + userThemes: [defaultTheme], + addUserTheme: (themes) => {}, + setUserTheme: (theme) => {}, + currentThemeId: 'default', }); -export const ThemeProvider = ({ children }: { children: React.ReactNode }) => { +export const ThemeProvider = ({ children }) => { const [themeMode, setThemeMode] = useState('light'); + const [userThemes, setUserThemes] = useState([defaultTheme]); + const [currentThemeId, setCurrentThemeId] = useState('default'); - const theme = useMemo( - () => (themeMode === 'light' ? lightTheme : darkTheme), - [themeMode] - ); + const currentTheme = + userThemes.find((theme) => theme.id === currentThemeId) || defaultTheme; + + const muiTheme = useMemo(() => { + if (themeMode === 'light') { + return createTheme({ + ...lightThemeOptions, + palette: { + ...currentTheme.light, + }, + }); + } else { + return createTheme({ + ...lightThemeOptions, + palette: { + ...currentTheme.dark, + }, + }); + } + }, [themeMode, currentTheme]); + + const saveSettings = ( + themes = userThemes, + mode = themeMode, + themeId = currentThemeId + ) => { + localStorage.setItem( + 'saved_ui_theme', + JSON.stringify({ + mode, + userThemes: themes, + currentThemeId: themeId, + }) + ); + }; const toggleTheme = () => { - setThemeMode((prevMode) => { - const newMode = prevMode === 'light' ? 'dark' : 'light'; - - const themeProperties = { - mode: newMode, - }; - - localStorage.setItem('saved_ui_theme', JSON.stringify(themeProperties)); - + setThemeMode((prev) => { + const newMode = prev === 'light' ? 'dark' : 'light'; + saveSettings(userThemes, newMode, currentThemeId); return newMode; }); }; - const getSavedTheme = useCallback(async () => { - try { - const themeProperties = JSON.parse( - localStorage.getItem(`saved_ui_theme`) || '{}' - ); + const addUserTheme = (themes) => { + setUserThemes(themes); + saveSettings(themes); + }; - const theme = themeProperties?.mode || 'light'; - setThemeMode(theme); - } catch (error) { - console.log('error', error); + const setUserTheme = (theme) => { + if (theme.id === 'default') { + setCurrentThemeId('default'); + saveSettings(userThemes, themeMode, 'default'); + } else { + setCurrentThemeId(theme.id); + saveSettings(userThemes, themeMode, theme.id); + } + }; + + const loadSettings = useCallback(() => { + const saved = localStorage.getItem('saved_ui_theme'); + if (saved) { + try { + const parsed = JSON.parse(saved); + if (parsed.mode === 'light' || parsed.mode === 'dark') + setThemeMode(parsed.mode); + if (Array.isArray(parsed.userThemes)) { + const filteredThemes = parsed.userThemes.filter( + (theme) => theme.id !== 'default' + ); + setUserThemes([defaultTheme, ...filteredThemes]); + } + if (parsed.currentThemeId) setCurrentThemeId(parsed.currentThemeId); + } catch (error) { + console.error('Failed to parse saved_ui_theme:', error); + } } }, []); useEffect(() => { - getSavedTheme(); - }, [getSavedTheme]); + loadSettings(); + }, [loadSettings]); return ( - - {children} + + {children} ); }; diff --git a/src/components/Theme/ThemeManager.tsx b/src/components/Theme/ThemeManager.tsx new file mode 100644 index 0000000..eca0e9f --- /dev/null +++ b/src/components/Theme/ThemeManager.tsx @@ -0,0 +1,403 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { + Box, + Button, + IconButton, + Typography, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + List, + ListItemText, + ListItemSecondaryAction, + TextField, + Tabs, + Tab, + ListItemButton, +} from '@mui/material'; +import { Sketch } from '@uiw/react-color'; +import DeleteIcon from '@mui/icons-material/Delete'; +import EditIcon from '@mui/icons-material/Edit'; +import AddIcon from '@mui/icons-material/Add'; +import CheckIcon from '@mui/icons-material/Check'; +import { useThemeContext } from './ThemeContext'; +import { darkThemeOptions } from '../../styles/theme-dark'; +import { lightThemeOptions } from '../../styles/theme-light'; +import ShortUniqueId from 'short-unique-id'; +import { rgbStringToHsva, rgbaStringToHsva } from '@uiw/color-convert'; +import FileDownloadIcon from '@mui/icons-material/FileDownload'; +import { saveFileToDiskGeneric } from '../../utils/generateWallet/generateWallet'; +import { handleImportClick } from '../../utils/fileReading'; +const uid = new ShortUniqueId({ length: 8 }); + +function detectColorFormat(color) { + if (typeof color !== 'string') return null; + if (color.startsWith('rgba')) return 'rgba'; + if (color.startsWith('rgb')) return 'rgb'; + return null; +} + +const validateTheme = (theme) => { + if (typeof theme !== 'object' || !theme) return false; + if (typeof theme.name !== 'string') return false; + if (!theme.light || typeof theme.light !== 'object') return false; + if (!theme.dark || typeof theme.dark !== 'object') return false; + + // Optional: deeper checks on structure + const requiredKeys = [ + 'primary', + 'secondary', + 'background', + 'text', + 'border', + 'other', + ]; + + for (const mode of ['light', 'dark']) { + const modeTheme = theme[mode]; + if (modeTheme.mode !== mode) return false; + + for (const key of requiredKeys) { + if (!modeTheme[key] || typeof modeTheme[key] !== 'object') { + return false; + } + } + } + + return true; +}; + +export default function ThemeManager() { + const { userThemes, addUserTheme, setUserTheme, currentThemeId } = + useThemeContext(); + const [openEditor, setOpenEditor] = useState(false); + const [themeDraft, setThemeDraft] = useState({ + id: '', + name: '', + light: {}, + dark: {}, + }); + const [currentTab, setCurrentTab] = useState('light'); + const nameInputRef = useRef(null); + + useEffect(() => { + if (openEditor && nameInputRef.current) { + nameInputRef.current.focus(); + } + }, [openEditor]); + + const handleAddTheme = () => { + setThemeDraft({ + id: '', + name: '', + light: structuredClone(lightThemeOptions.palette), + dark: structuredClone(darkThemeOptions.palette), + }); + setOpenEditor(true); + }; + + const handleEditTheme = (themeId) => { + const themeToEdit = userThemes.find((theme) => theme.id === themeId); + if (themeToEdit) { + setThemeDraft({ ...themeToEdit }); + setOpenEditor(true); + } + }; + + const handleSaveTheme = () => { + if (themeDraft.id) { + const updatedThemes = [...userThemes]; + const index = updatedThemes.findIndex( + (theme) => theme.id === themeDraft.id + ); + if (index !== -1) { + updatedThemes[index] = themeDraft; + addUserTheme(updatedThemes); + } + } else { + const newTheme = { ...themeDraft, id: uid.rnd() }; + const updatedThemes = [...userThemes, newTheme]; + addUserTheme(updatedThemes); + setUserTheme(newTheme); + } + setOpenEditor(false); + }; + + const handleDeleteTheme = (id) => { + const updatedThemes = userThemes.filter((theme) => theme.id !== id); + addUserTheme(updatedThemes); + + if (id === currentThemeId) { + // Find the default theme object in the list + const defaultTheme = updatedThemes.find( + (theme) => theme.id === 'default' + ); + + if (defaultTheme) { + setUserTheme(defaultTheme); + } else { + // Emergency fallback + setUserTheme({ + light: lightThemeOptions, + dark: darkThemeOptions, + }); + } + } + }; + + const handleApplyTheme = (theme) => { + setUserTheme(theme); + }; + + const handleColorChange = (mode, fieldPath, color) => { + setThemeDraft((prev) => { + const updated = { ...prev }; + const paths = fieldPath.split('.'); + updated[mode][paths[0]][paths[1]] = color.hex; + return updated; + }); + }; + + const renderColorPicker = (mode, label, fieldPath, currentValue) => { + let color = currentValue || '#ffffff'; + const format = detectColorFormat(currentValue); + if (format === 'rgba') { + color = rgbaStringToHsva(currentValue); + } else if (format === 'rgb') { + color = rgbStringToHsva(currentValue); + } + return ( + + + {label} + + handleColorChange(mode, fieldPath, color)} + /> + + ); + }; + + const exportTheme = async (theme) => { + try { + const copyTheme = structuredClone(theme); + delete copyTheme.id; + const fileName = `ui_theme_${theme.name}.json`; + + const blob = new Blob([JSON.stringify(copyTheme, null, 2)], { + type: 'application/json', + }); + + await saveFileToDiskGeneric(blob, fileName); + } catch (error) { + console.error(error); + } + }; + + const importTheme = async (theme) => { + try { + const fileContent = await handleImportClick('.json'); + const importedTheme = JSON.parse(fileContent); + if (!validateTheme(importedTheme)) { + throw new Error('Invalid theme format'); + } + const newTheme = { ...importedTheme, id: uid.rnd() }; + const updatedThemes = [...userThemes, newTheme]; + addUserTheme(updatedThemes); + setUserTheme(newTheme); + } catch (error) { + console.error(error); + } + }; + + return ( + + + Theme Manager + + + + + + {userThemes?.map((theme, index) => ( + + + + {theme.id !== 'default' && ( + <> + exportTheme(theme)}> + + + handleEditTheme(theme.id)}> + + + handleDeleteTheme(theme.id)}> + + + + )} + handleApplyTheme(theme)}> + + + + + ))} + + + setOpenEditor(false)} + fullWidth + maxWidth="md" + > + + {themeDraft.id ? 'Edit Theme' : 'Add New Theme'} + + + + setThemeDraft((prev) => ({ ...prev, name: e.target.value })) + } + /> + + setCurrentTab(newValue)} + sx={{ mt: 2, mb: 2 }} + > + + + + + + {renderColorPicker( + currentTab, + 'Primary Main', + 'primary.main', + themeDraft[currentTab]?.primary?.main + )} + {renderColorPicker( + currentTab, + 'Primary Dark', + 'primary.dark', + themeDraft[currentTab]?.primary?.dark + )} + {renderColorPicker( + currentTab, + 'Primary Light', + 'primary.light', + themeDraft[currentTab]?.primary?.light + )} + {renderColorPicker( + currentTab, + 'Secondary Main', + 'secondary.main', + themeDraft[currentTab]?.secondary?.main + )} + {renderColorPicker( + currentTab, + 'Background Default', + 'background.default', + themeDraft[currentTab]?.background?.default + )} + {renderColorPicker( + currentTab, + 'Background Paper', + 'background.paper', + themeDraft[currentTab]?.background?.paper + )} + {renderColorPicker( + currentTab, + 'Background Surface', + 'background.surface', + themeDraft[currentTab]?.background?.surface + )} + {renderColorPicker( + currentTab, + 'Text Primary', + 'text.primary', + themeDraft[currentTab]?.text?.primary + )} + {renderColorPicker( + currentTab, + 'Text Secondary', + 'text.secondary', + themeDraft[currentTab]?.text?.secondary + )} + {renderColorPicker( + currentTab, + 'Border Main', + 'border.main', + themeDraft[currentTab]?.border?.main + )} + {renderColorPicker( + currentTab, + 'Border Subtle', + 'border.subtle', + themeDraft[currentTab]?.border?.subtle + )} + {renderColorPicker( + currentTab, + 'Positive', + 'other.positive', + themeDraft[currentTab]?.other?.positive + )} + {renderColorPicker( + currentTab, + 'Danger', + 'other.danger', + themeDraft[currentTab]?.other?.danger + )} + {renderColorPicker( + currentTab, + 'Unread', + 'other.unread', + themeDraft[currentTab]?.other?.unread + )} + + + + + + + + + ); +} diff --git a/src/components/Theme/themeManager.css b/src/components/Theme/themeManager.css new file mode 100644 index 0000000..85a4538 --- /dev/null +++ b/src/components/Theme/themeManager.css @@ -0,0 +1,39 @@ +[data-color-mode*='dark'] .w-color-sketch { + --sketch-background: #323232 !important; +} + +[data-color-mode*='dark'] .w-color-swatch { + --sketch-swatch-border-top: 1px solid #525252 !important; +} + +[data-color-mode*='dark'] .w-color-block { + --block-background-color: #323232 !important; + --block-box-shadow: rgb(0 0 0 / 10%) 0 1px !important; +} + +[data-color-mode*='dark'] .w-color-editable-input { + --editable-input-label-color: #757575 !important; + --editable-input-box-shadow: #616161 0px 0px 0px 1px inset !important; + --editable-input-color: #bbb !important; +} + +[data-color-mode*='dark'] .w-color-github { + --github-border: 1px solid rgba(0, 0, 0, 0.2) !important; + --github-background-color: #323232 !important; + --github-box-shadow: rgb(0 0 0 / 15%) 0px 3px 12px !important; + --github-arrow-border-color: rgba(0, 0, 0, 0.15) !important; +} + +[data-color-mode*='dark'] .w-color-compact { + --compact-background-color: #323232 !important; +} + +[data-color-mode*='dark'] .w-color-material { + --material-background-color: #323232 !important; + --material-border-bottom-color: #707070 !important; +} + +[data-color-mode*='dark'] .w-color-alpha { + --alpha-pointer-background-color: #6a6a6a !important; + --alpha-pointer-box-shadow: rgb(0 0 0 / 37%) 0px 1px 4px 0px !important; +} diff --git a/src/styles/App-styles.ts b/src/styles/App-styles.ts index 980657b..af273e5 100644 --- a/src/styles/App-styles.ts +++ b/src/styles/App-styles.ts @@ -54,7 +54,6 @@ export const AuthenticatedContainerInnerTop = styled(Box)(({ theme }) => ({ })); export const TextP = styled(Typography)(({ theme }) => ({ - backgroundColor: theme.palette.background.default, color: theme.palette.text.primary, fontFamily: 'Inter', fontSize: '13px', @@ -62,7 +61,6 @@ export const TextP = styled(Typography)(({ theme }) => ({ })); export const TextItalic = styled('span')(({ theme }) => ({ - backgroundColor: theme.palette.background.default, color: theme.palette.text.primary, fontFamily: 'Inter', fontSize: '13px', @@ -71,7 +69,6 @@ export const TextItalic = styled('span')(({ theme }) => ({ })); export const TextSpan = styled('span')(({ theme }) => ({ - backgroundColor: theme.palette.background.default, color: theme.palette.text.primary, fontFamily: 'Inter', fontSize: '13px', @@ -131,9 +128,8 @@ export const CustomButton = styled(Box)(({ theme }) => ({ width: 'fit-content', '&:hover': { backgroundColor: theme.palette.background.paper, - color: theme.palette.text.secondary, 'svg path': { - fill: theme.palette.background.paper, + fill: theme.palette.background.secondary, }, }, })); diff --git a/src/styles/theme-dark.ts b/src/styles/theme-dark.ts index 9c9e610..8929561 100644 --- a/src/styles/theme-dark.ts +++ b/src/styles/theme-dark.ts @@ -1,26 +1,36 @@ import { createTheme, ThemeOptions } from '@mui/material/styles'; import { commonThemeOptions } from './theme-common'; -const darkThemeOptions: ThemeOptions = { +export const darkThemeOptions: ThemeOptions = { ...commonThemeOptions, palette: { mode: 'dark', primary: { - main: 'rgb(46, 61, 96)', - dark: 'rgb(5, 20, 53)', - light: 'rgb(45, 92, 201)', + main: 'rgb(100, 155, 240)', + dark: 'rgb(45, 92, 201)', + light: 'rgb(130, 185, 255)', }, secondary: { main: 'rgb(69, 173, 255)', }, background: { default: 'rgb(49, 51, 56)', - paper: 'rgb(96, 96, 97)', + paper: 'rgb(62, 64, 68)', + surface: 'rgb(58, 60, 65)', }, text: { primary: 'rgb(255, 255, 255)', secondary: 'rgb(179, 179, 179)', }, + border: { + main: 'rgba(255, 255, 255, 0.12)', + subtle: 'rgba(255, 255, 255, 0.08)', + }, + other: { + positive: 'rgb(94, 176, 73)', + danger: 'rgb(177, 70, 70)', + unread: 'rgb(66, 151, 226)', + }, }, components: { MuiCard: { @@ -76,6 +86,20 @@ const darkThemeOptions: ThemeOptions = { }, }, }, + MuiDialog: { + styleOverrides: { + paper: { + backgroundImage: 'none', + }, + }, + }, + MuiPopover: { + styleOverrides: { + paper: { + backgroundImage: 'none', + }, + }, + }, }, }; diff --git a/src/styles/theme-light.ts b/src/styles/theme-light.ts index 1bd114d..15b1f8b 100644 --- a/src/styles/theme-light.ts +++ b/src/styles/theme-light.ts @@ -1,25 +1,35 @@ import { createTheme, ThemeOptions } from '@mui/material/styles'; import { commonThemeOptions } from './theme-common'; -const lightThemeOptions: ThemeOptions = { +export const lightThemeOptions: ThemeOptions = { ...commonThemeOptions, palette: { mode: 'light', primary: { - main: 'rgba(244, 244, 251, 1)', + main: 'rgb(162, 162, 221)', // old light becomes main dark: 'rgb(113, 198, 212)', - light: 'rgb(162, 162, 221)', + light: 'rgba(244, 244, 251, 1)', // former main becomes light }, secondary: { main: 'rgba(194, 222, 236, 1)', }, background: { default: 'rgba(250, 250, 250, 1)', - paper: 'rgb(228, 228, 228)', + paper: 'rgb(220, 220, 220)', // darker card background + surface: 'rgb(240, 240, 240)', // optional middle gray for replies, side panels }, text: { - primary: 'rgba(0, 0, 0, 1)', - secondary: 'rgba(82, 82, 82, 1)', + primary: 'rgba(0, 0, 0, 0.87)', // 87% black (slightly softened) + secondary: 'rgba(0, 0, 0, 0.6)', // 60% black + }, + border: { + main: 'rgba(0, 0, 0, 0.12)', + subtle: 'rgba(0, 0, 0, 0.08)', + }, + other: { + positive: 'rgb(94, 176, 73)', + danger: 'rgb(177, 70, 70)', + unread: 'rgb(66, 151, 226)', }, }, components: { @@ -77,6 +87,20 @@ const lightThemeOptions: ThemeOptions = { }, }, }, + MuiDialog: { + styleOverrides: { + paper: { + backgroundImage: 'none', + }, + }, + }, + MuiPopover: { + styleOverrides: { + paper: { + backgroundImage: 'none', + }, + }, + }, }, }; diff --git a/src/styles/theme.d.ts b/src/styles/theme.d.ts new file mode 100644 index 0000000..e10c5c1 --- /dev/null +++ b/src/styles/theme.d.ts @@ -0,0 +1,29 @@ +import '@mui/material/styles'; + +declare module '@mui/material/styles' { + interface TypeBackground { + surface: string; + } + interface Palette { + border: { + main: string; + subtle: string; + }; + other: { + positive: string; + danger: string; + unread: string; + }; + } + interface PaletteOptions { + border?: { + main?: string; + subtle?: string; + }; + other?: { + positive?: string; + danger?: string; + unread?: string; + }; + } +} diff --git a/src/utils/fileReading/index.ts b/src/utils/fileReading/index.ts index a6295c8..a04435c 100644 --- a/src/utils/fileReading/index.ts +++ b/src/utils/fileReading/index.ts @@ -1,63 +1,93 @@ // @ts-nocheck class Semaphore { - constructor(count) { - this.count = count - this.waiting = [] - } - acquire() { - return new Promise(resolve => { - if (this.count > 0) { - this.count-- - resolve() - } else { - this.waiting.push(resolve) - } - }) - } - release() { - if (this.waiting.length > 0) { - const resolve = this.waiting.shift() - resolve() - } else { - this.count++ - } - } + constructor(count) { + this.count = count; + this.waiting = []; + } + acquire() { + return new Promise((resolve) => { + if (this.count > 0) { + this.count--; + resolve(); + } else { + this.waiting.push(resolve); + } + }); + } + release() { + if (this.waiting.length > 0) { + const resolve = this.waiting.shift(); + resolve(); + } else { + this.count++; + } + } } -let semaphore = new Semaphore(1) -let reader = new FileReader() +let semaphore = new Semaphore(1); +let reader = new FileReader(); -export const fileToBase64 = (file) => new Promise(async (resolve, reject) => { - const reader = new FileReader(); // Create a new instance - await semaphore.acquire(); - reader.readAsDataURL(file); - reader.onload = () => { - const dataUrl = reader.result; - semaphore.release(); - if (typeof dataUrl === 'string') { - resolve(dataUrl.split(',')[1]); - } else { - reject(new Error('Invalid data URL')); - } - reader.onload = null; // Clear the handler - reader.onerror = null; // Clear the handle - }; - reader.onerror = (error) => { - semaphore.release(); - reject(error); - reader.onload = null; // Clear the handler - reader.onerror = null; // Clear the handle - }; +export const fileToBase64 = (file) => + new Promise(async (resolve, reject) => { + const reader = new FileReader(); // Create a new instance + await semaphore.acquire(); + reader.readAsDataURL(file); + reader.onload = () => { + const dataUrl = reader.result; + semaphore.release(); + if (typeof dataUrl === 'string') { + resolve(dataUrl.split(',')[1]); + } else { + reject(new Error('Invalid data URL')); + } + reader.onload = null; // Clear the handler + reader.onerror = null; // Clear the handle + }; + reader.onerror = (error) => { + semaphore.release(); + reject(error); + reader.onload = null; // Clear the handler + reader.onerror = null; // Clear the handle + }; }); - -export const base64ToBlobUrl = (base64, mimeType = "image/png") => { - const binary = atob(base64); - const array = []; - for (let i = 0; i < binary.length; i++) { - array.push(binary.charCodeAt(i)); - } - const blob = new Blob([new Uint8Array(array)], { type: mimeType }); - return URL.createObjectURL(blob); - }; \ No newline at end of file +export const base64ToBlobUrl = (base64, mimeType = 'image/png') => { + const binary = atob(base64); + const array = []; + for (let i = 0; i < binary.length; i++) { + array.push(binary.charCodeAt(i)); + } + const blob = new Blob([new Uint8Array(array)], { type: mimeType }); + return URL.createObjectURL(blob); +}; + +export const handleImportClick = async (fileTypes) => { + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = fileTypes; + + // Create a promise to handle file selection and reading synchronously + return await new Promise((resolve, reject) => { + fileInput.onchange = () => { + const file = fileInput.files[0]; + if (!file) { + reject(new Error('No file selected')); + return; + } + + const reader = new FileReader(); + reader.onload = (e) => { + resolve(e.target.result); // Resolve with the file content + }; + reader.onerror = () => { + reject(new Error('Error reading file')); + }; + + reader.readAsText(file); // Read the file as text (Base64 string) + }; + + // Trigger the file input dialog + fileInput.click(); + }); +};