diff --git a/src/app/atoms/button/Button.scss b/src/app/atoms/button/Button.scss
index 7b12195c..e1a01bb0 100644
--- a/src/app/atoms/button/Button.scss
+++ b/src/app/atoms/button/Button.scss
@@ -26,10 +26,10 @@
&--icon {
@include dir.side(padding, var(--sp-tight), var(--sp-loose));
- .ic-raw {
- @include dir.side(margin, 0, var(--sp-extra-tight));
- flex-shrink: 0;
- }
+ }
+ .ic-raw {
+ @include dir.side(margin, 0, var(--sp-extra-tight));
+ flex-shrink: 0;
}
}
diff --git a/src/app/molecules/image-pack/ImagePack.jsx b/src/app/molecules/image-pack/ImagePack.jsx
new file mode 100644
index 00000000..cd1494de
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePack.jsx
@@ -0,0 +1,85 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import './ImagePack.scss';
+
+import initMatrix from '../../../client/initMatrix';
+
+import Button from '../../atoms/button/Button';
+import Text from '../../atoms/text/Text';
+import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
+import ImagePackProfile from './ImagePackProfile';
+import ImagePackItem from './ImagePackItem';
+import { ImagePack as ImagePackBuilder, getUserImagePack } from '../../organisms/emoji-board/custom-emoji';
+
+function getUsage(usage) {
+ if (usage.includes('emoticon') && usage.includes('sticker')) return 'both';
+ if (usage.includes('emoticon')) return 'emoticon';
+ if (usage.includes('sticker')) return 'sticker';
+
+ return 'both';
+}
+
+function ImagePack({ roomId, stateKey }) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+ const [viewMore, setViewMore] = useState(false);
+
+ const packEvent = roomId
+ ? room.currentState.getStateEvents('im.ponies.room_emotes', stateKey)
+ : mx.getAccountData('im.ponies.user_emotes');
+ const pack = roomId
+ ? ImagePackBuilder.parsePack(packEvent.getId(), packEvent.getContent(), room)
+ : getUserImagePack(mx);
+
+ return (
+
+
{pack.displayName}
+
false}
+ onEdit={() => false}
+ />
+
+ Image
+ Shortcode
+ Usage
+
+
+ {([...pack.images].slice(0, viewMore ? pack.images.size : 2)).map(([shortcode, image]) => (
+
+ ))}
+
+
+ {pack.images.size > 2 && (
+
+ )}
+
+
+ );
+}
+
+ImagePack.defaultProps = {
+ roomId: null,
+ stateKey: null,
+};
+
+ImagePack.propTypes = {
+ roomId: PropTypes.string,
+ stateKey: PropTypes.string,
+};
+
+export default ImagePack;
diff --git a/src/app/molecules/image-pack/ImagePack.scss b/src/app/molecules/image-pack/ImagePack.scss
new file mode 100644
index 00000000..47bcf84f
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePack.scss
@@ -0,0 +1,23 @@
+@use '../../partials/flex';
+
+.image-pack {
+ &-item {
+ border-top: 1px solid var(--bg-surface-border);
+ }
+
+ &__header {
+ margin-top: var(--sp-normal);
+ padding: var(--sp-extra-tight) var(--sp-normal);
+ display: flex;
+ align-items: center;
+ gap: var(--sp-normal);
+
+ & > *:nth-child(2) {
+ @extend .cp-fx__item-one;
+ }
+ }
+
+ &__footer {
+ padding: var(--sp-normal);
+ }
+}
\ No newline at end of file
diff --git a/src/app/molecules/image-pack/ImagePackItem.jsx b/src/app/molecules/image-pack/ImagePackItem.jsx
new file mode 100644
index 00000000..b5b2cbfc
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePackItem.jsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './ImagePackItem.scss';
+
+import Avatar from '../../atoms/avatar/Avatar';
+import Text from '../../atoms/text/Text';
+import Button from '../../atoms/button/Button';
+import RawIcon from '../../atoms/system-icons/RawIcon';
+
+import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
+
+function ImagePackItem({ url, shortcode, usage }) {
+ return (
+
+
+
+ {shortcode}
+
+
+
+
+
+ );
+}
+
+ImagePackItem.propTypes = {
+ url: PropTypes.string.isRequired,
+ shortcode: PropTypes.string.isRequired,
+ usage: PropTypes.oneOf(['emoticon', 'sticker', 'both']).isRequired,
+};
+
+export default ImagePackItem;
diff --git a/src/app/molecules/image-pack/ImagePackItem.scss b/src/app/molecules/image-pack/ImagePackItem.scss
new file mode 100644
index 00000000..702ca4e0
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePackItem.scss
@@ -0,0 +1,17 @@
+@use '../../partials/flex';
+
+.image-pack-item {
+ margin: 0 var(--sp-normal);
+ padding: var(--sp-tight) 0;
+ display: flex;
+ align-items: center;
+ gap: var(--sp-normal);
+
+ &__content {
+ @extend .cp-fx__item-one;
+ }
+
+ &__usage > button {
+ padding: 6px var(--sp-extra-tight);
+ }
+}
\ No newline at end of file
diff --git a/src/app/molecules/image-pack/ImagePackProfile.jsx b/src/app/molecules/image-pack/ImagePackProfile.jsx
new file mode 100644
index 00000000..245398bc
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePackProfile.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './ImagePackProfile.scss';
+
+import Text from '../../atoms/text/Text';
+import Avatar from '../../atoms/avatar/Avatar';
+import Button from '../../atoms/button/Button';
+import IconButton from '../../atoms/button/IconButton';
+
+import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
+import PencilIC from '../../../../public/res/ic/outlined/pencil.svg';
+
+function ImagePackProfile({
+ avatarUrl, displayName, attribution, usage, onUsage, onEdit,
+}) {
+ return (
+
+
+
+
+ {displayName}
+ {onEdit && }
+
+ {attribution &&
{attribution}}
+
+
+ Pack usage
+
+
+
+ );
+}
+
+ImagePackProfile.defaultProps = {
+ avatarUrl: null,
+ attribution: null,
+ onUsage: null,
+ onEdit: null,
+};
+ImagePackProfile.propTypes = {
+ avatarUrl: PropTypes.string,
+ displayName: PropTypes.string.isRequired,
+ attribution: PropTypes.string,
+ usage: PropTypes.oneOf(['emoticon', 'sticker', 'both']).isRequired,
+ onUsage: PropTypes.func,
+ onEdit: PropTypes.func,
+};
+
+export default ImagePackProfile;
diff --git a/src/app/molecules/image-pack/ImagePackProfile.scss b/src/app/molecules/image-pack/ImagePackProfile.scss
new file mode 100644
index 00000000..819a46a7
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePackProfile.scss
@@ -0,0 +1,22 @@
+@use '../../partials/flex';
+
+.image-pack-profile {
+ padding: var(--sp-normal);
+ display: flex;
+
+ &__content {
+ padding: 0 var(--sp-tight);
+ @extend .cp-fx__item-one;
+
+ & div:first-child {
+ display: flex;
+ align-items: center;
+ gap: var(--sp-extra-tight);
+ }
+ }
+ &__usage {
+ & > *:first-child {
+ margin-bottom: var(--sp-ultra-tight);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/molecules/image-pack/ImagePackUsageSelector.jsx b/src/app/molecules/image-pack/ImagePackUsageSelector.jsx
new file mode 100644
index 00000000..71efc521
--- /dev/null
+++ b/src/app/molecules/image-pack/ImagePackUsageSelector.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
+
+function ImagePackUsageSelector({ usage, onSelect }) {
+ return (
+
+ Usage
+
+
+
+
+ );
+}
+
+ImagePackUsageSelector.propTypes = {
+ usage: PropTypes.oneOf(['emoticon', 'sticker', 'both']).isRequired,
+ onSelect: PropTypes.func.isRequired,
+};
+
+export default ImagePackUsageSelector;
diff --git a/src/app/organisms/emoji-board/EmojiBoard.jsx b/src/app/organisms/emoji-board/EmojiBoard.jsx
index 13e393f5..b03ae6e2 100644
--- a/src/app/organisms/emoji-board/EmojiBoard.jsx
+++ b/src/app/organisms/emoji-board/EmojiBoard.jsx
@@ -213,8 +213,6 @@ function EmojiBoard({ onSelect, searchRef }) {
for (let i = 0; i < packs.length; i += 1) {
packs[i].packIndex = i;
}
-
- console.log(packs)
setAvailableEmojis(packs);
}
};
@@ -294,7 +292,7 @@ function EmojiBoard({ onSelect, searchRef }) {
{
availableEmojis.map((pack) => {
const src = initMatrix.matrixClient
- .mxcUrlToHttp(pack.avatar ?? pack.getEmojis()[0].mxc);
+ .mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
return (
openGroup(recentOffset + pack.packIndex)}
diff --git a/src/app/organisms/emoji-board/custom-emoji.js b/src/app/organisms/emoji-board/custom-emoji.js
index 6327c9bb..9ba7c5e7 100644
--- a/src/app/organisms/emoji-board/custom-emoji.js
+++ b/src/app/organisms/emoji-board/custom-emoji.js
@@ -11,9 +11,10 @@ class ImagePack {
const pack = packContent.pack ?? {};
const displayName = pack.display_name ?? room?.name ?? undefined;
- const avatar = pack.avatar_url ?? room?.getMxcAvatarUrl() ?? undefined;
+ const avatarUrl = pack.avatar_url ?? room?.getMxcAvatarUrl() ?? undefined;
const packUsage = pack.usage ?? ['emoticon', 'sticker'];
const { attribution } = pack;
+ const images = new Map();
const emoticons = [];
const stickers = [];
@@ -28,6 +29,7 @@ class ImagePack {
shortcode, mxc, body, usage, info,
};
+ images.set(shortcode, image);
if (usage.includes('emoticon')) {
emoticons.push(image);
}
@@ -38,9 +40,10 @@ class ImagePack {
return new ImagePack(eventId, {
displayName,
- avatar,
+ avatarUrl,
usage: packUsage,
attribution,
+ images,
emoticons,
stickers,
});
@@ -48,22 +51,28 @@ class ImagePack {
constructor(id, {
displayName,
- avatar,
+ avatarUrl,
usage,
attribution,
+ images,
emoticons,
stickers,
}) {
this.id = id;
this.displayName = displayName;
- this.avatar = avatar;
+ this.avatarUrl = avatarUrl;
this.usage = usage;
this.attribution = attribution;
+ this.images = images;
this.emoticons = emoticons;
this.stickers = stickers;
}
+ getImages() {
+ return this.images;
+ }
+
getEmojis() {
return this.emoticons;
}
@@ -175,6 +184,8 @@ function getEmojiForCompletion(room) {
}
export {
+ ImagePack,
+ getUserImagePack, getGlobalImagePacks, getRoomImagePacks,
getShortcodeToEmoji, getShortcodeToCustomEmoji,
getRelevantPacks, getEmojiForCompletion,
};
diff --git a/src/app/organisms/room/RoomSettings.jsx b/src/app/organisms/room/RoomSettings.jsx
index 50c5e512..1d6c478e 100644
--- a/src/app/organisms/room/RoomSettings.jsx
+++ b/src/app/organisms/room/RoomSettings.jsx
@@ -25,9 +25,11 @@ import RoomHistoryVisibility from '../../molecules/room-history-visibility/RoomH
import RoomEncryption from '../../molecules/room-encryption/RoomEncryption';
import RoomPermissions from '../../molecules/room-permissions/RoomPermissions';
import RoomMembers from '../../molecules/room-members/RoomMembers';
+import ImagePack from '../../molecules/image-pack/ImagePack';
import UserIC from '../../../../public/res/ic/outlined/user.svg';
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
+import EmojiIC from '../../../../public/res/ic/outlined/emoji.svg';
import SearchIC from '../../../../public/res/ic/outlined/search.svg';
import ShieldUserIC from '../../../../public/res/ic/outlined/shield-user.svg';
import LockIC from '../../../../public/res/ic/outlined/lock.svg';
@@ -42,6 +44,7 @@ const tabText = {
GENERAL: 'General',
SEARCH: 'Search',
MEMBERS: 'Members',
+ EMOJIS: 'Emojis',
PERMISSIONS: 'Permissions',
SECURITY: 'Security',
};
@@ -58,6 +61,10 @@ const tabItems = [{
iconSrc: UserIC,
text: tabText.MEMBERS,
disabled: false,
+}, {
+ iconSrc: EmojiIC,
+ text: tabText.EMOJIS,
+ disabled: false,
}, {
iconSrc: ShieldUserIC,
text: tabText.PERMISSIONS,
@@ -121,6 +128,29 @@ GeneralSettings.propTypes = {
roomId: PropTypes.string.isRequired,
};
+function RoomEmojis({ roomId }) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+
+ const packEvents = room.currentState.getStateEvents('im.ponies.room_emotes');
+ const unUsablePacks = [];
+ const usablePacks = packEvents.filter((mEvent) => {
+ if (typeof mEvent.getContent()?.images !== 'object') {
+ unUsablePacks.push(mEvent);
+ return false;
+ }
+ return true;
+ });
+
+ return usablePacks.map((mEvent) => (
+
+ ));
+}
+
function SecuritySettings({ roomId }) {
return (
<>
@@ -197,6 +227,7 @@ function RoomSettings({ roomId }) {
{selectedTab.text === tabText.GENERAL && }
{selectedTab.text === tabText.SEARCH && }
{selectedTab.text === tabText.MEMBERS && }
+ {selectedTab.text === tabText.EMOJIS && }
{selectedTab.text === tabText.PERMISSIONS && }
{selectedTab.text === tabText.SECURITY && }
@@ -210,7 +241,5 @@ RoomSettings.propTypes = {
roomId: PropTypes.string.isRequired,
};
-export {
- RoomSettings as default,
- tabText,
-};
+export default RoomSettings;
+export { tabText };
diff --git a/src/app/organisms/room/RoomSettings.scss b/src/app/organisms/room/RoomSettings.scss
index ab7fca5c..3547e8a8 100644
--- a/src/app/organisms/room/RoomSettings.scss
+++ b/src/app/organisms/room/RoomSettings.scss
@@ -76,6 +76,7 @@
.room-settings .room-permissions__card,
.room-settings .room-search__form,
.room-settings .room-search__result-item ,
-.room-settings .room-members {
+.room-settings .room-members,
+.room-settings .image-pack {
@extend .room-settings__card;
}
\ No newline at end of file