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' }` - For all translation in uppercase `{ postProcess: 'capitalizeAll' }`
- See `.src/i18n/i18n.ts` for processor definition - See `.src/i18n/i18n.ts` for processor definition
## Namespace ## Namespaces
These are the current namespaces, in which all translations are organized: 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 [sendqortState, setSendqortState] = useState<any>(null);
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false); const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
const isAuthenticated = extState === 'authenticated';
const { t } = useTranslation([ const { t } = useTranslation([
'auth', 'auth',
'core', 'core',
@ -1353,6 +1353,7 @@ function App() {
/> />
</Tooltip> </Tooltip>
)} )}
{authenticatedMode === 'ltc' && ( {authenticatedMode === 'ltc' && (
<Tooltip <Tooltip
title={ title={
@ -2059,6 +2060,7 @@ function App() {
useLocalNode={useLocalNode} useLocalNode={useLocalNode}
/> />
)} )}
{extState === 'authenticated' && isMainWindow && ( {extState === 'authenticated' && isMainWindow && (
<Box <Box
sx={{ sx={{
@ -2136,6 +2138,7 @@ function App() {
{isShowQortalRequest && !isMainWindow && ( {isShowQortalRequest && !isMainWindow && (
<> <>
<Spacer height="120px" /> <Spacer height="120px" />
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@ -2231,6 +2234,7 @@ function App() {
dangerouslySetInnerHTML={{ __html: messageQortalRequest?.html }} dangerouslySetInnerHTML={{ __html: messageQortalRequest?.html }}
/> />
)} )}
<Spacer height="15px" /> <Spacer height="15px" />
<TextP <TextP
@ -2308,6 +2312,7 @@ function App() {
)} )}
<Spacer height="29px" /> <Spacer height="29px" />
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@ -2325,6 +2330,7 @@ function App() {
postProcess: 'capitalizeFirstChar', postProcess: 'capitalizeFirstChar',
})} })}
</CustomButton> </CustomButton>
<CustomButton <CustomButton
sx={{ sx={{
minWidth: '102px', minWidth: '102px',
@ -2595,6 +2601,7 @@ function App() {
postProcess: 'capitalizeFirstChar', postProcess: 'capitalizeFirstChar',
})} })}
</CustomButton> </CustomButton>
<CustomButton <CustomButton
sx={{ sx={{
minWidth: '102px', minWidth: '102px',
@ -3977,8 +3984,27 @@ function App() {
/> />
)} )}
<LanguageSelector /> {!isAuthenticated && (
<ThemeSelector /> <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> </AppContainer>
); );
} }

View File

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

View File

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

View File

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

View File

@ -24,20 +24,23 @@ export const AppsDevModeNavBar = () => {
const [navigationController, setNavigationController] = useAtom( const [navigationController, setNavigationController] = useAtom(
navigationControllerAtom navigationControllerAtom
); );
const { t } = useTranslation([
'auth',
'core',
'group',
'question',
'tutorial',
]);
const theme = useTheme(); 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 [isNewTabWindow, setIsNewTabWindow] = useState(false);
const tabsRef = useRef(null); const tabsRef = useRef(null);
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
useEffect(() => { useEffect(() => {
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added) // 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 { extractComponents } from '../Chat/MessageDisplay';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward'; import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import { AppsPrivate } from './AppsPrivate'; import { AppsPrivate } from './AppsPrivate';
import ThemeSelector from '../Theme/ThemeSelector';
import LanguageSelector from '../Language/LanguageSelector';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export const AppsHomeDesktop = ({ export const AppsHomeDesktop = ({
@ -77,7 +75,7 @@ export const AppsHomeDesktop = ({
<Box <Box
sx={{ sx={{
alignItems: 'center', alignItems: 'center',
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.paper,
borderRadius: '20px', borderRadius: '20px',
display: 'flex', display: 'flex',
gap: '20px', gap: '20px',
@ -97,10 +95,10 @@ export const AppsHomeDesktop = ({
autoCorrect="off" autoCorrect="off"
placeholder="qortal://" placeholder="qortal://"
sx={{ sx={{
width: '100%',
backgroundColor: theme.palette.background.surface,
borderRadius: '7px', borderRadius: '7px',
color: theme.palette.text.primary, color: theme.palette.text.primary,
height: '35px',
width: '100%',
'& .MuiInput-input::placeholder': { '& .MuiInput-input::placeholder': {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: '20px', fontSize: '20px',
@ -169,9 +167,6 @@ export const AppsHomeDesktop = ({
myApp={myApp} myApp={myApp}
/> />
</AppsContainer> </AppsContainer>
<LanguageSelector />
<ThemeSelector />
</> </>
); );
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -348,6 +348,15 @@ export const MessageItem = memo(
scrollToItem(replyIndex); 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 <Box
sx={{ sx={{
padding: '5px', padding: '5px',
@ -393,6 +402,7 @@ export const MessageItem = memo(
{message?.images && messageHasImage(message) && ( {message?.images && messageHasImage(message) && (
<Embed embedLink={buildImageEmbedLink(message.images[0])} /> <Embed embedLink={buildImageEmbedLink(message.images[0])} />
)} )}
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@ -463,11 +473,12 @@ export const MessageItem = memo(
vertical: 'bottom', vertical: 'bottom',
horizontal: 'center', horizontal: 'center',
}} }}
PaperProps={{ slotProps={{
// TODO: deprecated paper: {
style: { style: {
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary, color: theme.palette.text.primary,
},
}, },
}} }}
> >
@ -593,6 +604,7 @@ export const MessageItem = memo(
})} })}
</Typography> </Typography>
)} )}
<Typography <Typography
sx={{ sx={{
fontSize: '14px', fontSize: '14px',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -336,8 +336,8 @@
"about": "über diese Q-App", "about": "über diese Q-App",
"q_mail": "Q-Mail", "q_mail": "Q-Mail",
"q_manager": "Q-Manager", "q_manager": "Q-Manager",
"q_sandbox": "q-sandbox", "q_sandbox": "Q-Sandbox",
"q_wallets": "q-wallets" "q_wallets": "Q-Wallets"
}, },
"receiver": "empfänger", "receiver": "empfänger",
"sender": "absender", "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.", "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.", "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.", "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_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 è 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_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_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!", "new_users": "i nuovi utenti iniziano qui!",
"safe_place": "salva il tuo account in un posto da ricordare!", "safe_place": "salva il tuo account in un posto da ricordare!",

View File

@ -14,7 +14,7 @@
"change": "modifica", "change": "modifica",
"change_avatar": "cambia Avatar", "change_avatar": "cambia Avatar",
"change_file": "modifica file", "change_file": "modifica file",
"change_language": "cambia il linguaggio", "change_language": "cambia la lingua",
"choose": "scegli", "choose": "scegli",
"choose_file": "scegli il file", "choose_file": "scegli il file",
"choose_image": "scegli l'immagine", "choose_image": "scegli l'immagine",
@ -47,7 +47,7 @@
"import_theme": "importa un tema", "import_theme": "importa un tema",
"invite": "invitare", "invite": "invitare",
"invite_member": "invita un nuovo membro", "invite_member": "invita un nuovo membro",
"join": "unisciti", "join": "unisciti a",
"leave_comment": "lascia un commento", "leave_comment": "lascia un commento",
"load_announcements": "carica annunci più vecchi", "load_announcements": "carica annunci più vecchi",
"login": "login", "login": "login",
@ -154,7 +154,7 @@
"image_embed": "immagine incorporare", "image_embed": "immagine incorporare",
"last_height": "ultima altezza", "last_height": "ultima altezza",
"level": "livello", "level": "livello",
"library": "biblioteca", "library": "libreria",
"list": { "list": {
"bans": "elenco degli esclusi", "bans": "elenco degli esclusi",
"groups": "elenco dei gruppi", "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_us": "si prega di inviarci un messaggio su Telegram o Discord se hai bisogno di 4 Qort per iniziare a chattare senza limitazioni",
"message": { "message": {
"error": { "error": {
"address_not_found": "il tuo indirizzo non è stato trovato", "address_not_found": "il tuo indirizzo non è stato trovato.",
"app_need_name": "la tua app ha bisogno di un nome", "app_need_name": "la tua app ha bisogno di un nome.",
"build_app": "impossibile creare app private", "build_app": "impossibile creare app privata.",
"decrypt_app": "impossibile decrittografare l'app privata '", "decrypt_app": "impossibile decrittografare l'app privata '",
"download_image": "impossibile scaricare l'immagine. Riprova più tardi facendo clic sul pulsante Aggiorna", "download_image": "impossibile scaricare l'immagine. Riprova più tardi facendo clic sul pulsante Aggiorna.",
"download_private_app": "impossibile scaricare l'app privata", "download_private_app": "impossibile scaricare l'app privata.",
"encrypt_app": "impossibile crittografare l'app. App non pubblicata '", "encrypt_app": "impossibile crittografare. App non pubblicata.",
"fetch_app": "impossibile recuperare l'app", "fetch_app": "impossibile recuperare l'app.",
"fetch_publish": "impossibile recuperare la pubblicazione", "fetch_publish": "impossibile recuperare la pubblicazione.",
"file_too_large": "file {{ filename }} is too large. Max size allowed is {{ size }} MB.", "file_too_large": "file {{ filename }} is too large. Max size allowed is {{ size }} MB.",
"generic": "si è verificato un errore", "generic": "si è verificato un errore",
"initiate_download": "impossibile avviare il download", "initiate_download": "impossibile avviare il download.",
"invalid_amount": "importo non valido", "invalid_amount": "importo non valido",
"invalid_base64": "dati Base64 non validi", "invalid_base64": "dati Base64 non validi",
"invalid_embed_link": "collegamento incorporato non valido", "invalid_embed_link": "collegamento incorporato non valido",
"invalid_image_embed_link_name": "iMMAGINE IMMAGINE INCONTRO IN ENTRARE. Param mancante.", "invalid_image_embed_link_name": "link incorporato dell'immagine non valido. Param mancante.",
"invalid_poll_embed_link_name": "sondaggio non valido Incorporare il collegamento. Nome mancante.", "invalid_poll_embed_link_name": "link incorporato del sondaggio non valido. Nome mancante.",
"invalid_signature": "firma non valida", "invalid_signature": "firma non valida",
"invalid_theme_format": "formato tema non valido", "invalid_theme_format": "formato tema non valido",
"invalid_zip": "zip non valido", "invalid_zip": "zip non valido",
"message_loading": "errore di caricamento del messaggio.", "message_loading": "errore di caricamento del messaggio",
"message_size": "your message size is of {{ size }} bytes out of a maximum of {{ maximum }}", "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_add": "impossibile aggiungere l'account di minting.",
"minting_account_remove": "impossibile rimuovere l'account di minting", "minting_account_remove": "impossibile rimuovere l'account di minting.",
"missing_fields": "missing: {{ fields }}", "missing_fields": "missing: {{ fields }}",
"navigation_timeout": "timeout di navigazione", "navigation_timeout": "timeout di navigazione",
"network_generic": "errore di rete", "network_generic": "errore di rete",
"password_not_matching": "i campi della password non corrispondono!", "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_app": "impossibile pubblicare l'app",
"publish_image": "impossibile pubblicare l'immagine", "publish_image": "impossibile pubblicare l'immagine",
"rate": "impossibile valutare", "rate": "impossibile valutare",
@ -220,8 +220,8 @@
"building": "creazione", "building": "creazione",
"building_app": "creazione app", "building_app": "creazione app",
"created_by": "creato da {{ owner }}", "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": "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_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.", "devmode_local_node": "si prega di utilizzare il tuo nodo locale per la modalità Dev! Logout e usa il nodo locale.",
"downloading": "download", "downloading": "download",
"downloading_decrypting_app": "download e decritting di app private.", "downloading_decrypting_app": "download e decritting di app private.",
@ -232,7 +232,7 @@
"fee_qort": "commissione: {{ message }} QORT", "fee_qort": "commissione: {{ message }} QORT",
"fetching_data": "recupero dei dati dell'app", "fetching_data": "recupero dei dati dell'app",
"foreign_fee": "commissione esterna: {{ message }}", "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)", "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", "mentioned": "menzionato",
"message_with_image": "questo messaggio ha già un'immagine", "message_with_image": "questo messaggio ha già un'immagine",
@ -258,26 +258,26 @@
"overwrite_qdn": "sovrascrivi a QDN", "overwrite_qdn": "sovrascrivi a QDN",
"password_confirm": "si prega di confermare una password", "password_confirm": "si prega di confermare una password",
"password_enter": "inserisci 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 }}", "people_reaction": "persone che hanno reagito con {{ reaction }}",
"processing_transaction": "elaborazione della transazione, per favore aspetta ...", "processing_transaction": "elaborazione della transazione, per favore aspetta ...",
"publish_data": "pubblica dati su Qortal: qualsiasi cosa, dalle app ai video. Completamente decentralizzato!", "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", "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.", "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_default": "ritorna a predefinito",
"revert_qdn": "ritorna a QDN", "revert_qdn": "ritorna a QDN",
"save_qdn": "salva su 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_file": "seleziona un file",
"select_image": "seleziona un'immagine per un logo", "select_image": "seleziona un'immagine per un logo",
"select_zip": "seleziona il file .zip contenente contenuto statico:", "select_zip": "seleziona il file .zip contenente contenuto statico:",
"sending": "invio ...", "sending": "invio ...",
"settings": "si utilizza il modo di esportazione/importazione per salvare le impostazioni.", "settings": "si utilizza il modo di esportazione/importazione per salvare le impostazioni.",
"space_for_admins": "mi dispiace, questo spazio è solo per gli amministratori.", "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.", "unsaved_changes": "hai cambiato modifiche alle app bloccate. Salvali su QDN.",
"updating": "aggiornamento" "updating": "aggiornamento"
}, },
@ -316,7 +316,7 @@
"voted": "votato con successo. Si prega di attendere un paio di minuti affinché la rete propaghi le modifiche." "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": "nome",
"name_app": "nome/app", "name_app": "nome/app",
"new_post_in": "nuovo post in {{ title }}", "new_post_in": "nuovo post in {{ title }}",
@ -339,10 +339,10 @@
"publish": "pubblicazione", "publish": "pubblicazione",
"q_apps": { "q_apps": {
"about": "su questo Q-app", "about": "su questo Q-app",
"q_mail": "Q-mail", "q_mail": "Q-Mail",
"q_manager": "Q-manager", "q_manager": "Q-Manager",
"q_sandbox": "Q-sandbox", "q_sandbox": "Q-Sandbox",
"q_wallets": "Q-wallet" "q_wallets": "Q-Wallets"
}, },
"receiver": "ricevitore", "receiver": "ricevitore",
"sender": "mittente", "sender": "mittente",
@ -358,7 +358,7 @@
"dark": "scuro", "dark": "scuro",
"dark_mode": "modalità scura", "dark_mode": "modalità scura",
"default": "tema di default", "default": "tema di default",
"light": "chiara", "light": "chiaro",
"light_mode": "modalità chiara", "light_mode": "modalità chiara",
"manager": "manager tema", "manager": "manager tema",
"name": "nome tema" "name": "nome tema"

View File

@ -65,26 +65,26 @@
"generic": { "generic": {
"avatar_publish_fee": "la pubblicazione di un Avatar richiede {{ fee }}", "avatar_publish_fee": "la pubblicazione di un Avatar richiede {{ fee }}",
"avatar_registered_name": "È necessario un nome registrato per impostare un avatar", "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!", "already_in_group": "sei già in questo gruppo!",
"block_delay_minimum": "ritardo minimo del blocco per le approvazioni delle transazioni di 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", "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", "closed_group": "questo è un gruppo chiuso/privato, quindi dovrai attendere fino a quando un amministratore accetta la tua richiesta",
"descrypt_wallet": "decrittazione del wallet ...", "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_announcement": "annunci di gruppo",
"group_approval_threshold": "soglia di approvazione del gruppo (numero / percentuale di amministratori che devono approvare una transazione)", "group_approval_threshold": "soglia di approvazione del gruppo (numero / percentuale di amministratori che devono approvare una transazione)",
"group_encrypted": "gruppo crittografato", "group_encrypted": "gruppo crittografato",
"group_invited_you": "{{group}} has invited you", "group_invited_you": "{{group}} has invited you",
"group_key_created": "primo tasto di gruppo creato.", "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_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_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 rivivere la chiave come salvaguardia.", "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_content": "contenuto non valido, mittente o timestamp nei dati di reazione",
"invalid_data": "contenuto di caricamento degli errori: dati non validi", "invalid_data": "contenuto di caricamento degli errori: dati non validi",
"latest_promotion": "verrà mostrata solo l'ultima promozione della settimana per il tuo gruppo.", "latest_promotion": "verrà mostrata solo l'ultima promozione della settimana per il tuo gruppo.",
"loading_members": "caricamento dell'elenco dei membri con nomi ... Attendi.", "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", "manage_minting": "gestisci il minting",
"minter_group": "al momento non fai parte del gruppo Minter", "minter_group": "al momento non fai parte del gruppo Minter",
"mintership_app": "visita l'app Q-Mintership per chiedere di diventare un minter", "mintership_app": "visita l'app Q-Mintership per chiedere di diventare un minter",

View File

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

View File

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

View File

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

View File

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