Merge pull request #33 from Qortal/feature/background-colors

Feature/background colors
This commit is contained in:
Phillip 2025-04-29 17:44:59 +03:00 committed by GitHub
commit 45a5b084e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
94 changed files with 2822 additions and 1983 deletions

416
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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() {
<CopyToClipboard text={rawWallet?.ltcAddress}>
<AddressBox>
{rawWallet?.ltcAddress?.slice(0, 6)}...
{rawWallet?.ltcAddress?.slice(-4)} <img src={Copy} />
{rawWallet?.ltcAddress?.slice(-4)}{' '}
<CopyIcon color={theme.palette.text.primary} />
</AddressBox>
</CopyToClipboard>
@ -1362,7 +1363,8 @@ function App() {
<CopyToClipboard text={rawWallet?.address0}>
<AddressBox>
{rawWallet?.address0?.slice(0, 6)}...
{rawWallet?.address0?.slice(-4)} <img src={Copy} />
{rawWallet?.address0?.slice(-4)}{' '}
<CopyIcon color={theme.palette.text.primary} />
</AddressBox>
</CopyToClipboard>
<Spacer height="10px" />
@ -1471,6 +1473,7 @@ function App() {
sx={{
height: '100%',
justifyContent: 'space-between',
borderLeft: `1px solid ${theme.palette.border.subtle}`,
}}
>
<Box
@ -1508,7 +1511,7 @@ function App() {
tooltip: {
sx: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
},
},
arrow: {
@ -1518,7 +1521,11 @@ function App() {
},
}}
>
<LogoutIcon />
<LogoutIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
@ -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() {
},
}}
>
<SettingsIcon />
<SettingsIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
@ -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() {
},
}}
>
<PersonSearchIcon />
<PersonSearchIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
@ -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() {
},
}}
>
<AccountBalanceWalletIcon />
<AccountBalanceWalletIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
@ -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);
}}
>
<WalletIcon width="25" />
<WalletIcon
color={theme.palette.text.secondary}
width="25"
/>
</ButtonBase>
</Tooltip>
</>
@ -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() {
},
}}
>
<EngineeringIcon />
<EngineeringIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
@ -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() {
},
}}
>
<HelpIcon />
<HelpIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
)}
@ -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() {
},
}}
>
<DownloadIcon />
<DownloadIcon
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
<Spacer height="40px" />
@ -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 && (
<>
<Spacer height="48px" />
<img src={Success} />
<SuccessIcon />
<Spacer height="45px" />
<TextP
sx={{
@ -2953,7 +2987,7 @@ function App() {
}}
>
<Spacer height="48px" />
<img src={Success} />
<SuccessIcon />
<Spacer height="45px" />
<TextP
sx={{
@ -2978,7 +3012,7 @@ function App() {
{extState === 'transfer-success-request' && (
<>
<Spacer height="48px" />
<img src={Success} />
<SuccessIcon />
<Spacer height="45px" />
<TextP
sx={{
@ -3003,7 +3037,7 @@ function App() {
{extState === 'buy-order-submitted' && (
<>
<Spacer height="48px" />
<img src={Success} />
<SuccessIcon />
<Spacer height="45px" />
<TextP
sx={{
@ -3087,12 +3121,12 @@ function App() {
<DialogActions>
<Button
sx={{
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: theme.palette.text.primary,
fontWeight: 'bold',
opacity: 0.7,
'&:hover': {
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: 'black',
opacity: 1,
},
@ -3107,12 +3141,12 @@ function App() {
</Button>
<Button
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,
},
@ -3406,10 +3440,10 @@ function App() {
}
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,
},
}}
/>
@ -3435,10 +3469,10 @@ function App() {
disableRipple
sx={{
'&.Mui-checked': {
color: 'white',
color: theme.palette.text.secondary,
},
'& .MuiSvgIcon-root': {
color: 'white',
color: theme.palette.text.secondary,
},
}}
/>
@ -3466,7 +3500,7 @@ function App() {
>
<CustomButtonAccept
color="black"
bgColor="var(--green)"
bgColor={theme.palette.other.positive}
sx={{
minWidth: '102px',
opacity:
@ -3502,7 +3536,7 @@ function App() {
</CustomButtonAccept>
<CustomButtonAccept
color="black"
bgColor="var(--danger)"
bgColor={theme.palette.other.danger}
sx={{
minWidth: '102px',
}}
@ -3559,7 +3593,7 @@ function App() {
>
<HelpIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
</ButtonBase>

View File

@ -562,11 +562,12 @@ export const NotAuthenticated = ({
}}
sx={{
backgroundColor:
hasSeenGettingStarted === false && 'var(--green)',
hasSeenGettingStarted === false && theme.palette.other.positive,
color: hasSeenGettingStarted === false && 'black',
'&:hover': {
backgroundColor:
hasSeenGettingStarted === false && 'var(--green)',
hasSeenGettingStarted === false &&
theme.palette.other.positive,
color: hasSeenGettingStarted === false && 'black',
},
}}
@ -631,15 +632,6 @@ export const NotAuthenticated = ({
}}
control={
<Switch
sx={{
'& .MuiSwitch-switchBase.Mui-checked': {
color: '#5EB049',
},
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track':
{
backgroundColor: theme.palette.background.default,
},
}}
checked={useLocalNode}
onChange={(event) => {
if (event.target.checked) {
@ -1086,7 +1078,7 @@ export const NotAuthenticated = ({
>
<HelpIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
</ButtonBase>

View File

@ -48,7 +48,7 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
const [password, setPassword] = useState('');
const [isOpenSeedModal, setIsOpenSeedModal] = useState(false);
const [isLoadingEncryptSeed, setIsLoadingEncryptSeed] = useState(false);
const theme = useTheme();
const { isShow, onCancel, onOk, show } = useModal();
const { getRootProps, getInputProps } = useDropzone({
@ -216,7 +216,7 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
maxHeight: '60vh',
overflowY: 'auto',
overflowX: 'hidden',
backgroundColor: 'rgb(30 30 32 / 70%)',
backgroundColor: theme.palette.background.paper,
}}
>
{wallets?.map((wallet, idx) => {
@ -429,7 +429,7 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
bgcolor: theme.palette.background.default,
flexGrow: 1,
'&:hover': {
backgroundColor: theme.palette.background.paper,
backgroundColor: theme.palette.action.hover,
transform: 'scale(1.01)',
},
transition: 'all 0.1s ease-in-out',
@ -539,12 +539,12 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
</Button>
<Button
sx={{
backgroundColor: 'var(--danger)',
backgroundColor: theme.palette.other.danger,
'&:hover': {
backgroundColor: 'var(--danger)',
backgroundColor: theme.palette.other.danger,
},
'&:focus': {
backgroundColor: 'var(--danger)',
backgroundColor: theme.palette.other.danger,
},
}}
size="small"

View File

@ -1,12 +1,18 @@
import React from 'react';
export const ChatIcon= ({ color = 'white', height = 15, width = 15 }) => {
return (
<svg width={width} height={height} viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 0C3.35915 0 0 3.35915 0 7.5V13.8169C0 14.4718 0.528169 15 1.1831 15H7.5C11.6408 15 15 11.6408 15 7.5C15 3.35915 11.6408 0 7.5 0ZM11.0915 10.669H3.90845C3.67606 10.669 3.48592 10.4789 3.48592 10.2465C3.48592 10.0141 3.67606 9.82394 3.90845 9.82394H11.0915C11.3239 9.82394 11.5141 10.0141 11.5141 10.2465C11.5141 10.4789 11.3239 10.669 11.0915 10.669ZM11.0915 8.34507H3.90845C3.67606 8.34507 3.48592 8.15493 3.48592 7.92254C3.48592 7.69014 3.67606 7.5 3.90845 7.5H11.0915C11.3239 7.5 11.5141 7.69014 11.5141 7.92254C11.5141 8.15493 11.3239 8.34507 11.0915 8.34507ZM11.0915 6.02113H3.90845C3.67606 6.02113 3.48592 5.83099 3.48592 5.59859C3.48592 5.3662 3.67606 5.17606 3.90845 5.17606H11.0915C11.3239 5.17606 11.5141 5.3662 11.5141 5.59859C11.5141 5.83099 11.3239 6.02113 11.0915 6.02113Z" fill={color}/>
</svg>
);
};
export const ChatIcon = ({ color = 'white', height = 15, width = 15 }) => {
return (
<svg
width={width}
height={height}
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.5 0C3.35915 0 0 3.35915 0 7.5V13.8169C0 14.4718 0.528169 15 1.1831 15H7.5C11.6408 15 15 11.6408 15 7.5C15 3.35915 11.6408 0 7.5 0ZM11.0915 10.669H3.90845C3.67606 10.669 3.48592 10.4789 3.48592 10.2465C3.48592 10.0141 3.67606 9.82394 3.90845 9.82394H11.0915C11.3239 9.82394 11.5141 10.0141 11.5141 10.2465C11.5141 10.4789 11.3239 10.669 11.0915 10.669ZM11.0915 8.34507H3.90845C3.67606 8.34507 3.48592 8.15493 3.48592 7.92254C3.48592 7.69014 3.67606 7.5 3.90845 7.5H11.0915C11.3239 7.5 11.5141 7.69014 11.5141 7.92254C11.5141 8.15493 11.3239 8.34507 11.0915 8.34507ZM11.0915 6.02113H3.90845C3.67606 6.02113 3.48592 5.83099 3.48592 5.59859C3.48592 5.3662 3.67606 5.17606 3.90845 5.17606H11.0915C11.3239 5.17606 11.5141 5.3662 11.5141 5.59859C11.5141 5.83099 11.3239 6.02113 11.0915 6.02113Z"
fill={color}
/>
</svg>
);
};

View File

@ -0,0 +1,33 @@
import { useTheme } from '@mui/material';
import { SVGProps } from './interfaces';
export const ComposeIcon: React.FC<SVGProps> = ({
color,
height = 20,
width = 20,
opacity,
...children
}) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
const setOpacity = opacity ? opacity : 1;
return (
<svg
{...children}
width={width}
height={height}
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M50.3 3c1.5 0 3.9 0.6 5.5 1.4 1.5 0.7 3.3 2.5 4 4 0.6 1.4 1.2 3.7 1.2 5.1 0 1.4-0.6 3.7-1.4 5.3-0.8 1.5-9.9 11.1-39.1 40l-6.7 1.6c-3.8 0.9-7.9 1.6-9.3 1.6-1.8 0-2.5-0.5-2.5-2 0-1.1 0.7-5.3 3.2-16.5l18.1-18.4c10-10 19.6-19.2 21.2-20.2 1.7-1 4.2-1.9 5.8-1.9zm-8.4 11.3c0 0.7 1.5 2.7 3.3 4.4 1.8 1.8 3.9 3.3 4.6 3.3 0.6 0 2.3-1.4 3.7-3 1.4-1.7 2.5-4 2.5-5.3 0.1-1.2-0.7-3-1.7-3.9-1-1-2.8-1.8-4-1.8-1.2 0-3.5 1.2-5.3 2.6-1.7 1.4-3.1 3.1-3.1 3.7z"
fill={setColor}
opacity={setOpacity}
fillRule="evenodd"
/>
</svg>
);
};

View File

@ -0,0 +1,25 @@
import { useTheme } from '@mui/material';
import React from 'react';
export const CopyIcon = ({ color, height = 11, width = 10 }) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
return (
<svg
width={width}
height={height}
viewBox="0 0 10 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3.92857 0.5H8.57143C9.36071 0.5 10 1.13929 10 1.92857V6.57143C10 7.36071 9.36071 8 8.57143 8H8.21429V4.42857C8.21429 3.24643 7.25357 2.28571 6.07143 2.28571H2.5V1.92857C2.5 1.13929 3.13929 0.5 3.92857 0.5ZM1.42857 3H6.07143C6.86041 3 7.5 3.63959 7.5 4.42857V9.07143C7.5 9.86041 6.86041 10.5 6.07143 10.5H1.42857C0.639593 10.5 0 9.86041 0 9.07143V4.42857C0 3.63959 0.639593 3 1.42857 3Z"
fill={setColor}
fill-opacity="0.5"
/>
</svg>
);
};

View File

@ -1,15 +1,18 @@
import React from 'react';
import { styled } from '@mui/system';
import { SVGProps } from './interfaces';
import { useTheme } from '@mui/material';
// Create a styled container with hover effects
const SvgContainer = styled('svg')({
const SvgContainer = styled('svg')<{ color?: string }>(({ color }) => ({
'& path': {
fill: 'rgba(41, 41, 43, 1)', // Default to red if no color prop
fill: color,
},
});
}));
export const CreateThreadIcon: React.FC<SVGProps> = ({ color }) => {
const theme = useTheme();
export const CreateThreadIcon: React.FC<SVGProps> = ({ color, opacity }) => {
const setColor = color || theme.palette.text.primary;
return (
<SvgContainer
width="20"
@ -17,6 +20,7 @@ export const CreateThreadIcon: React.FC<SVGProps> = ({ color, opacity }) => {
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
color={setColor}
>
<path
d="M0 9.80209V9.0205C0.0460138 8.67679 0.080024 8.31425 0.144043 7.98466C0.469856 6.30568 1.25577 4.79934 2.38071 3.6977C4.13924 1.88262 6.22987 0.985679 8.52256 0.674927C9.9086 0.485649 11.3116 0.565177 12.6758 0.910345C14.5124 1.34351 16.1889 2.2075 17.6053 3.67886C18.7276 4.84183 19.5319 6.24257 19.858 7.98466C19.918 8.31189 19.952 8.64383 20 8.97577V9.80209C19.9827 9.8676 19.9693 9.93447 19.96 10.0022C19.8708 11.2186 19.5113 12.3861 18.9177 13.3875C17.961 15.0025 16.6297 16.2594 15.0825 17.0082C12.4657 18.3525 9.75693 18.5667 6.98209 17.8346C6.8589 17.8074 6.73157 17.8264 6.61799 17.8887C5.15955 18.7339 3.70511 19.5908 2.24867 20.4501C2.18866 20.4854 2.12464 20.5183 2.0146 20.5748L3.78714 16.3703C3.37301 16.0148 2.96889 15.7017 2.60078 15.3415C1.42243 14.1879 0.556167 12.7895 0.182055 11.0192C0.0980294 10.6213 0.060018 10.2094 0 9.80209ZM14.0042 10.5931C14.1362 10.5968 14.2676 10.5698 14.3907 10.5135C14.5138 10.4572 14.6262 10.3728 14.7214 10.2651C14.8167 10.1574 14.8928 10.0286 14.9455 9.8861C14.9982 9.7436 15.0264 9.59023 15.0285 9.43484V9.4113C15.0285 9.25517 15.0024 9.10058 14.9516 8.95634C14.9008 8.8121 14.8264 8.68104 14.7326 8.57064C14.6388 8.46025 14.5274 8.37268 14.4048 8.31293C14.2823 8.25319 14.1509 8.22243 14.0182 8.22243C13.8855 8.22243 13.7542 8.25319 13.6316 8.31293C13.509 8.37268 13.3976 8.46025 13.3038 8.57064C13.21 8.68104 13.1356 8.8121 13.0848 8.95634C13.034 9.10058 13.0079 9.25517 13.0079 9.4113C13.0074 9.56588 13.0327 9.71906 13.0825 9.86211C13.1323 10.0052 13.2055 10.1353 13.2981 10.245C13.3906 10.3547 13.5005 10.442 13.6217 10.5017C13.7429 10.5614 13.8728 10.5925 14.0042 10.5931ZM10.003 10.5931C10.203 10.5926 10.3983 10.5225 10.5644 10.3915C10.7306 10.2606 10.86 10.0746 10.9364 9.85719C11.0129 9.63976 11.0329 9.40056 10.9939 9.16977C10.9549 8.93898 10.8588 8.72694 10.7175 8.5604C10.5763 8.39385 10.3962 8.28026 10.2002 8.23396C10.0041 8.18765 9.80084 8.21071 9.61591 8.30022C9.43099 8.38973 9.27273 8.54168 9.1611 8.7369C9.04948 8.93212 8.98949 9.16187 8.9887 9.39717C8.98975 9.71356 9.09688 10.0167 9.28682 10.2406C9.47675 10.4646 9.73413 10.5912 10.003 10.5931ZM4.98349 9.3854C4.9836 9.61979 5.04316 9.8488 5.15456 10.0431C5.26595 10.2374 5.42411 10.3882 5.60876 10.476C5.79341 10.5639 5.99616 10.5849 6.19102 10.5364C6.38588 10.4878 6.56399 10.3719 6.70252 10.2035C6.84105 10.0351 6.93371 9.82183 6.96861 9.59108C7.00352 9.36032 6.97909 9.12255 6.89845 8.90823C6.8178 8.69392 6.68463 8.51281 6.51597 8.38811C6.34732 8.26342 6.15087 8.20081 5.95179 8.20831C5.69208 8.21809 5.44579 8.34641 5.26507 8.56611C5.08434 8.78581 4.98336 9.07963 4.98349 9.3854Z"

View File

@ -1,14 +0,0 @@
import React from 'react';
export const MessagingIcon2= ({ color = '#8F8F91', height = 24, width =24 }) => {
return (
<svg width={width} height={height} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" clipRule="evenodd" d="M22.6636 0.00168233C22.6127 -0.000756257 22.5614 -0.000627677 22.5099 0.00261984C22.3724 0.0112798 22.2331 0.0405753 22.0969 0.093558L1.02096 8.28971C0.362343 8.54585 -0.00366118 9.18408 2.76147e-05 9.79253C0.00371641 10.401 0.377567 11.0341 1.03925 11.2822L9.02065 14.2752C9.34631 14.3974 9.60258 14.6536 9.72471 14.9793L12.7177 22.9607C12.9658 23.6224 13.5989 23.9963 14.2074 24C14.8158 24.0037 15.454 23.6376 15.7102 22.979L23.9063 1.90295C24.1182 1.35797 23.9526 0.768987 23.5917 0.408091C23.3549 0.171254 23.02 0.0187526 22.6636 0.00168233ZM18.4022 4.99812C18.5613 4.99815 18.7139 5.06138 18.8264 5.17391C18.9389 5.28643 19.0021 5.43902 19.0021 5.59813C19.0021 5.75724 18.9389 5.90983 18.8264 6.02235L13.2239 11.6244C13.1114 11.7369 12.9588 11.8001 12.7997 11.8001C12.6406 11.8001 12.488 11.7369 12.3755 11.6244C12.263 11.5119 12.1998 11.3593 12.1998 11.2002C12.1998 11.0411 12.263 10.8885 12.3755 10.776L17.9775 5.17391C18.0333 5.11813 18.0995 5.0739 18.1724 5.04374C18.2452 5.01357 18.3233 4.99807 18.4022 4.99812Z" fill={color}/>
</svg>
);
};

View File

@ -0,0 +1,24 @@
import { useTheme } from '@mui/material';
import React from 'react';
export const MessagingIconFilled = ({ color, height = 31, width = 31 }) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
return (
<svg
width={width}
height={height}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M22.6636 0.00168233C22.6127 -0.000756257 22.5614 -0.000627677 22.5099 0.00261984C22.3724 0.0112798 22.2331 0.0405753 22.0969 0.093558L1.02096 8.28971C0.362343 8.54585 -0.00366118 9.18408 2.76147e-05 9.79253C0.00371641 10.401 0.377567 11.0341 1.03925 11.2822L9.02065 14.2752C9.34631 14.3974 9.60258 14.6536 9.72471 14.9793L12.7177 22.9607C12.9658 23.6224 13.5989 23.9963 14.2074 24C14.8158 24.0037 15.454 23.6376 15.7102 22.979L23.9063 1.90295C24.1182 1.35797 23.9526 0.768987 23.5917 0.408091C23.3549 0.171254 23.02 0.0187526 22.6636 0.00168233ZM18.4022 4.99812C18.5613 4.99815 18.7139 5.06138 18.8264 5.17391C18.9389 5.28643 19.0021 5.43902 19.0021 5.59813C19.0021 5.75724 18.9389 5.90983 18.8264 6.02235L13.2239 11.6244C13.1114 11.7369 12.9588 11.8001 12.7997 11.8001C12.6406 11.8001 12.488 11.7369 12.3755 11.6244C12.263 11.5119 12.1998 11.3593 12.1998 11.2002C12.1998 11.0411 12.263 10.8885 12.3755 10.776L17.9775 5.17391C18.0333 5.11813 18.0995 5.0739 18.1724 5.04374C18.2452 5.01357 18.3233 4.99807 18.4022 4.99812Z"
fill={setColor}
/>
</svg>
);
};

View File

@ -14,8 +14,8 @@ export const QappDevelopText: React.FC<SVGProps> = ({
return (
<svg
{...children}
width="83"
height="40"
width="124"
height="60"
viewBox="0 0 83 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"

View File

@ -1,17 +1,23 @@
import React from 'react';
import { styled } from '@mui/system';
import { SVGProps } from './interfaces';
import { useTheme } from '@mui/material';
// Create a styled container with hover effects
const SvgContainer = styled('svg')({
// Make SvgContainer accept a prop
const SvgContainer = styled('svg')<{ color?: string }>(({ color }) => ({
'& path': {
fill: 'rgba(41, 41, 43, 1)', // Default to red if no color prop
fill: color,
},
});
}));
export const SendNewMessage: React.FC<SVGProps> = ({ color, opacity }) => {
export const SendNewMessage: React.FC<SVGProps> = ({ color, ...props }) => {
const theme = useTheme();
const setColor = color || theme.palette.text.primary;
return (
<SvgContainer
{...props}
color={setColor}
width="20"
height="20"
viewBox="0 0 20 20"

View File

@ -0,0 +1,37 @@
import { useTheme } from '@mui/material';
import { SVGProps } from './interfaces';
export const SortIcon: React.FC<SVGProps> = ({
color,
height = 16,
width = 15,
opacity,
...children
}) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
const setOpacity = opacity ? opacity : 1;
return (
<svg
{...children}
width={width}
height={height}
viewBox="0 0 15 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.3347 0.271977C14.0797 0.0885134 13.79 0 13.5034 0C13.0191 0 12.5424 0.251056 12.2542 0.711326L12.0008 1.11366L10.6942 3.20097L9.44204 5.19976C9.15388 5.66003 9 6.19916 9 6.75116V14.3987C9 15.2822 9.67136 16 10.4996 16C10.9145 16 11.2902 15.8214 11.5602 15.5301C11.8318 15.2404 11.9992 14.8397 11.9992 14.3987V7.57353C11.9992 7.11809 12.1275 6.6723 12.3628 6.29411L14.7465 2.48964C14.917 2.21605 15 1.90706 15 1.60129C15 1.08469 14.7646 0.577751 14.3332 0.270368L14.3347 0.271977Z"
fill={setColor}
opacity={setOpacity}
/>
<path
d="M4.30727 3.20032L3.00075 1.11344L2.74881 0.711183C2.46065 0.251006 1.98391 0 1.49962 0C1.21297 0 0.923309 0.0884956 0.668343 0.271923C0.235353 0.579244 0 1.08608 0 1.60257C0 1.90829 0.0829771 2.21722 0.254966 2.49075L2.63716 6.29445C2.87403 6.67257 3.00075 7.11826 3.00075 7.57361V14.399C3.00075 15.2824 3.67211 16 4.50038 16C5.32864 16 6 15.2824 6 14.399V6.75141C6 6.19952 5.84762 5.6605 5.55947 5.20032L4.30576 3.20193L4.30727 3.20032Z"
fill={setColor}
opacity={setOpacity}
/>
</svg>
);
};

View File

@ -1,4 +1,9 @@
import { useTheme } from '@mui/material';
export const StarEmptyIcon = () => {
const theme = useTheme();
const setColor = theme.palette.text.secondary;
return (
<svg
width="12"
@ -9,7 +14,7 @@ export const StarEmptyIcon = () => {
>
<path
d="M6.2726 0.162533L7.89126 3.31595C7.9357 3.40243 8.02078 3.46234 8.11994 3.47588L11.7399 3.98173C11.8542 3.99736 11.9496 4.07446 11.9853 4.18022C12.0206 4.28598 11.9913 4.40215 11.9084 4.47977L9.28882 6.93449V6.93397C9.21729 7.00117 9.18478 7.09807 9.20157 7.19288L9.81988 10.6588C9.83939 10.7682 9.79278 10.8786 9.69903 10.9443C9.60529 11.0094 9.48119 11.0182 9.37931 10.9667L6.14144 9.32987C6.05311 9.28559 5.9469 9.28559 5.85856 9.32987L2.62069 10.9667C2.51881 11.0182 2.39472 11.0094 2.30096 10.9443C2.20722 10.8786 2.16062 10.7682 2.18012 10.6588L2.79842 7.19288C2.81522 7.09807 2.78271 7.00117 2.71118 6.93397L0.0916083 4.47978C0.0086971 4.40216 -0.0205644 4.28599 0.0146582 4.18023C0.0504232 4.07448 0.145798 3.99738 0.260135 3.98175L3.88006 3.47589C3.97923 3.46235 4.0643 3.40244 4.10874 3.31596L5.7274 0.162545C5.77888 0.0630431 5.88455 0 5.99997 0C6.11539 0 6.22113 0.0630238 6.2726 0.162533Z"
fill="#727376"
fill={setColor}
/>
</svg>
);

View File

@ -1,4 +1,9 @@
import { useTheme } from '@mui/material';
export const StarFilledIcon = () => {
const theme = useTheme();
const setColor = theme.palette.text.primary;
return (
<svg
width="12"
@ -9,7 +14,7 @@ export const StarFilledIcon = () => {
>
<path
d="M6.2726 0.162533L7.89126 3.31595C7.9357 3.40243 8.02078 3.46234 8.11994 3.47588L11.7399 3.98173C11.8542 3.99736 11.9496 4.07446 11.9853 4.18022C12.0206 4.28598 11.9913 4.40215 11.9084 4.47977L9.28882 6.93449V6.93397C9.21729 7.00117 9.18478 7.09807 9.20157 7.19288L9.81988 10.6588C9.83939 10.7682 9.79278 10.8786 9.69903 10.9443C9.60529 11.0094 9.48119 11.0182 9.37931 10.9667L6.14144 9.32987C6.05311 9.28559 5.9469 9.28559 5.85856 9.32987L2.62069 10.9667C2.51881 11.0182 2.39472 11.0094 2.30096 10.9443C2.20722 10.8786 2.16062 10.7682 2.18012 10.6588L2.79842 7.19288C2.81522 7.09807 2.78271 7.00117 2.71118 6.93397L0.0916083 4.47978C0.0086971 4.40216 -0.0205644 4.28599 0.0146582 4.18023C0.0504232 4.07448 0.145798 3.99738 0.260135 3.98175L3.88006 3.47589C3.97923 3.46235 4.0643 3.40244 4.10874 3.31596L5.7274 0.162545C5.77888 0.0630431 5.88455 0 5.99997 0C6.11539 0 6.22113 0.0630238 6.2726 0.162533Z"
fill="white"
fill={setColor}
/>
</svg>
);

View File

@ -0,0 +1,32 @@
import { useTheme } from '@mui/material';
import { SVGProps } from './interfaces';
export const SuccessIcon: React.FC<SVGProps> = ({
color,
height = 155,
width = 156,
opacity,
...children
}) => {
const theme = useTheme();
const setColor = color ? color : theme.palette.text.primary;
const setOpacity = opacity ? opacity : 1;
return (
<svg
{...children}
width={width}
height={height}
viewBox="0 0 156 155"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M78 0C57.4456 0 37.7349 8.16507 23.1984 22.6984C8.66507 37.2332 0.5 56.9446 0.5 77.5C0.5 98.0554 8.66507 117.765 23.1984 132.302C37.7332 146.835 57.4445 155 78 155C98.5554 155 118.265 146.835 132.802 132.302C147.335 117.767 155.5 98.0554 155.5 77.5C155.48 56.9522 147.308 37.2523 132.779 22.7227C118.249 8.19318 98.5489 0.0215072 78.0014 0.00138561L78 0ZM66.5377 111.48L29.1001 77.2273L39.5907 65.765L66.0523 89.992L115.768 40.2557L126.764 51.2517L66.5377 111.48Z"
fill={setColor}
opacity={setOpacity}
/>
</svg>
);
};

View File

@ -1,9 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="20" height="20" fill="url(#pattern0)"/>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_127_477" transform="scale(0.015625)"/>
</pattern>
<image id="image0_127_477" width="64" height="64" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAACW0lEQVR4nO3bu2sUURSA8RsVMQRRfBArQ3yAb8RC0MZKsLBRtLHQQvEfEBEVS+2sjQHjo1TERhCLNHZWVsFGxShiFLTygSj+5OIKm2E3m12Tnbk789V7z+53zpl7z87uhFBRUZEiWIi9uIQx3MUozmMX+kIvgkU4iUkz8xxHeyoRWIlx7fEQy0LqYBivdMYzLA2Jy082EPuCERzDfpzCffxs8NoHSV4Omss/wmCTNTsw0WDNkdAj8jewoMXa5Q2SMJFMF2guP9ZKPtMJvzLrd4aE5W/OVr4uVtwT6jkXEpW/1a58LV7cGOsZCQnK34mTX4cxD2Ri3QuJyU9h4D/ixiOyntGQkHz9kbekw9jXTediSEy+4yRgDb6azu6QoHzbSYgbJh6bzstONtJ5AUMdzvZRqr9F7D5ca7D2eEi08rPuhFrl47CUZbzTk6Ro8k2TUJOPw1KW2GmrQsJt3/JyqMnHYSnLG6zvRfn6JAwUXX54jtq+GXFYyhLfb10vV34mClP5oUq+u7wtu/yGvN1DJa+qfDcpddu/x+a83UMlr6p8Nyl120+VXX5L3u6hkldVvptUbR/yRrXhyWO331qEyq/G6xyGnE2hCOBsDvL5Dzn/qP23rlt8KETbZ35X+1RK+UgcObsovy0UDZwurXwEt0srH8GLMssPllY+gsPzJP+x8PIRXJ0n+e0hBfC0zPL9+FFK+Qj2lVY+ggullZ+DL0Df8QSXsTakiL/ndDs3LuIzOGewB4tD6uBdE9nftUdN4kOJJ7Ax9CI4hM/4VmvnKziIFXl/toqKMG/8Ad4tdVYcSnGDAAAAAElFTkSuQmCC"/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,3 +0,0 @@
<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.92857 0.5H8.57143C9.36071 0.5 10 1.13929 10 1.92857V6.57143C10 7.36071 9.36071 8 8.57143 8H8.21429V4.42857C8.21429 3.24643 7.25357 2.28571 6.07143 2.28571H2.5V1.92857C2.5 1.13929 3.13929 0.5 3.92857 0.5ZM1.42857 3H6.07143C6.86041 3 7.5 3.63959 7.5 4.42857V9.07143C7.5 9.86041 6.86041 10.5 6.07143 10.5H1.42857C0.639593 10.5 0 9.86041 0 9.07143V4.42857C0 3.63959 0.639593 3 1.42857 3Z" fill="white" fill-opacity="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 574 B

View File

@ -1,3 +0,0 @@
<svg width="15" height="11" viewBox="0 0 15 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.76526 1.80943H6.51017C5.91236 1.80943 5.42723 2.37147 5.42723 3.06406V6.55419V6.82615H4L1.90297 9L2.00782 6.82615H0.8482C0.380282 6.82615 0 6.38558 0 5.84347V0.982675C0 0.440572 0.380282 0 0.8482 0H7.1518C7.62128 0 8 0.440572 8 0.982675V1.80943H7.76526ZM8.89437 2H14.0458C14.5722 2 15 2.44057 15 2.98268V7.84166C15 8.38558 14.5722 8.82434 14.0458 8.82434H12.7412L12.8592 11L10.5 8.82434H6.95423C6.42606 8.82434 6 8.38558 6 7.84166V7.01672V6.74476V6.47281V2.98268C6 2.44057 6.42606 2 6.95423 2H8.3662H8.63028H8.89437Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 688 B

View File

@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 0C4.06452 0 0 4.06452 0 9C0 13.9355 4.06452 18 9 18C13.9355 18 18 13.9355 18 9C18 4.06452 13.8629 0 9 0ZM9 16.8387C4.71774 16.8387 1.16129 13.2823 1.16129 9C1.16129 4.71774 4.71774 1.16129 9 1.16129C13.2823 1.16129 16.8387 4.71774 16.8387 9C16.8387 13.2823 13.2823 16.8387 9 16.8387ZM9.79861 13.2097C9.79861 13.5726 9.50829 13.9355 9.0728 13.9355H8.85506C8.49216 13.9355 8.12926 13.6451 8.12926 13.2097V7.18545C8.12926 6.82255 8.41958 6.45965 8.85506 6.45965H9.0728C9.43571 6.45965 9.79861 6.74997 9.79861 7.18545V13.2097ZM9.79823 4.86286C9.79823 5.30379 9.44078 5.66125 8.99984 5.66125C8.5589 5.66125 8.20145 5.30379 8.20145 4.86286C8.20145 4.42192 8.5589 4.06447 8.99984 4.06447C9.44078 4.06447 9.79823 4.42192 9.79823 4.86286Z" fill="white" fill-opacity="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 920 B

View File

@ -1,3 +0,0 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.14468 0L0.394043 2.66667L5.89531 8L0.394043 13.3333L3.14468 16L8.64594 10.6667L14.1472 16L16.8978 13.3333L11.3966 8L16.8978 2.66667L14.1472 0L8.64594 5.33333L3.14468 0Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 300 B

View File

@ -1,3 +0,0 @@
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.645 5.81803H15C15.9471 5.81803 16.8557 6.20131 17.5257 6.88278C18.195 7.56497 18.5714 8.49007 18.5714 9.45445V10.909C18.5714 11.8734 18.195 12.7985 17.5257 13.4807C16.8557 14.1622 15.9471 14.5454 15 14.5454C12.0164 14.5454 8.57143 14.5454 8.57143 14.5454C8.17714 14.5454 7.85714 14.8713 7.85714 15.2727C7.85714 15.6742 8.17714 16 8.57143 16H15C16.3264 16 17.5979 15.464 18.5357 14.5091C19.4736 13.5541 20 12.2596 20 10.909C20 10.4268 20 9.93664 20 9.45445C20 8.10461 19.4736 6.80932 18.5357 5.8544C17.5979 4.9002 16.3264 4.36347 15 4.36347H2.645L6.17929 1.27906C6.47857 1.01797 6.51286 0.55832 6.25643 0.253588C6 -0.0511433 5.54857 -0.0860541 5.24929 0.175041L0.249285 4.53874C0.0914279 4.67692 0 4.87838 0 5.09075C0 5.30312 0.0914279 5.50458 0.249285 5.64276L5.24929 10.0065C5.54857 10.2676 6 10.2326 6.25643 9.92791C6.51286 9.62318 6.47857 9.16353 6.17929 8.90244L2.645 5.81803Z" fill="white" fill-opacity="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,3 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.08728 0.00158245C2.72507 0.00158245 0 2.7262 0 6.08784C0 9.44948 2.72507 12.1741 6.08728 12.1741C7.62099 12.1741 9.02317 11.6043 10.0947 10.6668L13.3088 13.8803C13.3881 13.9596 13.4911 14 13.595 14C13.6988 14 13.8018 13.9596 13.8811 13.8803C14.0396 13.7218 14.0396 13.4643 13.8811 13.3066L10.667 10.093C11.6047 9.02162 12.1746 7.62202 12.1746 6.08626C12.1746 2.72461 9.44951 0 6.0873 0L6.08728 0.00158245ZM6.08728 11.3626C3.17756 11.3626 0.811637 8.99707 0.811637 6.08784C0.811637 3.17861 3.17756 0.813083 6.08728 0.813083C8.997 0.813083 11.3629 3.17861 11.3629 6.08784C11.3629 8.99707 8.997 11.3626 6.08728 11.3626Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 748 B

View File

@ -1,4 +0,0 @@
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.3347 0.271977C14.0797 0.0885134 13.79 0 13.5034 0C13.0191 0 12.5424 0.251056 12.2542 0.711326L12.0008 1.11366L10.6942 3.20097L9.44204 5.19976C9.15388 5.66003 9 6.19916 9 6.75116V14.3987C9 15.2822 9.67136 16 10.4996 16C10.9145 16 11.2902 15.8214 11.5602 15.5301C11.8318 15.2404 11.9992 14.8397 11.9992 14.3987V7.57353C11.9992 7.11809 12.1275 6.6723 12.3628 6.29411L14.7465 2.48964C14.917 2.21605 15 1.90706 15 1.60129C15 1.08469 14.7646 0.577751 14.3332 0.270368L14.3347 0.271977Z" fill="white"/>
<path d="M4.30727 3.20032L3.00075 1.11344L2.74881 0.711183C2.46065 0.251006 1.98391 0 1.49962 0C1.21297 0 0.923309 0.0884956 0.668343 0.271923C0.235353 0.579244 0 1.08608 0 1.60257C0 1.90829 0.0829771 2.21722 0.254966 2.49075L2.63716 6.29445C2.87403 6.67257 3.00075 7.11826 3.00075 7.57361V14.399C3.00075 15.2824 3.67211 16 4.50038 16C5.32864 16 6 15.2824 6 14.399V6.75141C6 6.19952 5.84762 5.6605 5.55947 5.20032L4.30576 3.20193L4.30727 3.20032Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,3 +0,0 @@
<svg width="156" height="155" viewBox="0 0 156 155" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M78 0C57.4456 0 37.7349 8.16507 23.1984 22.6984C8.66507 37.2332 0.5 56.9446 0.5 77.5C0.5 98.0554 8.66507 117.765 23.1984 132.302C37.7332 146.835 57.4445 155 78 155C98.5554 155 118.265 146.835 132.802 132.302C147.335 117.767 155.5 98.0554 155.5 77.5C155.48 56.9522 147.308 37.2523 132.779 22.7227C118.249 8.19318 98.5489 0.0215072 78.0014 0.00138561L78 0ZM66.5377 111.48L29.1001 77.2273L39.5907 65.765L66.0523 89.992L115.768 40.2557L126.764 51.2517L66.5377 111.48Z" fill="white" fill-opacity="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 615 B

View File

@ -1,4 +1,9 @@
import { IconButton, InputAdornment, TextFieldProps } from '@mui/material';
import {
IconButton,
InputAdornment,
TextFieldProps,
useTheme,
} from '@mui/material';
import React, { useRef, useState } from 'react';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
@ -39,7 +44,7 @@ export const BoundedNumericTextField = ({
const stringIsEmpty = (value: string) => {
return value === '';
};
const theme = useTheme();
const isAllZerosNum = /^0*\.?0*$/;
const isFloatNum = /^-?[0-9]*\.?[0-9]*$/;
const isIntegerNum = /^-?[0-9]+$/;
@ -133,7 +138,7 @@ export const BoundedNumericTextField = ({
>
<AddIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>{' '}
</IconButton>
@ -143,7 +148,7 @@ export const BoundedNumericTextField = ({
>
<RemoveIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>{' '}
</IconButton>

View File

@ -1,7 +1,19 @@
import React from 'react'
import './customloader.css'
import React from 'react';
import './customloader.css';
import { Box, useTheme } from '@mui/material';
export const CustomLoader = () => {
const theme = useTheme();
return (
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
)
}
<Box
sx={{
'--text-primary': theme.palette.text.primary,
}}
className="lds-ellipsis"
>
<div></div>
<div></div>
<div></div>
<div></div>
</Box>
);
};

View File

@ -1,28 +1,29 @@
import React, { useState, useEffect, useRef } from 'react'
import { useInView } from 'react-intersection-observer'
import CircularProgress from '@mui/material/CircularProgress'
import React, { useState, useEffect, useRef } from 'react';
import { useInView } from 'react-intersection-observer';
import CircularProgress from '@mui/material/CircularProgress';
import { useTheme } from '@mui/material';
interface Props {
onLoadMore: () => Promise<void>
onLoadMore: () => Promise<void>;
}
const LazyLoad: React.FC<Props> = ({ onLoadMore }) => {
const [isFetching, setIsFetching] = useState<boolean>(false)
const firstLoad = useRef(false)
const [isFetching, setIsFetching] = useState<boolean>(false);
const theme = useTheme();
const firstLoad = useRef(false);
const [ref, inView] = useInView({
threshold: 0.7
})
threshold: 0.7,
});
useEffect(() => {
if (inView) {
setIsFetching(true)
setIsFetching(true);
onLoadMore().finally(() => {
setIsFetching(false)
firstLoad.current = true
})
setIsFetching(false);
firstLoad.current = true;
});
}
}, [inView])
}, [inView]);
return (
<div
@ -30,18 +31,22 @@ const LazyLoad: React.FC<Props> = ({ onLoadMore }) => {
style={{
display: 'flex',
justifyContent: 'center',
minHeight: '25px'
minHeight: '25px',
}}
>
<div
style={{
visibility: isFetching ? 'visible' : 'hidden'
visibility: isFetching ? 'visible' : 'hidden',
}}
>
<CircularProgress />
<CircularProgress
sx={{
color: theme.palette.text.primary,
}}
/>
</div>
</div>
)
}
);
};
export default LazyLoad
export default LazyLoad;

View File

@ -1,5 +1,5 @@
.lds-ellipsis {
color: white;
color: var(--text-primary);
}
.lds-ellipsis,
.lds-ellipsis div {

View File

@ -186,7 +186,7 @@ export const AppInfo = ({ app, myName }) => {
}}
sx={{
backgroundColor: isInstalled
? '#0091E1'
? theme.palette.primary.main
: theme.palette.background.paper,
height: '29px',
maxWidth: '320px',

View File

@ -183,7 +183,7 @@ export const AppInfoSnippet = ({
}}
sx={{
backgroundColor: isInstalled
? '#0091E1'
? theme.palette.primary.main
: theme.palette.background.paper,
}}
>

View File

@ -20,7 +20,13 @@ import {
PublishQAppChoseFile,
PublishQAppInfo,
} from './Apps-styles';
import { InputBase, InputLabel, MenuItem, Select } from '@mui/material';
import {
InputBase,
InputLabel,
MenuItem,
Select,
useTheme,
} from '@mui/material';
import { styled } from '@mui/system';
import UnfoldMoreRoundedIcon from '@mui/icons-material/UnfoldMoreRounded';
import { Add } from '@mui/icons-material';
@ -59,11 +65,11 @@ const CustomSelect = styled(Select)({
});
const CustomMenuItem = styled(MenuItem)({
backgroundColor: '#1f1f1f', // Background for dropdown items
color: '#ccc',
'&:hover': {
backgroundColor: '#333', // Darker background on hover
},
// backgroundColor: '#1f1f1f', // Background for dropdown items
// color: '#ccc',
// '&:hover': {
// backgroundColor: '#333', // Darker background on hover
// },
});
export const AppPublish = ({ names, categories }) => {
@ -74,7 +80,7 @@ export const AppPublish = ({ names, categories }) => {
const [appType, setAppType] = useState('APP');
const [file, setFile] = useState(null);
const { show } = useContext(MyContext);
const theme = useTheme();
const [tag1, setTag1] = useState('');
const [tag2, setTag2] = useState('');
const [tag3, setTag3] = useState('');
@ -263,9 +269,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="18px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
Name/App
</InputLabel>
@ -278,11 +282,11 @@ export const AppPublish = ({ names, categories }) => {
<CustomMenuItem value="">
<em
style={{
color: 'var(--50-white, #FFFFFF80)',
color: theme.palette.text.secondary,
}}
>
Select Name/App
</em>{' '}
</em>
{/* This is the placeholder item */}
</CustomMenuItem>
{names.map((name) => {
@ -292,9 +296,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="15px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
App service type
</InputLabel>
@ -307,12 +309,11 @@ export const AppPublish = ({ names, categories }) => {
<CustomMenuItem value="">
<em
style={{
color: 'var(--50-white, #FFFFFF80)',
color: theme.palette.text.secondary,
}}
>
Select App Type
</em>{' '}
{/* This is the placeholder item */}
</em>
</CustomMenuItem>
<CustomMenuItem value={'APP'}>App</CustomMenuItem>
<CustomMenuItem value={'WEBSITE'}>Website</CustomMenuItem>
@ -320,9 +321,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="15px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
Title
</InputLabel>
@ -330,7 +329,7 @@ export const AppPublish = ({ names, categories }) => {
value={title}
onChange={(e) => setTitle(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -347,9 +346,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="15px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
Description
</InputLabel>
@ -357,7 +354,7 @@ export const AppPublish = ({ names, categories }) => {
value={description}
onChange={(e) => setDescription(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -374,9 +371,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="15px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
Category
</InputLabel>
@ -389,12 +384,11 @@ export const AppPublish = ({ names, categories }) => {
<CustomMenuItem value="">
<em
style={{
color: 'var(--50-white, #FFFFFF80)',
color: theme.palette.text.secondary,
}}
>
Select Category
</em>{' '}
{/* This is the placeholder item */}
</em>
</CustomMenuItem>
{categories?.map((category) => {
return (
@ -407,9 +401,7 @@ export const AppPublish = ({ names, categories }) => {
<Spacer height="15px" />
<InputLabel
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
>
<InputLabel sx={{ fontSize: '14px', marginBottom: '2px' }}>
Tags
</InputLabel>
@ -418,7 +410,7 @@ export const AppPublish = ({ names, categories }) => {
value={tag1}
onChange={(e) => setTag1(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -435,7 +427,7 @@ export const AppPublish = ({ names, categories }) => {
value={tag2}
onChange={(e) => setTag2(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -452,7 +444,7 @@ export const AppPublish = ({ names, categories }) => {
value={tag3}
onChange={(e) => setTag3(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -469,7 +461,7 @@ export const AppPublish = ({ names, categories }) => {
value={tag4}
onChange={(e) => setTag4(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',
@ -486,7 +478,7 @@ export const AppPublish = ({ names, categories }) => {
value={tag5}
onChange={(e) => setTag5(e.target.value)}
sx={{
border: '0.5px solid var(--50-white, #FFFFFF80)',
border: `0.5px solid ${theme.palette.action.disabled}`,
padding: '0px 15px',
borderRadius: '5px',
height: '36px',

View File

@ -27,7 +27,7 @@ const AppViewerContainer = React.forwardRef(
}
.frame-content {
overflow: hidden;
height: '100vh';
height: 100vh;
}
`}
</style>
@ -35,7 +35,7 @@ const AppViewerContainer = React.forwardRef(
}
style={{
border: 'none',
height: '100vh',
height: customHeight || '100vh',
left: (!isSelected || hide) && '-200vw',
overflow: 'hidden',
position: (!isSelected || hide) && 'fixed',

View File

@ -75,7 +75,7 @@ export const AppsWidthLimiter = styled(Box)(({ theme }) => ({
export const AppsSearchContainer = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
borderRadius: '8px',
color: theme.palette.text.primary,
display: 'flex',
@ -87,7 +87,7 @@ export const AppsSearchContainer = styled(Box)(({ theme }) => ({
export const AppsSearchLeft = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
flexGrow: 1,
@ -99,7 +99,7 @@ export const AppsSearchLeft = styled(Box)(({ theme }) => ({
export const AppsSearchRight = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
flexShrink: 1,
@ -141,7 +141,7 @@ export const AppLibrarySubTitle = styled(Typography)(({ theme }) => ({
export const AppCircle = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
borderColor:
theme.palette.mode === 'dark'
? 'rgb(209, 209, 209)'
@ -283,7 +283,7 @@ export const TabParent = styled(Box)(({ theme }) => ({
export const PublishQAppCTAParent = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
justifyContent: 'space-between',
@ -292,7 +292,7 @@ export const PublishQAppCTAParent = styled(Box)(({ theme }) => ({
export const PublishQAppCTALeft = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
justifyContent: 'flex-start',
@ -300,7 +300,7 @@ export const PublishQAppCTALeft = styled(Box)(({ theme }) => ({
export const PublishQAppCTARight = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
justifyContent: 'flex-end',
@ -308,8 +308,8 @@ export const PublishQAppCTARight = styled(Box)(({ theme }) => ({
export const PublishQAppCTAButton = styled(ButtonBase)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.paper,
borderColor: theme.palette.background.default,
backgroundColor: theme.palette.background.default,
borderColor: theme.palette.text.primary,
borderRadius: '25px',
borderStyle: 'solid',
borderWidth: '1px',
@ -322,10 +322,10 @@ export const PublishQAppCTAButton = styled(ButtonBase)(({ theme }) => ({
export const PublishQAppDotsBG = styled(Box)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
display: 'flex',
height: '60px',
height: '80px',
justifyContent: 'center',
width: '60px',
}));
@ -333,7 +333,7 @@ export const PublishQAppDotsBG = styled(Box)(({ theme }) => ({
export const PublishQAppInfo = styled(Typography)(({ theme }) => ({
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
fontSize: '10px',
fontSize: '16px',
fontStyle: 'italic',
fontWeight: 400,
lineHeight: 1.2,
@ -341,15 +341,18 @@ export const PublishQAppInfo = styled(Typography)(({ theme }) => ({
export const PublishQAppChoseFile = styled(ButtonBase)(({ theme }) => ({
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
borderRadius: '5px',
color: theme.palette.text.primary,
display: 'flex',
fontSize: '10px',
fontSize: '16px',
fontWeight: 600,
height: '30px',
height: '40px',
justifyContent: 'center',
width: '101px',
width: '120px',
'&:hover': {
backgroundColor: 'action.hover', // background on hover
},
}));
export const AppsCategoryInfo = styled(Box)(({ theme }) => ({

View File

@ -24,6 +24,7 @@ import { useRecoilState } from 'recoil';
import { enabledDevModeAtom } from '../../atoms/global';
import { AppsIcon } from '../../assets/Icons/AppsIcon';
import { CoreSyncStatus } from '../CoreSyncStatus';
import { MessagingIconFilled } from '../../assets/Icons/MessagingIconFilled';
const uid = new ShortUniqueId({ length: 8 });
@ -342,6 +343,8 @@ export const AppsDesktop = ({
gap: '25px',
height: '100vh',
width: '60px',
backgroundColor: theme.palette.background.surface,
borderRight: `1px solid ${theme.palette.border.subtle}`,
}}
>
<ButtonBase
@ -384,7 +387,7 @@ export const AppsDesktop = ({
<IconWrapper
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -392,11 +395,11 @@ export const AppsDesktop = ({
label="Chat"
disableWidth
>
<MessagingIcon
<MessagingIconFilled
height={30}
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary

View File

@ -1,15 +1,6 @@
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { AppsDevModeHome } from './AppsDevModeHome';
import { Spacer } from '../../common/Spacer';
import { MyContext, getBaseApiReact } from '../../App';
import { AppInfo } from './AppInfo';
import {
executeEvent,
@ -19,19 +10,15 @@ import {
import { AppsParent } from './Apps-styles';
import AppViewerContainer from './AppViewerContainer';
import ShortUniqueId from 'short-unique-id';
import { AppPublish } from './AppPublish';
import { AppsLibraryDesktop } from './AppsLibraryDesktop';
import { AppsCategoryDesktop } from './AppsCategoryDesktop';
import { AppsNavBarDesktop } from './AppsNavBarDesktop';
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 { HubsIcon } from '../../assets/Icons/HubsIcon';
import { AppsDevModeNavBar } from './AppsDevModeNavBar';
import { AppsIcon } from '../../assets/Icons/AppsIcon';
import { IconWrapper } from '../Desktop/DesktopFooter';
import { CoreSyncStatus } from '../CoreSyncStatus';
import { MessagingIconFilled } from '../../assets/Icons/MessagingIconFilled';
const uid = new ShortUniqueId({ length: 8 });
@ -303,7 +290,7 @@ export const AppsDevMode = ({
<IconWrapper
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -311,11 +298,11 @@ export const AppsDevMode = ({
label="Chat"
disableWidth
>
<MessagingIcon
<MessagingIconFilled
height={30}
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary

View File

@ -6,7 +6,7 @@ import {
} from './Apps-styles';
import { NavBack } from '../../assets/Icons/NavBack.tsx';
import { NavAdd } from '../../assets/Icons/NavAdd.tsx';
import { ButtonBase, Tab, Tabs } from '@mui/material';
import { ButtonBase, Tab, Tabs, useTheme } from '@mui/material';
import {
executeEvent,
subscribeToEvent,
@ -23,7 +23,7 @@ export const AppsDevModeNavBar = () => {
const [navigationController, setNavigationController] = useRecoilState(
navigationControllerAtom
);
const theme = useTheme();
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
const tabsRef = useRef(null);
const [anchorEl, setAnchorEl] = useState(null);
@ -81,7 +81,7 @@ export const AppsDevModeNavBar = () => {
sx={{
position: 'relative',
flexDirection: 'column',
width: '60px',
width: '59px',
height: 'unset',
maxHeight: '70vh',
borderRadius: '0px 30px 30px 0px',
@ -114,9 +114,9 @@ export const AppsDevModeNavBar = () => {
scrollButtons={true}
sx={{
'& .MuiTabs-indicator': {
backgroundColor: 'white',
backgroundColor: theme.palette.text.primary,
},
maxHeight: `320px`, // Ensure the tabs container fits within the available space
maxHeight: `275px`, // Ensure the tabs container fits within the available space
overflow: 'hidden', // Prevents overflow on small screens
}}
>
@ -133,7 +133,7 @@ export const AppsDevModeNavBar = () => {
} // Pass custom component
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
padding: '0px',
margin: '0px',

View File

@ -69,10 +69,7 @@ export const AppsHomeDesktop = ({
display: 'flex',
gap: '20px',
alignItems: 'center',
backgroundColor:
theme.palette.mode === 'dark'
? 'rgba(41, 41, 43, 1)'
: 'rgb(209, 209, 209)',
backgroundColor: theme.palette.background.paper,
padding: '7px',
borderRadius: '20px',
width: '100%',
@ -91,9 +88,9 @@ export const AppsHomeDesktop = ({
placeholder="qortal://"
sx={{
width: '100%',
color: theme.palette.mode === 'dark' ? 'white' : 'black',
color: theme.palette.text.primary,
'& .MuiInput-input::placeholder': {
color: 'rgba(84, 84, 84, 0.70) !important',
color: theme.palette.text.secondary,
fontSize: '20px',
fontStyle: 'normal',
fontWeight: 400,
@ -115,7 +112,9 @@ export const AppsHomeDesktop = ({
<ButtonBase onClick={() => openQortalUrl()}>
<ArrowOutwardIcon
sx={{
color: qortalUrl ? 'white' : 'rgba(84, 84, 84, 0.70)',
color: qortalUrl
? theme.palette.text.primary
: theme.palette.text.secondary,
}}
/>
</ButtonBase>

View File

@ -39,7 +39,8 @@ import { Spacer } from '../../common/Spacer';
import { AppInfoSnippet } from './AppInfoSnippet';
import { Virtuoso } from 'react-virtuoso';
import { executeEvent } from '../../utils/events';
import { ShowMessageReturnButton } from '../Group/Forum/Mail-styles';
import { ComposeP, ShowMessageReturnButton } from '../Group/Forum/Mail-styles';
import { ReturnIcon } from '../../assets/Icons/ReturnIcon.tsx';
const officialAppList = [
'q-tube',
@ -273,7 +274,10 @@ export const AppsLibraryDesktop = ({
onClick={() => {
executeEvent('navigateBack', {});
}}
></ShowMessageReturnButton>
>
<ReturnIcon />
<ComposeP>Return to Apps Dashboard</ComposeP>
</ShowMessageReturnButton>
<Spacer height="20px" />
@ -467,11 +471,13 @@ export const AppsLibraryDesktop = ({
borderRadius: '6px',
borderStyle: 'solid',
borderWidth: '4px',
boxShadow: '2px 4px 0px 0px #000000',
display: 'flex',
height: '50px',
justifyContent: 'center',
padding: '0px 20px',
'&:hover': {
backgroundColor: 'action.hover', // background on hover
},
}}
>
All
@ -495,11 +501,13 @@ export const AppsLibraryDesktop = ({
borderRadius: '6px',
borderStyle: 'solid',
borderWidth: '4px',
boxShadow: '2px 4px 0px 0px #000000',
display: 'flex',
height: '50px',
justifyContent: 'center',
padding: '0px 20px',
'&:hover': {
backgroundColor: 'action.hover', // background on hover
},
}}
>
{category?.name}

View File

@ -160,7 +160,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
maxHeight: '70vh',
padding: '10px',
position: 'relative',
width: '60px',
width: '59px',
}}
>
<AppsNavBarLeft
@ -190,7 +190,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
'& .MuiTabs-indicator': {
backgroundColor: theme.palette.background.default,
},
maxHeight: `320px`, // Ensure the tabs container fits within the available space
maxHeight: `275px`, // Ensure the tabs container fits within the available space
overflow: 'hidden', // Prevents overflow on small screens
}}
>
@ -361,7 +361,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
height={20}
sx={{
color: isSelectedAppPinned
? 'var(--danger)'
? theme.palette.other.danger
: theme.palette.text.primary,
}}
/>
@ -372,7 +372,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
fontSize: '12px',
fontWeight: 600,
color: isSelectedAppPinned
? 'var(--danger)'
? theme.palette.other.danger
: theme.palette.text.primary,
},
}}

View File

@ -261,6 +261,12 @@ export const AppsPrivate = ({ myName }) => {
}}
maxWidth="md"
fullWidth={true}
PaperProps={{
style: {
backgroundColor: theme.palette.background.paper,
boxShadow: 'none',
},
}}
>
<Box>
<Tabs

View File

@ -1,4 +1,10 @@
import { Box, Checkbox, FormControlLabel, Typography } from '@mui/material';
import {
Box,
Checkbox,
FormControlLabel,
Typography,
useTheme,
} from '@mui/material';
import { Spacer } from '../../common/Spacer';
import { Return } from '../../assets/Icons/Return';
import { CustomButton, CustomLabel, TextP } from '../../styles/App-styles';
@ -24,7 +30,7 @@ export const DownloadWallet = ({
useState<string>('');
const [newPassword, setNewPassword] = useState<string>('');
const [keepCurrentPassword, setKeepCurrentPassword] = useState<boolean>(true);
const theme = useTheme();
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
useState<string>('');
@ -184,6 +190,14 @@ export const DownloadWallet = ({
edge="start"
tabIndex={-1}
disableRipple
sx={{
'&.Mui-checked': {
color: theme.palette.text.secondary,
},
'& .MuiSvgIcon-root': {
color: theme.palette.text.secondary,
},
}}
/>
}
label={

View File

@ -110,7 +110,6 @@ export const BuyQortInformation = ({ balance }) => {
</Typography>
<List
sx={{
bgcolor: theme.palette.background.default,
maxWidth: 360,
width: '100%',
}}
@ -118,21 +117,13 @@ export const BuyQortInformation = ({ balance }) => {
>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon
sx={{
color: theme.palette.primary.dark,
}}
/>
<RadioButtonCheckedIcon />
</ListItemIcon>
<ListItemText primary="Create transactions on the Qortal Blockchain" />
</ListItem>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon
sx={{
color: theme.palette.primary.dark,
}}
/>
<RadioButtonCheckedIcon />
</ListItemIcon>
<ListItemText primary="Having at least 4 QORT in your balance allows you to send chat messages at near instant speed." />
</ListItem>

View File

@ -101,7 +101,6 @@ export const AnnouncementItem = ({
sx={{
fontWight: 600,
fontFamily: 'Inter',
color: 'cadetBlue',
}}
>
{message?.name}

View File

@ -690,7 +690,8 @@ export const ChatDirect = ({
<Typography
sx={{
fontSize: '12px',
color: messageSize > 4000 ? 'var(--danger)' : 'unset',
color:
messageSize > 4000 ? theme.palette.other.danger : 'unset',
}}
>{`Your message size is of ${messageSize} bytes out of a maximum of 4000`}</Typography>
</Box>

View File

@ -997,6 +997,7 @@ export const ChatGroup = ({
opacity: hide ? 0 : 1,
position: hide ? 'absolute' : 'relative',
width: '100%',
padding: '10px',
}}
>
<ChatList
@ -1021,7 +1022,7 @@ export const ChatGroup = ({
{(!!secretKey || isPrivate === false) && (
<div
style={{
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
bottom: isFocusedParent ? '0px' : 'unset',
boxSizing: 'border-box',
display: 'flex',
@ -1034,6 +1035,8 @@ export const ChatGroup = ({
top: isFocusedParent ? '0px' : 'unset',
width: '100%',
zIndex: isFocusedParent ? 5 : 'unset',
border: `1px solid ${theme.palette.border.subtle}`,
borderRadius: '10px',
}}
>
<div
@ -1115,7 +1118,8 @@ export const ChatGroup = ({
<Typography
sx={{
fontSize: '12px',
color: messageSize > 4000 ? 'var(--danger)' : 'unset',
color:
messageSize > 4000 ? theme.palette.other.danger : 'unset',
}}
>{`Your message size is of ${messageSize} bytes out of a maximum of 4000`}</Typography>
</Box>
@ -1214,7 +1218,7 @@ export const ChatGroup = ({
>
<CloseIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>

View File

@ -2,7 +2,7 @@ import { useCallback, useState, useEffect, useRef, useMemo } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { MessageItem } from './MessageItem';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import { Box, Typography, useTheme } from '@mui/material';
import { Box, Button, Typography, useTheme } from '@mui/material';
import { ChatOptions } from './ChatOptions';
import ErrorBoundary from '../../common/ErrorBoundary';
@ -390,7 +390,7 @@ export const ChatList = ({
<button
onClick={() => scrollToBottom()}
style={{
backgroundColor: 'var(--unread)',
backgroundColor: theme.palette.other.unread,
border: 'none',
borderRadius: '20px',
bottom: 20,
@ -407,10 +407,11 @@ export const ChatList = ({
</button>
)}
{showScrollDownButton && !showScrollButton && (
<button
<Button
onClick={() => scrollToBottom()}
variant="contained"
style={{
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
border: 'none',
borderRadius: '20px',
bottom: 20,
@ -422,10 +423,11 @@ export const ChatList = ({
position: 'absolute',
right: 20,
zIndex: 10,
textTransform: 'none',
}}
>
Scroll to bottom
</button>
</Button>
)}
</div>
{enableMentions && (hasSecretKey || isPrivate === false) && (

View File

@ -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 (
<Box
sx={{
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
borderBottomLeftRadius: '20px',
borderTopLeftRadius: '20px',
display: 'flex',
flexDirection: 'column',
flexGrow: 0,
flexShrink: 0,
height: '100%',
height: '98%',
overflow: 'auto',
width: '300px',
}}
@ -398,7 +398,11 @@ export const ChatOptions = ({
>
<AppsSearchContainer>
<AppsSearchLeft>
<img src={IconSearch} />
<SearchIcon
sx={{
color: theme.palette.text.primary,
}}
/>
<InputBase
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
@ -576,7 +580,7 @@ export const ChatOptions = ({
<Box
sx={{
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
borderBottomLeftRadius: '20px',
borderTopLeftRadius: '20px',
display: 'flex',
@ -710,8 +714,8 @@ export const ChatOptions = ({
mentionList?.length > 0 &&
(!lastMentionTimestamp ||
lastMentionTimestamp < mentionList[0]?.timestamp)
? 'var(--unread)'
: 'white',
? theme.palette.other.unread
: theme.palette.text.primary,
}}
/>
</Tooltip>
@ -767,7 +771,6 @@ const ShowMessage = ({ message, goToMessage, messages }) => {
sx={{
fontWight: 600,
fontFamily: 'Inter',
color: 'cadetBlue',
}}
>
{message?.senderName}

View File

@ -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',

View File

@ -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(
<Spacer height="20px" />
<Box
sx={{
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
borderRadius: '5px',
cursor: 'pointer',
display: 'flex',
@ -319,9 +318,10 @@ export const MessageItem = React.memo(
>
<Box
sx={{
background: theme.palette.background.default,
background: theme.palette.text.primary,
height: '100%',
width: '5px',
flexShrink: 0,
}}
/>
<Box
@ -384,7 +384,7 @@ export const MessageItem = React.memo(
<ButtonBase
key={reaction}
sx={{
background: theme.palette.background.paper,
background: theme.palette.background.surface,
borderRadius: '7px',
height: '30px',
minWidth: '45px',
@ -571,7 +571,7 @@ export const ReplyPreview = ({ message, isEdit = false }) => {
return (
<Box
sx={{
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.surface,
borderRadius: '5px',
cursor: 'pointer',
display: 'flex',
@ -584,9 +584,10 @@ export const ReplyPreview = ({ message, isEdit = false }) => {
>
<Box
sx={{
background: theme.palette.background.default,
background: theme.palette.text.primary,
height: '100%',
width: '5px',
flexShrink: 0,
}}
/>
<Box

View File

@ -365,6 +365,7 @@ export default ({
membersWithNames,
enableMentions,
}) => {
const theme = useTheme();
const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useRecoilState(
isDisabledEditorEnterAtom
);
@ -483,12 +484,16 @@ export default ({
}, []);
return (
<div
style={{
<Box
sx={{
display: 'flex',
flexDirection: 'column',
height: '100%',
justifyContent: 'space-between',
'--text-primary': theme.palette.text.primary,
'--text-secondary': theme.palette.text.secondary,
'--background-default': theme.palette.background.default,
'--background-secondary': theme.palette.background.paper,
}}
>
<EditorProvider
@ -537,6 +542,6 @@ export default ({
},
}}
/>
</div>
</Box>
);
};

View File

@ -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 (
<div
onContextMenu={handleContextMenu} // For desktop right-click
onTouchStart={handleTouchStart} // For mobile long-press start
onTouchEnd={handleTouchEnd} // For mobile long-press end
onContextMenu={handleContextMenu} // For desktop right-click
onTouchStart={handleTouchStart} // For mobile long-press start
onTouchEnd={handleTouchEnd} // For mobile long-press end
style={{ width: '100%', height: '100%' }}
>
{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();
}}
>
<MenuItem onClick={(e) => {
handleClose(e)
executeEvent("markAsRead", {
groupId
});
}}>
<MenuItem
onClick={(e) => {
handleClose(e);
executeEvent('markAsRead', {
groupId,
});
}}
>
<ListItemIcon sx={{ minWidth: '32px' }}>
<MailOutlineIcon fontSize="small" />
<MailOutlineIcon
sx={{
color: theme.palette.text.primary,
}}
fontSize="small"
/>
</ListItemIcon>
<Typography variant="inherit" sx={{ fontSize: '14px' }}>
Mark As Read
</Typography>
</MenuItem>
<MenuItem onClick={(e) => {
handleClose(e)
handleSetGroupMute()
}}>
<MenuItem
onClick={(e) => {
handleClose(e);
handleSetGroupMute();
}}
>
<ListItemIcon sx={{ minWidth: '32px' }}>
<NotificationsOffIcon fontSize="small" sx={{
color: isMuted && 'red'
}} />
<NotificationsOffIcon
fontSize="small"
sx={{
color: isMuted ? 'red' : theme.palette.text.primary,
}}
/>
</ListItemIcon>
<Typography variant="inherit" sx={{ fontSize: '14px', color: isMuted && 'red' }}>
<Typography
variant="inherit"
sx={{ fontSize: '14px', color: isMuted && 'red' }}
>
{isMuted ? 'Unmute ' : 'Mute '}Push Notifications
</Typography>
</MenuItem>
@ -167,5 +187,3 @@ export const ContextMenu = ({ children, groupId, getUserSettings, mutedGroups })
</div>
);
};

View File

@ -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 }) => {
}}
>
<ListItemIcon sx={{ minWidth: '32px' }}>
<PushPinIcon fontSize="small" />
<PushPinIcon
sx={{
color: theme.palette.text.primary,
}}
fontSize="small"
/>
</ListItemIcon>
<Typography variant="inherit" sx={{ fontSize: '14px' }}>
<Typography sx={{ fontSize: '14px' }} color="text.primary">
Unpin app
</Typography>
</MenuItem>

View File

@ -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

View File

@ -104,14 +104,14 @@ export const DesktopHeader = ({
{isPrivate && (
<LockIcon
sx={{
color: 'var(--green)',
color: theme.palette.other.positive,
}}
/>
)}
{isPrivate === false && (
<NoEncryptionGmailerrorredIcon
sx={{
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
/>
)}
@ -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

View File

@ -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}`,
}}
>
<ButtonBase
@ -101,7 +103,7 @@ export const DesktopSideBar = ({
<IconWrapper
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -109,11 +111,11 @@ export const DesktopSideBar = ({
label="Chat"
disableWidth
>
<MessagingIcon
<MessagingIconFilled
height={30}
color={
hasUnreadDirects || hasUnreadGroups
? 'var(--unread)'
? theme.palette.other.unread
: desktopViewMode === 'chat'
? theme.palette.text.primary
: theme.palette.text.secondary

View File

@ -1,5 +1,5 @@
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";
import { MyContext, getBaseApiReact } from "../../App";
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { MyContext, getBaseApiReact } from '../../App';
import {
Card,
CardContent,
@ -15,285 +15,295 @@ import {
Dialog,
IconButton,
CircularProgress,
} from "@mui/material";
import { base64ToBlobUrl } from "../../utils/fileReading";
import { saveFileToDiskGeneric } from "../../utils/generateWallet/generateWallet";
useTheme,
} from '@mui/material';
import { base64ToBlobUrl } from '../../utils/fileReading';
import { saveFileToDiskGeneric } from '../../utils/generateWallet/generateWallet';
import AttachmentIcon from '@mui/icons-material/Attachment';
import RefreshIcon from "@mui/icons-material/Refresh";
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
import { CustomLoader } from "../../common/CustomLoader";
import { Spacer } from "../../common/Spacer";
import { FileAttachmentContainer, FileAttachmentFont } from "./Embed-styles";
import DownloadIcon from "@mui/icons-material/Download";
import RefreshIcon from '@mui/icons-material/Refresh';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { CustomLoader } from '../../common/CustomLoader';
import { Spacer } from '../../common/Spacer';
import { FileAttachmentContainer, FileAttachmentFont } from './Embed-styles';
import DownloadIcon from '@mui/icons-material/Download';
import SaveIcon from '@mui/icons-material/Save';
import { useSetRecoilState } from "recoil";
import { blobControllerAtom } from "../../atoms/global";
import { decodeIfEncoded } from "../../utils/decode";
import { useSetRecoilState } from 'recoil';
import { blobControllerAtom } from '../../atoms/global';
import { decodeIfEncoded } from '../../utils/decode';
export const AttachmentCard = ({
resourceData,
resourceDetails,
owner,
refresh,
openExternal,
external,
isLoadingParent,
errorMsg,
encryptionType,
selectedGroupId
}) => {
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 (
<Card
};
return (
<Card
sx={{
backgroundColor: theme.palette.background.default,
height: '250px',
// height: isOpen ? "auto" : "150px",
}}
>
<Box
sx={{
backgroundColor: "#1F2023",
height: "250px",
// height: isOpen ? "auto" : "150px",
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '16px 16px 0px 16px',
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "16px 16px 0px 16px",
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<Box
<AttachmentIcon
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
color: theme.palette.text.primary,
}}
>
<AttachmentIcon
/>
<Typography>ATTACHMENT embed</Typography>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<ButtonBase>
<RefreshIcon
onClick={refresh}
sx={{
color: "white",
fontSize: '24px',
color: theme.palette.text.primary,
}}
/>
<Typography>ATTACHMENT embed</Typography>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
}}
>
</ButtonBase>
{external && (
<ButtonBase>
<RefreshIcon
onClick={refresh}
<OpenInNewIcon
onClick={openExternal}
sx={{
fontSize: "24px",
color: "white",
fontSize: '24px',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>
{external && (
<ButtonBase>
<OpenInNewIcon
onClick={openExternal}
sx={{
fontSize: "24px",
color: "white",
}}
/>
</ButtonBase>
)}
</Box>
</Box>
<Box
sx={{
padding: "8px 16px 8px 16px",
}}
>
<Typography
sx={{
fontSize: "12px",
color: "white",
}}
>
Created by {decodeIfEncoded(owner)}
</Typography>
<Typography
sx={{
fontSize: "12px",
color: "cadetblue",
}}
>
{encryptionType === 'private' ? "ENCRYPTED" : encryptionType === 'group' ? 'GROUP ENCRYPTED' : "Not encrypted"}
</Typography>
</Box>
<Divider sx={{ borderColor: "rgb(255 255 255 / 10%)" }} />
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
alignItems: "center",
}}
>
{isLoadingParent && isOpen && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
}}
>
{" "}
<CustomLoader />{" "}
</Box>
)}
{errorMsg && (
<Box
</Box>
</Box>
<Box
sx={{
padding: '8px 16px 8px 16px',
}}
>
<Typography
sx={{
fontSize: '12px',
}}
>
Created by {decodeIfEncoded(owner)}
</Typography>
<Typography
sx={{
fontSize: '12px',
}}
>
{encryptionType === 'private'
? 'ENCRYPTED'
: encryptionType === 'group'
? 'GROUP ENCRYPTED'
: 'Not encrypted'}
</Typography>
</Box>
<Divider sx={{ borderColor: 'rgb(255 255 255 / 10%)' }} />
<Box
sx={{
display: 'flex',
flexDirection: 'column',
width: '100%',
alignItems: 'center',
}}
>
{isLoadingParent && isOpen && (
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
{' '}
<CustomLoader />{' '}
</Box>
)}
{errorMsg && (
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
{' '}
<Typography
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
fontSize: '14px',
color: theme.palette.other.danger,
}}
>
{" "}
{errorMsg}
</Typography>{' '}
</Box>
)}
</Box>
<Box>
<CardContent>
{resourceData?.fileName && (
<>
<Typography
sx={{
fontSize: "14px",
color: "var(--danger)",
fontSize: '14px',
}}
>
{errorMsg}
</Typography>{" "}
</Box>
{resourceData?.fileName}
</Typography>
<Spacer height="10px" />
</>
)}
</Box>
<Box>
<CardContent>
{resourceData?.fileName && (
<ButtonBase
sx={{
width: '90%',
maxWidth: '400px',
}}
onClick={() => {
if (resourceDetails?.status?.status === 'READY') {
if (encryptionType) {
saveToDiskEncrypted();
return;
}
saveToDisk();
return;
}
downloadResource(resourceData);
}}
>
<FileAttachmentContainer>
<Typography>
{resourceDetails?.status?.status === 'DOWNLOADED'
? 'BUILDING'
: resourceDetails?.status?.status}
</Typography>
{!resourceDetails && (
<>
<Typography sx={{
fontSize: '14px'
}}>{resourceData?.fileName}</Typography>
<Spacer height="10px" />
<DownloadIcon />
<FileAttachmentFont>Download File</FileAttachmentFont>
</>
)}
<ButtonBase sx={{
width: '90%',
maxWidth: '400px'
}} onClick={()=> {
if(resourceDetails?.status?.status === 'READY'){
if(encryptionType){
saveToDiskEncrypted()
return
}
saveToDisk()
return
}
downloadResource(resourceData)
}}>
<FileAttachmentContainer >
<Typography>{resourceDetails?.status?.status === 'DOWNLOADED' ? 'BUILDING' : resourceDetails?.status?.status}</Typography>
{!resourceDetails && (
<>
<DownloadIcon />
<FileAttachmentFont>Download File</FileAttachmentFont>
</>
)}
{resourceDetails && resourceDetails?.status?.status !== 'READY' && resourceDetails?.status?.status !== 'FAILED_TO_DOWNLOAD' && (
<>
<CircularProgress sx={{
color: 'white'
}} size={20} />
<FileAttachmentFont>Downloading: {resourceDetails?.status?.percentLoaded || '0'}%</FileAttachmentFont>
</>
)}
{resourceDetails && resourceDetails?.status?.status === 'READY' && (
<>
<SaveIcon />
<FileAttachmentFont>Save to Disk</FileAttachmentFont>
</>
)}
</FileAttachmentContainer>
</ButtonBase>
</CardContent>
</Box>
</Card>
);
};
{resourceDetails &&
resourceDetails?.status?.status !== 'READY' &&
resourceDetails?.status?.status !== 'FAILED_TO_DOWNLOAD' && (
<>
<CircularProgress
size={20}
sx={{
color: theme.palette.text.primary,
}}
/>
<FileAttachmentFont>
Downloading:{' '}
{resourceDetails?.status?.percentLoaded || '0'}%
</FileAttachmentFont>
</>
)}
{resourceDetails &&
resourceDetails?.status?.status === 'READY' && (
<>
<SaveIcon />
<FileAttachmentFont>Save to Disk</FileAttachmentFont>
</>
)}
</FileAttachmentContainer>
</ButtonBase>
</CardContent>
</Box>
</Card>
);
};

View File

@ -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 (
<Card
image,
fetchImage,
owner,
refresh,
openExternal,
external,
isLoadingParent,
errorMsg,
encryptionType,
}) => {
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 (
<Card
sx={{
backgroundColor: theme.palette.background.default,
height: height,
transition: 'height 0.6s ease-in-out',
}}
>
<Box
sx={{
backgroundColor: "#1F2023",
height: height,
transition: "height 0.6s ease-in-out",
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '16px 16px 0px 16px',
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "16px 16px 0px 16px",
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<Box
<ImageIcon
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
color: theme.palette.text.primary,
}}
>
<ImageIcon
/>
<Typography>IMAGE embed</Typography>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<ButtonBase>
<RefreshIcon
onClick={refresh}
sx={{
color: "white",
fontSize: '24px',
color: theme.palette.text.primary,
}}
/>
<Typography>IMAGE embed</Typography>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
}}
>
</ButtonBase>
{external && (
<ButtonBase>
<RefreshIcon
onClick={refresh}
<OpenInNewIcon
onClick={openExternal}
sx={{
fontSize: "24px",
color: "white",
fontSize: '24px',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>
{external && (
<ButtonBase>
<OpenInNewIcon
onClick={openExternal}
sx={{
fontSize: "24px",
color: "white",
}}
/>
</ButtonBase>
)}
)}
</Box>
</Box>
<Box
sx={{
padding: '8px 16px 8px 16px',
}}
>
<Typography
sx={{
fontSize: '12px',
}}
>
Created by {decodeIfEncoded(owner)}
</Typography>
<Typography
sx={{
fontSize: '12px',
}}
>
{encryptionType === 'private'
? 'ENCRYPTED'
: encryptionType === 'group'
? 'GROUP ENCRYPTED'
: 'Not encrypted'}
</Typography>
</Box>
<Divider sx={{ borderColor: 'rgb(255 255 255 / 10%)' }} />
<Box
sx={{
display: 'flex',
flexDirection: 'column',
width: '100%',
alignItems: 'center',
}}
>
{isLoadingParent && isOpen && (
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
{' '}
<CustomLoader />{' '}
</Box>
</Box>
<Box
sx={{
padding: "8px 16px 8px 16px",
}}
>
<Typography
)}
{errorMsg && (
<Box
sx={{
fontSize: "12px",
color: "white",
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
Created by {decodeIfEncoded(owner)}
</Typography>
<Typography
sx={{
fontSize: "12px",
color: "cadetblue",
}}
>
{encryptionType === 'private' ? "ENCRYPTED" : encryptionType === 'group' ? 'GROUP ENCRYPTED' : "Not encrypted"}
</Typography>
</Box>
<Divider sx={{ borderColor: "rgb(255 255 255 / 10%)" }} />
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
alignItems: "center",
}}
>
{isLoadingParent && isOpen && (
<Box
{' '}
<Typography
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
fontSize: '14px',
color: theme.palette.other.danger,
}}
>
{" "}
<CustomLoader />{" "}
</Box>
)}
{errorMsg && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
}}
>
{" "}
<Typography
sx={{
fontSize: "14px",
color: "var(--danger)",
}}
>
{errorMsg}
</Typography>{" "}
</Box>
)}
</Box>
<Box>
<CardContent>
<ImageViewer src={image} />
</CardContent>
</Box>
</Card>
);
};
{errorMsg}
</Typography>{' '}
</Box>
)}
</Box>
export function ImageViewer({ src, alt = "" }) {
const [isFullscreen, setIsFullscreen] = useState(false);
const handleOpenFullscreen = () => setIsFullscreen(true);
const handleCloseFullscreen = () => setIsFullscreen(false);
return (
<>
{/* Image in container */}
<Box>
<CardContent>
<ImageViewer src={image} />
</CardContent>
</Box>
</Card>
);
};
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 */}
<Box
sx={{
maxWidth: '100%', // Prevent horizontal overflow
display: 'flex',
justifyContent: 'center',
cursor: 'pointer',
}}
onClick={handleOpenFullscreen}
>
<img
src={src}
alt={alt}
style={{
maxWidth: '100%',
maxHeight: '450px', // Adjust max height for small containers
objectFit: 'contain', // Preserve aspect ratio
}}
/>
</Box>
{/* Fullscreen Viewer */}
<Dialog
open={isFullscreen}
onClose={handleCloseFullscreen}
maxWidth="lg"
fullWidth
fullScreen
sx={{
'& .MuiDialog-paper': {
margin: 0,
maxWidth: '100%',
width: '100%',
height: '100vh',
overflow: 'hidden', // Prevent scrollbars
},
}}
>
<Box
sx={{
maxWidth: "100%", // Prevent horizontal overflow
display: "flex",
justifyContent: "center",
cursor: "pointer",
position: 'relative',
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: theme.palette.background.paper, // Optional: dark background for fullscreen mode
}}
onClick={handleOpenFullscreen}
>
{/* Close Button */}
<IconButton
onClick={handleCloseFullscreen}
sx={{
position: 'absolute',
top: 8,
right: 8,
zIndex: 10,
color: theme.palette.text.primary,
}}
>
<CloseIcon />
</IconButton>
{/* Fullscreen Image */}
<img
src={src}
alt={alt}
style={{
maxWidth: "100%",
maxHeight: "450px", // Adjust max height for small containers
objectFit: "contain", // Preserve aspect ratio
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain', // Preserve aspect ratio
}}
/>
</Box>
{/* Fullscreen Viewer */}
<Dialog
open={isFullscreen}
onClose={handleCloseFullscreen}
maxWidth="lg"
fullWidth
fullScreen
sx={{
"& .MuiDialog-paper": {
margin: 0,
maxWidth: "100%",
width: "100%",
height: "100vh",
overflow: "hidden", // Prevent scrollbars
},
}}
>
<Box
sx={{
position: "relative",
width: "100%",
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#000", // Optional: dark background for fullscreen mode
}}
>
{/* Close Button */}
<IconButton
onClick={handleCloseFullscreen}
sx={{
position: "absolute",
top: 8,
right: 8,
zIndex: 10,
color: "white",
}}
>
<CloseIcon />
</IconButton>
{/* Fullscreen Image */}
<img
src={src}
alt={alt}
style={{
maxWidth: "100%",
maxHeight: "100%",
objectFit: "contain", // Preserve aspect ratio
}}
/>
</Box>
</Dialog>
</>
);
}
</Dialog>
</>
);
}

View File

@ -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 (
<Card
sx={{
backgroundColor: '#1F2023',
backgroundColor: theme.palette.background.default,
height: isOpen ? 'auto' : '150px',
}}
>
@ -124,7 +126,7 @@ export const PollCard = ({
>
<PollIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
<Typography>POLL embed</Typography>
@ -141,7 +143,7 @@ export const PollCard = ({
onClick={refresh}
sx={{
fontSize: '24px',
color: 'white',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>
@ -151,7 +153,7 @@ export const PollCard = ({
onClick={openExternal}
sx={{
fontSize: '24px',
color: 'white',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>
@ -186,9 +188,6 @@ export const PollCard = ({
<Button
size="small"
variant="contained"
sx={{
backgroundColor: 'var(--green)',
}}
onClick={() => {
setIsOpen(true);
}}
@ -221,7 +220,7 @@ export const PollCard = ({
<Typography
sx={{
fontSize: '14px',
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
>
{errorMsg}
@ -260,16 +259,7 @@ export const PollCard = ({
<FormControlLabel
key={index}
value={index}
control={
<Radio
sx={{
color: 'white', // Unchecked color
'&.Mui-checked': {
color: 'var(--green)', // Checked color
},
}}
/>
}
control={<Radio />}
label={option?.optionName}
sx={{
'& .MuiFormControlLabel-label': {

View File

@ -63,7 +63,7 @@ export const GeneralNotifications = ({ address }) => {
tooltip: {
sx: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
},
},
arrow: {
@ -76,8 +76,8 @@ export const GeneralNotifications = ({ address }) => {
<NotificationsIcon
sx={{
color: hasNewPayment
? 'var(--unread)'
: theme.palette.text.primary,
? theme.palette.other.unread
: theme.palette.text.secondary,
}}
/>
</Tooltip>
@ -149,7 +149,7 @@ export const GeneralNotifications = ({ address }) => {
>
<AccountBalanceWalletIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>{' '}
{formatDate(latestTx?.timestamp)}

View File

@ -9,6 +9,7 @@ import {
DialogActions,
DialogContent,
Typography,
useTheme,
} from '@mui/material';
import { CustomButton, CustomButtonAccept } from '../../styles/App-styles';
import { getBaseApiReact, MyContext } from '../../App';
@ -23,6 +24,7 @@ export const JoinGroup = ({ memberGroups }) => {
const [groupInfo, setGroupInfo] = useState(null);
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
const handleJoinGroup = async (e) => {
setGroupInfo(null);
@ -151,7 +153,7 @@ export const JoinGroup = ({ memberGroups }) => {
<CircularProgress
size={25}
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>{' '}
</Box>
@ -228,7 +230,7 @@ export const JoinGroup = ({ memberGroups }) => {
>
<CustomButtonAccept
color="black"
bgColor="var(--green)"
bgColor={theme.palette.other.positive}
sx={{
minWidth: '102px',
height: '45px',
@ -242,7 +244,7 @@ export const JoinGroup = ({ memberGroups }) => {
<CustomButtonAccept
color="black"
bgColor="var(--danger)"
bgColor={theme.palette.other.danger}
sx={{
minWidth: '102px',
height: '45px',

View File

@ -6,6 +6,7 @@ import {
Popover,
TextField,
Typography,
useTheme,
} from '@mui/material';
import {
useCallback,
@ -45,7 +46,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
const [inputValue, setInputValue] = useState('');
const [filteredItems, setFilteredItems] = useState(groups);
const [isLoading, setIsLoading] = useState(false);
const theme = useTheme();
const handleFilter = useCallback(
(query) => {
if (query) {
@ -254,14 +255,14 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
{group?.isOpen === false && (
<LockIcon
sx={{
color: 'var(--green)',
color: theme.palette.other.positive,
}}
/>
)}
{group?.isOpen === true && (
<NoEncryptionGmailerrorredIcon
sx={{
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
/>
)}

View File

@ -1,45 +0,0 @@
import { useMemo } from 'react';
import DOMPurify from 'dompurify';
import 'react-quill/dist/quill.snow.css';
import 'react-quill/dist/quill.core.css';
import 'react-quill/dist/quill.bubble.css';
import { Box, styled } from '@mui/material';
import { convertQortalLinks } from '../../../utils/qortalLink';
const CrowdfundInlineContent = styled(Box)(({ theme }) => ({
display: 'flex',
fontFamily: 'Mulish',
fontSize: '19px',
fontWeight: 400,
letterSpacing: 0,
color: theme.palette.text.primary,
width: '100%',
}));
export const DisplayHtml = ({ html, textColor }: any) => {
const cleanContent = useMemo(() => {
if (!html) return null;
const sanitize: string = DOMPurify.sanitize(html, {
USE_PROFILES: { html: true },
});
const anchorQortal = convertQortalLinks(sanitize);
return anchorQortal;
}, [html]);
if (!cleanContent) return null;
return (
<CrowdfundInlineContent>
<div
className="ql-editor-display"
style={{
color: textColor || 'white',
fontWeight: 400,
fontSize: '16px',
}}
dangerouslySetInnerHTML={{ __html: cleanContent }}
/>
</CrowdfundInlineContent>
);
};

View File

@ -5,7 +5,7 @@ import React, {
useRef,
useState,
} from 'react';
import { Avatar, Box, Popover, Typography } from '@mui/material';
import { Avatar, Box, Popover, Typography, useTheme } from '@mui/material';
// import { MAIL_SERVICE_TYPE, THREAD_SERVICE_TYPE } from "../../constants/mail";
import { Thread } from './Thread';
import {
@ -49,7 +49,6 @@ import {
handleUnencryptedPublishes,
} from '../../Chat/GroupAnnouncements';
import CheckSVG from '../../../assets/svgs/Check.svg';
import SortSVG from '../../../assets/svgs/Sort.svg';
import ArrowDownSVG from '../../../assets/svgs/ArrowDown.svg';
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
import { executeEvent } from '../../../utils/events';
@ -57,9 +56,11 @@ import RefreshIcon from '@mui/icons-material/Refresh';
import { getArbitraryEndpointReact, getBaseApiReact } from '../../../App';
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group';
import { useTranslation } from 'react-i18next';
import { SortIcon } from '../../../assets/Icons/SortIcon';
import { CustomButton } from '../../../styles/App-styles';
const filterOptions = ['Recently active', 'Newest', 'Oldest'];
import CheckIcon from '@mui/icons-material/Check';
export const threadIdentifier = 'DOCUMENT';
export const GroupMail = ({
@ -83,7 +84,7 @@ export const GroupMail = ({
const [tempPublishedList, setTempPublishedList] = useState([]);
const dataPublishes = useRef({});
const { t } = useTranslation(['core']);
const theme = useTheme();
const [isLoading, setIsLoading] = useState(false);
const groupIdRef = useRef<any>(null);
const groupId = useMemo(() => {
@ -605,13 +606,19 @@ export const GroupMail = ({
}}
sx={{
backgroundColor:
filterMode === filter ? 'rgba(74, 158, 244, 1)' : 'unset',
filterMode === filter
? theme.palette.action.selected
: 'unset',
}}
key={filter}
>
<InstanceListContainerRowCheck>
{filter === filterMode && (
<InstanceListContainerRowCheckIcon src={CheckSVG} />
<CheckIcon
sx={{
color: theme.palette.text.primary,
}}
/>
)}
</InstanceListContainerRowCheck>
<InstanceListContainerRowMain>
@ -657,7 +664,7 @@ export const GroupMail = ({
}}
ref={anchorElInstanceFilter}
>
<ComposeIcon src={SortSVG} />
<SortIcon />
<SelectInstanceContainerFilterInner>
<ComposeP>Sort by</ComposeP>
@ -680,8 +687,8 @@ export const GroupMail = ({
<RefreshIcon
onClick={refetchThreadsLists}
sx={{
color: 'white',
cursor: 'pointer',
color: theme.palette.text.primary,
}}
/>
</Box>
@ -771,7 +778,7 @@ export const GroupMail = ({
</div>
)}
</div>
<Box
<CustomButton
onClick={() => {
setTimeout(() => {
executeEvent('threadFetchMode', {
@ -781,7 +788,6 @@ export const GroupMail = ({
}}
sx={{
alignItems: 'center',
backgroundColor: '#27282c',
borderRadius: '5px',
bottom: '2px',
cursor: 'pointer',
@ -790,14 +796,11 @@ export const GroupMail = ({
padding: '5px',
position: 'absolute',
right: '2px',
'&:hover': {
background: 'rgba(255, 255, 255, 0.60)',
},
minWidth: 'unset',
}}
>
<Typography
sx={{
color: 'white',
fontSize: '12px',
}}
>
@ -807,11 +810,11 @@ export const GroupMail = ({
</Typography>
<ArrowForwardIosIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
fontSize: '12px',
}}
/>
</Box>
</CustomButton>
</SingleThreadParent>
);
})}

View File

@ -1,16 +1,6 @@
import { Typography, Box, TextField } from '@mui/material';
import { Typography, Box } from '@mui/material';
import { styled } from '@mui/system';
export const InstanceContainer = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
width: '100%',
backgroundColor: 'var(--color-instance)',
height: '59px',
flexShrink: 0,
justifyContent: 'space-between',
}));
export const MailContainer = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
@ -88,7 +78,7 @@ export const ComposeContainer = styled(Box)(({ theme }) => ({
transition: '0.2s background-color',
justifyContent: 'center',
'&:hover': {
backgroundColor: 'rgba(67, 68, 72, 1)',
backgroundColor: theme.palette.action.hover,
},
}));
@ -141,19 +131,6 @@ export const SelectInstanceContainer = styled(Box)(({ theme }) => ({
gap: '17px',
}));
export const SelectInstanceContainerInner = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: '3px',
cursor: 'pointer',
padding: '8px',
transition: 'all 0.2s',
'&:hover': {
borderRadius: '8px',
background: '#434448',
},
}));
export const SelectInstanceContainerFilterInner = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
@ -174,100 +151,21 @@ export const InstanceP = styled(Typography)(({ theme }) => ({
fontWeight: 500,
}));
export const MailMessageRowContainer = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
justifyContent: 'space-between',
borderRadius: '56px 5px 10px 56px',
paddingRight: '15px',
transition: 'background 0.2s',
gap: '10px',
'&:hover': {
background: '#434448',
},
}));
export const MailMessageRowProfile = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
justifyContent: 'flex-start',
gap: '10px',
width: '50%',
overflow: 'hidden',
}));
export const MailMessageRowInfo = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
justifyContent: 'flex-start',
gap: '7px',
width: '50%',
}));
export const MailMessageRowInfoStatusNotDecrypted = styled(Typography)(
({ theme }) => ({
fontSize: '16px',
fontWeight: 900,
textTransform: 'uppercase',
paddingTop: '2px',
})
);
export const MailMessageRowInfoStatusRead = styled(Typography)(({ theme }) => ({
fontSize: '16px',
fontWeight: 300,
}));
export const MessageExtraInfo = styled(Box)(({ theme }) => ({
export const InstanceListParent = styled(Typography)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: '2px',
overflow: 'hidden',
width: '425px', // only one width now
minHeight: '246px',
maxHeight: '325px',
padding: '10px 0px 7px 0px',
border: '1px solid rgba(0, 0, 0, 0.1)',
}));
export const MessageExtraName = styled(Typography)(({ theme }) => ({
fontSize: '16px',
fontWeight: 900,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
}));
export const MessageExtraDate = styled(Typography)(({ theme }) => ({
fontSize: '15px',
fontWeight: 500,
}));
export const MessagesContainer = styled(Box)(({ theme }) => ({
width: '460px',
maxWidth: '90%',
export const InstanceListHeader = styled(Typography)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: '12px',
width: '100%',
}));
export const InstanceListParent = styled(Box)`
display: flex;
flex-direction: column;
width: 100%;
min-height: 246px;
max-height: 325px;
width: 425px;
padding: 10px 0px 7px 0px;
background-color: var(--color-instance-popover-bg);
border: 1px solid rgba(0, 0, 0, 0.1);
`;
export const InstanceListHeader = styled(Box)`
display: flex;
flex-direction: column;
width: 100%;
background-color: var(--color-instance-popover-bg);
`;
export const InstanceFooter = styled(Box)`
display: flex;
flex-direction: column;
@ -330,7 +228,7 @@ export const InstanceListContainerRow = styled(Box)(({ theme }) => ({
cursor: 'pointer',
transition: '0.2s background',
'&:hover': {
background: 'rgba(67, 68, 72, 1)',
background: theme.palette.action.hover,
},
flexShrink: 0,
}));
@ -378,44 +276,6 @@ export const InstanceListContainerRowGroupIcon = styled('img')({
userSelect: 'none',
objectFit: 'contain',
});
export const TypeInAliasTextfield = styled(TextField)({
width: '340px', // Adjust the width as needed
borderRadius: '5px',
backgroundColor: 'rgba(30, 30, 32, 1)',
border: 'none',
outline: 'none',
input: {
fontSize: 16,
color: 'white',
'&::placeholder': {
fontSize: 16,
color: 'rgba(255, 255, 255, 0.2)',
},
border: 'none',
outline: 'none',
padding: '10px',
},
'& .MuiOutlinedInput-root': {
'& fieldset': {
border: 'none',
},
'&:hover fieldset': {
border: 'none',
},
'&.Mui-focused fieldset': {
border: 'none',
},
},
'& .MuiInput-underline:before': {
borderBottom: 'none',
},
'& .MuiInput-underline:hover:not(.Mui-disabled):before': {
borderBottom: 'none',
},
'& .MuiInput-underline:after': {
borderBottom: 'none',
},
});
export const NewMessageCloseImg = styled('img')({
width: 'auto',
@ -427,6 +287,7 @@ export const NewMessageCloseImg = styled('img')({
export const NewMessageHeaderP = styled(Typography)(({ theme }) => ({
fontSize: '18px',
fontWeight: 600,
color: theme.palette.text.primary,
}));
export const NewMessageInputRow = styled(Box)(({ theme }) => ({
@ -480,29 +341,24 @@ export const NewMessageAttachmentImg = styled('img')({
border: '1px dashed #646464',
});
export const NewMessageSendButton = styled(Box)`
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.9);
display: inline-flex;
padding: 8px 16px 8px 12px;
justify-content: center;
align-items: center;
gap: 8px;
width: fit-content;
transition: all 0.2s;
color: black;
min-width: 120px;
gap: 8px;
position: relative;
cursor: pointer;
&:hover {
background-color: rgba(41, 41, 43, 1);
color: white;
svg path {
fill: white; // Fill color changes to white on hover
}
}
`;
export const NewMessageSendButton = styled(Box)(({ theme }) => ({
borderRadius: '4px',
border: `1px solid ${theme.palette.border.main}`, // you can replace with theme.palette.divider or whatever you want later
display: 'inline-flex',
padding: '8px 16px 8px 12px',
justifyContent: 'center',
alignItems: 'center',
width: 'fit-content',
transition: 'all 0.2s',
color: theme.palette.text.primary, // replace later with theme.palette.text.primary if needed
minWidth: '120px',
position: 'relative',
gap: '8px',
cursor: 'pointer',
'&:hover': {
backgroundColor: theme.palette.action.hover, // replace with theme value if needed
},
}));
export const NewMessageSendP = styled(Typography)`
font-family: Roboto;
@ -524,14 +380,7 @@ export const ShowMessageNameP = styled(Typography)`
text-overflow: ellipsis;
overflow: hidden;
`;
export const ShowMessageTimeP = styled(Typography)`
color: rgba(255, 255, 255, 0.5);
font-family: Roboto;
font-size: 15px;
font-style: normal;
font-weight: 500;
line-height: normal;
`;
export const ShowMessageSubjectP = styled(Typography)`
font-family: Roboto;
font-size: 16px;
@ -541,61 +390,44 @@ export const ShowMessageSubjectP = styled(Typography)`
text-align: left;
`;
export const ShowMessageButton = styled(Box)`
display: inline-flex;
padding: 8px 16px 8px 16px;
align-items: center;
justify-content: center;
gap: 8px;
width: fit-content;
transition: all 0.2s;
color: white;
background-color: rgba(41, 41, 43, 1)
min-width: 120px;
gap: 8px;
border-radius: 4px;
border: 0.5px solid rgba(255, 255, 255, 0.70);
font-family: Roboto;
export const ShowMessageButton = styled(Box)(({ theme }) => ({
display: 'inline-flex',
padding: '8px 16px',
alignItems: 'center',
justifyContent: 'center',
width: 'fit-content',
transition: 'all 0.2s',
color: theme.palette.text.primary, // you'll replace with theme value
minWidth: '120px',
gap: '8px',
borderRadius: '4px',
border: theme.palette.border.main, // you'll replace
fontFamily: 'Roboto',
cursor: 'pointer',
'&:hover': {
background: theme.palette.action.hover, // you'll replace
borderRadius: '4px',
},
}));
min-width: 120px;
cursor: pointer;
&:hover {
border-radius: 4px;
border: 0.5px solid rgba(255, 255, 255, 0.70);
background: #434448;
}
`;
export const ShowMessageReturnButton = styled(Box)`
display: inline-flex;
padding: 8px 16px 8px 16px;
align-items: center;
justify-content: center;
gap: 8px;
width: fit-content;
transition: all 0.2s;
color: white;
background-color: rgba(41, 41, 43, 1)
min-width: 120px;
gap: 8px;
border-radius: 4px;
font-family: Roboto;
min-width: 120px;
cursor: pointer;
&:hover {
border-radius: 4px;
background: #434448;
}
`;
export const ShowMessageButtonP = styled(Typography)`
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 120%; /* 19.2px */
letter-spacing: -0.16px;
color: white;
`;
export const ShowMessageReturnButton = styled(Box)(({ theme }) => ({
display: 'inline-flex',
padding: '8px 16px',
alignItems: 'center',
justifyContent: 'center',
width: 'fit-content',
transition: 'all 0.2s',
color: theme.palette.text.primary, // you'll replace with theme value
minWidth: '120px',
gap: '8px',
borderRadius: '4px',
fontFamily: 'Roboto',
cursor: 'pointer',
'&:hover': {
background: theme.palette.action.hover, // you'll replace
borderRadius: '4px',
},
}));
export const ShowMessageButtonImg = styled('img')({
width: 'auto',
@ -630,18 +462,16 @@ export const MoreImg = styled('img')({
},
});
export const MoreP = styled(Typography)`
color: rgba(255, 255, 255, 0.5);
/* Attachments */
font-family: Roboto;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 120%; /* 19.2px */
letter-spacing: -0.16px;
white-space: nowrap;
`;
export const MoreP = styled(Typography)(({ theme }) => ({
color: theme.palette.text.primary, // Now dynamic
fontFamily: 'Roboto',
fontSize: '16px',
fontStyle: 'normal',
fontWeight: 400,
lineHeight: '120%', // 19.2px
letterSpacing: '-0.16px',
whiteSpace: 'nowrap',
}));
export const ThreadContainerFullWidth = styled(Box)(({ theme }) => ({
display: 'flex',
@ -658,7 +488,6 @@ export const ThreadContainer = styled(Box)(({ theme }) => ({
}));
export const GroupNameP = styled(Typography)`
color: #fff;
font-size: 25px;
font-style: normal;
font-weight: 700;
@ -667,7 +496,6 @@ export const GroupNameP = styled(Typography)`
`;
export const AllThreadP = styled(Typography)`
color: #fff;
font-size: 20px;
font-style: normal;
font-weight: 400;
@ -675,32 +503,32 @@ export const AllThreadP = styled(Typography)`
letter-spacing: 0.15px;
`;
export const SingleThreadParent = styled(Box)`
border-radius: 35px 4px 4px 35px;
position: relative;
background: #434448;
display: flex;
padding: 13px;
cursor: pointer;
margin-bottom: 5px;
height: 76px;
align-items: center;
transition: 0.2s all;
&:hover {
background: rgba(255, 255, 255, 0.2);
}
`;
export const SingleThreadParent = styled(Box)(({ theme }) => ({
borderRadius: '35px 4px 4px 35px',
position: 'relative',
display: 'flex',
padding: '13px',
cursor: 'pointer',
marginBottom: '5px',
height: '76px',
alignItems: 'center',
transition: '0.2s all',
backgroundColor: theme.palette.background.paper, // or remove if you want no background by default
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
}));
export const SingleTheadMessageParent = styled(Box)`
border-radius: 35px 4px 4px 35px;
background: #434448;
display: flex;
padding: 13px;
cursor: pointer;
margin-bottom: 5px;
height: 76px;
align-items: center;
`;
export const SingleTheadMessageParent = styled(Box)(({ theme }) => ({
borderRadius: '35px 4px 4px 35px',
background: theme.palette.background.paper,
display: 'flex',
padding: '13px',
cursor: 'pointer',
marginBottom: '5px',
height: '76px',
alignItems: 'center',
}));
export const ThreadInfoColumn = styled(Box)(({ theme }) => ({
display: 'flex',
@ -713,7 +541,6 @@ export const ThreadInfoColumn = styled(Box)(({ theme }) => ({
}));
export const ThreadInfoColumnNameP = styled(Typography)`
color: #fff;
font-family: Roboto;
font-size: 16px;
font-style: normal;
@ -724,26 +551,25 @@ export const ThreadInfoColumnNameP = styled(Typography)`
overflow: hidden;
`;
export const ThreadInfoColumnbyP = styled('span')`
color: rgba(255, 255, 255, 0.8);
font-family: Roboto;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: normal;
`;
export const ThreadInfoColumnbyP = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
fontFamily: 'Roboto',
fontSize: '16px',
fontStyle: 'normal',
fontWeight: 500,
lineHeight: 'normal',
}));
export const ThreadInfoColumnTime = styled(Typography)`
color: rgba(255, 255, 255, 0.8);
font-family: Roboto;
font-size: 15px;
font-style: normal;
font-weight: 500;
line-height: normal;
`;
export const ThreadInfoColumnTime = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
fontFamily: 'Roboto',
fontSize: '15px',
fontStyle: 'normal',
fontWeight: 500,
lineHeight: 'normal',
}));
export const ThreadSingleTitle = styled(Typography)`
color: #fff;
font-family: Roboto;
font-size: 23px;
font-style: normal;
@ -755,7 +581,6 @@ export const ThreadSingleTitle = styled(Typography)`
`;
export const ThreadSingleLastMessageP = styled(Typography)`
color: #fff;
font-family: Roboto;
font-size: 12px;
font-style: normal;
@ -764,7 +589,6 @@ export const ThreadSingleLastMessageP = styled(Typography)`
`;
export const ThreadSingleLastMessageSpanP = styled('span')`
color: #fff;
font-family: Roboto;
font-size: 12px;
font-style: normal;
@ -792,6 +616,6 @@ export const CloseContainer = styled(Box)(({ theme }) => ({
height: '50px',
borderRadius: '0px 12px 0px 0px',
'&:hover': {
backgroundColor: 'rgba(162, 31, 31, 1)',
backgroundColor: theme.palette.action.hover,
},
}));

View File

@ -1,12 +1,9 @@
import React, { useEffect, useRef, useState } from 'react';
import { Box, CircularProgress, Input } from '@mui/material';
import { Box, CircularProgress, Input, useTheme } from '@mui/material';
import ShortUniqueId from 'short-unique-id';
import ModalCloseSVG from '../../../assets/svgs/ModalClose.svg';
import ComposeIconSVG from '../../../assets/svgs/ComposeIcon.svg';
import {
CloseContainer,
ComposeContainer,
ComposeIcon,
ComposeP,
InstanceFooter,
InstanceListContainer,
@ -29,6 +26,8 @@ import { MessageDisplay } from '../../Chat/MessageDisplay';
import { CustomizedSnackbars } from '../../Snackbar/Snackbar';
import { saveTempPublish } from '../../Chat/GroupAnnouncements';
import { useTranslation } from 'react-i18next';
import { ComposeIcon } from '../../../assets/Icons/ComposeIcon';
import CloseIcon from '@mui/icons-material/Close';
const uid = new ShortUniqueId({ length: 8 });
@ -152,6 +151,7 @@ export const NewThread = ({
const [openSnack, setOpenSnack] = React.useState(false);
const [infoSnack, setInfoSnack] = React.useState(null);
const editorRef = useRef(null);
const theme = useTheme();
const setEditorRef = (editorInstance) => {
editorRef.current = editorInstance;
};
@ -406,7 +406,7 @@ export const NewThread = ({
}}
onClick={() => setIsOpen(true)}
>
<ComposeIcon src={ComposeIconSVG} />
<ComposeIcon />
<ComposeP>{currentThread ? 'New Post' : 'New Thread'}</ComposeP>
</ComposeContainer>
@ -417,7 +417,7 @@ export const NewThread = ({
maxWidth: '950px',
height: '700px',
borderRadius: '12px 12px 0px 0px',
background: '#434448',
background: theme.palette.background.paper,
padding: '0px',
gap: '0px',
}}
@ -429,7 +429,7 @@ export const NewThread = ({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#434448',
backgroundColor: theme.palette.background.paper,
}}
>
<NewMessageHeaderP>
@ -441,12 +441,16 @@ export const NewThread = ({
}}
onClick={closeModal}
>
<NewMessageCloseImg src={ModalCloseSVG} />
<CloseIcon
sx={{
color: theme.palette.text.primary,
}}
/>
</CloseContainer>
</InstanceListHeader>
<InstanceListContainer
sx={{
backgroundColor: '#434448',
backgroundColor: theme.palette.background.paper,
padding: '20px 42px',
height: 'calc(100% - 165px)',
flexShrink: 0,
@ -468,9 +472,7 @@ export const NewThread = ({
autoCorrect="off"
sx={{
width: '100%',
color: 'white',
'& .MuiInput-input::placeholder': {
color: 'rgba(255,255,255, 0.70) !important',
fontSize: '20px',
fontStyle: 'normal',
fontWeight: 400,
@ -525,7 +527,7 @@ export const NewThread = ({
<InstanceFooter
sx={{
backgroundColor: '#434448',
backgroundColor: theme.palette.background.paper,
padding: '20px 42px',
alignItems: 'center',
height: '90px',
@ -543,7 +545,12 @@ export const NewThread = ({
alignItems: 'center',
}}
>
<CircularProgress sx={{}} size={'12px'} />
<CircularProgress
sx={{
color: theme.palette.text.primary,
}}
size={'12px'}
/>
</Box>
)}
@ -552,9 +559,14 @@ export const NewThread = ({
</NewMessageSendP>
{isMessage ? (
<SendNewMessage opacity={1} height="25px" width="25px" />
<SendNewMessage />
) : (
<CreateThreadIcon opacity={1} height="25px" width="25px" />
<CreateThreadIcon
color={theme.palette.text.primary}
opacity={1}
height="25px"
width="25px"
/>
)}
</NewMessageSendButton>
</InstanceFooter>

View File

@ -5,7 +5,14 @@ import React, {
useRef,
useState,
} from 'react';
import { Avatar, Box, Button, ButtonBase, Typography } from '@mui/material';
import {
Avatar,
Box,
Button,
ButtonBase,
Typography,
useTheme,
} from '@mui/material';
import { ShowMessage } from './ShowMessageWithoutModal';
import {
ComposeP,
@ -22,7 +29,6 @@ import {
} from './Mail-styles';
import { Spacer } from '../../../common/Spacer';
import { threadIdentifier } from './GroupMail';
import ReturnSVG from '../../../assets/svgs/Return.svg';
import { NewThread } from './NewThread';
import {
decryptPublishes,
@ -43,6 +49,7 @@ import { CustomLoader } from '../../../common/CustomLoader';
import { WrapperUserAction } from '../../WrapperUserAction';
import { formatTimestampForum } from '../../../utils/time';
import { useTranslation } from 'react-i18next';
import { ReturnIcon } from '../../../assets/Icons/ReturnIcon';
const requestQueueSaveToLocal = new RequestQueueWithPromise(1);
@ -116,7 +123,7 @@ export const Thread = ({
const [postReply, setPostReply] = useState(null);
const [hasLastPage, setHasLastPage] = useState(false);
const { t } = useTranslation(['core']);
const theme = useTheme();
// Update: Use a new ref for the scrollable container
const threadContainerRef = useRef(null);
const threadBeginningRef = useRef(null);
@ -606,7 +613,7 @@ export const Thread = ({
closeThread();
}}
>
<MailIconImg src={ReturnSVG} />
<ReturnIcon />
<ComposeP>
{t('group:action.return_to_thread', {
postProcess: 'capitalize',
@ -619,7 +626,7 @@ export const Thread = ({
<ButtonBase onClick={scrollToPosition}>
<ArrowUpwardIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
cursor: 'pointer',
fontSize: '36px',
}}
@ -629,7 +636,7 @@ export const Thread = ({
<ButtonBase onClick={scrollToPosition}>
<ArrowDownwardIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
cursor: 'pointer',
fontSize: '36px',
}}
@ -825,7 +832,6 @@ export const Thread = ({
<Typography
sx={{
fontSize: '18px',
color: 'white',
}}
>
{fullMessage?.error}
@ -925,7 +931,6 @@ export const Thread = ({
<Typography
sx={{
fontSize: '18px',
color: 'white',
}}
>
{t('core:downloading_qdn', { postProcess: 'capitalize' })}
@ -958,9 +963,6 @@ export const Thread = ({
groupInfo?.groupId
);
}}
sx={{
color: 'white',
}}
>
{t('group:action.refetch_page', {
postProcess: 'capitalize',

View File

@ -1556,12 +1556,13 @@ export const Group = ({
<div
style={{
alignItems: 'flex-start',
background: theme.palette.background.default,
background: theme.palette.background.surface,
borderRadius: '0px 15px 15px 0px',
display: 'flex',
flexDirection: 'column',
height: '100%',
width: '380px',
padding: '0px 2px',
}}
>
<Box
@ -1581,7 +1582,7 @@ export const Group = ({
<IconWrapper
color={
groupChatHasUnread || groupsAnnHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'groups'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1594,7 +1595,7 @@ export const Group = ({
height={24}
color={
groupChatHasUnread || groupsAnnHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'groups'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1611,7 +1612,7 @@ export const Group = ({
customWidth="75px"
color={
directChatHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'directs'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1623,7 +1624,7 @@ export const Group = ({
height={24}
color={
directChatHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'directs'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1744,7 +1745,7 @@ export const Group = ({
direct?.timestamp) && (
<MarkChatUnreadIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
)}
@ -1779,7 +1780,7 @@ export const Group = ({
</div>
);
};
console.log('groupsProperties', groupsProperties);
const renderGroups = () => {
return (
<div
@ -1789,8 +1790,9 @@ export const Group = ({
flexDirection: 'column',
alignItems: 'flex-start',
height: '100%',
background: theme.palette.background.default,
background: theme.palette.background.surface,
borderRadius: '0px 15px 15px 0px',
padding: '0px 2px',
}}
>
<Box
@ -1810,7 +1812,7 @@ export const Group = ({
<IconWrapper
color={
groupChatHasUnread || groupsAnnHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'groups'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1823,7 +1825,7 @@ export const Group = ({
height={24}
color={
groupChatHasUnread || groupsAnnHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'groups'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1840,7 +1842,7 @@ export const Group = ({
customWidth="75px"
color={
directChatHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'directs'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1852,7 +1854,7 @@ export const Group = ({
height={24}
color={
directChatHasUnread
? 'var(--unread)'
? theme.palette.other.unread
: desktopSideView === 'directs'
? theme.palette.text.primary
: theme.palette.text.secondary
@ -1957,7 +1959,7 @@ export const Group = ({
}/qortal_avatar?async=true`} /> */}
<LockIcon
sx={{
color: 'var(--green)',
color: theme.palette.other.positive,
}}
/>
</Box>
@ -1975,7 +1977,7 @@ export const Group = ({
>
<NoEncryptionGmailerrorredIcon
sx={{
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
/>
</Box>
@ -2016,7 +2018,7 @@ export const Group = ({
!groupAnnouncements[group?.groupId]?.seentimestamp && (
<CampaignIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
marginRight: '5px',
}}
/>
@ -2032,7 +2034,7 @@ export const Group = ({
group?.timestamp) && (
<MarkChatUnreadIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
)}

View File

@ -71,7 +71,7 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
fontSize: '1rem',
}}
>
{t('group:group_invites', { postProcess: 'capitalize' })}{' '}
{t('group:group.invites', { postProcess: 'capitalize' })}{' '}
{groupsWithJoinRequests?.length > 0 &&
` (${groupsWithJoinRequests?.length})`}
</Typography>

View File

@ -7,7 +7,7 @@ import IconButton from '@mui/material/IconButton';
import { RequestQueueWithPromise } from '../../utils/queue/queue';
import GroupAddIcon from '@mui/icons-material/GroupAdd';
import { executeEvent } from '../../utils/events';
import { Box, ButtonBase, Collapse, Typography } from '@mui/material';
import { Box, ButtonBase, Collapse, Typography, useTheme } from '@mui/material';
import { CustomLoader } from '../../common/CustomLoader';
import { MyContext, getBaseApiReact } from '../../App';
import { myGroupsWhereIAmAdminAtom } from '../../atoms/global';
@ -35,7 +35,7 @@ export const GroupJoinRequests = ({
const [loading, setLoading] = React.useState(true);
const { txList, setTxList } = React.useContext(MyContext);
const setMyGroupsWhereIAmAdmin = useSetRecoilState(myGroupsWhereIAmAdminAtom);
const theme = useTheme();
const getJoinRequests = async () => {
try {
setLoading(true);
@ -244,7 +244,7 @@ export const GroupJoinRequests = ({
<IconButton edge="end" aria-label="comments">
<GroupAddIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
fontSize: '18px',
}}
/>

View File

@ -1,254 +0,0 @@
import { useState } from 'react';
import {
Button,
Menu,
MenuItem,
ListItemIcon,
ListItemText,
Box,
} from '@mui/material';
import { ArrowDownIcon } from '../../assets/Icons/ArrowDownIcon';
import { NotificationIcon2 } from '../../assets/Icons/NotificationIcon2';
import { ChatIcon } from '../../assets/Icons/ChatIcon';
import { ThreadsIcon } from '../../assets/Icons/ThreadsIcon';
import { MembersIcon } from '../../assets/Icons/MembersIcon';
export const GroupMenu = ({
setGroupSection,
groupSection,
setOpenManageMembers,
goToAnnouncements,
goToChat,
hasUnreadChat,
hasUnreadAnnouncements,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
marginTop: '14px',
marginBottom: '14px',
}}
>
<Button
aria-controls={open ? 'home-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
variant="contained"
sx={{
backgroundColor: 'var(--bg-primary)',
width: '148px',
borderRadius: '5px',
fontSize: '12px',
fontWeight: 600,
color: '#fff',
textTransform: 'none',
padding: '5px',
height: '25px',
}}
>
<Box
sx={{
display: 'flex',
gap: '6px',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
}}
>
<Box
sx={{
display: 'flex',
gap: '6px',
alignItems: 'center',
}}
>
{groupSection === 'announcement' && (
<>
{' '}
<NotificationIcon2
color={
hasUnreadAnnouncements || hasUnreadChat
? 'var(--danger)'
: 'white'
}
/>{' '}
{' Announcements'}
</>
)}
{groupSection === 'chat' && (
<>
{' '}
<ChatIcon
color={
hasUnreadAnnouncements || hasUnreadChat
? 'var(--danger)'
: 'white'
}
/>{' '}
{' Group Chats'}
</>
)}
{groupSection === 'forum' && (
<>
{' '}
<ThreadsIcon
color={
hasUnreadAnnouncements || hasUnreadChat
? 'var(--danger)'
: 'white'
}
/>{' '}
{' Threads'}
</>
)}
</Box>
<ArrowDownIcon color="white" />
</Box>
</Button>
<Menu
id="home-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
slotProps={{
paper: {
sx: {
backgroundColor: 'var(--bg-primary)',
color: '#fff',
width: '148px',
borderRadius: '5px',
},
},
}}
sx={{
marginTop: '10px',
}}
>
<MenuItem
onClick={() => {
goToChat();
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: '24px !important',
}}
>
<ChatIcon color={hasUnreadChat ? 'var(--danger)' : '#fff'} />
</ListItemIcon>
<ListItemText
sx={{
'& .MuiTypography-root': {
fontSize: '12px',
fontWeight: 600,
color: hasUnreadChat ? 'var(--danger)' : '#fff',
},
}}
primary="Chat"
/>
</MenuItem>
<MenuItem
onClick={() => {
goToAnnouncements();
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: '24px !important',
}}
>
<NotificationIcon2
color={hasUnreadAnnouncements ? 'var(--danger)' : '#fff'}
/>
</ListItemIcon>
<ListItemText
sx={{
'& .MuiTypography-root': {
fontSize: '12px',
fontWeight: 600,
color: hasUnreadAnnouncements ? 'var(--danger)' : '#fff',
},
}}
primary="Announcements"
/>
</MenuItem>
<MenuItem
onClick={() => {
setGroupSection('forum');
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: '24px !important',
}}
>
<ThreadsIcon color={'#fff'} />
</ListItemIcon>
<ListItemText
sx={{
'& .MuiTypography-root': {
fontSize: '12px',
fontWeight: 600,
},
}}
primary="Threads"
/>
</MenuItem>
<MenuItem
onClick={() => {
setOpenManageMembers(true);
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: '24px !important',
}}
>
<MembersIcon sx={{ color: '#fff' }} />
</ListItemIcon>
<ListItemText
sx={{
'& .MuiTypography-root': {
fontSize: '12px',
fontWeight: 600,
},
}}
primary="Members"
/>
</MenuItem>
</Menu>
</Box>
);
};

View File

@ -242,27 +242,6 @@ export const HomeDesktop = ({
)}
</Box>
<Spacer height="26px" />
{/* <Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
}}
>
<Button
variant="outlined"
startIcon={<RefreshIcon />}
onClick={refreshHomeDataFunc}
sx={{
color: "white",
}}
>
Refresh home data
</Button>
</Box> */}
<Spacer height="180px" />
</Box>
);

View File

@ -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 = () => {
<Avatar
sx={{
backgroundColor: '#27282c',
color: 'white',
color: theme.palette.text.primary,
}}
alt={promotion?.name}
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
@ -687,7 +689,6 @@ 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 && (
<LockIcon
sx={{
color: 'var(--green)',
color: theme.palette.other.positive,
}}
/>
)}
{promotion?.isOpen === true && (
<NoEncryptionGmailerrorredIcon
sx={{
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
/>
)}
@ -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,
},
}}
/>

View File

@ -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 && (
<Typography
sx={{
color: 'white',
color: theme.palette.text.primary,
marginLeft: 'auto',
}}
>

View File

@ -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}
>
<AppBar sx={{ position: 'relative', bgcolor: '#232428' }}>
<AppBar
sx={{
position: 'relative',
bgcolor: theme.palette.background.default,
}}
>
<Toolbar>
<Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div">
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
Manage Members
</Typography>
<IconButton
@ -189,8 +195,8 @@ export const ManageMembers = ({
</AppBar>
<Box
sx={{
bgcolor: '#27282c',
color: 'white',
bgcolor: theme.palette.background.default,
color: theme.palette.text.primary,
flexGrow: 1,
overflowY: 'auto',
}}
@ -205,7 +211,7 @@ export const ManageMembers = ({
allowScrollButtonsMobile // Show scroll buttons on mobile as well
sx={{
'& .MuiTabs-indicator': {
backgroundColor: 'white',
backgroundColor: theme.palette.background.default,
},
maxWidth: '100%', // Ensure the tabs container fits within the available space
overflow: 'hidden', // Prevents overflow on small screens
@ -216,7 +222,7 @@ export const ManageMembers = ({
{...a11yProps(0)}
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
fontSize: '1rem',
}}
@ -227,7 +233,7 @@ export const ManageMembers = ({
{...a11yProps(1)}
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
fontSize: '1rem',
}}
@ -238,7 +244,7 @@ export const ManageMembers = ({
{...a11yProps(2)}
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
fontSize: '1rem',
}}
@ -249,7 +255,7 @@ export const ManageMembers = ({
{...a11yProps(3)}
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
fontSize: '1rem',
}}
@ -260,7 +266,7 @@ export const ManageMembers = ({
{...a11yProps(4)}
sx={{
'&.Mui-selected': {
color: 'white',
color: theme.palette.text.primary,
},
fontSize: '1rem',
}}

View File

@ -153,7 +153,9 @@ export const QMailMessages = ({ userName, userAddress }) => {
</Typography>
<MarkEmailUnreadIcon
sx={{
color: anyUnread ? 'var(--unread)' : 'white',
color: anyUnread
? theme.palette.other.unread
: theme.palette.text.primary,
}}
/>
{isExpanded ? (
@ -165,7 +167,9 @@ export const QMailMessages = ({ userName, userAddress }) => {
) : (
<ExpandMoreIcon
sx={{
color: anyUnread ? 'var(--unread)' : 'white',
color: anyUnread
? theme.palette.other.unread
: theme.palette.text.primary,
marginLeft: 'auto',
}}
/>
@ -262,26 +266,26 @@ export const QMailMessages = ({ userName, userAddress }) => {
isLessThanOneWeekOld(mail?.created) ? (
<MailIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
) : !lastEnteredTimestamp ? (
<MailOutlineIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
) : lastEnteredTimestamp < mail?.created &&
isLessThanOneWeekOld(mail?.created) ? (
<MailIcon
sx={{
color: 'var(--unread)',
color: theme.palette.other.unread,
}}
/>
) : (
<MailOutlineIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
)}

View File

@ -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<HTMLInputElement>) => {
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked);
window
.sendMessage('addUserSettings', {
@ -123,9 +132,7 @@ export const Settings = ({ address, open, setOpen }) => {
onClose={handleClose}
TransitionComponent={Transition}
>
<AppBar
sx={{ position: 'relative', bgcolor: theme.palette.background }}
>
<AppBar sx={{ position: 'relative' }}>
<Toolbar>
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
General Settings
@ -144,7 +151,6 @@ export const Settings = ({ address, open, setOpen }) => {
<Box
sx={{
bgcolor: theme.palette.background,
flexGrow: 1,
overflowY: 'auto',
color: theme.palette.text.primary,
@ -165,9 +171,6 @@ export const Settings = ({ address, open, setOpen }) => {
/>
{window?.electronAPI && (
<FormControlLabel
sx={{
color: 'white',
}}
control={
<LocalNodeSwitch
checked={isEnabledDevMode}
@ -183,6 +186,7 @@ export const Settings = ({ address, open, setOpen }) => {
label="Enable dev mode"
/>
)}
<ThemeManager />
</Box>
</Dialog>
</Fragment>

View File

@ -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<any[]>([]);
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 && (
<LockIcon
sx={{
color: 'var(--green)',
color: theme.palette.other.positive,
}}
/>
)}
{invite?.isOpen === true && (
<NoEncryptionGmailerrorredIcon
sx={{
color: 'var(--danger)',
color: theme.palette.other.danger,
}}
/>
)}

View File

@ -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 = () => {
<ButtonBase onClick={handleClose}>
<CloseIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
</ButtonBase>

View File

@ -116,7 +116,7 @@ export const QortPrice = () => {
>
<Tooltip
title={
<span style={{ color: 'white', fontSize: '14px', fontWeight: 700 }}>
<span style={{ fontSize: '14px', fontWeight: 700 }}>
Based on the latest 20 trades
</span>
}
@ -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 = () => {
</Typography>
{!ltcPerQort ? (
<BarSpinner width="16px" color="white" />
<BarSpinner width="16px" color={theme.palette.text.primary} />
) : (
<Typography
sx={{
@ -187,7 +187,7 @@ export const QortPrice = () => {
</Typography>
{!supply ? (
<BarSpinner width="16px" color="white" />
<BarSpinner width="16px" color={theme.palette.text.primary} />
) : (
<Typography
sx={{
@ -200,7 +200,7 @@ export const QortPrice = () => {
</Box>
<Tooltip
title={
<span style={{ color: 'white', fontSize: '14px', fontWeight: 700 }}>
<span style={{ fontSize: '14px', fontWeight: 700 }}>
{lastBlock?.timestamp && formatDate(lastBlock?.timestamp)}
</span>
}
@ -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 = () => {
</Typography>
{!lastBlock?.height ? (
<BarSpinner width="16px" color="white" />
<BarSpinner width="16px" color={theme.palette.text.primary} />
) : (
<Typography
sx={{

View File

@ -8,6 +8,7 @@ import {
ButtonBase,
Popover,
Typography,
useTheme,
} from '@mui/material';
import { Spacer } from '../common/Spacer';
import ImageUploader from '../common/ImageUploader';
@ -222,6 +223,7 @@ const PopoverComp = ({
isLoading,
myName,
}) => {
const theme = useTheme();
return (
<Popover
id={id}
@ -260,7 +262,7 @@ const PopoverComp = ({
>
<ErrorIcon
sx={{
color: 'white',
color: theme.palette.text.primary,
}}
/>
<Typography>

View File

@ -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 = ({
<Button
size="small"
sx={{
backgroundColor: 'var(--danger)',
backgroundColor: theme.palette.other.danger,
color: theme.palette.text.primary,
fontWeight: 'bold',
maxWidth: '90%',
opacity: 0.7,
width: '200px',
'&:hover': {
backgroundColor: 'var(--danger)',
backgroundColor: theme.palette.other.danger,
color: theme.palette.text.primary,
opacity: 1,
},
@ -763,13 +763,13 @@ export const Minting = ({
<Button
size="small"
sx={{
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: theme.palette.text.primary,
fontWeight: 'bold',
opacity: 0.7,
'&:hover': {
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: 'black',
opacity: 1,
},

View File

@ -43,7 +43,7 @@ export const QMailStatus = () => {
{hasNewMail && (
<div
style={{
backgroundColor: 'var(--unread)',
backgroundColor: theme.palette.other.unread,
borderRadius: '50%',
height: '15px',
outline: '1px solid white',
@ -77,7 +77,7 @@ export const QMailStatus = () => {
tooltip: {
sx: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
},
},
arrow: {
@ -87,7 +87,11 @@ export const QMailStatus = () => {
},
}}
>
<Mail />
<Mail
sx={{
color: theme.palette.text.secondary,
}}
/>
</Tooltip>
</ButtonBase>
);

View File

@ -1,28 +1,29 @@
import React, { useCallback, useContext, useEffect, useState } from 'react'
import React, { useCallback, useContext, useEffect, useState } from 'react';
import {
Avatar,
Box,
Button,
ButtonBase,
Collapse,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Input,
ListItem,
ListItemAvatar,
ListItemButton,
ListItemIcon,
ListItemText,
List,
MenuItem,
Popover,
Select,
TextField,
Typography,
} from "@mui/material";
Avatar,
Box,
Button,
ButtonBase,
Collapse,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Input,
ListItem,
ListItemAvatar,
ListItemButton,
ListItemIcon,
ListItemText,
List,
MenuItem,
Popover,
Select,
TextField,
Typography,
useTheme,
} from '@mui/material';
import { Label } from './Group/AddGroup';
import { Spacer } from '../common/Spacer';
import { LoadingButton } from '@mui/lab';
@ -35,278 +36,313 @@ import CheckIcon from '@mui/icons-material/Check';
import ErrorIcon from '@mui/icons-material/Error';
enum Availability {
NULL = 'null',
LOADING = 'loading',
AVAILABLE = 'available',
NOT_AVAILABLE = 'not-available'
NULL = 'null',
LOADING = 'loading',
AVAILABLE = 'available',
NOT_AVAILABLE = 'not-available',
}
export const RegisterName = ({setOpenSnack, setInfoSnack, userInfo, show, setTxList, balance}) => {
const [isOpen, setIsOpen] = useState(false)
const [registerNameValue, setRegisterNameValue] = useState('')
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false)
const [isNameAvailable, setIsNameAvailable] = useState<Availability>(Availability.NULL)
const [nameFee, setNameFee] = useState(null)
export const RegisterName = ({
setOpenSnack,
setInfoSnack,
userInfo,
show,
setTxList,
balance,
}) => {
const [isOpen, setIsOpen] = useState(false);
const [registerNameValue, setRegisterNameValue] = useState('');
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
const [isNameAvailable, setIsNameAvailable] = useState<Availability>(
Availability.NULL
);
const [nameFee, setNameFee] = useState(null);
const theme = useTheme();
const checkIfNameExisits = async (name) => {
if (!name?.trim()) {
setIsNameAvailable(Availability.NULL);
const checkIfNameExisits = async (name)=> {
if(!name?.trim()){
setIsNameAvailable(Availability.NULL)
return
return;
}
setIsNameAvailable(Availability.LOADING)
setIsNameAvailable(Availability.LOADING);
try {
const res = await fetch(`${getBaseApiReact()}/names/` + name);
const data = await res.json()
if(data?.message === 'name unknown'){
setIsNameAvailable(Availability.AVAILABLE)
} else {
setIsNameAvailable(Availability.NOT_AVAILABLE)
}
const res = await fetch(`${getBaseApiReact()}/names/` + name);
const data = await res.json();
if (data?.message === 'name unknown') {
setIsNameAvailable(Availability.AVAILABLE);
} else {
setIsNameAvailable(Availability.NOT_AVAILABLE);
}
} catch (error) {
console.error(error)
console.error(error);
} finally {
}
}
// Debounce logic
useEffect(() => {
const handler = setTimeout(() => {
checkIfNameExisits(registerNameValue);
}, 500);
// Cleanup timeout if searchValue changes before the timeout completes
return () => {
clearTimeout(handler);
};
}, [registerNameValue]);
};
// Debounce logic
useEffect(() => {
const handler = setTimeout(() => {
checkIfNameExisits(registerNameValue);
}, 500);
const openRegisterNameFunc = useCallback((e) => {
setIsOpen(true)
// Cleanup timeout if searchValue changes before the timeout completes
return () => {
clearTimeout(handler);
};
}, [registerNameValue]);
}, [ setIsOpen]);
useEffect(() => {
subscribeToEvent("openRegisterName", openRegisterNameFunc);
return () => {
unsubscribeFromEvent("openRegisterName", openRegisterNameFunc);
};
}, [openRegisterNameFunc]);
const openRegisterNameFunc = useCallback(
(e) => {
setIsOpen(true);
},
[setIsOpen]
);
useEffect(()=> {
const nameRegistrationFee = async ()=> {
try {
const fee = await getFee("REGISTER_NAME");
setNameFee(fee?.fee)
} catch (error) {
console.error(error)
}
}
nameRegistrationFee()
}, [])
useEffect(() => {
subscribeToEvent('openRegisterName', openRegisterNameFunc);
const registerName = async () => {
return () => {
unsubscribeFromEvent('openRegisterName', openRegisterNameFunc);
};
}, [openRegisterNameFunc]);
useEffect(() => {
const nameRegistrationFee = async () => {
try {
if (!userInfo?.address) throw new Error("Your address was not found");
if(!registerNameValue) throw new Error('Enter a name')
const fee = await getFee("REGISTER_NAME");
await show({
message: "Would you like to register this name?",
publishFee: fee.fee + " QORT",
});
setIsLoadingRegisterName(true);
new Promise((res, rej) => {
window
.sendMessage("registerName", {
name: registerNameValue,
})
.then((response) => {
if (!response?.error) {
res(response);
setIsLoadingRegisterName(false);
setInfoSnack({
type: "success",
message:
"Successfully registered. It may take a couple of minutes for the changes to propagate",
});
setIsOpen(false);
setRegisterNameValue("");
setOpenSnack(true);
setTxList((prev) => [
{
...response,
type: "register-name",
label: `Registered name: awaiting confirmation. This may take a couple minutes.`,
labelDone: `Registered name: success!`,
done: false,
},
...prev.filter((item) => !item.done),
]);
return;
}
setInfoSnack({
type: "error",
message: response?.error,
});
setOpenSnack(true);
rej(response.error);
})
.catch((error) => {
setInfoSnack({
type: "error",
message: error.message || "An error occurred",
});
setOpenSnack(true);
rej(error);
});
});
const fee = await getFee('REGISTER_NAME');
setNameFee(fee?.fee);
} catch (error) {
if (error?.message) {
setOpenSnack(true)
setInfoSnack({
type: "error",
message: error?.message,
});
}
} finally {
setIsLoadingRegisterName(false);
console.error(error);
}
};
nameRegistrationFee();
}, []);
const registerName = async () => {
try {
if (!userInfo?.address) throw new Error('Your address was not found');
if (!registerNameValue) throw new Error('Enter a name');
const fee = await getFee('REGISTER_NAME');
await show({
message: 'Would you like to register this name?',
publishFee: fee.fee + ' QORT',
});
setIsLoadingRegisterName(true);
new Promise((res, rej) => {
window
.sendMessage('registerName', {
name: registerNameValue,
})
.then((response) => {
if (!response?.error) {
res(response);
setIsLoadingRegisterName(false);
setInfoSnack({
type: 'success',
message:
'Successfully registered. It may take a couple of minutes for the changes to propagate',
});
setIsOpen(false);
setRegisterNameValue('');
setOpenSnack(true);
setTxList((prev) => [
{
...response,
type: 'register-name',
label: `Registered name: awaiting confirmation. This may take a couple minutes.`,
labelDone: `Registered name: success!`,
done: false,
},
...prev.filter((item) => !item.done),
]);
return;
}
setInfoSnack({
type: 'error',
message: response?.error,
});
setOpenSnack(true);
rej(response.error);
})
.catch((error) => {
setInfoSnack({
type: 'error',
message: error.message || 'An error occurred',
});
setOpenSnack(true);
rej(error);
});
});
} catch (error) {
if (error?.message) {
setOpenSnack(true);
setInfoSnack({
type: 'error',
message: error?.message,
});
}
} finally {
setIsLoadingRegisterName(false);
}
};
return (
<Dialog
open={isOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Register name"}
</DialogTitle>
<DialogContent>
<Box
open={isOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle>
<DialogContent>
<Box
sx={{
width: "400px",
width: '400px',
maxWidth: '90vw',
height: "500px",
height: '500px',
maxHeight: '90vh',
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
padding: "10px",
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '10px',
padding: '10px',
}}
>
<Label>Choose a name</Label>
<TextField
autoComplete='off'
autoFocus
autoComplete="off"
autoFocus
onChange={(e) => setRegisterNameValue(e.target.value)}
value={registerNameValue}
placeholder="Choose a name"
/>
{(!balance || (nameFee && balance && balance < nameFee))&& (
{(!balance || (nameFee && balance && balance < nameFee)) && (
<>
<Spacer height="10px" />
<Box sx={{
display: 'flex',
gap: '5px',
alignItems: 'center'
}}>
<ErrorIcon sx={{
color: 'white'
}} />
<Typography>Your balance is {balance ?? 0} QORT. A name registration requires a {nameFee} QORT fee</Typography>
</Box>
<Spacer height="10px" />
<Spacer height="10px" />
<Box
sx={{
display: 'flex',
gap: '5px',
alignItems: 'center',
}}
>
<ErrorIcon
sx={{
color: theme.palette.text.primary,
}}
/>
<Typography>
Your balance is {balance ?? 0} QORT. A name registration
requires a {nameFee} QORT fee
</Typography>
</Box>
<Spacer height="10px" />
</>
)}
<Spacer height="5px" />
{isNameAvailable === Availability.AVAILABLE && (
<Box sx={{
<Box
sx={{
display: 'flex',
gap: '5px',
alignItems: 'center'
}}>
<CheckIcon sx={{
color: 'white'
}} />
<Typography>{registerNameValue} is available</Typography>
alignItems: 'center',
}}
>
<CheckIcon
sx={{
color: theme.palette.text.primary,
}}
/>
<Typography>{registerNameValue} is available</Typography>
</Box>
)}
{isNameAvailable === Availability.NOT_AVAILABLE && (
<Box sx={{
{isNameAvailable === Availability.NOT_AVAILABLE && (
<Box
sx={{
display: 'flex',
gap: '5px',
alignItems: 'center'
}}>
<ErrorIcon sx={{
color: 'white'
}} />
<Typography>{registerNameValue} is unavailable</Typography>
alignItems: 'center',
}}
>
<ErrorIcon
sx={{
color: theme.palette.text.primary,
}}
/>
<Typography>{registerNameValue} is unavailable</Typography>
</Box>
)}
{isNameAvailable === Availability.LOADING && (
<Box sx={{
{isNameAvailable === Availability.LOADING && (
<Box
sx={{
display: 'flex',
gap: '5px',
alignItems: 'center'
}}>
<BarSpinner width="16px" color="white" />
<Typography>Checking if name already existis</Typography>
alignItems: 'center',
}}
>
<BarSpinner width="16px" color={theme.palette.text.primary} />
<Typography>Checking if name already existis</Typography>
</Box>
)}
<Spacer height="25px" />
<Typography sx={{
textDecoration: 'underline'
}}>Benefits of a name</Typography>
<List
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
aria-label="contacts"
>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon sx={{
color: 'white'
}} />
</ListItemIcon>
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
</ListItem>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon sx={{
color: 'white'
}} />
</ListItemIcon>
<ListItemText primary="Secure ownership of data published by your name. You can even sell your name, along with your data to a third party." />
</ListItem>
</List>
<Typography
sx={{
textDecoration: 'underline',
}}
>
Benefits of a name
</Typography>
<List
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
aria-label="contacts"
>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon
sx={{
color: theme.palette.text.primary,
}}
/>
</ListItemIcon>
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
</ListItem>
<ListItem disablePadding>
<ListItemIcon>
<RadioButtonCheckedIcon
sx={{
color: theme.palette.text.primary,
}}
/>
</ListItemIcon>
<ListItemText primary="Secure ownership of data published by your name. You can even sell your name, along with your data to a third party." />
</ListItem>
</List>
</Box>
</DialogContent>
<DialogActions>
<Button
disabled={isLoadingRegisterName}
variant="contained"
onClick={() => {
setIsOpen(false)
setRegisterNameValue('')
}}
>
Close
</Button>
<Button
disabled={!registerNameValue.trim() ||isLoadingRegisterName || isNameAvailable !== Availability.AVAILABLE || !balance || ((balance && nameFee) && +balance < +nameFee)}
variant="contained"
onClick={registerName}
autoFocus
>
Register Name
</Button>
</DialogActions>
</Dialog>
)
}
</DialogContent>
<DialogActions>
<Button
disabled={isLoadingRegisterName}
variant="contained"
onClick={() => {
setIsOpen(false);
setRegisterNameValue('');
}}
>
Close
</Button>
<Button
disabled={
!registerNameValue.trim() ||
isLoadingRegisterName ||
isNameAvailable !== Availability.AVAILABLE ||
!balance ||
(balance && nameFee && +balance < +nameFee)
}
variant="contained"
onClick={registerName}
autoFocus
>
Register Name
</Button>
</DialogActions>
</Dialog>
);
};

View File

@ -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 }) => {
<LoadingButton
sx={{
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: 'black',
opacity: 0.7,
fontWeight: 'bold',
'&:hover': {
backgroundColor: 'var(--green)',
backgroundColor: theme.palette.other.positive,
color: 'black',
opacity: 1,
},
@ -432,12 +432,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,
},

View File

@ -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 (
<ThemeContext.Provider value={{ themeMode, toggleTheme }}>
<MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
<ThemeContext.Provider
value={{
themeMode,
toggleTheme,
userThemes,
addUserTheme,
setUserTheme,
currentThemeId,
}}
>
<MuiThemeProvider theme={muiTheme}>{children}</MuiThemeProvider>
</ThemeContext.Provider>
);
};

View File

@ -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 (
<Box
mb={2}
{...{ 'data-color-mode': mode === 'dark' ? 'dark' : 'light' }}
>
<Typography variant="body2" mb={1}>
{label}
</Typography>
<Sketch
key={`${mode}-${fieldPath}`}
color={color}
onChange={(color) => handleColorChange(mode, fieldPath, color)}
/>
</Box>
);
};
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 (
<Box p={2}>
<Typography variant="h5" gutterBottom>
Theme Manager
</Typography>
<Button
variant="contained"
startIcon={<AddIcon />}
onClick={handleAddTheme}
>
Add Theme
</Button>
<Button
sx={{
marginLeft: '20px',
}}
variant="contained"
startIcon={<AddIcon />}
onClick={importTheme}
>
Import theme
</Button>
<List>
{userThemes?.map((theme, index) => (
<ListItemButton
key={theme?.id || index}
selected={theme?.id === currentThemeId}
>
<ListItemText
primary={`${theme?.name || `Theme ${index + 1}`} ${theme?.id === currentThemeId ? '(Current)' : ''}`}
/>
<ListItemSecondaryAction>
{theme.id !== 'default' && (
<>
<IconButton onClick={() => exportTheme(theme)}>
<FileDownloadIcon />
</IconButton>
<IconButton onClick={() => handleEditTheme(theme.id)}>
<EditIcon />
</IconButton>
<IconButton onClick={() => handleDeleteTheme(theme.id)}>
<DeleteIcon />
</IconButton>
</>
)}
<IconButton onClick={() => handleApplyTheme(theme)}>
<CheckIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItemButton>
))}
</List>
<Dialog
open={openEditor}
onClose={() => setOpenEditor(false)}
fullWidth
maxWidth="md"
>
<DialogTitle>
{themeDraft.id ? 'Edit Theme' : 'Add New Theme'}
</DialogTitle>
<DialogContent>
<TextField
inputRef={nameInputRef}
margin="dense"
label="Theme Name"
fullWidth
value={themeDraft.name}
onChange={(e) =>
setThemeDraft((prev) => ({ ...prev, name: e.target.value }))
}
/>
<Tabs
value={currentTab}
onChange={(e, newValue) => setCurrentTab(newValue)}
sx={{ mt: 2, mb: 2 }}
>
<Tab label="Light" value="light" />
<Tab label="Dark" value="dark" />
</Tabs>
<Box>
{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
)}
</Box>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenEditor(false)}>Cancel</Button>
<Button
disabled={!themeDraft.name}
onClick={handleSaveTheme}
variant="contained"
>
Save
</Button>
</DialogActions>
</Dialog>
</Box>
);
}

View File

@ -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;
}

View File

@ -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,
},
},
}));

View File

@ -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',
},
},
},
},
};

View File

@ -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',
},
},
},
},
};

29
src/styles/theme.d.ts vendored Normal file
View File

@ -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;
};
}
}

View File

@ -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);
};
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();
});
};