Merge remote-tracking branch 'qortal/develop' into feature/large-files-and-names

This commit is contained in:
PhilReact 2025-05-30 01:28:23 +03:00
commit b6a7e44c06
38 changed files with 345 additions and 229 deletions

View File

@ -20,7 +20,7 @@ Translation in GUI:
- For all translation in uppercase `{ postProcess: 'capitalizeAll' }`
- See `.src/i18n/i18n.ts` for processor definition
## Namespace
## Namespaces
These are the current namespaces, in which all translations are organized:

View File

@ -307,7 +307,7 @@ function App() {
const [sendqortState, setSendqortState] = useState<any>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
const isAuthenticated = extState === 'authenticated';
const { t } = useTranslation([
'auth',
'core',
@ -1353,6 +1353,7 @@ function App() {
/>
</Tooltip>
)}
{authenticatedMode === 'ltc' && (
<Tooltip
title={
@ -2059,6 +2060,7 @@ function App() {
useLocalNode={useLocalNode}
/>
)}
{extState === 'authenticated' && isMainWindow && (
<Box
sx={{
@ -2136,6 +2138,7 @@ function App() {
{isShowQortalRequest && !isMainWindow && (
<>
<Spacer height="120px" />
<Box
sx={{
display: 'flex',
@ -2231,6 +2234,7 @@ function App() {
dangerouslySetInnerHTML={{ __html: messageQortalRequest?.html }}
/>
)}
<Spacer height="15px" />
<TextP
@ -2308,6 +2312,7 @@ function App() {
)}
<Spacer height="29px" />
<Box
sx={{
display: 'flex',
@ -2325,6 +2330,7 @@ function App() {
postProcess: 'capitalizeFirstChar',
})}
</CustomButton>
<CustomButton
sx={{
minWidth: '102px',
@ -2595,6 +2601,7 @@ function App() {
postProcess: 'capitalizeFirstChar',
})}
</CustomButton>
<CustomButton
sx={{
minWidth: '102px',
@ -3977,8 +3984,27 @@ function App() {
/>
)}
<LanguageSelector />
<ThemeSelector />
{!isAuthenticated && (
<Box
sx={{
alignItems: 'flex-start',
bottom: '1%',
display: 'flex',
flexDirection: 'column',
left: '3px',
position: 'absolute',
width: 'auto',
}}
>
<Box sx={{ alignSelf: 'left' }}>
<LanguageSelector />
</Box>
<Box sx={{ alignSelf: 'center' }}>
<ThemeSelector />
</Box>
</Box>
)}
</AppContainer>
);
}

View File

@ -25,6 +25,8 @@ import { CoreSyncStatus } from '../CoreSyncStatus';
import { MessagingIconFilled } from '../../assets/Icons/MessagingIconFilled';
import { useAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
import LanguageSelector from '../Language/LanguageSelector';
import ThemeSelector from '../Theme/ThemeSelector';
const uid = new ShortUniqueId({ length: 8 });
@ -358,7 +360,7 @@ export const AppsDesktop = ({
flexDirection: 'column',
gap: '25px',
height: '100vh',
width: '60px',
width: 'auto', // must adapt to the choosen language
}}
>
<ButtonBase
@ -458,6 +460,7 @@ export const AppsDesktop = ({
</IconWrapper>
</ButtonBase>
)}
{mode !== 'home' && (
<AppsNavBarDesktop
disableBack={isNewTabWindow && mode === 'viewer'}
@ -501,6 +504,7 @@ export const AppsDesktop = ({
{mode === 'appInfo' && !selectedTab && (
<AppInfo app={selectedAppInfo} myName={myName} />
)}
{mode === 'appInfo-from-category' && !selectedTab && (
<AppInfo app={selectedAppInfo} myName={myName} />
)}
@ -560,6 +564,26 @@ export const AppsDesktop = ({
</Box>
</>
)}
<Box
sx={{
alignItems: 'flex-start',
bottom: '1%',
display: 'flex',
flexDirection: 'column',
left: '3px',
position: 'absolute',
width: 'auto',
}}
>
<Box sx={{ alignSelf: 'left' }}>
<LanguageSelector />
</Box>
<Box sx={{ alignSelf: 'center' }}>
<ThemeSelector />
</Box>
</Box>
</AppsParent>
);
};

View File

@ -18,6 +18,8 @@ import { IconWrapper } from '../Desktop/DesktopFooter';
import { CoreSyncStatus } from '../CoreSyncStatus';
import { MessagingIconFilled } from '../../assets/Icons/MessagingIconFilled';
import { useTranslation } from 'react-i18next';
import LanguageSelector from '../Language/LanguageSelector';
import ThemeSelector from '../Theme/ThemeSelector';
const uid = new ShortUniqueId({ length: 8 });
@ -229,11 +231,12 @@ export const AppsDevMode = ({
<Box
sx={{
alignItems: 'center',
borderRight: `1px solid ${theme.palette.border.subtle}`,
display: 'flex',
flexDirection: 'column',
gap: '25px',
height: '100vh',
width: '60px',
width: 'auto', // must adapt to the choosen language
}}
>
<ButtonBase
@ -351,6 +354,24 @@ export const AppsDevMode = ({
</ButtonBase>
{mode !== 'home' && <AppsDevModeNavBar />}
<Box
sx={{
alignItems: 'flex-start',
bottom: '1%',
display: 'flex',
flexDirection: 'column',
position: 'absolute',
width: 'auto',
}}
>
<Box sx={{ alignSelf: 'left' }}>
<LanguageSelector />
</Box>
<Box sx={{ alignSelf: 'center' }}>
<ThemeSelector />
</Box>
</Box>
</Box>
{mode === 'home' && (
@ -360,7 +381,7 @@ export const AppsDevMode = ({
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
width: '100%',
width: 'auto',
}}
>
<Spacer height="30px" />
@ -399,7 +420,7 @@ export const AppsDevMode = ({
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
width: '100%',
width: 'auto',
}}
>
<Spacer height="30px" />

View File

@ -319,6 +319,7 @@ export const AppsDevModeHome = ({
<AppCircle>
<Add>+</Add>
</AppCircle>
<AppCircleLabel>
{t('core:server', { postProcess: 'capitalizeFirstChar' })}
</AppCircleLabel>
@ -358,6 +359,7 @@ export const AppsDevModeHome = ({
<AppCircle>
<Add>+</Add>
</AppCircle>
<AppCircleLabel>
{t('core:directory', { postProcess: 'capitalizeFirstChar' })}
</AppCircleLabel>
@ -499,6 +501,7 @@ export const AppsDevModeHome = ({
postProcess: 'capitalizeFirstChar',
})}
</Label>
<Input
placeholder={t('core:domain', {
postProcess: 'capitalizeFirstChar',
@ -521,6 +524,7 @@ export const AppsDevModeHome = ({
postProcess: 'capitalizeFirstChar',
})}
</Label>
<Input
placeholder={t('core:port', {
postProcess: 'capitalizeFirstChar',

View File

@ -24,20 +24,23 @@ export const AppsDevModeNavBar = () => {
const [navigationController, setNavigationController] = useAtom(
navigationControllerAtom
);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group', 'question', 'tutorial']);
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
const tabsRef = useRef(null);
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
useEffect(() => {
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added)

View File

@ -14,8 +14,6 @@ import { SortablePinnedApps } from './SortablePinnedApps';
import { extractComponents } from '../Chat/MessageDisplay';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import { AppsPrivate } from './AppsPrivate';
import ThemeSelector from '../Theme/ThemeSelector';
import LanguageSelector from '../Language/LanguageSelector';
import { useTranslation } from 'react-i18next';
export const AppsHomeDesktop = ({
@ -77,7 +75,7 @@ export const AppsHomeDesktop = ({
<Box
sx={{
alignItems: 'center',
backgroundColor: theme.palette.background.default,
backgroundColor: theme.palette.background.paper,
borderRadius: '20px',
display: 'flex',
gap: '20px',
@ -97,10 +95,10 @@ export const AppsHomeDesktop = ({
autoCorrect="off"
placeholder="qortal://"
sx={{
width: '100%',
backgroundColor: theme.palette.background.surface,
borderRadius: '7px',
color: theme.palette.text.primary,
height: '35px',
width: '100%',
'& .MuiInput-input::placeholder': {
color: theme.palette.text.secondary,
fontSize: '20px',
@ -169,9 +167,6 @@ export const AppsHomeDesktop = ({
myApp={myApp}
/>
</AppsContainer>
<LanguageSelector />
<ThemeSelector />
</>
);
};

View File

@ -347,6 +347,7 @@ export const AppsLibraryDesktop = ({
{officialApps?.map((qapp) => {
return (
<ButtonBase
key={`${qapp?.service}-${qapp?.name}`}
sx={{
width: '80px',
}}

View File

@ -186,6 +186,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
>
<NavBack />
</ButtonBase>
<Tabs
orientation="vertical"
ref={tabsRef}
@ -269,9 +270,6 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
@ -281,6 +279,9 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
horizontal: 'center',
}}
slotProps={{
list: {
'aria-labelledby': 'basic-button',
},
paper: {
sx: {
backgroundColor: theme.palette.background.default,

View File

@ -311,7 +311,11 @@ export const AppsPrivate = ({ myName, myAddress }) => {
<AddIcon />
</AppCircle>
<AppCircleLabel>Private</AppCircleLabel>
<AppCircleLabel>
{t('core:app_private', {
postProcess: 'capitalizeFirstChar',
})}
</AppCircleLabel>
</AppCircleContainer>
</ButtonBase>
@ -336,10 +340,12 @@ export const AppsPrivate = ({ myName, myAddress }) => {
}}
maxWidth="md"
fullWidth={true}
PaperProps={{
style: {
backgroundColor: theme.palette.background.paper,
boxShadow: 'none',
slotProps={{
paper: {
style: {
backgroundColor: theme.palette.background.paper,
boxShadow: 'none',
},
},
}}
>
@ -384,6 +390,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
/>
</Tabs>
</Box>
{valueTabPrivateApp === 0 && (
<>
<DialogContent>
@ -399,6 +406,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
postProcess: 'capitalizeFirstChar',
})}
</Label>
<Label>
{t('group:message.generic.only_private_groups', {
postProcess: 'capitalizeFirstChar',
@ -452,6 +460,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
<Label>
{t('core:name', { postProcess: 'capitalizeFirstChar' })}
</Label>
<Input
placeholder={t('core:name', {
postProcess: 'capitalizeFirstChar',
@ -510,6 +519,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
postProcess: 'capitalizeFirstChar',
})}
</Button>
<Button
disabled={
!privateAppValues.name ||
@ -528,6 +538,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
</DialogActions>
</>
)}
{valueTabPrivateApp === 1 && (
<>
<DialogContent>
@ -549,8 +560,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
backgroundColor: theme.palette.background.paper,
fontSize: '14px',
}}
>{`
50mb MB max`}</PublishQAppInfo>
>{` 50mb MB max`}</PublishQAppInfo>
{file && (
<>
<Spacer height="5px" />
@ -669,6 +679,7 @@ export const AppsPrivate = ({ myName, myAddress }) => {
postProcess: 'capitalizeFirstChar',
})}
</Label>
<Input
placeholder={t('core:identifier', {
postProcess: 'capitalizeFirstChar',

View File

@ -249,11 +249,11 @@ export const SortablePinnedApps = ({
>
{transformPinnedApps.map((app) => (
<SortableItem
app={app}
id={`${app?.service}-${app?.name}`}
isDesktop={isDesktop}
key={`${app?.service}-${app?.name}`}
id={`${app?.service}-${app?.name}`}
name={app?.name}
app={app}
/>
))}
</SortableContext>

View File

@ -58,7 +58,6 @@ const uidImages = new ShortUniqueId({ length: 12 });
export const ChatGroup = ({
selectedGroup,
secretKey,
setSecretKey,
getSecretKey,
myAddress,
handleNewEncryptionNotification,
@ -1186,7 +1185,7 @@ export const ChatGroup = ({
{(!!secretKey || isPrivate === false) && (
<div
style={{
backgroundColor: theme.palette.background.paper,
backgroundColor: theme.palette.background.surface,
border: `1px solid ${theme.palette.border.subtle}`,
borderRadius: '10px',
bottom: isFocusedParent ? '0px' : 'unset',

View File

@ -348,6 +348,15 @@ export const MessageItem = memo(
scrollToItem(replyIndex);
}}
>
<Box
sx={{
background: theme.palette.text.primary,
height: '100%',
width: '5px',
flexShrink: 0,
}} // This is the little bar at left of replied messages
/>
<Box
sx={{
padding: '5px',
@ -393,6 +402,7 @@ export const MessageItem = memo(
{message?.images && messageHasImage(message) && (
<Embed embedLink={buildImageEmbedLink(message.images[0])} />
)}
<Box
sx={{
display: 'flex',
@ -463,11 +473,12 @@ export const MessageItem = memo(
vertical: 'bottom',
horizontal: 'center',
}}
PaperProps={{
// TODO: deprecated
style: {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
slotProps={{
paper: {
style: {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
},
},
}}
>
@ -593,6 +604,7 @@ export const MessageItem = memo(
})}
</Typography>
)}
<Typography
sx={{
fontSize: '14px',

View File

@ -43,6 +43,9 @@ export const IconWrapper = ({
fontFamily: 'Inter',
fontSize: '12px',
fontWeight: 500,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{label}

View File

@ -1,7 +1,7 @@
import { Box, ButtonBase, useTheme } from '@mui/material';
import { HomeIcon } from '../../assets/Icons/HomeIcon';
import { Save } from '../Save/Save';
import { IconWrapper } from '../Desktop/DesktopFooter';
import { IconWrapper } from './DesktopFooter';
import { enabledDevModeAtom } from '../../atoms/global';
import { AppsIcon } from '../../assets/Icons/AppsIcon';
import ThemeSelector from '../Theme/ThemeSelector';
@ -26,7 +26,6 @@ export const DesktopSideBar = ({
myName,
}) => {
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const theme = useTheme();
const { t } = useTranslation([
'auth',
@ -46,7 +45,7 @@ export const DesktopSideBar = ({
flexDirection: 'column',
gap: '25px',
height: '100vh',
width: '60px',
width: 'auto', // must adapt to the choosen language
}}
>
<ButtonBase
@ -151,9 +150,24 @@ export const DesktopSideBar = ({
</ButtonBase>
)}
<LanguageSelector />
<Box
sx={{
alignItems: 'flex-start',
bottom: '1%',
display: 'flex',
flexDirection: 'column',
position: 'absolute',
width: 'auto',
}}
>
<Box sx={{ alignSelf: 'left' }}>
<LanguageSelector />
</Box>
<ThemeSelector />
<Box sx={{ alignSelf: 'center' }}>
<ThemeSelector />
</Box>
</Box>
</Box>
);
};

View File

@ -127,7 +127,7 @@ export const VideoPlayer: FC<VideoPlayerProps> = ({
if (name && identifier && service) {
return `${node || getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}`;
}
return '';
return null;
}, [service, name, identifier]);
useEffect(() => {

View File

@ -40,6 +40,7 @@ import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import { useTranslation } from 'react-i18next';
import { useSetAtom } from 'jotai';
import { txListAtom } from '../../atoms/global';
import { ErrorRounded } from '@mui/icons-material';
export const Label = styled('label')`
display: block;
@ -123,13 +124,17 @@ export const AddGroup = ({ address, open, setOpen }) => {
const fee = await getFee('CREATE_GROUP');
await show({
message: t('core:message.question.perform_transaction', {
action: 'CREATE_GROUP',
postProcess: 'capitalizeFirstChar',
}),
publishFee: fee.fee + ' QORT',
});
try {
await show({
message: t('core:message.question.perform_transaction', {
action: 'CREATE_GROUP',
postProcess: 'capitalizeFirstChar',
}),
publishFee: fee.fee + ' QORT',
});
} catch (error) {
console.log(error);
}
await new Promise((res, rej) => {
window
@ -223,7 +228,9 @@ export const AddGroup = ({ address, open, setOpen }) => {
fullScreen
open={open}
onClose={handleClose}
TransitionComponent={Transition}
slots={{
transition: Transition,
}}
>
<AppBar
sx={{

View File

@ -49,7 +49,7 @@ import { IconWrapper } from '../Desktop/DesktopFooter';
import { DesktopHeader } from '../Desktop/DesktopHeader';
import { AppsDesktop } from '../Apps/AppsDesktop';
import { AppsDevMode } from '../Apps/AppsDevMode';
import { DesktopSideBar } from '../Desktop/DesktopSideBar';
import { DesktopSideBar } from '../Desktop/DesktopLeftSideBar';
import { HubsIcon } from '../../assets/Icons/HubsIcon';
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
import { formatEmailDate } from './QMailMessages';
@ -1913,7 +1913,7 @@ export const Group = ({
setInfo={setInfoSnack}
/>
<div
<div // TODO use Box
style={{
alignItems: 'flex-start',
display: 'flex',
@ -2131,6 +2131,7 @@ export const Group = ({
</Typography>
</div>
)}
{isPrivate &&
!admins.includes(myAddress) &&
!secretKey &&
@ -2149,13 +2150,14 @@ export const Group = ({
width: '100%',
}}
>
{' '}
<Typography>
{t('group:message.generic.not_part_group', {
postProcess: 'capitalizeFirstChar',
})}
</Typography>
<Spacer height="25px" />
<Typography>
<strong>
{t('group:message.generic.only_encrypted', {
@ -2163,13 +2165,17 @@ export const Group = ({
})}
</strong>
</Typography>
<Spacer height="25px" />
<Typography>
{t('group:message.generic.notify_admins', {
postProcess: 'capitalizeFirstChar',
})}
</Typography>
<Spacer height="25px" />
{adminsWithNames.map((admin) => {
return (
<Box
@ -2284,6 +2290,7 @@ export const Group = ({
)}
</Box>
</Box>
{openManageMembers && (
<ManageMembers
selectedGroup={selectedGroup}

View File

@ -62,7 +62,7 @@ export const GroupList = ({
<div
style={{
alignItems: 'flex-start',
background: theme.palette.background.default,
background: theme.palette.background.surface,
borderRadius: '0px 15px 15px 0px',
display: 'flex',
flexDirection: 'column',

View File

@ -205,7 +205,9 @@ export const ManageMembers = ({
fullScreen
open={open}
onClose={handleClose}
TransitionComponent={Transition}
slots={{
transition: Transition,
}}
>
<AppBar
sx={{

View File

@ -154,7 +154,7 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
useEffect(() => {
getUserSettings();
}, []);
});
return (
<Fragment>
@ -162,7 +162,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
fullScreen
open={open}
onClose={handleClose}
TransitionComponent={Transition}
slots={{
transition: Transition,
}}
>
<AppBar sx={{ position: 'relative' }}>
<Toolbar>
@ -173,8 +175,8 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
</Typography>
<IconButton
edge="start"
color="inherit"
edge="start"
onClick={handleClose}
aria-label={t('core:action.close', {
postProcess: 'capitalizeFirstChar',
@ -227,6 +229,7 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
})}
/>
)}
{isEnabledDevMode && <ExportPrivateKey rawWallet={rawWallet} />}
<ThemeManager />
</Box>
@ -241,6 +244,7 @@ const ExportPrivateKey = ({ rawWallet }) => {
const [isOpen, setIsOpen] = useState(false);
const { setOpenSnackGlobal, setInfoSnackCustom } =
useContext(QORTAL_APP_CONTEXT);
const theme = useTheme();
const { t } = useTranslation([
'auth',
'core',
@ -377,13 +381,13 @@ const ExportPrivateKey = ({ rawWallet }) => {
setPrivateKey('');
}}
>
{t('group:action.cancel', {
{t('core:action.cancel', {
postProcess: 'capitalizeFirstChar',
})}
</Button>
<Button variant="contained" onClick={exportPrivateKeyFunc}>
{t('group:action.decrypt', {
{t('core:action.decrypt', {
postProcess: 'capitalizeFirstChar',
})}
</Button>

View File

@ -2,6 +2,8 @@ import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { supportedLanguages } from '../../i18n/i18n';
import {
Box,
Button,
FormControl,
MenuItem,
Select,
@ -26,16 +28,7 @@ const LanguageSelector = () => {
supportedLanguages[currentLang] || supportedLanguages['en'];
return (
<div
ref={selectorRef}
style={{
bottom: '5%',
display: 'flex',
gap: '12px',
left: '1.5vh',
position: 'absolute',
}}
>
<Box ref={selectorRef}>
{!showSelect && (
<Tooltip
key={currentLang}
@ -43,13 +36,10 @@ const LanguageSelector = () => {
postProcess: 'capitalizeFirstChar',
})}
>
<button
<Button
onClick={() => setShowSelect(true)}
style={{
fontSize: '1.5rem',
border: 'none',
background: 'none',
cursor: 'pointer',
fontSize: '1.3rem',
}}
aria-label={t('core:current_language', {
language: name,
@ -57,7 +47,7 @@ const LanguageSelector = () => {
})}
>
{flag}
</button>
</Button>
</Tooltip>
)}
@ -70,13 +60,13 @@ const LanguageSelector = () => {
}}
>
<Select
open
labelId="language-select-label"
id="language-select"
value={currentLang}
onChange={handleChange}
autoFocus
id="language-select"
labelId="language-select-label"
onChange={handleChange}
onClose={() => setShowSelect(false)}
open
value={currentLang}
>
{Object.entries(supportedLanguages).map(([code, { name }]) => (
<MenuItem key={code} value={code}>
@ -86,7 +76,7 @@ const LanguageSelector = () => {
</Select>
</FormControl>
)}
</div>
</Box>
);
};

View File

@ -1,5 +1,6 @@
import {
Alert,
AppBar,
Box,
Button,
Card,
@ -10,6 +11,7 @@ import {
Divider,
IconButton,
Snackbar,
Toolbar,
Typography,
useTheme,
} from '@mui/material';
@ -573,34 +575,26 @@ export const Minting = ({ setIsOpenMinting, myAddress, show }) => {
},
}}
>
<DialogTitle
id="alert-dialog-title"
sx={{
textAlign: 'center',
color: theme.palette.text.primary,
fontWeight: 'bold',
opacity: 1,
}}
>
{t('group:message.generic.manage_minting', {
postProcess: 'capitalizeAll',
})}
</DialogTitle>
<AppBar sx={{ position: 'relative' }}>
<Toolbar>
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
{t('group:message.generic.manage_minting', {
postProcess: 'capitalizeFirstChar',
})}
</Typography>
<IconButton
sx={{
position: 'absolute',
right: 8,
top: 8,
}}
color="inherit"
onClick={() => setIsOpenMinting(false)}
aria-label={t('core:action.close', {
postProcess: 'capitalizeFirstChar',
})}
>
<CloseIcon />
</IconButton>
<IconButton
color="inherit"
edge="start"
onClick={() => setIsOpenMinting(false)}
aria-label={t('core:action.close', {
postProcess: 'capitalizeFirstChar',
})}
>
<CloseIcon />
</IconButton>
</Toolbar>
</AppBar>
<DialogContent
sx={{
@ -914,16 +908,6 @@ export const Minting = ({ setIsOpenMinting, myAddress, show }) => {
)}
</DialogContent>
<DialogActions>
<Button
// disabled={isLoadingPublish}
variant="contained"
onClick={() => setIsOpenMinting(false)}
>
{t('core:action.close', { postProcess: 'capitalizeFirstChar' })}
</Button>
</DialogActions>
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={openSnack}

View File

@ -29,9 +29,7 @@ import HelpIcon from '@mui/icons-material/Help';
import { CustomizedSnackbars } from './Snackbar/Snackbar';
import { cleanUrl, gateways } from '../background/background.ts';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import ThemeSelector from './Theme/ThemeSelector';
import { useTranslation } from 'react-i18next';
import LanguageSelector from './Language/LanguageSelector';
import { QORTAL_APP_CONTEXT } from '../App';
export const manifestData = {
@ -482,7 +480,8 @@ export const NotAuthenticated = ({
return (
<>
<Spacer height="35px" />
<div
<Box
className="image-container"
style={{
width: '136px',
@ -490,7 +489,7 @@ export const NotAuthenticated = ({
}}
>
<img src={Logo1Dark} className="base-image" />
</div>
</Box>
<Spacer height="30px" />
@ -513,6 +512,7 @@ export const NotAuthenticated = ({
</TextP>
<Spacer height="30px" />
<Box
sx={{
display: 'flex',
@ -547,6 +547,7 @@ export const NotAuthenticated = ({
</Box>
<Spacer height="6px" />
<Box
sx={{
display: 'flex',
@ -624,6 +625,7 @@ export const NotAuthenticated = ({
<>
<Spacer height="15px" />
<Box
sx={{
display: 'flex',
@ -648,6 +650,7 @@ export const NotAuthenticated = ({
>
{t('auth:advanced_users', { postProcess: 'capitalizeFirstChar' })}
</Typography>
<Box
sx={{
alignItems: 'center',
@ -725,6 +728,7 @@ export const NotAuthenticated = ({
postProcess: 'capitalizeFirstChar',
})}
</Button>
<Typography
sx={{
fontSize: '12px',
@ -736,6 +740,7 @@ export const NotAuthenticated = ({
</Typography>
</>
)}
<Button
size="small"
onClick={() => {
@ -747,6 +752,7 @@ export const NotAuthenticated = ({
{t('auth:node.choose', { postProcess: 'capitalizeFirstChar' })}
</Button>
</>
<Typography
sx={{
color: theme.palette.text.primary,
@ -765,6 +771,7 @@ export const NotAuthenticated = ({
info={infoSnack}
setInfo={setInfoSnack}
/>
{show && (
<Dialog
open={show}
@ -784,6 +791,7 @@ export const NotAuthenticated = ({
{t('auth:node.custom_many', { postProcess: 'capitalizeFirstChar' })}
:
</DialogTitle>
<DialogContent>
<Box
sx={{
@ -817,6 +825,7 @@ export const NotAuthenticated = ({
>
http://127.0.0.1:12391
</Typography>
<Box
sx={{
display: 'flex',
@ -867,6 +876,7 @@ export const NotAuthenticated = ({
{customNodes?.map((node, index) => {
return (
<Box
key={index}
sx={{
display: 'flex',
gap: '10px',
@ -1068,6 +1078,7 @@ export const NotAuthenticated = ({
>
{t('auth:apikey.enter', { postProcess: 'capitalizeFirstChar' })}
</DialogTitle>
<DialogContent>
<Box
sx={{
@ -1177,10 +1188,6 @@ export const NotAuthenticated = ({
}}
/>
</ButtonBase>
<LanguageSelector />
<ThemeSelector />
</>
);
};

View File

@ -10,12 +10,12 @@ import {
DialogActions,
List,
ListItemText,
ListItemSecondaryAction,
TextField,
Tabs,
Tab,
ListItemButton,
useTheme,
ListItem,
} from '@mui/material';
import { Sketch } from '@uiw/react-color';
import DeleteIcon from '@mui/icons-material/Delete';
@ -31,6 +31,7 @@ import FileDownloadIcon from '@mui/icons-material/FileDownload';
import { saveFileToDiskGeneric } from '../../utils/generateWallet/generateWallet';
import { handleImportClick } from '../../utils/fileReading';
import { useTranslation } from 'react-i18next';
import '../../styles/themeManager.css';
const uid = new ShortUniqueId({ length: 8 });
@ -189,6 +190,7 @@ export default function ThemeManager() {
<Typography variant="body2" mb={1}>
{label}
</Typography>
<Sketch
key={`${mode}-${fieldPath}`}
color={color}
@ -269,24 +271,28 @@ export default function ThemeManager() {
<ListItemText
primary={`${theme?.name || `Theme ${index + 1}`} ${theme?.id === currentThemeId ? '(Current)' : ''}`}
/>
<ListItemSecondaryAction>
{theme.id !== 'default' && (
<>
<IconButton onClick={() => exportTheme(theme)}>
<FileDownloadIcon />
<ListItem
secondaryAction={
<Box sx={{ display: 'flex', gap: 1 }}>
{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>
<IconButton onClick={() => handleEditTheme(theme.id)}>
<EditIcon />
</IconButton>
<IconButton onClick={() => handleDeleteTheme(theme.id)}>
<DeleteIcon />
</IconButton>
</>
)}
<IconButton onClick={() => handleApplyTheme(theme)}>
<CheckIcon />
</IconButton>
</ListItemSecondaryAction>
</Box>
}
></ListItem>
</ListItemButton>
))}
</List>

View File

@ -1,8 +1,9 @@
import { useThemeContext } from './ThemeContext';
import { IconButton, Tooltip } from '@mui/material';
import { Box, IconButton, Tooltip } from '@mui/material';
import LightModeIcon from '@mui/icons-material/LightMode';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import { useTranslation } from 'react-i18next';
import { useRef } from 'react';
const ThemeSelector = () => {
const { t } = useTranslation([
@ -13,17 +14,10 @@ const ThemeSelector = () => {
'tutorial',
]);
const { themeMode, toggleTheme } = useThemeContext();
const selectorRef = useRef(null);
return (
<div
style={{
bottom: '1%',
display: 'flex',
gap: '12px',
left: '1.2vh',
position: 'absolute',
}}
>
<Box ref={selectorRef}>
<Tooltip
title={
themeMode === 'dark'
@ -39,7 +33,7 @@ const ThemeSelector = () => {
{themeMode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
</Tooltip>
</div>
</Box>
);
};

View File

@ -54,6 +54,7 @@ export const Tutorials = () => {
{openTutorialModal?.multi?.map((item, index) => {
return (
<Tab
key={index}
sx={{
'&.Mui-selected': {
color: theme.palette.text.primary,

View File

@ -29,7 +29,6 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import { Spacer } from '../../common/Spacer';
import { formatTimestamp } from '../../utils/time';
import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen';
import SearchIcon from '@mui/icons-material/Search';
import {
executeEvent,
subscribeToEvent,
@ -65,6 +64,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
const [isLoadingUser, setIsLoadingUser] = useState(false);
const [isLoadingPayments, setIsLoadingPayments] = useState(false);
const [payments, setPayments] = useState([]);
const lookupFunc = useCallback(
async (messageAddressOrName) => {
try {
@ -481,6 +481,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
/>
</Box>
)}
{!isLoadingPayments && addressInfo && (
<Card
sx={{

View File

@ -1,12 +1,11 @@
import bcrypt from 'bcryptjs'
import bcrypt from 'bcryptjs';
self.onmessage = function (e) {
const { hashBase64, salt } = e.data;
try {
const result = bcrypt.hashSync(hashBase64, salt);
self.postMessage({ result });
} catch (error) {
self.postMessage({ error: error.message });
}
};
const { hashBase64, salt } = e.data;
try {
const result = bcrypt.hashSync(hashBase64, salt);
self.postMessage({ result });
} catch (error) {
self.postMessage({ error: error.message });
}
};

View File

@ -336,8 +336,8 @@
"about": "über diese Q-App",
"q_mail": "Q-Mail",
"q_manager": "Q-Manager",
"q_sandbox": "q-sandbox",
"q_wallets": "q-wallets"
"q_sandbox": "Q-Sandbox",
"q_wallets": "Q-Wallets"
},
"receiver": "empfänger",
"sender": "absender",

View File

@ -116,8 +116,8 @@
"additional_wallet": "usa quest'opzione per collegare ulteriori portafogli Qortal già creati, per potervi accedere in seguito. Avrai bisogno di accedere al tuo file JSON di backup.",
"digital_id": "il tuo wallet è come il tuo ID digitale su Qortal ed e verrà usato per accedere a Qortal. Contiene il tuo indirizzo pubblico e il nome Qortal che alla fine sceglierai. Ogni transazione che fai è collegata al tuo ID, nel quale potrai gestire tutte le tue criptovalute Qort e altre criptovalute negoziabili su Qortal.",
"existing_account": "hai già un account Qortal? Inserisci qui la tua frase di backup segreta per accedervi. Questa frase è uno dei modi per recuperare il tuo account.",
"key_encrypt_admin": "questa chiave crittografa i contenuti relativi ad amministratore. Solo gli amministratori vedrebbero il contenuto crittografato.",
"key_encrypt_group": "questa chiave crittografa i contenuti relativi al gruppo. Questo è l'unico usato in questa interfaccia utente al momento. Tutti i membri del gruppo saranno in grado di vedere i contenuti crittografati con questa chiave.",
"key_encrypt_admin": "questa chiave crittografa i contenuti relativi ad amministratore. Solo gli amministratori vedranno il contenuto crittografato.",
"key_encrypt_group": "questa chiave crittografa i contenuti relativi al gruppo. Questo al momento è l'unico modo usato. Tutti i membri del gruppo saranno in grado di vedere i contenuti crittografati con questa chiave.",
"new_account": "la creazione di un account consiste nella creazione di un wallet e di un ID digitale per iniziare a utilizzare Qortal. Una volta creato l'account, potrai iniziare a fare cose come ottenere dei Qort, acquistare un nome e un Avatar, pubblicare video e blog e molto altro.",
"new_users": "i nuovi utenti iniziano qui!",
"safe_place": "salva il tuo account in un posto da ricordare!",

View File

@ -14,7 +14,7 @@
"change": "modifica",
"change_avatar": "cambia Avatar",
"change_file": "modifica file",
"change_language": "cambia il linguaggio",
"change_language": "cambia la lingua",
"choose": "scegli",
"choose_file": "scegli il file",
"choose_image": "scegli l'immagine",
@ -47,7 +47,7 @@
"import_theme": "importa un tema",
"invite": "invitare",
"invite_member": "invita un nuovo membro",
"join": "unisciti",
"join": "unisciti a",
"leave_comment": "lascia un commento",
"load_announcements": "carica annunci più vecchi",
"login": "login",
@ -154,7 +154,7 @@
"image_embed": "immagine incorporare",
"last_height": "ultima altezza",
"level": "livello",
"library": "biblioteca",
"library": "libreria",
"list": {
"bans": "elenco degli esclusi",
"groups": "elenco dei gruppi",
@ -175,35 +175,35 @@
"message_us": "si prega di inviarci un messaggio su Telegram o Discord se hai bisogno di 4 Qort per iniziare a chattare senza limitazioni",
"message": {
"error": {
"address_not_found": "il tuo indirizzo non è stato trovato",
"app_need_name": "la tua app ha bisogno di un nome",
"build_app": "impossibile creare app private",
"address_not_found": "il tuo indirizzo non è stato trovato.",
"app_need_name": "la tua app ha bisogno di un nome.",
"build_app": "impossibile creare app privata.",
"decrypt_app": "impossibile decrittografare l'app privata '",
"download_image": "impossibile scaricare l'immagine. Riprova più tardi facendo clic sul pulsante Aggiorna",
"download_private_app": "impossibile scaricare l'app privata",
"encrypt_app": "impossibile crittografare l'app. App non pubblicata '",
"fetch_app": "impossibile recuperare l'app",
"fetch_publish": "impossibile recuperare la pubblicazione",
"download_image": "impossibile scaricare l'immagine. Riprova più tardi facendo clic sul pulsante Aggiorna.",
"download_private_app": "impossibile scaricare l'app privata.",
"encrypt_app": "impossibile crittografare. App non pubblicata.",
"fetch_app": "impossibile recuperare l'app.",
"fetch_publish": "impossibile recuperare la pubblicazione.",
"file_too_large": "file {{ filename }} is too large. Max size allowed is {{ size }} MB.",
"generic": "si è verificato un errore",
"initiate_download": "impossibile avviare il download",
"initiate_download": "impossibile avviare il download.",
"invalid_amount": "importo non valido",
"invalid_base64": "dati Base64 non validi",
"invalid_embed_link": "collegamento incorporato non valido",
"invalid_image_embed_link_name": "iMMAGINE IMMAGINE INCONTRO IN ENTRARE. Param mancante.",
"invalid_poll_embed_link_name": "sondaggio non valido Incorporare il collegamento. Nome mancante.",
"invalid_image_embed_link_name": "link incorporato dell'immagine non valido. Param mancante.",
"invalid_poll_embed_link_name": "link incorporato del sondaggio non valido. Nome mancante.",
"invalid_signature": "firma non valida",
"invalid_theme_format": "formato tema non valido",
"invalid_zip": "zip non valido",
"message_loading": "errore di caricamento del messaggio.",
"message_size": "your message size is of {{ size }} bytes out of a maximum of {{ maximum }}",
"minting_account_add": "impossibile aggiungere l'account di minting",
"minting_account_remove": "impossibile rimuovere l'account di minting",
"message_loading": "errore di caricamento del messaggio",
"message_size": "la dimensione del messaggio è di {{ size }} byte su un massimo di {{maximum }}",
"minting_account_add": "impossibile aggiungere l'account di minting.",
"minting_account_remove": "impossibile rimuovere l'account di minting.",
"missing_fields": "missing: {{ fields }}",
"navigation_timeout": "timeout di navigazione",
"network_generic": "errore di rete",
"password_not_matching": "i campi della password non corrispondono!",
"password_wrong": "impossibile autenticare. Password sbagliata",
"password_wrong": "impossibile autenticare. Password sbagliata.",
"publish_app": "impossibile pubblicare l'app",
"publish_image": "impossibile pubblicare l'immagine",
"rate": "impossibile valutare",
@ -220,8 +220,8 @@
"building": "creazione",
"building_app": "creazione app",
"created_by": "creato da {{ owner }}",
"buy_order_request": "l'applicazione <br/><italic>{{hostname}}</italic> <br/><span>sta effettuando {{count}} ordine d'acquisto</span>",
"buy_order_request_other": "l'applicazione <br/><italic>{{hostname}}</italic> <br/><span>sta effettuando {{count}} ordini d'acquisto</span>",
"buy_order_request": "l'applicazione <br/><italic>{{hostname}}</italic> <br/><span>sta effettuando {{count}} ordine d'acquisto</span>.",
"buy_order_request_other": "l'applicazione <br/><italic>{{hostname}}</italic> <br/><span>sta effettuando {{count}} ordini d'acquisto</span>.",
"devmode_local_node": "si prega di utilizzare il tuo nodo locale per la modalità Dev! Logout e usa il nodo locale.",
"downloading": "download",
"downloading_decrypting_app": "download e decritting di app private.",
@ -232,7 +232,7 @@
"fee_qort": "commissione: {{ message }} QORT",
"fetching_data": "recupero dei dati dell'app",
"foreign_fee": "commissione esterna: {{ message }}",
"get_qort_trade_portal": "ottieni Qort con il portale di trade crosschain di Qortal",
"get_qort_trade_portal": "ottieni QORT con il portale di trade crosschain di Qortal",
"minimal_qort_balance": "avere almeno {{ quantity }} QORT a bilancio (4 qort per la chat, 1.25 per il nome, 0.75 per alcune transazioni)",
"mentioned": "menzionato",
"message_with_image": "questo messaggio ha già un'immagine",
@ -258,26 +258,26 @@
"overwrite_qdn": "sovrascrivi a QDN",
"password_confirm": "si prega di confermare una password",
"password_enter": "inserisci una password",
"payment_request": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting a payment</span>",
"payment_request": "l'applicazione <br/><italic>{{hostname}}</italic> <br/><span>sta richiedendo un pagamento</span>",
"people_reaction": "persone che hanno reagito con {{ reaction }}",
"processing_transaction": "elaborazione della transazione, per favore aspetta ...",
"publish_data": "pubblica dati su Qortal: qualsiasi cosa, dalle app ai video. Completamente decentralizzato!",
"publishing": "publishing. Attendere, per favore.",
"publishing": "in pubblicazione. Attendere, per favore.",
"qdn": "usa il salvataggio QDN",
"rating": "rating for {{ service }} {{ name }}",
"rating": "valutazione di {{ service }} {{ name }}",
"register_name": "hai bisogno di un nome Qortal registrato per salvare in QDN le app bloccate.",
"replied_to": "replied to {{ person }}",
"replied_to": "risposta a {{ person }}",
"revert_default": "ritorna a predefinito",
"revert_qdn": "ritorna a QDN",
"save_qdn": "salva su QDN",
"secure_ownership": "proprietà sicura dei dati pubblicati con il tuo nome. Puoi anche vendere il tuo nome, insieme ai tuoi dati a una terza parte.",
"secure_ownership": "sicura proprietà dei dati pubblicati con il tuo nome. Puoi anche vendere il tuo nome, insieme ai tuoi dati a una terza parte.",
"select_file": "seleziona un file",
"select_image": "seleziona un'immagine per un logo",
"select_zip": "seleziona il file .zip contenente contenuto statico:",
"sending": "invio ...",
"settings": "si utilizza il modo di esportazione/importazione per salvare le impostazioni.",
"space_for_admins": "mi dispiace, questo spazio è solo per gli amministratori.",
"unread_messages": "messaggi non letto di seguito",
"unread_messages": "messaggi non letti qua sotto",
"unsaved_changes": "hai cambiato modifiche alle app bloccate. Salvali su QDN.",
"updating": "aggiornamento"
},
@ -316,7 +316,7 @@
"voted": "votato con successo. Si prega di attendere un paio di minuti affinché la rete propaghi le modifiche."
}
},
"minting_status": "stato di minting",
"minting_status": "stato minting",
"name": "nome",
"name_app": "nome/app",
"new_post_in": "nuovo post in {{ title }}",
@ -339,10 +339,10 @@
"publish": "pubblicazione",
"q_apps": {
"about": "su questo Q-app",
"q_mail": "Q-mail",
"q_manager": "Q-manager",
"q_sandbox": "Q-sandbox",
"q_wallets": "Q-wallet"
"q_mail": "Q-Mail",
"q_manager": "Q-Manager",
"q_sandbox": "Q-Sandbox",
"q_wallets": "Q-Wallets"
},
"receiver": "ricevitore",
"sender": "mittente",
@ -358,7 +358,7 @@
"dark": "scuro",
"dark_mode": "modalità scura",
"default": "tema di default",
"light": "chiara",
"light": "chiaro",
"light_mode": "modalità chiara",
"manager": "manager tema",
"name": "nome tema"

View File

@ -65,26 +65,26 @@
"generic": {
"avatar_publish_fee": "la pubblicazione di un Avatar richiede {{ fee }}",
"avatar_registered_name": "È necessario un nome registrato per impostare un avatar",
"admin_only": "verranno mostrati solo gruppi in cui sei un amministratore",
"admin_only": "verranno mostrati solo i gruppi in cui sei un amministratore",
"already_in_group": "sei già in questo gruppo!",
"block_delay_minimum": "ritardo minimo del blocco per le approvazioni delle transazioni di gruppo",
"block_delay_maximum": "ritardo massimo del blocco per le approvazioni delle transazioni di gruppo",
"closed_group": "questo è un gruppo chiuso/privato, quindi dovrai attendere fino a quando un amministratore accetta la tua richiesta",
"descrypt_wallet": "decrittazione del wallet ...",
"encryption_key": "la prima chiave di crittografia comune del gruppo è in procinto di creare. Si prega di attendere qualche minuto per essere recuperato dalla rete. Controllo ogni 2 minuti ...",
"encryption_key": "la prima chiave di crittografia comune del gruppo è in fase di creazione. Si prega di attendere qualche minuto per essere recuperato dalla rete. Controllo ogni 2 minuti ...",
"group_announcement": "annunci di gruppo",
"group_approval_threshold": "soglia di approvazione del gruppo (numero / percentuale di amministratori che devono approvare una transazione)",
"group_encrypted": "gruppo crittografato",
"group_invited_you": "{{group}} has invited you",
"group_key_created": "primo tasto di gruppo creato.",
"group_member_list_changed": "l'elenco dei membri del gruppo è cambiato. Si prega di rivivere nuovamente la chiave segreta.",
"group_no_secret_key": "non esiste una chiave segreta di gruppo. Sii il primo amministratore a pubblicarne uno!",
"group_secret_key_no_owner": "l'ultima chiave segreta del gruppo è stata pubblicata da un non proprietario. Come proprietario del gruppo si prega di rivivere la chiave come salvaguardia.",
"group_no_secret_key": "non esiste una chiave segreta di gruppo. Potresti essere il primo amministratore a pubblicarne una!",
"group_secret_key_no_owner": "l'ultima chiave segreta del gruppo è stata pubblicata da un non proprietario. Come proprietario del gruppo si prega di ricriptare la chiave per sicurezza.",
"invalid_content": "contenuto non valido, mittente o timestamp nei dati di reazione",
"invalid_data": "contenuto di caricamento degli errori: dati non validi",
"latest_promotion": "verrà mostrata solo l'ultima promozione della settimana per il tuo gruppo.",
"loading_members": "caricamento dell'elenco dei membri con nomi ... Attendi.",
"max_chars": "max 200 caratteri. Pubblica tassa",
"max_chars": "max 200 caratteri. Commissione",
"manage_minting": "gestisci il minting",
"minter_group": "al momento non fai parte del gruppo Minter",
"mintership_app": "visita l'app Q-Mintership per chiedere di diventare un minter",

View File

@ -339,8 +339,8 @@
"about": "об этом Q-App",
"q_mail": "Q-Mail",
"q_manager": "Q-Manager",
"q_sandbox": "Q-SANDBOX",
"q_wallets": "Q-Wallet"
"q_sandbox": "Q-Sandbox",
"q_wallets": "Q-Wallets"
},
"receiver": "приемник",
"sender": "отправитель",

View File

@ -337,9 +337,9 @@
"q_apps": {
"about": "关于这个Q-App",
"q_mail": "Q邮件",
"q_manager": "Q-Manager",
"q_sandbox": "Q-Sandbox",
"q_wallets": "Q-Wallet"
"q_manager": "Q-经理",
"q_sandbox": "Q-沙箱",
"q_wallets": "Q-钱包"
},
"receiver": "接收者",
"sender": "发件人",

View File

@ -6,7 +6,7 @@ export const darkThemeOptions: ThemeOptions = {
palette: {
mode: 'dark',
primary: {
main: 'rgba(0, 133, 255, 1)',
main: 'rgb(100, 155, 240)',
dark: 'rgb(45, 92, 201)',
light: 'rgb(130, 185, 255)',
},
@ -14,9 +14,9 @@ export const darkThemeOptions: ThemeOptions = {
main: 'rgb(69, 173, 255)',
},
background: {
default: 'rgba(6, 10, 30, 1)',
default: 'rgb(49, 51, 56)',
surface: 'rgb(58, 60, 65)',
paper: 'rgb(62, 64, 68)',
surface: 'rgb(113, 113, 114)',
},
text: {
primary: 'rgb(255, 255, 255)',

View File

@ -15,8 +15,8 @@ export const lightThemeOptions: ThemeOptions = {
},
background: {
default: 'rgba(250, 250, 250, 1)',
paper: 'rgb(220, 220, 220)', // darker card background
surface: 'rgb(240, 240, 240)', // optional middle gray for replies, side panels
paper: 'rgb(220, 220, 220)', // darker card background
},
text: {
primary: 'rgba(0, 0, 0, 0.87)', // 87% black (slightly softened)