@ermis-network/ermis-chat-react 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -0
- package/dist/index.cjs +5087 -11279
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +632 -152
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +273 -9
- package/dist/index.d.ts +273 -9
- package/dist/index.mjs +5085 -11295
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/Channel.tsx +0 -3
- package/src/components/ChannelActions.tsx +6 -1
- package/src/components/ChannelHeader.tsx +8 -32
- package/src/components/ChannelInfo/AddMemberModal.tsx +7 -1
- package/src/components/ChannelInfo/ChannelInfo.tsx +82 -2
- package/src/components/ChannelInfo/EditChannelModal.tsx +2 -2
- package/src/components/ChannelInfo/MediaGridItem.tsx +215 -78
- package/src/components/ChannelInfo/useChannelInfoTabs.tsx +170 -129
- package/src/components/ChannelList.tsx +72 -13
- package/src/components/CreateChannelModal.tsx +131 -12
- package/src/components/FilesPreview.tsx +8 -12
- package/src/components/FlatTopicGroupItem.tsx +27 -16
- package/src/components/ForwardMessageModal.tsx +11 -3
- package/src/components/MediaLightbox.tsx +444 -304
- package/src/components/MessageActionsBox.tsx +2 -0
- package/src/components/MessageInput.tsx +41 -12
- package/src/components/MessageItem.tsx +70 -25
- package/src/components/MessageQuickReactions.tsx +131 -128
- package/src/components/MessageReactions.tsx +47 -2
- package/src/components/MessageRenderers.tsx +1030 -433
- package/src/components/PinnedMessages.tsx +40 -12
- package/src/components/QuotedMessagePreview.tsx +99 -8
- package/src/components/RecoveryPin/RecoveryPin.tsx +279 -0
- package/src/components/RecoveryPin/index.ts +19 -0
- package/src/components/TopicList.tsx +20 -5
- package/src/components/TypingIndicator.tsx +3 -3
- package/src/components/UserPicker.tsx +26 -25
- package/src/components/VirtualMessageList.tsx +345 -125
- package/src/context/ChatProvider.tsx +27 -1
- package/src/hooks/useChannelListUpdates.ts +22 -1
- package/src/hooks/useChannelMessages.ts +338 -51
- package/src/hooks/useChannelRowUpdates.ts +18 -6
- package/src/hooks/useChatUser.ts +9 -1
- package/src/hooks/useE2eeAttachmentRenderer.ts +204 -0
- package/src/hooks/useE2eeFileUpload.ts +38 -0
- package/src/hooks/useFileUpload.ts +25 -5
- package/src/hooks/useForwardMessage.ts +210 -13
- package/src/hooks/useLoadMessages.ts +16 -4
- package/src/hooks/useMentions.ts +60 -6
- package/src/hooks/useMessageActions.ts +14 -8
- package/src/hooks/useMessageSend.ts +64 -12
- package/src/hooks/usePendingE2eeSends.ts +29 -0
- package/src/hooks/useRecoveryPin.ts +287 -0
- package/src/hooks/useScrollToMessage.ts +29 -4
- package/src/hooks/useTopicGroupUpdates.ts +49 -11
- package/src/index.ts +23 -0
- package/src/messageTypeUtils.ts +14 -0
- package/src/styles/_channel-info.css +9 -0
- package/src/styles/_channel-list.css +37 -14
- package/src/styles/_media-lightbox.css +36 -3
- package/src/styles/_message-bubble.css +381 -41
- package/src/styles/_message-input.css +8 -0
- package/src/styles/_message-list.css +67 -10
- package/src/styles/_message-quick-reactions.css +101 -59
- package/src/styles/_message-reactions.css +18 -32
- package/src/styles/_recovery-pin.css +97 -0
- package/src/styles/_tokens.css +5 -5
- package/src/styles/_typing-indicator.css +23 -13
- package/src/styles/index.css +1 -0
- package/src/types.ts +115 -1
- package/src/utils/avatarColors.ts +1 -1
- package/src/utils.ts +38 -18
|
@@ -4,6 +4,7 @@ import { isPendingMember, isSkippedMember } from '../channelRoleUtils';
|
|
|
4
4
|
import { isDirectChannel } from '../channelTypeUtils';
|
|
5
5
|
import { getLastMessagePreview } from '../utils';
|
|
6
6
|
import { SystemMessageTranslations, SignalMessageTranslations } from '@ermis-network/ermis-chat-sdk';
|
|
7
|
+
import { useChatClient } from './useChatClient';
|
|
7
8
|
|
|
8
9
|
/** Preview data for the most recent message across the topic group */
|
|
9
10
|
export type LatestMessagePreview = {
|
|
@@ -21,6 +22,8 @@ export type TopicGroupUpdatesOptions = {
|
|
|
21
22
|
videoMessageLabel?: React.ReactNode;
|
|
22
23
|
voiceRecordingMessageLabel?: React.ReactNode;
|
|
23
24
|
fileMessageLabel?: React.ReactNode;
|
|
25
|
+
encryptedMessageLabel?: React.ReactNode;
|
|
26
|
+
encryptedMessageUnavailableLabel?: React.ReactNode;
|
|
24
27
|
systemMessageTranslations?: SystemMessageTranslations;
|
|
25
28
|
signalMessageTranslations?: SignalMessageTranslations;
|
|
26
29
|
};
|
|
@@ -46,12 +49,24 @@ export function useTopicGroupUpdates(
|
|
|
46
49
|
updateCount: number;
|
|
47
50
|
latestMessagePreview: LatestMessagePreview | null;
|
|
48
51
|
} {
|
|
52
|
+
const { client: chatClient, activeChannel } = useChatClient();
|
|
49
53
|
const [updateCount, setUpdateCount] = useState(0);
|
|
50
54
|
const bump = useCallback(() => setUpdateCount((c) => c + 1), []);
|
|
51
55
|
|
|
52
56
|
// Subscribe to realtime events on parent + all topics
|
|
53
57
|
useEffect(() => {
|
|
54
58
|
const subs: { unsubscribe: () => void }[] = [];
|
|
59
|
+
const client = channel.getClient();
|
|
60
|
+
const isTopicGroupCid = (cid?: string) => {
|
|
61
|
+
if (!cid) return false;
|
|
62
|
+
if (cid === channel.cid) return true;
|
|
63
|
+
return (channel.state?.topics || []).some((topic: Channel) => topic.cid === cid);
|
|
64
|
+
};
|
|
65
|
+
const handleE2eePreviewUpdate = (event: any) => {
|
|
66
|
+
if (isTopicGroupCid(event?.cid)) {
|
|
67
|
+
bump();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
55
70
|
|
|
56
71
|
// Parent channel events
|
|
57
72
|
subs.push(channel.on('message.new', bump));
|
|
@@ -61,6 +76,9 @@ export function useTopicGroupUpdates(
|
|
|
61
76
|
subs.push(channel.on('channel.topic.created', bump));
|
|
62
77
|
subs.push(channel.on('channel.pinned', bump));
|
|
63
78
|
subs.push(channel.on('channel.unpinned', bump));
|
|
79
|
+
subs.push(client.on('e2ee.message_decrypted' as any, handleE2eePreviewUpdate));
|
|
80
|
+
subs.push(client.on('e2ee.local_messages_loaded' as any, handleE2eePreviewUpdate));
|
|
81
|
+
subs.push(client.on('e2ee.post_join_sync' as any, handleE2eePreviewUpdate));
|
|
64
82
|
|
|
65
83
|
// Topic children events
|
|
66
84
|
const currentTopics = channel.state?.topics || [];
|
|
@@ -90,17 +108,19 @@ export function useTopicGroupUpdates(
|
|
|
90
108
|
|
|
91
109
|
// Helper: check if user is excluded from unread counting
|
|
92
110
|
const isExcludedUser = (ch: Channel): boolean => {
|
|
93
|
-
const
|
|
111
|
+
const client = ch.getClient();
|
|
112
|
+
const activeCh = client.activeChannels[ch.cid] || ch;
|
|
113
|
+
const ms = activeCh.state?.membership as Record<string, unknown> | undefined;
|
|
94
114
|
if (!ms) return false;
|
|
95
115
|
const isBannedSelf = Boolean(ms.banned);
|
|
96
116
|
|
|
97
117
|
// Topic support: check parent channel's ban status
|
|
98
|
-
const parentCid =
|
|
99
|
-
const parentChannel = parentCid ?
|
|
118
|
+
const parentCid = activeCh.data?.parent_cid as string | undefined;
|
|
119
|
+
const parentChannel = parentCid ? client.activeChannels[parentCid] : undefined;
|
|
100
120
|
const isBannedParent = Boolean(parentChannel?.state?.membership?.banned);
|
|
101
121
|
|
|
102
122
|
const isBanned = isBannedSelf || isBannedParent;
|
|
103
|
-
const isBlocked = isDirectChannel(
|
|
123
|
+
const isBlocked = isDirectChannel(activeCh) && Boolean(ms.blocked);
|
|
104
124
|
const isPending = isPendingMember(ms.channel_role as string);
|
|
105
125
|
const isSkipped = isSkippedMember(ms.channel_role as string);
|
|
106
126
|
return isBanned || isBlocked || isPending || isSkipped;
|
|
@@ -109,8 +129,10 @@ export function useTopicGroupUpdates(
|
|
|
109
129
|
// Helper: get unread count for a channel (reads from SDK state directly)
|
|
110
130
|
const getUnreadCount = (ch: Channel): number => {
|
|
111
131
|
if (!currentUserId || isExcludedUser(ch)) return 0;
|
|
112
|
-
// Primary: use the SDK's tracked unreadCount
|
|
113
|
-
const
|
|
132
|
+
// Primary: use the SDK's tracked unreadCount from activeChannels to avoid stale state
|
|
133
|
+
const client = ch.getClient();
|
|
134
|
+
const activeCh = client.activeChannels[ch.cid] || ch;
|
|
135
|
+
const state = activeCh.state as unknown as Record<string, unknown> | undefined;
|
|
114
136
|
const count = (state?.unreadCount as number) ?? 0;
|
|
115
137
|
return count;
|
|
116
138
|
};
|
|
@@ -118,7 +140,9 @@ export function useTopicGroupUpdates(
|
|
|
118
140
|
// Sort topics: pinned first → last activity descending
|
|
119
141
|
const topics = useMemo(() => {
|
|
120
142
|
const allTopics = channel.state?.topics || [];
|
|
121
|
-
|
|
143
|
+
const client = channel.getClient();
|
|
144
|
+
const upToDateTopics = allTopics.map(t => client.activeChannels[t.cid] || t);
|
|
145
|
+
return upToDateTopics.sort((a: Channel, b: Channel) => {
|
|
122
146
|
const aPinned = a.data?.is_pinned === true;
|
|
123
147
|
const bPinned = b.data?.is_pinned === true;
|
|
124
148
|
if (aPinned && !bPinned) return -1;
|
|
@@ -130,16 +154,29 @@ export function useTopicGroupUpdates(
|
|
|
130
154
|
|
|
131
155
|
// Aggregated unread count across parent + all topics
|
|
132
156
|
const aggregatedUnreadCount = useMemo(() => {
|
|
133
|
-
|
|
157
|
+
const client = channel.getClient();
|
|
158
|
+
const activeParent = client.activeChannels[channel.cid] || channel;
|
|
159
|
+
|
|
160
|
+
// Ignore the currently active channel's unread count to match UI behavior
|
|
161
|
+
// where active channels don't show unread badges.
|
|
162
|
+
const activeChannelCid = Object.values(client.activeChannels || {}).find(c => c.state && c.cid === activeChannel?.cid)?.cid || activeChannel?.cid;
|
|
163
|
+
|
|
164
|
+
let total = 0;
|
|
165
|
+
if (activeParent.cid !== activeChannelCid) {
|
|
166
|
+
total += getUnreadCount(activeParent);
|
|
167
|
+
}
|
|
134
168
|
|
|
135
169
|
const allTopics = channel.state?.topics || [];
|
|
136
170
|
allTopics.forEach((topic: Channel) => {
|
|
137
|
-
|
|
171
|
+
const activeTopic = client.activeChannels[topic.cid] || topic;
|
|
172
|
+
if (activeTopic.cid !== activeChannelCid) {
|
|
173
|
+
total += getUnreadCount(activeTopic);
|
|
174
|
+
}
|
|
138
175
|
});
|
|
139
176
|
|
|
140
177
|
return total;
|
|
141
178
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
142
|
-
}, [channel, channel.state?.topics, currentUserId, updateCount]);
|
|
179
|
+
}, [channel, channel.state?.topics, currentUserId, updateCount, activeChannel?.cid]);
|
|
143
180
|
|
|
144
181
|
const hasUnread = aggregatedUnreadCount > 0;
|
|
145
182
|
|
|
@@ -188,10 +225,11 @@ export function useTopicGroupUpdates(
|
|
|
188
225
|
options?.videoMessageLabel,
|
|
189
226
|
options?.voiceRecordingMessageLabel,
|
|
190
227
|
options?.fileMessageLabel,
|
|
228
|
+
options?.encryptedMessageLabel,
|
|
229
|
+
options?.encryptedMessageUnavailableLabel,
|
|
191
230
|
options?.systemMessageTranslations,
|
|
192
231
|
options?.signalMessageTranslations,
|
|
193
232
|
]);
|
|
194
233
|
|
|
195
234
|
return { topics, aggregatedUnreadCount, hasUnread, updateCount, latestMessagePreview };
|
|
196
235
|
}
|
|
197
|
-
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,9 @@ export { useTopicGroupUpdates } from './hooks/useTopicGroupUpdates';
|
|
|
27
27
|
export { useDragAndDrop } from './hooks/useDragAndDrop';
|
|
28
28
|
export { useMessageSend } from './hooks/useMessageSend';
|
|
29
29
|
export { useFileUpload } from './hooks/useFileUpload';
|
|
30
|
+
export { useE2eeFileUpload } from './hooks/useE2eeFileUpload';
|
|
31
|
+
export { useE2eeAttachmentRenderer } from './hooks/useE2eeAttachmentRenderer';
|
|
32
|
+
export { usePendingE2eeSends } from './hooks/usePendingE2eeSends';
|
|
30
33
|
export { useEmojiPicker } from './hooks/useEmojiPicker';
|
|
31
34
|
export { useStickerPicker } from './hooks/useStickerPicker';
|
|
32
35
|
export type { UseStickerPickerOptions } from './hooks/useStickerPicker';
|
|
@@ -184,6 +187,8 @@ export { useChannelMessages, markChannelAsFullyQueried } from './hooks/useChanne
|
|
|
184
187
|
export type { UseChannelMessagesOptions } from './hooks/useChannelMessages';
|
|
185
188
|
|
|
186
189
|
export { useForwardMessage } from './hooks/useForwardMessage';
|
|
190
|
+
export { useRecoveryPin } from './hooks/useRecoveryPin';
|
|
191
|
+
export type { UseRecoveryPinReturn, RecoveryPinStatus, RecoveryRestoredMessage, RecoveryStatusInfo } from './hooks/useRecoveryPin';
|
|
187
192
|
|
|
188
193
|
export { QuotedMessagePreview } from './components/QuotedMessagePreview';
|
|
189
194
|
export type { QuotedMessagePreviewProps } from './components/QuotedMessagePreview';
|
|
@@ -245,6 +250,24 @@ export type { UserPickerProps, UserPickerUser, UserPickerItemProps, UserPickerSe
|
|
|
245
250
|
|
|
246
251
|
export { CreateChannelModal } from './components/CreateChannelModal';
|
|
247
252
|
export type { CreateChannelModalProps } from './types';
|
|
253
|
+
export {
|
|
254
|
+
RecoveryPinSetup,
|
|
255
|
+
RecoveryPinRestore,
|
|
256
|
+
RecoveryPinChange,
|
|
257
|
+
RecoveryStatus,
|
|
258
|
+
RecoveryGap,
|
|
259
|
+
RecoveryGate,
|
|
260
|
+
RecoveryRestoreProgress,
|
|
261
|
+
} from './components/RecoveryPin';
|
|
262
|
+
export type {
|
|
263
|
+
RecoveryPinSetupProps,
|
|
264
|
+
RecoveryPinRestoreProps,
|
|
265
|
+
RecoveryPinChangeProps,
|
|
266
|
+
RecoveryStatusProps,
|
|
267
|
+
RecoveryGapProps,
|
|
268
|
+
RecoveryGateProps,
|
|
269
|
+
RecoveryRestoreProgressProps,
|
|
270
|
+
} from './components/RecoveryPin';
|
|
248
271
|
|
|
249
272
|
// Call Components
|
|
250
273
|
export { ErmisCallContext } from './context/ErmisCallContext';
|
package/src/messageTypeUtils.ts
CHANGED
|
@@ -63,6 +63,20 @@ export function isVideo(attachment: any): boolean {
|
|
|
63
63
|
return !!(isVideoAttachment(attachment) || (!attachment.type && attachment.mime_type?.startsWith('video/')));
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
export function isAudioAttachment(attachment: any): boolean {
|
|
67
|
+
return attachment?.type === ATTACHMENT_TYPES.AUDIO;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function isAudio(attachment: any): boolean {
|
|
71
|
+
return !!(
|
|
72
|
+
isAudioAttachment(attachment) ||
|
|
73
|
+
isVoiceRecordingAttachment(attachment) ||
|
|
74
|
+
attachment.mime_type?.startsWith('audio/') ||
|
|
75
|
+
attachment.file_name?.toLowerCase().endsWith('.mp3') ||
|
|
76
|
+
attachment.title?.toLowerCase().endsWith('.mp3')
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
export const MESSAGE_DISPLAY_TYPES = {
|
|
67
81
|
NORMAL: 'normal',
|
|
68
82
|
DELETED: 'deleted',
|
|
@@ -500,6 +500,15 @@
|
|
|
500
500
|
margin-left: 2px;
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
.ermis-channel-info__media-spinner {
|
|
504
|
+
width: 16px;
|
|
505
|
+
height: 16px;
|
|
506
|
+
border: 2px solid rgba(255, 255, 255, 0.35);
|
|
507
|
+
border-top-color: #fff;
|
|
508
|
+
border-radius: 50%;
|
|
509
|
+
animation: ermis-lightbox-spin 0.8s linear infinite;
|
|
510
|
+
}
|
|
511
|
+
|
|
503
512
|
/* ============================================
|
|
504
513
|
Links List
|
|
505
514
|
============================================ */
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
.ermis-channel-header {
|
|
5
5
|
display: flex;
|
|
6
6
|
align-items: center;
|
|
7
|
-
gap: var(--ermis-spacing-
|
|
7
|
+
gap: var(--ermis-spacing-sm);
|
|
8
8
|
padding: var(--ermis-spacing-md) var(--ermis-spacing-lg);
|
|
9
9
|
border-bottom: 1px solid var(--ermis-border);
|
|
10
|
-
background-color: var(--ermis-bg-
|
|
10
|
+
background-color: var(--ermis-bg-primary);
|
|
11
11
|
font-family: var(--ermis-font-family);
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
.ermis-channel-header__topic-avatar {
|
|
40
|
-
width:
|
|
41
|
-
height:
|
|
42
|
-
min-width:
|
|
40
|
+
width: 44px;
|
|
41
|
+
height: 44px;
|
|
42
|
+
min-width: 44px;
|
|
43
43
|
border-radius: var(--ermis-radius-md);
|
|
44
44
|
background-color: var(--ermis-bg-primary);
|
|
45
45
|
display: flex;
|
|
46
46
|
align-items: center;
|
|
47
47
|
justify-content: center;
|
|
48
|
-
font-size:
|
|
48
|
+
font-size: 24px;
|
|
49
49
|
color: var(--ermis-text-secondary);
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
display: flex;
|
|
133
133
|
align-items: center;
|
|
134
134
|
gap: var(--ermis-spacing-md);
|
|
135
|
-
padding: var(--ermis-spacing-md) var(--ermis-spacing-lg);
|
|
135
|
+
padding: calc(var(--ermis-spacing-md) - 0.05rem) var(--ermis-spacing-lg);
|
|
136
136
|
cursor: pointer;
|
|
137
137
|
border-left: 2px solid transparent;
|
|
138
138
|
transition: background-color var(--ermis-transition), border-color var(--ermis-transition);
|
|
@@ -180,6 +180,31 @@
|
|
|
180
180
|
background-color: var(--ermis-text-muted);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
.ermis-channel-list__avatar-unread-badge {
|
|
184
|
+
display: none;
|
|
185
|
+
position: absolute;
|
|
186
|
+
top: -2px;
|
|
187
|
+
right: -2px;
|
|
188
|
+
min-width: 16px;
|
|
189
|
+
height: 16px;
|
|
190
|
+
padding: 0 4px;
|
|
191
|
+
border-radius: var(--ermis-radius-full);
|
|
192
|
+
background-color: var(--ermis-color-danger, #ef4444);
|
|
193
|
+
color: #fff;
|
|
194
|
+
font-size: 9px;
|
|
195
|
+
font-weight: 700;
|
|
196
|
+
line-height: 1;
|
|
197
|
+
border: 1.5px solid var(--ermis-bg-primary);
|
|
198
|
+
z-index: 2;
|
|
199
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.channel-sidebar-collapsed .ermis-channel-list__avatar-unread-badge {
|
|
203
|
+
display: flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
justify-content: center;
|
|
206
|
+
}
|
|
207
|
+
|
|
183
208
|
.ermis-channel-list__item-top-row {
|
|
184
209
|
display: flex;
|
|
185
210
|
align-items: baseline;
|
|
@@ -196,7 +221,7 @@
|
|
|
196
221
|
}
|
|
197
222
|
|
|
198
223
|
.ermis-channel-list__item-name {
|
|
199
|
-
font-size: var(--ermis-font-size-sm);
|
|
224
|
+
font-size: calc(var(--ermis-font-size-sm) + 1px);
|
|
200
225
|
font-weight: 500;
|
|
201
226
|
color: var(--ermis-text-primary);
|
|
202
227
|
white-space: nowrap;
|
|
@@ -214,7 +239,7 @@
|
|
|
214
239
|
}
|
|
215
240
|
|
|
216
241
|
.ermis-channel-list__item-last-message {
|
|
217
|
-
font-size: var(--ermis-font-size-
|
|
242
|
+
font-size: calc(var(--ermis-font-size-sm));
|
|
218
243
|
color: var(--ermis-text-muted);
|
|
219
244
|
white-space: nowrap;
|
|
220
245
|
overflow: hidden;
|
|
@@ -266,8 +291,7 @@
|
|
|
266
291
|
}
|
|
267
292
|
|
|
268
293
|
.ermis-channel-list__item-last-message-source {
|
|
269
|
-
color: var(--ermis-
|
|
270
|
-
font-weight: 500;
|
|
294
|
+
color: var(--ermis-text-secondary);
|
|
271
295
|
}
|
|
272
296
|
|
|
273
297
|
.ermis-channel-list__item-actions-wrapper,
|
|
@@ -312,13 +336,12 @@
|
|
|
312
336
|
|
|
313
337
|
/* --- Unread channel indicator --- */
|
|
314
338
|
.ermis-channel-list__item--unread .ermis-channel-list__item-name {
|
|
315
|
-
font-weight:
|
|
339
|
+
font-weight: 600;
|
|
316
340
|
color: var(--ermis-text-primary);
|
|
317
341
|
}
|
|
318
342
|
|
|
319
343
|
.ermis-channel-list__item--unread .ermis-channel-list__item-last-message {
|
|
320
344
|
color: var(--ermis-text-secondary);
|
|
321
|
-
font-weight: 600;
|
|
322
345
|
}
|
|
323
346
|
|
|
324
347
|
.ermis-channel-list__unread-badge {
|
|
@@ -524,4 +547,4 @@
|
|
|
524
547
|
|
|
525
548
|
.ermis-channel-list__error-retry:hover svg {
|
|
526
549
|
transform: rotate(180deg);
|
|
527
|
-
}
|
|
550
|
+
}
|
|
@@ -23,8 +23,12 @@
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
@keyframes ermis-lightbox-fade-in {
|
|
26
|
-
from {
|
|
27
|
-
|
|
26
|
+
from {
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
to {
|
|
30
|
+
opacity: 1;
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/* ----------------------------------------------------------
|
|
@@ -74,6 +78,11 @@
|
|
|
74
78
|
color: #fff;
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
.ermis-lightbox__action-btn:disabled {
|
|
82
|
+
opacity: 0.4;
|
|
83
|
+
cursor: not-allowed;
|
|
84
|
+
}
|
|
85
|
+
|
|
77
86
|
/* ----------------------------------------------------------
|
|
78
87
|
Content area
|
|
79
88
|
---------------------------------------------------------- */
|
|
@@ -157,8 +166,32 @@
|
|
|
157
166
|
animation: ermis-lightbox-spin 0.8s linear infinite;
|
|
158
167
|
}
|
|
159
168
|
|
|
169
|
+
.ermis-lightbox__video-retry {
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
gap: 10px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.ermis-lightbox__progress-label {
|
|
175
|
+
color: rgba(255, 255, 255, 0.86);
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
font-weight: 500;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.ermis-lightbox__media-placeholder {
|
|
181
|
+
width: min(80vw, 720px);
|
|
182
|
+
height: min(60vh, 420px);
|
|
183
|
+
border-radius: 4px;
|
|
184
|
+
background: rgba(255, 255, 255, 0.08);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ermis-lightbox__image--poster {
|
|
188
|
+
filter: none;
|
|
189
|
+
}
|
|
190
|
+
|
|
160
191
|
@keyframes ermis-lightbox-spin {
|
|
161
|
-
to {
|
|
192
|
+
to {
|
|
193
|
+
transform: rotate(360deg);
|
|
194
|
+
}
|
|
162
195
|
}
|
|
163
196
|
|
|
164
197
|
/* ----------------------------------------------------------
|