Skip to content

Commit

Permalink
Merge pull request PolkaGate#1388 from AMIRKHANEF/UpdateProfiles
Browse files Browse the repository at this point in the history
Update profiles
  • Loading branch information
Nick-1979 authored Jun 25, 2024
2 parents 6e6faa8 + db93cff commit 50988fc
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 127 deletions.
8 changes: 4 additions & 4 deletions packages/extension-polkagate/src/components/ProfileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ interface Props {
export default function ProfileInput({ disabled = false, placeHolder = '', setProfileName, profileName, helperText = '', label, style }: Props): React.ReactElement<Props> {
const containerRef = useRef<HTMLDivElement>(null);

const userDefinedProfiles = useProfiles();
const profiles = useProfiles();

const [isPopperOpen, setTogglePopper] = useState<boolean>(false);
const [focus, setFocus] = useState<boolean>(false);
const [enteredProfile, setEnteredProfile] = useState<string | undefined>();
const [dropdownWidth, setDropdownWidth] = useState<string>('0');

const autocompleteOptions = useMemo(() => userDefinedProfiles?.map((profile, index) => ({ index, profile })), [userDefinedProfiles]);
const autocompleteOptions = useMemo(() => profiles?.userDefinedProfiles?.map((profile, index) => ({ index, profile })), [profiles?.userDefinedProfiles]);

useEffect(() => {
profileName && setEnteredProfile(profileName);
Expand All @@ -54,8 +54,8 @@ export default function ProfileInput({ disabled = false, placeHolder = '', setPr
}, [setProfileName]);

const openPopper = useCallback(() =>
userDefinedProfiles && userDefinedProfiles?.length > 0 && !enteredProfile && !isPopperOpen && setTogglePopper(true)
, [userDefinedProfiles?.length, enteredProfile, isPopperOpen]);
profiles?.userDefinedProfiles && profiles.userDefinedProfiles?.length > 0 && !enteredProfile && !isPopperOpen && setTogglePopper(true)
, [profiles?.userDefinedProfiles?.length, enteredProfile, isPopperOpen]);

const closePopper = useCallback(() =>
setTogglePopper(false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ export default function HomePageFullScreen(): React.ReactElement {
noChainSwitch
/>
<Grid container item sx={{ bgcolor: 'backgroundFL.secondary', maxWidth: '1282px' }}>
<ProfileTabs
orderedAccounts={initialAccountList}
/>
<Grid container item justifyContent='space-around' sx={{ bgcolor: 'backgroundFL.secondary', height: 'calc(100vh - 105px)', maxWidth: '1282px', overflow: 'scroll', pb: '40px' }}>
<Grid container item justifyContent='space-around' sx={{ bgcolor: 'backgroundFL.secondary', height: 'calc(100vh - 70px)', maxWidth: '1282px', overflow: 'scroll', pb: '40px' }}>
<ProfileTabs
orderedAccounts={initialAccountList}
/>
<Grid container direction='column' item rowGap='20px' width='760px'>
{profileAccounts &&
<DraggableAccountsList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

/* eslint-disable react/jsx-max-props-per-line */

import { Divider, Grid, Popover, useTheme } from '@mui/material';
import { Divider, Grid, Popover, useTheme, IconButton, type Theme } from '@mui/material';
import React, { useCallback, useContext, useState } from 'react';

import { type TFunction } from '@polkagate/apps-config/types';
import DoneIcon from '@mui/icons-material/Done';
import { ActionContext, InputWithLabel, MenuItem, VaadinIcon } from '../../../components';
import { useInfo, useTranslation, useProfiles } from '../../../hooks';
import { updateMeta } from '../../../messaging';
Expand All @@ -15,13 +16,51 @@ interface Props {
setUpperAnchorEl: React.Dispatch<React.SetStateAction<HTMLButtonElement | null>>
}

interface InputBoxProps {
editName: (newName: string | null) => void;
newName: string | undefined;
addToNewProfile: (profile?: string) => void;
t: TFunction;
theme: Theme;
}

const InputBox = ({ addToNewProfile, editName, newName, t, theme }: InputBoxProps) => {
return (
<Grid container item alignItems='flex-end' justifyContent='space-evenly'>
<Grid container item xs>
<InputWithLabel
isFocused
fontSize={16}
fontWeight={400}
height={35}
label={t('Choose a name for the profile')}
labelFontSize='14px'
onChange={editName}
onEnter={() => newName && addToNewProfile(newName as string)}
placeholder={t('Profile Name')}
value={newName}
/>
</Grid>
<Grid container item height='fit-content' ml='10px' width='fit-content'>
<IconButton
disabled={!newName}
onClick={() => addToNewProfile(newName as string)}
sx={{ p: 0 }}
>
<DoneIcon sx={{ color: 'secondary.light', fontSize: '32px', stroke: theme.palette.secondary.light, strokeWidth: 1.5 }} />
</IconButton>
</Grid>
</Grid>
);
}

function ProfileMenu({ address, setUpperAnchorEl }: Props): React.ReactElement<Props> {
const theme = useTheme();
const { t } = useTranslation();

const onAction = useContext(ActionContext);
const { account, chain } = useInfo(address);
const userDefinedProfiles = useProfiles();
const profiles = useProfiles();

const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | HTMLDivElement | null>();
const [showName, setShowName] = useState<boolean>();
Expand Down Expand Up @@ -76,17 +115,12 @@ function ProfileMenu({ address, setUpperAnchorEl }: Props): React.ReactElement<P
const Menus = () => (
<Grid alignItems='flex-start' container display='block' item sx={{ borderRadius: '10px', minWidth: '300px', p: '10px' }}>
{showName
? <InputWithLabel
isFocused
fontSize={16}
fontWeight={400}
height={35}
label={t('Choose a name for the profile')}
labelFontSize='14px'
onChange={editName}
onEnter={() => addToNewProfile(newName as string)}
placeholder={t('Profile Name')}
value={newName}
? <InputBox
addToNewProfile={addToNewProfile}
editName={editName}
newName={newName}
t={t}
theme={theme}
/>
: <MenuItem
iconComponent={
Expand All @@ -98,8 +132,8 @@ function ProfileMenu({ address, setUpperAnchorEl }: Props): React.ReactElement<P
/>
}
<Divider sx={{ bgcolor: 'secondary.light', height: '1px', my: '7px' }} />
{userDefinedProfiles?.length
? userDefinedProfiles?.map((profile) => (
{profiles?.userDefinedProfiles?.length
? profiles.userDefinedProfiles?.map((profile) => (
<MenuItem
iconComponent={
<VaadinIcon icon='vaadin:folder-open-o' style={{ height: '20px', color: theme.palette.text.primary }} />
Expand Down Expand Up @@ -127,7 +161,7 @@ function ProfileMenu({ address, setUpperAnchorEl }: Props): React.ReactElement<P

return (
<>
<Grid aria-describedby={id} component='button' container item onClick={onAddClick} sx={{ bgcolor: 'transparent', border: 'none', color:theme.palette.text.primary, height: 'fit-content', p: 0, width: 'inherit' }}>
<Grid aria-describedby={id} component='button' container item onClick={onAddClick} sx={{ bgcolor: 'transparent', border: 'none', color: theme.palette.text.primary, height: 'fit-content', p: 0, width: 'inherit' }}>
<MenuItem
iconComponent={
<VaadinIcon icon='vaadin:folder-add' style={{ height: '20px', color: `${theme.palette.text.primary}` }} />
Expand All @@ -139,12 +173,12 @@ function ProfileMenu({ address, setUpperAnchorEl }: Props): React.ReactElement<P
</Grid>
{!!profileName &&
<>
<Grid component='button' container item onClick={onRemove} sx={{ bgcolor: 'transparent', border: 'none', color: theme.palette.text.primary, height: 'fit-content', p: 0, width: 'inherit' }}>
<Grid component='button' container item onClick={onRemove} sx={{ '> div div:last-child p': { maxWidth: '220px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, bgcolor: 'transparent', border: 'none', color: theme.palette.text.primary, height: 'fit-content', p: 0, width: 'inherit' }}>
<MenuItem
iconComponent={
<VaadinIcon icon='vaadin:folder-remove' style={{ height: '20px', color: `${theme.palette.text.primary}` }} />
}
text={t('Remove from {{profileName}} profile', { replace: { profileName } })}
text={t('Remove from {{profileName}}', { replace: { profileName } })}
withHoverEffect
/>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import { Grid, Typography, useTheme } from '@mui/material';
import React, { useCallback, useMemo, useEffect, useState } from 'react';
import { useProfileAccounts, useTranslation } from '../../../hooks';
import { getStorage, setStorage, watchStorage } from '../../../components/Loading';
import { pgBoxShadow } from '../../../util/utils';
import { VaadinIcon } from '../../../components/index';
import { showAccount } from '../../../messaging';
import { keyframes } from '@emotion/react';
import { HIDDEN_PERCENT } from './ProfileTabs';

interface Props {
Expand All @@ -18,41 +16,38 @@ interface Props {
setSelectedProfile: React.Dispatch<React.SetStateAction<string | undefined>>;
isHovered: boolean | undefined;
text: string;
index: number;
}

// Define keyframes for the swinging animation around the x-axis
const swingAnimation = keyframes`
0% { transform: rotateX(0deg); }
20% { transform: rotateX(30deg); }
40% { transform: rotateX(-20deg); }
60% { transform: rotateX(10deg); }
80% { transform: rotateX(-10deg); }
100% { transform: rotateX(0deg); }
`;

export default function ProfileTab({ isHovered, text, selectedProfile, setSelectedProfile, orderedAccounts }: Props): React.ReactElement {
export default function ProfileTab({ isHovered, text, selectedProfile, setSelectedProfile, orderedAccounts, index }: Props): React.ReactElement {
const { t } = useTranslation();
const theme = useTheme();

const PREDEFINED_TAB_COLORS = useMemo(() => {
return [
{ text: t('All'), colorLight: '#D1C4E9', colorDark: '#5E35B1' },
{ text: t('Local'), colorLight: '#C8E6C9', colorDark: '#388E3C' },
{ text: t('Ledger'), colorLight: '#FFCCBC', colorDark: '#D84315' },
{ text: t('Watch-only'), colorLight: '#B3E5FC', colorDark: '#0288D1' },
{ text: t('QR-attached'), colorLight: '#F8BBD0', colorDark: '#D81B60' },
{ lightColor: '#D1C4E9', darkColor: '#99004F' },
{ lightColor: '#C8E6C9', darkColor: '#468189' },
{ lightColor: '#B3E5FC', darkColor: '#846C5B' },
{ lightColor: '#F8BBD0', darkColor: '#A63C06' },
{ lightColor: '#ACE894', darkColor: '#D81B60' },
{ lightColor: '#F5D5ED', darkColor: '#2B4162' },
{ lightColor: '#EBCFB2', darkColor: '#9D8189' },
{ lightColor: '#FCF0CC', darkColor: '#5F4842' },
]
}, [t, theme]);

const profileAccounts = useProfileAccounts(orderedAccounts, text);

const [animate, setAnimate] = useState<boolean>(true);
/** set by user click on a profile tab */
const [toHiddenAll, setToHiddenAll] = useState<boolean>();

const getColor = useCallback((_text: string) => {
const selectedProfile = PREDEFINED_TAB_COLORS.find(({ text }) => text === _text);
const color = theme.palette.mode === 'dark' ? selectedProfile?.colorDark : selectedProfile?.colorLight;
const isDarkMode = useMemo(() => theme.palette.mode === 'dark', [theme.palette.mode]);
const shadow = useMemo(() => isDarkMode ? '0px 2px 5px 1px rgba(255, 255, 255, 0.10)' : '0px 2px 3px 1px rgba(000, 000, 000, 0.13)', [isDarkMode]);
const shadowOnHover = useMemo(() => isDarkMode ? '0px 2px 5px 1px rgba(255, 255, 255, 0.20)' : '0px 2px 3px 1px rgba(000, 000, 000, 0.20)', [isDarkMode]);

const getColor = useCallback((index: number) => {
const selectedProfile = PREDEFINED_TAB_COLORS[index];
const color = isDarkMode ? selectedProfile?.darkColor : selectedProfile?.lightColor;

return color;
}, [PREDEFINED_TAB_COLORS]);
Expand Down Expand Up @@ -83,6 +78,8 @@ export default function ProfileTab({ isHovered, text, selectedProfile, setSelect

const isHiddenAll = isAllProfileAccountsHidden !== undefined ? isAllProfileAccountsHidden : toHiddenAll;

const hideCard = useMemo(() => !Boolean(isSelected || isHovered || visibleContent), [isSelected, isHovered, visibleContent]);

useEffect(() => {
if (profileAccounts && toHiddenAll !== undefined) {
hideAccounts(profileAccounts);
Expand All @@ -96,58 +93,40 @@ export default function ProfileTab({ isHovered, text, selectedProfile, setSelect
}).catch(console.error);

watchStorage('profile', setSelectedProfile).catch(console.error);

// Disable animation after initial render
const timer = setTimeout(() => {
setAnimate(false);
}, 1000);

return () => clearTimeout(timer);
}, [t]);

return (
<Grid item container onClick={onClick}
justifyContent='center'
alignItems='center'
columnGap='5px'
px='8px'
sx={{
cursor: 'pointer',
flexShrink: 0,
mx: '1px',
bgcolor: getColor(text) || 'background.paper',
borderBottomLeftRadius: '12px',
WebkitBorderBottomRightRadius: '12px',
bgcolor: getColor(index) || 'background.paper',
borderRadius: '0 0 12px 12px',
minWidth: '100px',
borderBottom: isSelected
? `1.5px solid ${theme.palette.secondary.light}`
: `1.5px solid ${theme.palette.divider}`,
transition: 'transform 0.3s, box-shadow 0.3s',
transition: 'transform 0.2s, box-shadow 0.2s',
boxShadow: shadow,
'&:hover': {
transform: 'perspective(1000px) translateZ(10px)',
boxShadow: pgBoxShadow(theme),
boxShadow: shadowOnHover,
},
animation: animate ? `${swingAnimation} 1s ease-in-out` : 'none',
perspective: '1000px',
width: 'fit-content',
transformOrigin: 'top',
position: 'relative',
transform: isSelected && !isHovered ? `translateY(${HIDDEN_PERCENT})` : undefined
transform: hideCard ? `translateY(-${HIDDEN_PERCENT})` : undefined
}}>
<VaadinIcon icon={'vaadin:check'} style={{ height: '13px', marginRight: '-20px', visibility: isSelected ? 'visible' : 'hidden' }} />
<Typography color={'text.primary'} display='block' fontSize='15px' fontWeight={400} textAlign='center'
sx={{
userSelect: 'none',
px: '20px',
visibility: visibleContent ? 'visible' : 'hidden',
transition: 'visibility 0.3s ease-in-out'
}}>
{text}
<VaadinIcon icon={'vaadin:check'} style={{ height: '13px', visibility: isSelected ? 'visible' : 'hidden', width: '15px' }} />
<Typography color={'text.primary'} display='block' fontSize='16px' fontWeight={isSelected ? 500 : 400} textAlign='center' sx={{ visibility: visibleContent ? 'visible' : 'hidden', transition: isSelected ? 'none' : 'visibility 0.1s ease-in-out', maxWidth: '100px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{t(text)}
</Typography>
<VaadinIcon icon={isHiddenAll ? 'vaadin:eye-slash' : ''}
style={{
height: '13px',
marginLeft: '-20px',
visibility: visibleContent ? 'visible' : 'hidden',
transition: 'visibility 0.3s ease-in-out'
transition: isSelected ? 'none' : 'visibility 0.1s ease-in-out',
width: '15px'
}} />
</Grid>
);
Expand Down
Loading

0 comments on commit 50988fc

Please sign in to comment.