Change pack avatar, name & attribution
This commit is contained in:
parent
6ae79e080f
commit
91b18cc5fd
6 changed files with 103 additions and 22 deletions
|
@ -107,7 +107,17 @@ function useImagePackHandles(pack, sendPackContent) {
|
||||||
return newKey;
|
return newKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditProfile = () => false;
|
const handleAvatarChange = (url) => {
|
||||||
|
pack.setAvatarUrl(url);
|
||||||
|
sendPackContent(pack.getContent());
|
||||||
|
forceUpdate();
|
||||||
|
};
|
||||||
|
const handleEditProfile = (name, attribution) => {
|
||||||
|
pack.setDisplayName(name);
|
||||||
|
pack.setAttribution(attribution);
|
||||||
|
sendPackContent(pack.getContent());
|
||||||
|
forceUpdate();
|
||||||
|
};
|
||||||
const handleUsageChange = (newUsage) => {
|
const handleUsageChange = (newUsage) => {
|
||||||
const usage = [];
|
const usage = [];
|
||||||
if (newUsage === 'emoticon' || newUsage === 'both') usage.push('emoticon');
|
if (newUsage === 'emoticon' || newUsage === 'both') usage.push('emoticon');
|
||||||
|
@ -163,6 +173,7 @@ function useImagePackHandles(pack, sendPackContent) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
handleAvatarChange,
|
||||||
handleEditProfile,
|
handleEditProfile,
|
||||||
handleUsageChange,
|
handleUsageChange,
|
||||||
handleRenameItem,
|
handleRenameItem,
|
||||||
|
@ -180,6 +191,7 @@ function ImagePack({ roomId, stateKey }) {
|
||||||
const { pack, sendPackContent } = useRoomImagePack(roomId, stateKey);
|
const { pack, sendPackContent } = useRoomImagePack(roomId, stateKey);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
handleAvatarChange,
|
||||||
handleEditProfile,
|
handleEditProfile,
|
||||||
handleUsageChange,
|
handleUsageChange,
|
||||||
handleRenameItem,
|
handleRenameItem,
|
||||||
|
@ -196,12 +208,13 @@ function ImagePack({ roomId, stateKey }) {
|
||||||
return (
|
return (
|
||||||
<div className="image-pack">
|
<div className="image-pack">
|
||||||
<ImagePackProfile
|
<ImagePackProfile
|
||||||
avatarUrl={mx.mxcUrlToHttp(pack.avatarUrl)}
|
avatarUrl={pack.avatarUrl ? mx.mxcUrlToHttp(pack.avatarUrl, 42, 42, 'crop') : null}
|
||||||
displayName={pack.displayName ?? 'Unknown'}
|
displayName={pack.displayName ?? 'Unknown'}
|
||||||
attribution={pack.attribution}
|
attribution={pack.attribution}
|
||||||
usage={getUsage(pack.usage)}
|
usage={getUsage(pack.usage)}
|
||||||
onUsageChange={canChange ? handleUsageChange : undefined}
|
onUsageChange={canChange ? handleUsageChange : null}
|
||||||
onEdit={canChange ? handleEditProfile : undefined}
|
onAvatarChange={canChange ? handleAvatarChange : null}
|
||||||
|
onEditProfile={canChange ? handleEditProfile : null}
|
||||||
/>
|
/>
|
||||||
{ canChange && (
|
{ canChange && (
|
||||||
<ImagePackUpload onUpload={handleAddItem} />
|
<ImagePackUpload onUpload={handleAddItem} />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './ImagePackProfile.scss';
|
import './ImagePackProfile.scss';
|
||||||
|
|
||||||
|
@ -9,14 +9,30 @@ import Text from '../../atoms/text/Text';
|
||||||
import Avatar from '../../atoms/avatar/Avatar';
|
import Avatar from '../../atoms/avatar/Avatar';
|
||||||
import Button from '../../atoms/button/Button';
|
import Button from '../../atoms/button/Button';
|
||||||
import IconButton from '../../atoms/button/IconButton';
|
import IconButton from '../../atoms/button/IconButton';
|
||||||
|
import Input from '../../atoms/input/Input';
|
||||||
|
import ImageUpload from '../image-upload/ImageUpload';
|
||||||
import ImagePackUsageSelector from './ImagePackUsageSelector';
|
import ImagePackUsageSelector from './ImagePackUsageSelector';
|
||||||
|
|
||||||
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
||||||
import PencilIC from '../../../../public/res/ic/outlined/pencil.svg';
|
import PencilIC from '../../../../public/res/ic/outlined/pencil.svg';
|
||||||
|
|
||||||
function ImagePackProfile({
|
function ImagePackProfile({
|
||||||
avatarUrl, displayName, attribution, usage, onUsageChange, onEdit,
|
avatarUrl, displayName, attribution, usage,
|
||||||
|
onUsageChange, onAvatarChange, onEditProfile,
|
||||||
}) {
|
}) {
|
||||||
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const { nameInput, attributionInput } = e.target;
|
||||||
|
const name = nameInput.value.trim() || undefined;
|
||||||
|
const att = attributionInput.value.trim() || undefined;
|
||||||
|
|
||||||
|
onEditProfile(name, att);
|
||||||
|
setIsEdit(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleUsageSelect = (event) => {
|
const handleUsageSelect = (event) => {
|
||||||
openReusableContextMenu(
|
openReusableContextMenu(
|
||||||
'bottom',
|
'bottom',
|
||||||
|
@ -35,13 +51,42 @@ function ImagePackProfile({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="image-pack-profile">
|
<div className="image-pack-profile">
|
||||||
{avatarUrl && <Avatar text={displayName} bgColor="blue" imageSrc={avatarUrl} size="normal" />}
|
{
|
||||||
|
onAvatarChange
|
||||||
|
? (
|
||||||
|
<ImageUpload
|
||||||
|
bgColor="#555"
|
||||||
|
text={displayName}
|
||||||
|
imageSrc={avatarUrl}
|
||||||
|
size="normal"
|
||||||
|
onUpload={onAvatarChange}
|
||||||
|
onRequestRemove={() => onAvatarChange(undefined)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: <Avatar bgColor="#555" text={displayName} imageSrc={avatarUrl} size="normal" />
|
||||||
|
}
|
||||||
<div className="image-pack-profile__content">
|
<div className="image-pack-profile__content">
|
||||||
<div>
|
{
|
||||||
<Text>{displayName}</Text>
|
isEdit
|
||||||
{onEdit && <IconButton size="extra-small" onClick={onEdit} src={PencilIC} tooltip="Edit" />}
|
? (
|
||||||
</div>
|
<form onSubmit={handleSubmit}>
|
||||||
{attribution && <Text variant="b3">{attribution}</Text>}
|
<Input name="nameInput" label="Name" value={displayName} required />
|
||||||
|
<Input name="attributionInput" label="Attribution" value={attribution} resizable />
|
||||||
|
<div>
|
||||||
|
<Button variant="primary" type="submit">Save</Button>
|
||||||
|
<Button onClick={() => setIsEdit(false)}>Cancel</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<Text>{displayName}</Text>
|
||||||
|
{onEditProfile && <IconButton size="extra-small" onClick={() => setIsEdit(true)} src={PencilIC} tooltip="Edit" />}
|
||||||
|
</div>
|
||||||
|
{attribution && <Text variant="b3">{attribution}</Text>}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="image-pack-profile__usage">
|
<div className="image-pack-profile__usage">
|
||||||
<Text variant="b3">Pack usage</Text>
|
<Text variant="b3">Pack usage</Text>
|
||||||
|
@ -64,7 +109,8 @@ ImagePackProfile.defaultProps = {
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
attribution: null,
|
attribution: null,
|
||||||
onUsageChange: null,
|
onUsageChange: null,
|
||||||
onEdit: null,
|
onAvatarChange: null,
|
||||||
|
onEditProfile: null,
|
||||||
};
|
};
|
||||||
ImagePackProfile.propTypes = {
|
ImagePackProfile.propTypes = {
|
||||||
avatarUrl: PropTypes.string,
|
avatarUrl: PropTypes.string,
|
||||||
|
@ -72,7 +118,8 @@ ImagePackProfile.propTypes = {
|
||||||
attribution: PropTypes.string,
|
attribution: PropTypes.string,
|
||||||
usage: PropTypes.oneOf(['emoticon', 'sticker', 'both']).isRequired,
|
usage: PropTypes.oneOf(['emoticon', 'sticker', 'both']).isRequired,
|
||||||
onUsageChange: PropTypes.func,
|
onUsageChange: PropTypes.func,
|
||||||
onEdit: PropTypes.func,
|
onAvatarChange: PropTypes.func,
|
||||||
|
onEditProfile: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImagePackProfile;
|
export default ImagePackProfile;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
&__content {
|
&__content {
|
||||||
@extend .cp-fx__item-one;
|
@extend .cp-fx__item-one;
|
||||||
|
|
||||||
& div:first-child {
|
& > div:first-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--sp-extra-tight);
|
gap: var(--sp-extra-tight);
|
||||||
|
@ -18,6 +18,16 @@
|
||||||
padding: var(--sp-ultra-tight);
|
padding: var(--sp-ultra-tight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
& > form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--sp-extra-tight);
|
||||||
|
& > div:last-child {
|
||||||
|
margin: var(--sp-extra-tight) 0;
|
||||||
|
display: flex;
|
||||||
|
gap: var(--sp-tight);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__usage {
|
&__usage {
|
||||||
& > *:first-child {
|
& > *:first-child {
|
||||||
|
|
|
@ -41,6 +41,7 @@ function ImagePackUpload({ onUpload }) {
|
||||||
const img = evt.target.files[0];
|
const img = evt.target.files[0];
|
||||||
if (!img) return;
|
if (!img) return;
|
||||||
setImgFile(img);
|
setImgFile(img);
|
||||||
|
shortcodeRef.current.focus();
|
||||||
};
|
};
|
||||||
const handleRemove = () => {
|
const handleRemove = () => {
|
||||||
setImgFile(null);
|
setImgFile(null);
|
||||||
|
|
|
@ -7,9 +7,13 @@ import initMatrix from '../../../client/initMatrix';
|
||||||
import Text from '../../atoms/text/Text';
|
import Text from '../../atoms/text/Text';
|
||||||
import Avatar from '../../atoms/avatar/Avatar';
|
import Avatar from '../../atoms/avatar/Avatar';
|
||||||
import Spinner from '../../atoms/spinner/Spinner';
|
import Spinner from '../../atoms/spinner/Spinner';
|
||||||
|
import RawIcon from '../../atoms/system-icons/RawIcon';
|
||||||
|
|
||||||
|
import PlusIC from '../../../../public/res/ic/outlined/plus.svg';
|
||||||
|
|
||||||
function ImageUpload({
|
function ImageUpload({
|
||||||
text, bgColor, imageSrc, onUpload, onRequestRemove,
|
text, bgColor, imageSrc, onUpload, onRequestRemove,
|
||||||
|
size,
|
||||||
}) {
|
}) {
|
||||||
const [uploadPromise, setUploadPromise] = useState(null);
|
const [uploadPromise, setUploadPromise] = useState(null);
|
||||||
const uploadImageRef = useRef(null);
|
const uploadImageRef = useRef(null);
|
||||||
|
@ -50,10 +54,14 @@ function ImageUpload({
|
||||||
imageSrc={imageSrc}
|
imageSrc={imageSrc}
|
||||||
text={text}
|
text={text}
|
||||||
bgColor={bgColor}
|
bgColor={bgColor}
|
||||||
size="large"
|
size={size}
|
||||||
/>
|
/>
|
||||||
<div className={`img-upload__process ${uploadPromise === null ? ' img-upload__process--stopped' : ''}`}>
|
<div className={`img-upload__process ${uploadPromise === null ? ' img-upload__process--stopped' : ''}`}>
|
||||||
{uploadPromise === null && <Text variant="b3" weight="bold">Upload</Text>}
|
{uploadPromise === null && (
|
||||||
|
size === 'large'
|
||||||
|
? <Text variant="b3" weight="bold">Upload</Text>
|
||||||
|
: <RawIcon src={PlusIC} color="white" />
|
||||||
|
)}
|
||||||
{uploadPromise !== null && <Spinner size="small" />}
|
{uploadPromise !== null && <Spinner size="small" />}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
@ -75,6 +83,7 @@ ImageUpload.defaultProps = {
|
||||||
text: null,
|
text: null,
|
||||||
bgColor: 'transparent',
|
bgColor: 'transparent',
|
||||||
imageSrc: null,
|
imageSrc: null,
|
||||||
|
size: 'large',
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageUpload.propTypes = {
|
ImageUpload.propTypes = {
|
||||||
|
@ -83,6 +92,7 @@ ImageUpload.propTypes = {
|
||||||
imageSrc: PropTypes.string,
|
imageSrc: PropTypes.string,
|
||||||
onUpload: PropTypes.func.isRequired,
|
onUpload: PropTypes.func.isRequired,
|
||||||
onRequestRemove: PropTypes.func.isRequired,
|
onRequestRemove: PropTypes.func.isRequired,
|
||||||
|
size: PropTypes.oneOf(['large', 'normal']),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImageUpload;
|
export default ImageUpload;
|
||||||
|
|
|
@ -15,18 +15,18 @@ class ImagePack {
|
||||||
this.id = eventId;
|
this.id = eventId;
|
||||||
this.content = JSON.parse(JSON.stringify(content));
|
this.content = JSON.parse(JSON.stringify(content));
|
||||||
|
|
||||||
this.displayName = room?.name ?? undefined;
|
|
||||||
this.avatarUrl = room?.getMxcAvatarUrl() ?? undefined;
|
|
||||||
|
|
||||||
this.applyPack(content);
|
this.applyPack(content);
|
||||||
this.applyImages(content);
|
this.applyImages(content);
|
||||||
|
|
||||||
|
this.displayName ??= room?.name;
|
||||||
|
this.avatarUrl ??= room?.getMxcAvatarUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPack(content) {
|
applyPack(content) {
|
||||||
const pack = content.pack ?? {};
|
const pack = content.pack ?? {};
|
||||||
|
|
||||||
this.displayName = pack.display_name ?? this.displayName;
|
this.displayName = pack.display_name;
|
||||||
this.avatarUrl = pack.avatar_url ?? this.avatarUrl;
|
this.avatarUrl = pack.avatar_url;
|
||||||
this.usage = pack.usage ?? ['emoticon', 'sticker'];
|
this.usage = pack.usage ?? ['emoticon', 'sticker'];
|
||||||
this.attribution = pack.attribution;
|
this.attribution = pack.attribution;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue