diff --git a/web/avatars/emoji-avatar-selection-modal.css b/web/avatars/emoji-avatar-selection-modal.css
index d24865221..645728b2d 100644
--- a/web/avatars/emoji-avatar-selection-modal.css
+++ b/web/avatars/emoji-avatar-selection-modal.css
@@ -1,51 +1,48 @@
div.modalContainer {
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 594px;
}
/* https://github.com/missive/emoji-mart/discussions/663 */
em-emoji-picker {
max-height: 300px;
}
div.modalBody {
padding: 20px;
}
div.tabBody {
+ height: 300px;
padding-top: 20px;
display: flex;
justify-content: center;
align-items: center;
}
div.avatarContainer {
display: flex;
justify-content: center;
padding-top: 20px;
}
div.emojiPickerContainer {
display: flex;
justify-content: center;
align-items: center;
}
-div.colorSelectorContainer {
- margin: 20px 60px;
-}
-
div.saveButtonContainer {
display: flex;
flex-direction: column;
}
div.saveAvatarButtonContent {
display: flex;
justify-content: center;
align-items: center;
min-height: 24px;
gap: 4px;
}
diff --git a/web/avatars/emoji-avatar-selection-modal.react.js b/web/avatars/emoji-avatar-selection-modal.react.js
index c92d39817..b9f889a32 100644
--- a/web/avatars/emoji-avatar-selection-modal.react.js
+++ b/web/avatars/emoji-avatar-selection-modal.react.js
@@ -1,169 +1,170 @@
// @flow
import data from '@emoji-mart/data';
import Picker from '@emoji-mart/react';
import invariant from 'invariant';
import * as React from 'react';
import { EditUserAvatarContext } from 'lib/components/base-edit-user-avatar-provider.react.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
import {
defaultAnonymousUserEmojiAvatar,
getAvatarForUser,
getDefaultAvatar,
} from 'lib/shared/avatar-utils.js';
import type {
ClientAvatar,
ClientEmojiAvatar,
} from 'lib/types/avatar-types.js';
import Avatar from './avatar.react.js';
import css from './emoji-avatar-selection-modal.css';
import Button, { buttonThemes } from '../components/button.react.js';
import Tabs from '../components/tabs.react.js';
import LoadingIndicator from '../loading-indicator.react.js';
import Modal from '../modals/modal.react.js';
import ColorSelector from '../modals/threads/color-selector.react.js';
import { useSelector } from '../redux/redux-utils.js';
type TabType = 'emoji' | 'color';
function EmojiAvatarSelectionModal(): React.Node {
const { popModal } = useModalContext();
const editUserAvatarContext = React.useContext(EditUserAvatarContext);
invariant(editUserAvatarContext, 'editUserAvatarContext should be set');
const { setUserAvatar, userAvatarSaveInProgress } = editUserAvatarContext;
const [updateAvatarStatus, setUpdateAvatarStatus] =
React.useState('success' | 'failure')>();
const currentUserInfo = useSelector(state => state.currentUserInfo);
const currentUserAvatar: ClientAvatar = getAvatarForUser(currentUserInfo);
const defaultUserAvatar: ClientEmojiAvatar = currentUserInfo?.username
? getDefaultAvatar(currentUserInfo.username)
: defaultAnonymousUserEmojiAvatar;
// eslint-disable-next-line no-unused-vars
const [pendingAvatarEmoji, setPendingAvatarEmoji] = React.useState(
currentUserAvatar.type === 'emoji'
? currentUserAvatar.emoji
: defaultUserAvatar.emoji,
);
const [pendingAvatarColor, setPendingAvatarColor] = React.useState(
currentUserAvatar.type === 'emoji'
? currentUserAvatar.color
: defaultUserAvatar.color,
);
const pendingEmojiAvatar: ClientEmojiAvatar = React.useMemo(
() => ({
type: 'emoji',
emoji: pendingAvatarEmoji,
color: pendingAvatarColor,
}),
[pendingAvatarColor, pendingAvatarEmoji],
);
const onEmojiSelect = React.useCallback(selection => {
setUpdateAvatarStatus();
setPendingAvatarEmoji(selection.native);
}, []);
const onColorSelection = React.useCallback((hex: string) => {
setUpdateAvatarStatus();
setPendingAvatarColor(hex);
}, []);
const onSaveAvatar = React.useCallback(async () => {
try {
await setUserAvatar(pendingEmojiAvatar);
setUpdateAvatarStatus('success');
} catch {
setUpdateAvatarStatus('failure');
}
}, [pendingEmojiAvatar, setUserAvatar]);
let saveButtonContent;
let buttonColor;
if (userAvatarSaveInProgress) {
buttonColor = buttonThemes.standard;
saveButtonContent = ;
} else if (updateAvatarStatus === 'success') {
buttonColor = buttonThemes.success;
saveButtonContent = (
<>
{'Avatar update succeeded.'}
>
);
} else if (updateAvatarStatus === 'failure') {
buttonColor = buttonThemes.danger;
saveButtonContent = (
<>
{'Avatar update failed. Please try again.'}
>
);
} else {
buttonColor = buttonThemes.standard;
saveButtonContent = 'Save Avatar';
}
const [currentTabType, setCurrentTabType] = React.useState('emoji');
return (
-
);
}
export default EmojiAvatarSelectionModal;
diff --git a/web/modals/threads/color-selector-button.css b/web/modals/threads/color-selector-button.css
index dbdeff1fe..be04a8c84 100644
--- a/web/modals/threads/color-selector-button.css
+++ b/web/modals/threads/color-selector-button.css
@@ -1,17 +1,29 @@
.container {
height: 48px;
width: 48px;
border-radius: 24px;
}
+.containerLarge {
+ height: 80px;
+ width: 80px;
+ border-radius: 40px;
+}
+
.active,
.container:hover {
background-color: var(--color-selector-active-bg);
}
div.colorSplotch {
height: 32px;
width: 32px;
border-radius: 16px;
cursor: pointer;
}
+
+div.colorSplotchLarge {
+ height: 60px;
+ width: 60px;
+ border-radius: 30px;
+}
diff --git a/web/modals/threads/color-selector-button.react.js b/web/modals/threads/color-selector-button.react.js
index 6d64e2849..010756aa1 100644
--- a/web/modals/threads/color-selector-button.react.js
+++ b/web/modals/threads/color-selector-button.react.js
@@ -1,41 +1,49 @@
// @flow
import classNames from 'classnames';
import * as React from 'react';
import tinycolor from 'tinycolor2';
import css from './color-selector-button.css';
import Button from '../../components/button.react.js';
type ColorSelectorButtonProps = {
+color: string,
+currentColor: string,
+onColorSelection: (hex: string) => void,
+ +size?: 'small' | 'large',
};
function ColorSelectorButton(props: ColorSelectorButtonProps): React.Node {
- const { color, currentColor, onColorSelection } = props;
+ const { color, currentColor, onColorSelection, size } = props;
const active = tinycolor.equals(color, currentColor);
- const containerClassName = classNames(css.container, {
+ const containerClassName = classNames({
+ [css.container]: true,
+ [css.containerLarge]: size === 'large',
[css.active]: active,
});
+ const colorSplotchClassName = classNames({
+ [css.colorSplotch]: true,
+ [css.colorSplotchLarge]: size === 'large',
+ });
+
const colorSplotchStyle = React.useMemo(
() => ({
backgroundColor: `#${color}`,
}),
[color],
);
const onColorSplotchClicked = React.useCallback(() => {
onColorSelection(color);
}, [onColorSelection, color]);
return (
);
}
export default ColorSelectorButton;
diff --git a/web/modals/threads/color-selector.css b/web/modals/threads/color-selector.css
index fb4231e8a..8ebec7629 100644
--- a/web/modals/threads/color-selector.css
+++ b/web/modals/threads/color-selector.css
@@ -1,11 +1,15 @@
div.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
column-gap: 12px;
row-gap: 6px;
width: 100%;
padding: 6px 0;
}
+
+div.containerLarge {
+ row-gap: 36px;
+}
diff --git a/web/modals/threads/color-selector.react.js b/web/modals/threads/color-selector.react.js
index a6ff8788a..29237a5ca 100644
--- a/web/modals/threads/color-selector.react.js
+++ b/web/modals/threads/color-selector.react.js
@@ -1,33 +1,41 @@
// @flow
+import classNames from 'classnames';
import * as React from 'react';
import { selectedThreadColors } from 'lib/shared/color-utils.js';
import ColorSelectorButton from './color-selector-button.react.js';
import css from './color-selector.css';
type ColorSelectorProps = {
+currentColor: string,
+onColorSelection: (hex: string) => void,
+ +size?: 'small' | 'large',
};
function ColorSelector(props: ColorSelectorProps): React.Node {
- const { currentColor, onColorSelection } = props;
+ const { currentColor, onColorSelection, size } = props;
const colorSelectorButtons = React.useMemo(
() =>
selectedThreadColors.map(color => (
)),
- [currentColor, onColorSelection],
+ [currentColor, onColorSelection, size],
);
- return {colorSelectorButtons}
;
+ const containerClassName = classNames({
+ [css.container]: true,
+ [css.containerLarge]: size === 'large',
+ });
+
+ return {colorSelectorButtons}
;
}
export default ColorSelector;