refactor(settings-modal): align avatar settings UI with crypto wallets

Refactor avatar settings to match crypto wallets UI structure and styling. Use flexbox layout for consistent spacing, align input widths, use ErrorDisplay component for errors, and add delete avatar functionality with translations.
This commit is contained in:
plebeius
2025-12-09 18:22:39 +01:00
parent dbf67f55b6
commit 078de21839
38 changed files with 181 additions and 93 deletions
@@ -26,61 +26,94 @@
}
.avatarSettingsForm {
padding: 10px 0 15px 10px;
padding: 5px 0 15px 10px;
}
.avatarSettingsForm input {
width: 200px;
.settingField {
margin-top: 5px;
margin-left: 5px;
position: relative;
display: flex;
align-items: center;
flex-wrap: nowrap;
}
.settingField input {
flex: 0 1 200px;
min-width: 0;
max-width: 200px;
padding: 2px;
margin-left: 5px;
box-shadow: var(--box-shadow-input);
}
.avatarSettingInput input {
margin-bottom: 10px;
display: block;
.settingField[class*='step']::before {
margin-left: -5px;
}
.avatarSettingInput a {
color: var(--link-primary);
.settingField.step1::before {
content: '1.\00a0';
}
.avatarSettingInput a {
.settingField.step2::before {
content: '2.\00a0';
}
.settingField.step3::before {
content: '3.\00a0';
}
.settingField.step4::before {
content: '4.\00a0';
}
.settingField a {
color: var(--post-link-text-color);
text-decoration: var(--post-content-link-text-decoration);
}
.avatarSettingInput a:hover {
.settingField a:hover {
color: var(--post-link-text-color-hover);
text-decoration: var(--post-content-link-text-decoration-hover);
}
.settingTitle {
font-style: italic;
text-transform: lowercase;
font-style: inherit;
text-transform: none;
white-space: nowrap;
flex-shrink: 0;
}
.copyMessage {
padding-bottom: 10px;
.timestampfield {
margin-left: 10px;
}
.pasteSignature span {
display: block;
}
.pasteSignature button {
.buttons {
margin-top: 10px;
margin-left: 5px;
}
.save {
margin-right: 5px;
}
.state {
text-transform: lowercase;
padding-top: 10px;
padding-left: 10px;
max-width: 300px;
color: var(--post-mobile-abbr-text-color);
}
.copyMessage a {
color: var(--text-primary);
.error {
color: red;
}
.copyMessage a:hover {
text-decoration: underline;
}
.deleteAvatarContainer {
margin-top: 20px;
margin-left: 5px;
}
.removeAvatar {
color: red;
}
@@ -4,6 +4,8 @@ import { setAccount, useAccount, useAuthorAvatar } from '@plebbit/plebbit-react-
import styles from './avatar-settings.module.css';
import { Trans, useTranslation } from 'react-i18next';
import LoadingEllipsis from '../../loading-ellipsis';
import ErrorDisplay from '../../error-display/error-display';
import _ from 'lodash';
const AvatarPreview = ({ avatar }: any) => {
const { t } = useTranslation();
@@ -31,7 +33,7 @@ const AvatarPreview = ({ avatar }: any) => {
</div>
{state !== 'succeeded' && account?.author?.avatar && (
<div className={styles.state}>
{!error && stateText} {error && error?.message}
{!error && stateText} {error && <ErrorDisplay error={error} />}
</div>
)}
</>
@@ -111,15 +113,26 @@ const AvatarSettings = () => {
return alert(t('missing_signature'));
}
setAccount({ ...account, author: { ...account?.author, avatar } });
alert(`saved`);
alert(t('saved'));
};
const _removeAvatar = () => {
if (window.confirm(t('delete_confirm', { value: 'avatar', interpolation: { escapeValue: false } }))) {
setAccount({ ...account, author: { ...account?.author, avatar: undefined } });
setChainTicker(undefined);
setTokenAddress(undefined);
setTokenId(undefined);
setTimestamp(undefined);
setSignature(undefined);
}
};
return (
<div className={styles.avatarSettings}>
<AvatarPreview avatar={avatar} />
<div className={styles.avatarSettingsForm}>
<div className={styles.avatarSettingInput}>
<span className={styles.settingTitle}>{t('chain_ticker')}</span>
<div className={`${styles.settingField} ${styles.step1}`}>
<span className={styles.settingTitle}>{_.capitalize(t('chain_ticker'))}: </span>
<input
type='text'
placeholder='eth/sol/avax'
@@ -130,7 +143,7 @@ const AvatarSettings = () => {
onChange={(e) => setChainTicker(e.target.value)}
/>
</div>
<div className={styles.avatarSettingInput}>
<div className={`${styles.settingField} ${styles.step2}`}>
<span className={styles.settingTitle}>
<Trans
i18nKey='token_address_whitelist'
@@ -146,6 +159,7 @@ const AvatarSettings = () => {
),
}}
/>
:{' '}
</span>
<input
type='text'
@@ -157,43 +171,33 @@ const AvatarSettings = () => {
onChange={(e) => setTokenAddress(e.target.value)}
/>
</div>
<div className={styles.avatarSettingInput}>
<span className={styles.settingTitle}>{t('token_id')}</span>
<input
type='text'
placeholder='Token ID'
autoCorrect='off'
autoComplete='off'
spellCheck='false'
defaultValue={account?.author?.avatar?.id}
onChange={(e) => setTokenId(e.target.value)}
/>
<div className={`${styles.settingField} ${styles.step3}`}>
<span className={styles.settingTitle}>
<Trans
i18nKey='copy_message_etherscan'
values={{ copy: hasCopied ? t('copied') : t('copy') }}
components={{
1: <button key='copy-message-button' onClick={copyMessageToSign} />,
// eslint-disable-next-line
2: <a key='etherscan-link' href='https://etherscan.io/verifiedSignatures' target='_blank' rel='noopener noreferrer' />,
}}
/>
</span>
</div>
<div className={styles.copyMessage}>
<Trans
i18nKey='copy_message_etherscan'
values={{ copy: hasCopied ? t('copied') : t('copy') }}
components={{
1: <button key='copy-message-button' onClick={copyMessageToSign} />,
// eslint-disable-next-line
2: <a key='etherscan-link' href='https://etherscan.io/verifiedSignatures' target='_blank' rel='noopener noreferrer' />,
}}
/>
</div>
<div className={styles.avatarSettingInput}>
<span className={styles.settingTitle}>{t('timestamp')}</span>
<div className={styles.settingField}>
<span className={`${styles.settingTitle} ${styles.timestampfield}`}>{_.capitalize(t('timestamp'))}: </span>
<input
type='text'
placeholder='Timestamp'
autoCorrect='off'
autoComplete='off'
spellCheck='false'
value={timestamp}
value={timestamp || ''}
onChange={(e) => setTimestamp(Number(e.target.value))}
/>
</div>
<div className={styles.pasteSignature}>
<span className={styles.settingTitle}>{t('paste_signature')}</span>
<div className={`${styles.settingField} ${styles.step4}`}>
<span className={styles.settingTitle}>{_.capitalize(t('paste_signature'))}: </span>
<input
type='text'
placeholder='0x...'
@@ -203,7 +207,16 @@ const AvatarSettings = () => {
defaultValue={account?.author?.avatar?.signature?.signature}
onChange={(e) => setSignature(e.target.value)}
/>
<button onClick={save}>{t('save')}</button>
</div>
<div className={styles.buttons}>
<button className={styles.save} onClick={save}>
{t('save_changes')}
</button>
</div>
<div className={styles.deleteAvatarContainer}>
<button className={styles.removeAvatar} onClick={_removeAvatar}>
{t('delete_avatar')}
</button>
</div>
</div>
</div>
@@ -52,9 +52,16 @@
content: '5. ';
}
.walletField input {
width: 200px;
.walletField {
position: relative;
}
.settingField input {
flex: 1 1 auto;
min-width: 0;
max-width: 100%;
padding: 2px;
margin-left: 5px;
box-shadow: var(--box-shadow-input);
}