vue-parley 4.9.2 → 5.2.0
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 +26 -4
- package/dist/chat.css +412 -68
- package/dist/chunks/Call-DvVJ7IsY.mjs +1717 -0
- package/dist/chunks/Call-DvVJ7IsY.mjs.map +1 -0
- package/dist/chunks/Call-h9r4EZ5Y.cjs +1717 -0
- package/dist/chunks/Call-h9r4EZ5Y.cjs.map +1 -0
- package/dist/chunks/data-CsUe_T0I.cjs +1894 -0
- package/dist/chunks/data-CsUe_T0I.cjs.map +1 -0
- package/dist/chunks/data-VApcOLKg.mjs +1894 -0
- package/dist/chunks/data-VApcOLKg.mjs.map +1 -0
- package/dist/chunks/duotone-CZ2lLMty.cjs +95 -0
- package/dist/chunks/duotone-CZ2lLMty.cjs.map +1 -0
- package/dist/chunks/duotone-DWysXhVh.mjs +95 -0
- package/dist/chunks/duotone-DWysXhVh.mjs.map +1 -0
- package/dist/chunks/{index-CqkX2ds2.cjs → index-BSzP10Mk.cjs} +1211 -712
- package/dist/chunks/index-BSzP10Mk.cjs.map +1 -0
- package/dist/chunks/{index-BBr7KDrd.mjs → index-C5yf_PW0.mjs} +1231 -732
- package/dist/chunks/index-C5yf_PW0.mjs.map +1 -0
- package/dist/chunks/light-CewGh2Ah.cjs +95 -0
- package/dist/chunks/light-CewGh2Ah.cjs.map +1 -0
- package/dist/chunks/light-DtApNkwW.mjs +95 -0
- package/dist/chunks/light-DtApNkwW.mjs.map +1 -0
- package/dist/chunks/{session-DBA9iE_n.mjs → session-CKOlYafG.mjs} +391 -33
- package/dist/chunks/session-CKOlYafG.mjs.map +1 -0
- package/dist/chunks/{session-DAl8n0Eh.cjs → session-DhajXqvC.cjs} +391 -33
- package/dist/chunks/session-DhajXqvC.cjs.map +1 -0
- package/dist/chunks/thin-Ccq8qzb_.mjs +95 -0
- package/dist/chunks/thin-Ccq8qzb_.mjs.map +1 -0
- package/dist/chunks/thin-Dlw1Y57w.cjs +95 -0
- package/dist/chunks/thin-Dlw1Y57w.cjs.map +1 -0
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +20 -20
- package/dist/types/app/components/call/Call.vue.d.ts +1 -2
- package/dist/types/app/components/call/Call.vue.d.ts.map +1 -1
- package/dist/types/app/components/call/CallIcon.vue.d.ts +4 -0
- package/dist/types/app/components/call/CallIcon.vue.d.ts.map +1 -1
- package/dist/types/app/components/call/CallParticipants.vue.d.ts +14 -0
- package/dist/types/app/components/call/CallParticipants.vue.d.ts.map +1 -0
- package/dist/types/app/components/call/CallTile.vue.d.ts +46 -0
- package/dist/types/app/components/call/CallTile.vue.d.ts.map +1 -0
- package/dist/types/app/components/call/tokens.d.ts +204 -0
- package/dist/types/app/components/call/tokens.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatInput.vue.d.ts.map +1 -1
- package/dist/types/app/components/chat/ChatPageBar.vue.d.ts.map +1 -1
- package/dist/types/app/components/chat/chat-input/InputAttachement.vue.d.ts.map +1 -1
- package/dist/types/app/components/chat/contact/ContactAvatar.vue.d.ts.map +1 -1
- package/dist/types/app/components/general/IconButton.vue.d.ts +1 -1
- package/dist/types/app/components/general/IconButton.vue.d.ts.map +1 -1
- package/dist/types/app/components/global/BEmojiPicker.vue.d.ts +11 -4
- package/dist/types/app/components/global/BEmojiPicker.vue.d.ts.map +1 -1
- package/dist/types/app/components/global/BIcon.vue.d.ts +1 -1
- package/dist/types/app/components/global/BIcon.vue.d.ts.map +1 -1
- package/dist/types/app/components/global/emoji/data.d.ts +13 -0
- package/dist/types/app/components/global/emoji/data.d.ts.map +1 -0
- package/dist/types/app/components/global/emoji/types.d.ts +12 -0
- package/dist/types/app/components/global/emoji/types.d.ts.map +1 -0
- package/dist/types/app/components/global/icons/bold.d.ts.map +1 -1
- package/dist/types/app/components/global/icons/duotone.d.ts.map +1 -1
- package/dist/types/app/components/global/icons/fill.d.ts.map +1 -1
- package/dist/types/app/components/global/icons/light.d.ts.map +1 -1
- package/dist/types/app/components/global/icons/regular.d.ts.map +1 -1
- package/dist/types/app/components/global/icons/thin.d.ts.map +1 -1
- package/dist/types/app/composables/call/limits.d.ts +18 -0
- package/dist/types/app/composables/call/limits.d.ts.map +1 -0
- package/dist/types/app/composables/call/peer.d.ts +14 -1
- package/dist/types/app/composables/call/peer.d.ts.map +1 -1
- package/dist/types/app/composables/call/peers.d.ts +22 -3
- package/dist/types/app/composables/call/peers.d.ts.map +1 -1
- package/dist/types/app/composables/call/session.d.ts +55 -7
- package/dist/types/app/composables/call/session.d.ts.map +1 -1
- package/dist/types/app/composables/call/signaling.d.ts +23 -6
- package/dist/types/app/composables/call/signaling.d.ts.map +1 -1
- package/dist/types/app/composables/call/useCallLayout.d.ts +38 -0
- package/dist/types/app/composables/call/useCallLayout.d.ts.map +1 -0
- package/dist/types/app/composables/call/useCallNotices.d.ts +23 -0
- package/dist/types/app/composables/call/useCallNotices.d.ts.map +1 -0
- package/dist/types/app/composables/call/useCallUi.d.ts +3 -0
- package/dist/types/app/composables/call/useCallUi.d.ts.map +1 -1
- package/dist/types/app/composables/chat/useChatRecording.d.ts +1 -1
- package/dist/types/app/composables/useCall.d.ts +12 -1
- package/dist/types/app/composables/useCall.d.ts.map +1 -1
- package/dist/types/app/composables/useHostI18n.d.ts +1 -1
- package/dist/types/app/composables/useHostI18n.d.ts.map +1 -1
- package/dist/types/app/index.d.ts +2 -2
- package/dist/types/app/index.d.ts.map +1 -1
- package/dist/types/app/stores/callStore.d.ts +207 -24
- package/dist/types/app/stores/callStore.d.ts.map +1 -1
- package/dist/types/app/types/index.d.ts +26 -1
- package/dist/types/app/types/index.d.ts.map +1 -1
- package/dist/types/app/utils/avatar.d.ts +25 -0
- package/dist/types/app/utils/avatar.d.ts.map +1 -0
- package/dist/types/i18n/locales/index.d.ts +146 -0
- package/dist/types/i18n/locales/index.d.ts.map +1 -1
- package/package.json +6 -4
- package/dist/chunks/Call-B8Po7lDD.mjs +0 -1155
- package/dist/chunks/Call-B8Po7lDD.mjs.map +0 -1
- package/dist/chunks/Call-Cz-Hk_YZ.cjs +0 -1155
- package/dist/chunks/Call-Cz-Hk_YZ.cjs.map +0 -1
- package/dist/chunks/duotone-DEZDBwbj.mjs +0 -90
- package/dist/chunks/duotone-DEZDBwbj.mjs.map +0 -1
- package/dist/chunks/duotone-Dx8FFD3-.cjs +0 -90
- package/dist/chunks/duotone-Dx8FFD3-.cjs.map +0 -1
- package/dist/chunks/index-BBr7KDrd.mjs.map +0 -1
- package/dist/chunks/index-CqkX2ds2.cjs.map +0 -1
- package/dist/chunks/light-BdqG_1xJ.mjs +0 -90
- package/dist/chunks/light-BdqG_1xJ.mjs.map +0 -1
- package/dist/chunks/light-DWwZlbLY.cjs +0 -90
- package/dist/chunks/light-DWwZlbLY.cjs.map +0 -1
- package/dist/chunks/session-DAl8n0Eh.cjs.map +0 -1
- package/dist/chunks/session-DBA9iE_n.mjs.map +0 -1
- package/dist/chunks/thin-BzrijWaM.cjs +0 -90
- package/dist/chunks/thin-BzrijWaM.cjs.map +0 -1
- package/dist/chunks/thin-CXKKNj_8.mjs +0 -90
- package/dist/chunks/thin-CXKKNj_8.mjs.map +0 -1
|
@@ -0,0 +1,1717 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted, watch, nextTick, reactive, onBeforeUnmount, computed, defineComponent, openBlock, createElementBlock, createBlock, unref, mergeProps, withCtx, createVNode, normalizeClass, createElementVNode, normalizeStyle, createSlots, toDisplayString, createCommentVNode, withDirectives, Fragment, useModel, renderList, createTextVNode, mergeModels, withModifiers, Transition, vShow } from "vue";
|
|
2
|
+
import { u as useCallStore, a as useLocalI18n, c as chat, n as nameInitials, b as avatarToneStyle, _ as _sfc_main$5, d as useDirection, e as useChatStore, f as formatDuration } from "./index-C5yf_PW0.mjs";
|
|
3
|
+
import { useElementSize, useEventListener, useWindowSize, useDraggable } from "@vueuse/core";
|
|
4
|
+
import Button from "primevue/button";
|
|
5
|
+
import Menu from "primevue/menu";
|
|
6
|
+
import Tooltip from "primevue/tooltip";
|
|
7
|
+
import Avatar from "primevue/avatar";
|
|
8
|
+
import Drawer from "primevue/drawer";
|
|
9
|
+
const CONTROLS_HIDE_AFTER_MS = 3e3;
|
|
10
|
+
function useCallUi(opts) {
|
|
11
|
+
const { localStream, screenStream, remoteVideos, remoteScreens } = opts;
|
|
12
|
+
const localVideo = ref(null);
|
|
13
|
+
const localScreen = ref(null);
|
|
14
|
+
const remoteRefs = ref({});
|
|
15
|
+
const remoteScreenRefs = ref({});
|
|
16
|
+
const remoteParents = ref({});
|
|
17
|
+
const showControls = ref(true);
|
|
18
|
+
let controlsTimeout;
|
|
19
|
+
function resetControlsTimeout() {
|
|
20
|
+
showControls.value = true;
|
|
21
|
+
clearTimeout(controlsTimeout);
|
|
22
|
+
controlsTimeout = setTimeout(
|
|
23
|
+
() => showControls.value = false,
|
|
24
|
+
CONTROLS_HIDE_AFTER_MS
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const inputEvents = ["mousemove", "click", "keydown"];
|
|
28
|
+
onMounted(() => {
|
|
29
|
+
resetControlsTimeout();
|
|
30
|
+
inputEvents.forEach((e) => document.addEventListener(e, resetControlsTimeout));
|
|
31
|
+
});
|
|
32
|
+
onUnmounted(() => {
|
|
33
|
+
inputEvents.forEach((e) => document.removeEventListener(e, resetControlsTimeout));
|
|
34
|
+
clearTimeout(controlsTimeout);
|
|
35
|
+
detachAll();
|
|
36
|
+
});
|
|
37
|
+
const isFullscreen = ref(false);
|
|
38
|
+
function toggleFullscreen(target = document.documentElement) {
|
|
39
|
+
var _a;
|
|
40
|
+
if (!document.fullscreenElement) {
|
|
41
|
+
void ((_a = target.requestFullscreen) == null ? void 0 : _a.call(target));
|
|
42
|
+
isFullscreen.value = true;
|
|
43
|
+
} else {
|
|
44
|
+
void document.exitFullscreen();
|
|
45
|
+
isFullscreen.value = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const toggleRemote = (tileId, el) => {
|
|
49
|
+
const container = el ?? remoteParents.value[tileId];
|
|
50
|
+
if (container) toggleFullscreen(container);
|
|
51
|
+
};
|
|
52
|
+
const videoPaused = ref({});
|
|
53
|
+
function toggleVideoPause(tileId, el) {
|
|
54
|
+
if (!(el instanceof HTMLVideoElement)) return;
|
|
55
|
+
if (videoPaused.value[tileId]) void el.play();
|
|
56
|
+
else el.pause();
|
|
57
|
+
videoPaused.value[tileId] = !videoPaused.value[tileId];
|
|
58
|
+
}
|
|
59
|
+
const soundBlocked = ref(false);
|
|
60
|
+
async function play(el) {
|
|
61
|
+
try {
|
|
62
|
+
await el.play();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
if ((err == null ? void 0 : err.name) !== "NotAllowedError" || el.muted) return;
|
|
65
|
+
el.muted = true;
|
|
66
|
+
soundBlocked.value = true;
|
|
67
|
+
await el.play().catch((e) => console.error("[vue-chat] Remote video can't play:", e));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function enableSound() {
|
|
71
|
+
soundBlocked.value = false;
|
|
72
|
+
for (const el of Object.values(remoteRefs.value)) {
|
|
73
|
+
if (!el) continue;
|
|
74
|
+
el.muted = false;
|
|
75
|
+
void play(el);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const attach = (el, stream) => {
|
|
79
|
+
if (!el) return;
|
|
80
|
+
if (el.srcObject !== stream) el.srcObject = stream;
|
|
81
|
+
void play(el);
|
|
82
|
+
};
|
|
83
|
+
async function reattach() {
|
|
84
|
+
await nextTick();
|
|
85
|
+
if (localStream.value && localVideo.value && localVideo.value.srcObject !== localStream.value)
|
|
86
|
+
localVideo.value.srcObject = localStream.value;
|
|
87
|
+
if (localScreen.value && localScreen.value.srcObject !== screenStream.value)
|
|
88
|
+
localScreen.value.srcObject = screenStream.value;
|
|
89
|
+
for (const [id, { stream }] of Object.entries(remoteVideos.value))
|
|
90
|
+
attach(remoteRefs.value[id], stream);
|
|
91
|
+
for (const [id, { stream }] of Object.entries(remoteScreens.value))
|
|
92
|
+
attach(remoteScreenRefs.value[id], stream);
|
|
93
|
+
}
|
|
94
|
+
watch(
|
|
95
|
+
[
|
|
96
|
+
localStream,
|
|
97
|
+
screenStream,
|
|
98
|
+
() => ({ ...remoteVideos.value }),
|
|
99
|
+
() => ({ ...remoteScreens.value }),
|
|
100
|
+
opts.isMinimized,
|
|
101
|
+
() => {
|
|
102
|
+
var _a;
|
|
103
|
+
return (_a = opts.layoutKey) == null ? void 0 : _a.call(opts);
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
reattach,
|
|
107
|
+
{ immediate: true }
|
|
108
|
+
);
|
|
109
|
+
function detachAll() {
|
|
110
|
+
const all = [
|
|
111
|
+
localVideo.value,
|
|
112
|
+
localScreen.value,
|
|
113
|
+
...Object.values(remoteRefs.value),
|
|
114
|
+
...Object.values(remoteScreenRefs.value)
|
|
115
|
+
];
|
|
116
|
+
for (const el of all) if (el) el.srcObject = null;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
localVideo,
|
|
120
|
+
localScreen,
|
|
121
|
+
remoteRefs,
|
|
122
|
+
remoteScreenRefs,
|
|
123
|
+
remoteParents,
|
|
124
|
+
showControls,
|
|
125
|
+
resetControlsTimeout,
|
|
126
|
+
isFullscreen,
|
|
127
|
+
toggleFullscreen: () => toggleFullscreen(),
|
|
128
|
+
toggleRemote,
|
|
129
|
+
videoPaused,
|
|
130
|
+
toggleVideoPause,
|
|
131
|
+
soundBlocked,
|
|
132
|
+
enableSound,
|
|
133
|
+
detachAll,
|
|
134
|
+
reattach
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function useCall({ layoutKey } = {}) {
|
|
138
|
+
const callStore = useCallStore();
|
|
139
|
+
const session = callStore.session;
|
|
140
|
+
if (!session) {
|
|
141
|
+
throw new Error("[vue-chat] useCall() needs a running call: callStore.startCall() first");
|
|
142
|
+
}
|
|
143
|
+
const { media, peers } = session;
|
|
144
|
+
const ui = useCallUi({
|
|
145
|
+
localStream: media.localStream,
|
|
146
|
+
screenStream: media.screenStream,
|
|
147
|
+
remoteVideos: peers.remoteVideos,
|
|
148
|
+
remoteScreens: peers.remoteScreens,
|
|
149
|
+
isMinimized: () => callStore.isMinimized,
|
|
150
|
+
layoutKey
|
|
151
|
+
});
|
|
152
|
+
async function switchCamera(deviceId) {
|
|
153
|
+
const stream = await session.switchCamera(deviceId);
|
|
154
|
+
if (stream && ui.localVideo.value) ui.localVideo.value.srcObject = stream;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
// Call state
|
|
158
|
+
participantCount: session.participantCount,
|
|
159
|
+
tileCount: session.tileCount,
|
|
160
|
+
participants: session.participants,
|
|
161
|
+
phase: session.phase,
|
|
162
|
+
hadOthers: session.hadOthers,
|
|
163
|
+
maxParticipants: session.maxParticipants,
|
|
164
|
+
remoteMedia: peers.remoteMedia,
|
|
165
|
+
peerStatus: peers.peerStatus,
|
|
166
|
+
remoteNames: peers.remoteNames,
|
|
167
|
+
localStream: media.localStream,
|
|
168
|
+
remoteVideos: peers.remoteVideos,
|
|
169
|
+
remoteScreens: peers.remoteScreens,
|
|
170
|
+
// Local media
|
|
171
|
+
cameras: media.cameras,
|
|
172
|
+
isAudioOn: media.isAudioOn,
|
|
173
|
+
isVideoOn: media.isVideoOn,
|
|
174
|
+
isScreenSharing: media.isScreenSharing,
|
|
175
|
+
isFlashlightOn: media.isFlashlightOn,
|
|
176
|
+
isFlashlightSupported: media.isFlashlightSupported,
|
|
177
|
+
toggleAudio: media.toggleAudio,
|
|
178
|
+
toggleVideo: media.toggleVideo,
|
|
179
|
+
toggleFlashlight: media.toggleFlashlight,
|
|
180
|
+
toggleScreenShare: session.toggleScreenShare,
|
|
181
|
+
switchCamera,
|
|
182
|
+
endCall: callStore.endCall,
|
|
183
|
+
// View
|
|
184
|
+
showCameraModal: ref(false),
|
|
185
|
+
showControls: ui.showControls,
|
|
186
|
+
resetControlsTimeout: ui.resetControlsTimeout,
|
|
187
|
+
isFullscreen: ui.isFullscreen,
|
|
188
|
+
toggleFullscreen: ui.toggleFullscreen,
|
|
189
|
+
toggleRemote: ui.toggleRemote,
|
|
190
|
+
videoPaused: ui.videoPaused,
|
|
191
|
+
soundBlocked: ui.soundBlocked,
|
|
192
|
+
enableSound: ui.enableSound,
|
|
193
|
+
toggleVideoPause: ui.toggleVideoPause,
|
|
194
|
+
localVideo: ui.localVideo,
|
|
195
|
+
localScreen: ui.localScreen,
|
|
196
|
+
remoteRefs: ui.remoteRefs,
|
|
197
|
+
remoteScreenRefs: ui.remoteScreenRefs,
|
|
198
|
+
remoteParents: ui.remoteParents,
|
|
199
|
+
reattach: ui.reattach,
|
|
200
|
+
retryPeer: session.retryPeer
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const THRESHOLD = 0.04;
|
|
204
|
+
const HOLD_MS = 400;
|
|
205
|
+
const POLL_MS = 120;
|
|
206
|
+
function useSpeaking(streams) {
|
|
207
|
+
const speaking = reactive({});
|
|
208
|
+
const meters = /* @__PURE__ */ new Map();
|
|
209
|
+
let context = null;
|
|
210
|
+
let timer;
|
|
211
|
+
const drop = (id) => {
|
|
212
|
+
const meter = meters.get(id);
|
|
213
|
+
if (!meter) return;
|
|
214
|
+
meter.source.disconnect();
|
|
215
|
+
meters.delete(id);
|
|
216
|
+
delete speaking[id];
|
|
217
|
+
};
|
|
218
|
+
const poll = () => {
|
|
219
|
+
const now = performance.now();
|
|
220
|
+
for (const [id, meter] of meters) {
|
|
221
|
+
meter.analyser.getByteTimeDomainData(meter.buffer);
|
|
222
|
+
let sum = 0;
|
|
223
|
+
for (const sample of meter.buffer) {
|
|
224
|
+
const centred = (sample - 128) / 128;
|
|
225
|
+
sum += centred * centred;
|
|
226
|
+
}
|
|
227
|
+
if (Math.sqrt(sum / meter.buffer.length) > THRESHOLD) meter.lastLoud = now;
|
|
228
|
+
const lit2 = now - meter.lastLoud < HOLD_MS;
|
|
229
|
+
if (speaking[id] !== lit2) speaking[id] = lit2;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
watch(
|
|
233
|
+
streams,
|
|
234
|
+
(current) => {
|
|
235
|
+
for (const id of [...meters.keys()]) {
|
|
236
|
+
if (current[id] !== meters.get(id).stream) drop(id);
|
|
237
|
+
}
|
|
238
|
+
for (const [id, stream] of Object.entries(current)) {
|
|
239
|
+
if (!stream || meters.has(id) || !stream.getAudioTracks().length) continue;
|
|
240
|
+
if (typeof AudioContext === "undefined") return;
|
|
241
|
+
context ?? (context = new AudioContext());
|
|
242
|
+
if (context.state === "suspended") void context.resume().catch(() => {
|
|
243
|
+
});
|
|
244
|
+
const source = context.createMediaStreamSource(stream);
|
|
245
|
+
const analyser = context.createAnalyser();
|
|
246
|
+
analyser.fftSize = 512;
|
|
247
|
+
source.connect(analyser);
|
|
248
|
+
meters.set(id, {
|
|
249
|
+
stream,
|
|
250
|
+
source,
|
|
251
|
+
analyser,
|
|
252
|
+
buffer: new Uint8Array(analyser.fftSize),
|
|
253
|
+
lastLoud: 0
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (meters.size && !timer) timer = setInterval(poll, POLL_MS);
|
|
257
|
+
if (!meters.size && timer) {
|
|
258
|
+
clearInterval(timer);
|
|
259
|
+
timer = void 0;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{ immediate: true, deep: 1 }
|
|
263
|
+
);
|
|
264
|
+
onBeforeUnmount(() => {
|
|
265
|
+
clearInterval(timer);
|
|
266
|
+
for (const id of [...meters.keys()]) drop(id);
|
|
267
|
+
void (context == null ? void 0 : context.close().catch(() => {
|
|
268
|
+
}));
|
|
269
|
+
});
|
|
270
|
+
return speaking;
|
|
271
|
+
}
|
|
272
|
+
function useCallLayout({ participants, width, height }) {
|
|
273
|
+
const cameraTile = (p) => p.isSelf ? { id: "self_cam", kind: "self", participantId: p.id } : { id: `remote_video_${p.id}`, kind: "camera", participantId: p.id };
|
|
274
|
+
const screenTile = (p) => ({
|
|
275
|
+
id: p.isSelf ? "self_screen" : `remote_screen_${p.id}`,
|
|
276
|
+
kind: "screen",
|
|
277
|
+
participantId: p.id
|
|
278
|
+
});
|
|
279
|
+
const cameraTiles = computed(() => participants.value.map(cameraTile));
|
|
280
|
+
const screenTiles = computed(
|
|
281
|
+
() => participants.value.filter((p) => p.screen).map(screenTile)
|
|
282
|
+
);
|
|
283
|
+
const tiles = computed(
|
|
284
|
+
() => participants.value.flatMap((p) => p.screen ? [cameraTile(p), screenTile(p)] : [cameraTile(p)])
|
|
285
|
+
);
|
|
286
|
+
const screenSince = /* @__PURE__ */ new Map();
|
|
287
|
+
let screenOrder = 0;
|
|
288
|
+
const newestScreen = ref(null);
|
|
289
|
+
watch(
|
|
290
|
+
screenTiles,
|
|
291
|
+
(current) => {
|
|
292
|
+
const ids = new Set(current.map((t) => t.id));
|
|
293
|
+
for (const id of [...screenSince.keys()]) if (!ids.has(id)) screenSince.delete(id);
|
|
294
|
+
for (const id of ids) if (!screenSince.has(id)) screenSince.set(id, ++screenOrder);
|
|
295
|
+
const ranked = [...ids].sort(
|
|
296
|
+
(a, b) => Number(a === "self_screen") - Number(b === "self_screen") || screenSince.get(b) - screenSince.get(a)
|
|
297
|
+
);
|
|
298
|
+
newestScreen.value = ranked[0] ?? null;
|
|
299
|
+
},
|
|
300
|
+
{ immediate: true }
|
|
301
|
+
);
|
|
302
|
+
const pinnedId = ref(null);
|
|
303
|
+
function togglePin(tileId) {
|
|
304
|
+
pinnedId.value = pinnedId.value === tileId ? null : tileId;
|
|
305
|
+
}
|
|
306
|
+
watch(tiles, (current) => {
|
|
307
|
+
if (pinnedId.value && !current.some((t) => t.id === pinnedId.value)) pinnedId.value = null;
|
|
308
|
+
});
|
|
309
|
+
const remoteCount = computed(() => participants.value.length - 1);
|
|
310
|
+
const mode = computed(() => {
|
|
311
|
+
if (pinnedId.value || newestScreen.value) return "stage";
|
|
312
|
+
if (remoteCount.value <= 0) return "solo";
|
|
313
|
+
if (remoteCount.value === 1) return "pair";
|
|
314
|
+
return "grid";
|
|
315
|
+
});
|
|
316
|
+
const stageTile = computed(() => {
|
|
317
|
+
if (mode.value !== "stage") return null;
|
|
318
|
+
const id = pinnedId.value ?? newestScreen.value;
|
|
319
|
+
return tiles.value.find((t) => t.id === id) ?? null;
|
|
320
|
+
});
|
|
321
|
+
const stripTiles = computed(
|
|
322
|
+
() => mode.value === "stage" ? tiles.value.filter((t) => {
|
|
323
|
+
var _a;
|
|
324
|
+
return t.id !== ((_a = stageTile.value) == null ? void 0 : _a.id);
|
|
325
|
+
}) : []
|
|
326
|
+
);
|
|
327
|
+
const gridTiles = computed(() => mode.value === "grid" ? cameraTiles.value : []);
|
|
328
|
+
const orientation = computed(
|
|
329
|
+
() => height.value > width.value ? "portrait" : "landscape"
|
|
330
|
+
);
|
|
331
|
+
const gridClass = "grid size-full grid-cols-2 grid-rows-2 gap-(--call-gap)";
|
|
332
|
+
const cellClass = (index) => gridTiles.value.length === 3 && index === 2 ? "col-span-2 w-[calc(50%-var(--call-gap)/2)] justify-self-center" : "";
|
|
333
|
+
const key = computed(
|
|
334
|
+
() => {
|
|
335
|
+
var _a;
|
|
336
|
+
return `${mode.value}|${((_a = stageTile.value) == null ? void 0 : _a.id) ?? ""}|${tiles.value.map((t) => t.id).join()}`;
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
return {
|
|
340
|
+
mode,
|
|
341
|
+
tiles,
|
|
342
|
+
gridTiles,
|
|
343
|
+
stageTile,
|
|
344
|
+
stripTiles,
|
|
345
|
+
pinnedId,
|
|
346
|
+
togglePin,
|
|
347
|
+
orientation,
|
|
348
|
+
gridClass,
|
|
349
|
+
cellClass,
|
|
350
|
+
key
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const NOTICE_MS = 3e3;
|
|
354
|
+
function useCallNotices(participants, t, and, locale) {
|
|
355
|
+
const current = ref(null);
|
|
356
|
+
const liveText = ref("");
|
|
357
|
+
let joined = [];
|
|
358
|
+
let left = [];
|
|
359
|
+
let timer;
|
|
360
|
+
let counter = 0;
|
|
361
|
+
const list = (names) => {
|
|
362
|
+
if (names.length <= 1) return names[0] ?? "";
|
|
363
|
+
const comma = locale().startsWith("fa") || locale().startsWith("ar") ? "، " : ", ";
|
|
364
|
+
return `${names.slice(0, -1).join(comma)} ${and()} ${names[names.length - 1]}`;
|
|
365
|
+
};
|
|
366
|
+
function show() {
|
|
367
|
+
const parts = [
|
|
368
|
+
joined.length ? t("chat.call.joined", { names: list(joined) }, joined.length) : "",
|
|
369
|
+
left.length ? t("chat.call.left", { names: list(left) }, left.length) : ""
|
|
370
|
+
].filter(Boolean);
|
|
371
|
+
if (!parts.length) return;
|
|
372
|
+
const text = parts.join(" · ");
|
|
373
|
+
current.value = { text, id: ++counter };
|
|
374
|
+
liveText.value = text;
|
|
375
|
+
clearTimeout(timer);
|
|
376
|
+
timer = setTimeout(() => {
|
|
377
|
+
current.value = null;
|
|
378
|
+
joined = [];
|
|
379
|
+
left = [];
|
|
380
|
+
}, NOTICE_MS);
|
|
381
|
+
}
|
|
382
|
+
watch(
|
|
383
|
+
() => participants.value.filter((p) => !p.isSelf).map((p) => [p.id, p.name]),
|
|
384
|
+
(now, before) => {
|
|
385
|
+
if (!before) return;
|
|
386
|
+
const was = new Map(before);
|
|
387
|
+
const is = new Map(now);
|
|
388
|
+
let changed = false;
|
|
389
|
+
for (const [id, name] of is) {
|
|
390
|
+
if (was.has(id)) continue;
|
|
391
|
+
const i = left.indexOf(name);
|
|
392
|
+
if (i >= 0) left.splice(i, 1);
|
|
393
|
+
else joined.push(name);
|
|
394
|
+
changed = true;
|
|
395
|
+
}
|
|
396
|
+
for (const [id, name] of was) {
|
|
397
|
+
if (is.has(id)) continue;
|
|
398
|
+
const i = joined.indexOf(name);
|
|
399
|
+
if (i >= 0) joined.splice(i, 1);
|
|
400
|
+
left.push(name);
|
|
401
|
+
changed = true;
|
|
402
|
+
}
|
|
403
|
+
if (changed) {
|
|
404
|
+
if (joined.length || left.length) show();
|
|
405
|
+
else current.value = null;
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
{ immediate: true }
|
|
409
|
+
);
|
|
410
|
+
onBeforeUnmount(() => clearTimeout(timer));
|
|
411
|
+
return { current, liveText };
|
|
412
|
+
}
|
|
413
|
+
const _hoisted_1$3 = ["innerHTML"];
|
|
414
|
+
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
415
|
+
__name: "CallIcon",
|
|
416
|
+
props: {
|
|
417
|
+
name: {}
|
|
418
|
+
},
|
|
419
|
+
setup(__props) {
|
|
420
|
+
const ICONS = {
|
|
421
|
+
mic: '<path fill="currentColor" d="M9.875 13.125Q9 12.25 9 11V5q0-1.25.875-2.125T12 2t2.125.875T15 5v6q0 1.25-.875 2.125T12 14t-2.125-.875M11 20v-2.075q-2.3-.325-3.937-1.95t-1.988-3.95q-.05-.425.225-.725T6 11t.713.288T7.1 12q.35 1.75 1.738 2.875T12 16q1.8 0 3.175-1.137T16.9 12q.1-.425.388-.712T18 11t.7.3t.225.725q-.35 2.275-1.975 3.925T13 17.925V20q0 .425-.288.713T12 21t-.712-.288T11 20"/>',
|
|
422
|
+
micOff: '<path fill="currentColor" d="M16.8 14.575q-.35-.2-.45-.612t.1-.763q.175-.275.288-.587t.162-.638q.1-.425.388-.7T18 11t.7.3t.225.725q-.075.575-.262 1.125t-.488 1.05q-.2.35-.612.463t-.763-.088m-3.5-4.125L9.575 6.725Q9.3 6.45 9.15 6.088T9 5.325V5q0-1.25.875-2.125T12 2t2.125.875T15 5v4.725q0 .675-.612.938T13.3 10.45M11 20v-2.1q-2.3-.3-3.937-1.925t-1.988-3.95q-.05-.425.225-.725T6 11t.713.288T7.1 12q.35 1.75 1.738 2.875T12 16q.85 0 1.613-.262T15 15l1.425 1.425q-.725.575-1.588.963T13 17.9V20q0 .425-.288.713T12 21t-.712-.288T11 20m8.1 1.9l-17-17q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l17 17q.275.275.275.7t-.275.7t-.7.275t-.7-.275"/>',
|
|
423
|
+
videocam: '<path fill="currentColor" d="M4 20q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4h12q.825 0 1.413.588T18 6v4.5l3.15-3.15q.25-.25.55-.125t.3.475v8.6q0 .35-.3.475t-.55-.125L18 13.5V18q0 .825-.587 1.413T16 20z"/>',
|
|
424
|
+
videocamOff: '<path fill="currentColor" d="m18 10.5l3.15-3.15q.25-.25.55-.125t.3.475v8.6q0 .35-.3.475t-.55-.125l-3.325-3.325q-.25.35-.712.425t-.813-.275L8.525 5.7q-.25-.25-.288-.525t.088-.55t.35-.45T9.25 4H16q.825 0 1.413.588T18 6zm1.85 12.15L1.35 4.15q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l18.5 18.5q.275.275.275.7t-.275.7t-.7.275t-.7-.275M4 4l14 14q0 .825-.587 1.413T16 20H4q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4"/>',
|
|
425
|
+
presentToAll: '<path fill="currentColor" d="M11 11.825V15q0 .425.288.713T12 16t.713-.288T13 15v-3.15l.9.875q.3.275.7.288t.7-.288t.3-.712t-.3-.713l-2.6-2.6q-.3-.3-.7-.3t-.7.3l-2.6 2.6q-.3.3-.287.7t.312.7q.3.275.7.288t.7-.288zM4 20q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4h16q.825 0 1.413.588T22 6v12q0 .825-.587 1.413T20 20z"/>',
|
|
426
|
+
cancelPresentation: '<path fill="currentColor" d="m10.6 12l-1.9 1.9q-.275.275-.275.7t.275.7t.7.275t.7-.275l1.9-1.9l1.9 1.9q.275.275.7.275t.7-.275t.275-.7t-.275-.7L13.4 12l1.9-1.9q.275-.275.275-.7t-.275-.7t-.7-.275t-.7.275L12 10.6l-1.9-1.9q-.275-.275-.7-.275t-.7.275t-.275.7t.275.7zM4 20q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4h16q.825 0 1.413.588T22 6v12q0 .825-.587 1.413T20 20z"/>',
|
|
427
|
+
callEnd: '<path fill="currentColor" d="M12 8q2.95 0 5.813 1.188T22.9 12.75q.3.3.3.7t-.3.7l-2.3 2.25q-.275.275-.638.3t-.662-.2l-2.9-2.2q-.2-.15-.3-.35t-.1-.45v-2.85q-.95-.3-1.95-.475T12 10t-2.05.175T8 10.65v2.85q0 .25-.1.45t-.3.35l-2.9 2.2q-.3.225-.663.2t-.637-.3l-2.3-2.25q-.3-.3-.3-.7t.3-.7q2.2-2.375 5.075-3.562T12 8"/>',
|
|
428
|
+
fullscreen: '<path fill="currentColor" d="M5 19h2q.425 0 .713.288T8 20t-.288.713T7 21H4q-.425 0-.712-.288T3 20v-3q0-.425.288-.712T4 16t.713.288T5 17zm14 0v-2q0-.425.288-.712T20 16t.713.288T21 17v3q0 .425-.288.713T20 21h-3q-.425 0-.712-.288T16 20t.288-.712T17 19zM5 5v2q0 .425-.288.713T4 8t-.712-.288T3 7V4q0-.425.288-.712T4 3h3q.425 0 .713.288T8 4t-.288.713T7 5zm14 0h-2q-.425 0-.712-.288T16 4t.288-.712T17 3h3q.425 0 .713.288T21 4v3q0 .425-.288.713T20 8t-.712-.288T19 7z"/>',
|
|
429
|
+
fullscreenExit: '<path fill="currentColor" d="M6 18H4q-.425 0-.712-.288T3 17t.288-.712T4 16h3q.425 0 .713.288T8 17v3q0 .425-.288.713T7 21t-.712-.288T6 20zm12 0v2q0 .425-.288.713T17 21t-.712-.288T16 20v-3q0-.425.288-.712T17 16h3q.425 0 .713.288T21 17t-.288.713T20 18zM6 6V4q0-.425.288-.712T7 3t.713.288T8 4v3q0 .425-.288.713T7 8H4q-.425 0-.712-.288T3 7t.288-.712T4 6zm12 0h2q.425 0 .713.288T21 7t-.288.713T20 8h-3q-.425 0-.712-.288T16 7V4q0-.425.288-.712T17 3t.713.288T18 4z"/>',
|
|
430
|
+
flashlightOn: '<path fill="currentColor" d="M6 5V4q0-.825.588-1.412T8 2h8q.825 0 1.413.588T18 4v1zm7.063 10.063q.437-.438.437-1.063t-.437-1.062T12 12.5t-1.062.438T10.5 14t.438 1.063T12 15.5t1.063-.437M8 20v-9L6.325 8.5q-.175-.25-.25-.525T6 7.4V7h12v.4q0 .3-.075.575t-.25.525L16 11v9q0 .825-.587 1.413T14 22h-4q-.825 0-1.412-.587T8 20"/>',
|
|
431
|
+
flashlightOff: '<path fill="currentColor" d="M8 20v-9.2L2.1 4.9q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l17 17q.275.275.275.7t-.275.7t-.7.275t-.7-.275L16 18.8V20q0 .825-.587 1.413T14 22h-4q-.825 0-1.412-.587T8 20M7.85 5l-1.7-1.7q.2-.575.7-.937T8 2h8q.825 0 1.413.588T18 4v1zM16 13.15L9.85 7H18v.4q0 .3-.075.575t-.25.525L16 11z"/>',
|
|
432
|
+
pause: '<path fill="currentColor" d="M16 19q-.825 0-1.412-.587T14 17V7q0-.825.588-1.412T16 5t1.413.588T18 7v10q0 .825-.587 1.413T16 19m-8 0q-.825 0-1.412-.587T6 17V7q0-.825.588-1.412T8 5t1.413.588T10 7v10q0 .825-.587 1.413T8 19"/>',
|
|
433
|
+
play: '<path fill="currentColor" d="M8 17.175V6.825q0-.425.3-.713t.7-.287q.125 0 .263.037t.262.113l8.15 5.175q.225.15.338.375t.112.475t-.112.475t-.338.375l-8.15 5.175q-.125.075-.262.113T9 18.175q-.4 0-.7-.288t-.3-.712"/>',
|
|
434
|
+
group: '<path fill="currentColor" d="M1 17.2q0-.85.438-1.562T2.6 14.55q1.55-.775 3.15-1.162T9 13t3.25.388t3.15 1.162q.725.375 1.163 1.088T17 17.2v.8q0 .825-.587 1.413T15 20H3q-.825 0-1.412-.587T1 18zM18.45 20q.275-.45.413-.962T19 18v-1q0-1.1-.612-2.113T16.65 13.15q1.275.15 2.4.513t2.1.887q.9.5 1.375 1.112T23 17v1q0 .825-.587 1.413T21 20zM6.175 10.825Q5 9.65 5 8t1.175-2.825T9 4t2.825 1.175T13 8t-1.175 2.825T9 12t-2.825-1.175m11.65 0Q16.65 12 15 12q-.275 0-.7-.062t-.7-.138q.675-.8 1.038-1.775T15 8t-.362-2.025T13.6 4.2q.35-.125.7-.163T15 4q1.65 0 2.825 1.175T19 8t-1.175 2.825"/>',
|
|
435
|
+
pictureInPicture: '<path fill="currentColor" d="M4 20q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4h16q.825 0 1.413.588T22 6v12q0 .825-.587 1.413T20 20zm8-3h6q.425 0 .713-.288T19 16v-4q0-.425-.288-.712T18 11h-6q-.425 0-.712.288T11 12v4q0 .425.288.713T12 17m3-3"/>',
|
|
436
|
+
openInFull: '<path fill="currentColor" d="M4 21q-.425 0-.712-.288T3 20v-6q0-.425.288-.712T4 13t.713.288T5 14v3.6L17.6 5H14q-.425 0-.712-.288T13 4t.288-.712T14 3h6q.425 0 .713.288T21 4v6q0 .425-.288.713T20 11t-.712-.288T19 10V6.4L6.4 19H10q.425 0 .713.288T11 20t-.288.713T10 21z"/>',
|
|
437
|
+
volumeUp: '<path fill="currentColor" d="M19 11.975q0-2.075-1.1-3.787t-2.95-2.563q-.375-.175-.55-.537t-.05-.738q.15-.4.538-.575t.787 0Q18.1 4.85 19.55 7.063T21 11.974t-1.45 4.913t-3.875 3.287q-.4.175-.788 0t-.537-.575q-.125-.375.05-.737t.55-.538q1.85-.85 2.95-2.562t1.1-3.788M7 15H4q-.425 0-.712-.288T3 14v-4q0-.425.288-.712T4 9h3l3.3-3.3q.475-.475 1.088-.213t.612.938v11.15q0 .675-.612.938T10.3 18.3zm9.5-3q0 1.05-.475 1.988t-1.25 1.537q-.25.15-.513.013T14 15.1V8.85q0-.3.263-.437t.512.012q.775.625 1.25 1.575t.475 2"/>',
|
|
438
|
+
cameraSwitch: '<path fill="currentColor" d="M8 17q-.825 0-1.412-.587T6 15V9q0-.825.588-1.412T8 7h1l.7-.7q.15-.15.338-.225T10.425 6h3.15q.2 0 .388.075t.337.225l.7.7h1q.825 0 1.412.588T18 9v6q0 .825-.587 1.413T16 17zm4-3q.825 0 1.413-.587T14 12t-.587-1.412T12 10t-1.412.588T10 12t.588 1.413T12 14m0 10q-4.4 0-7.712-2.762T.174 14.275Q.1 13.85.337 13.5T1 13.1t.75.213t.4.687q.65 3.275 3.113 5.475T11.1 21.95l-.85-.85q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l3.3 3.3q.175.175.113.4t-.288.275q-.675.175-1.362.25T12 24m0-24q4.4 0 7.713 2.75t4.112 6.975q.075.425-.162.775t-.663.4t-.75-.213t-.4-.687q-.65-3.275-3.113-5.475T12.9 2.05l.85.85q.275.275.275.7t-.275.7t-.7.275t-.7-.275L9.05 1Q8.875.825 8.938.6t.287-.275Q9.9.15 10.588.075T12 0"/>',
|
|
439
|
+
arrowDropUp: '<path fill="currentColor" d="M8.2 14q-.225 0-.362-.15T7.7 13.5q0-.05.15-.35l3.625-3.625q.125-.125.25-.175T12 9.3t.275.05t.25.175l3.625 3.625q.075.075.113.163t.037.187q0 .2-.137.35T15.8 14z"/>',
|
|
440
|
+
moreVert: '<path fill="currentColor" d="M12 20q-.825 0-1.412-.587T10 18t.588-1.412T12 16t1.413.588T14 18t-.587 1.413T12 20m0-6q-.825 0-1.412-.587T10 12t.588-1.412T12 10t1.413.588T14 12t-.587 1.413T12 14m0-6q-.825 0-1.412-.587T10 6t.588-1.412T12 4t1.413.588T14 6t-.587 1.413T12 8"/>',
|
|
441
|
+
check: '<path fill="currentColor" d="m9.55 15.15l8.475-8.475q.3-.3.7-.3t.7.3t.3.713t-.3.712l-9.175 9.2q-.3.3-.7.3t-.7-.3L4.55 13q-.3-.3-.288-.712t.313-.713t.713-.3t.712.3z"/>',
|
|
442
|
+
keep: '<path fill="currentColor" d="M16 5v7l1.7 1.7q.15.15.225.338t.075.387V15q0 .425-.288.712T17 16h-4v5.85q0 .425-.288.713T12 22.85t-.712-.288T11 21.85V16H7q-.425 0-.712-.288T6 15v-.575q0-.2.075-.387T6.3 13.7L8 12V5q-.425 0-.712-.288T7 4t.288-.712T8 3h8q.425 0 .713.288T17 4t-.288.713T16 5"/>',
|
|
443
|
+
keepOff: '<path fill="currentColor" d="m14.3 11.475l-7.05-7.05q-.125-.125-.187-.275T7 3.85q0-.325.225-.588t.6-.262H16q.425 0 .713.287T17 4q0 .4-.363.563T16 5v5.75q0 .675-.612.938t-1.088-.213M11 22v-6H7.4q-.625 0-1-.437t-.375-.988q0-.275.113-.55T6.5 13.5L8 12v-1.15L2.1 4.9q-.275-.275-.288-.687T2.1 3.5q.275-.275.7-.275t.7.275l16.975 16.975q.3.3.288.713t-.313.712q-.3.275-.7.288t-.7-.288l-5.9-5.9H13v6q0 .425-.288.713T12 23t-.712-.288T11 22"/>',
|
|
444
|
+
close: '<path fill="currentColor" d="m12 13.4l-4.9 4.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7l4.9-4.9l-4.9-4.9q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.9 4.9l4.9-4.9q.275-.275.7-.275t.7.275t.275.7t-.275.7L13.4 12l4.9 4.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275z"/>',
|
|
445
|
+
refresh: '<path fill="currentColor" d="M12 20q-3.35 0-5.675-2.325T4 12t2.325-5.675T12 4q1.725 0 3.3.712T18 6.75V5q0-.425.288-.712T19 4t.713.288T20 5v5q0 .425-.288.713T19 11h-5q-.425 0-.712-.288T13 10t.288-.712T14 9h3.2q-.8-1.4-2.187-2.2T12 6Q9.5 6 7.75 7.75T6 12t1.75 4.25T12 18q1.7 0 3.113-.862t2.187-2.313q.2-.35.563-.487t.737-.013q.4.125.575.525t-.025.75q-1.025 2-2.925 3.2T12 20"/>'
|
|
446
|
+
};
|
|
447
|
+
return (_ctx, _cache) => {
|
|
448
|
+
return openBlock(), createElementBlock("svg", {
|
|
449
|
+
viewBox: "0 0 24 24",
|
|
450
|
+
fill: "currentColor",
|
|
451
|
+
"aria-hidden": "true",
|
|
452
|
+
focusable: "false",
|
|
453
|
+
innerHTML: ICONS[__props.name]
|
|
454
|
+
}, null, 8, _hoisted_1$3);
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
459
|
+
...{ inheritAttrs: false },
|
|
460
|
+
__name: "CallButton",
|
|
461
|
+
props: {
|
|
462
|
+
icon: {},
|
|
463
|
+
label: {},
|
|
464
|
+
iconClass: { default: "size-5" }
|
|
465
|
+
},
|
|
466
|
+
setup(__props) {
|
|
467
|
+
return (_ctx, _cache) => {
|
|
468
|
+
return openBlock(), createBlock(unref(Button), mergeProps({
|
|
469
|
+
rounded: "",
|
|
470
|
+
text: "",
|
|
471
|
+
severity: "secondary"
|
|
472
|
+
}, _ctx.$attrs, { "aria-label": __props.label }), {
|
|
473
|
+
icon: withCtx(() => [
|
|
474
|
+
createVNode(_sfc_main$4, {
|
|
475
|
+
name: __props.icon,
|
|
476
|
+
class: normalizeClass(__props.iconClass)
|
|
477
|
+
}, null, 8, ["name", "class"])
|
|
478
|
+
]),
|
|
479
|
+
_: 1
|
|
480
|
+
}, 16, ["aria-label"]);
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
const translucent = {
|
|
485
|
+
background: "rgb(255 255 255 / 0.12)",
|
|
486
|
+
hoverBackground: "rgb(255 255 255 / 0.2)",
|
|
487
|
+
activeBackground: "rgb(255 255 255 / 0.28)",
|
|
488
|
+
borderColor: "transparent",
|
|
489
|
+
hoverBorderColor: "transparent",
|
|
490
|
+
activeBorderColor: "transparent",
|
|
491
|
+
color: "#ffffff",
|
|
492
|
+
hoverColor: "#ffffff",
|
|
493
|
+
activeColor: "#ffffff"
|
|
494
|
+
};
|
|
495
|
+
const lit = {
|
|
496
|
+
background: "#ffffff",
|
|
497
|
+
hoverBackground: "rgb(255 255 255 / 0.9)",
|
|
498
|
+
activeBackground: "rgb(255 255 255 / 0.8)",
|
|
499
|
+
borderColor: "#ffffff",
|
|
500
|
+
hoverBorderColor: "#ffffff",
|
|
501
|
+
activeBorderColor: "#ffffff",
|
|
502
|
+
color: "#171717",
|
|
503
|
+
hoverColor: "#171717",
|
|
504
|
+
activeColor: "#171717"
|
|
505
|
+
};
|
|
506
|
+
const off = {
|
|
507
|
+
background: "#ef4444",
|
|
508
|
+
hoverBackground: "#dc2626",
|
|
509
|
+
activeBackground: "#b91c1c",
|
|
510
|
+
borderColor: "transparent",
|
|
511
|
+
hoverBorderColor: "transparent",
|
|
512
|
+
activeBorderColor: "transparent",
|
|
513
|
+
color: "#ffffff",
|
|
514
|
+
hoverColor: "#ffffff",
|
|
515
|
+
activeColor: "#ffffff"
|
|
516
|
+
};
|
|
517
|
+
const callScheme = { root: { secondary: translucent, contrast: lit, danger: off } };
|
|
518
|
+
const callButtonDt = { colorScheme: { light: callScheme, dark: callScheme } };
|
|
519
|
+
const callMenuDt = {
|
|
520
|
+
root: { background: "#262626", borderColor: "rgb(255 255 255 / 0.1)", color: "#f5f5f5" },
|
|
521
|
+
item: {
|
|
522
|
+
focusBackground: "rgb(255 255 255 / 0.1)",
|
|
523
|
+
color: "#f5f5f5",
|
|
524
|
+
focusColor: "#ffffff",
|
|
525
|
+
icon: { color: "#a3a3a3", focusColor: "#ffffff" }
|
|
526
|
+
},
|
|
527
|
+
submenuLabel: { background: "transparent", color: "#a3a3a3" }
|
|
528
|
+
};
|
|
529
|
+
const callDrawerDt = {
|
|
530
|
+
root: { background: "#262626", borderColor: "rgb(255 255 255 / 0.1)", color: "#f5f5f5" },
|
|
531
|
+
header: { padding: "1rem 1rem 0.5rem" },
|
|
532
|
+
content: { padding: "0 0.5rem 1rem" }
|
|
533
|
+
};
|
|
534
|
+
const tileButton = {
|
|
535
|
+
dt: callButtonDt,
|
|
536
|
+
text: false,
|
|
537
|
+
size: "small",
|
|
538
|
+
iconClass: "size-4.5",
|
|
539
|
+
class: "size-9! [@media(hover:none)]:size-11!"
|
|
540
|
+
};
|
|
541
|
+
const tileActions = "absolute end-2 bottom-2 z-20 flex items-center gap-x-1.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none [@media(hover:none)]:opacity-100";
|
|
542
|
+
const nameChip = "min-w-0 truncate rounded-md bg-black/60 px-2 py-0.5 text-label-sm text-white backdrop-blur-sm select-none";
|
|
543
|
+
const focusRing = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-900";
|
|
544
|
+
const tip = (value) => ({ value, class: "vue-chat font-chat-family" });
|
|
545
|
+
const _hoisted_1$2 = ["data-participant-id", "data-kind"];
|
|
546
|
+
const _hoisted_2$2 = ["data-testid"];
|
|
547
|
+
const _hoisted_3$2 = ["data-testid", "muted"];
|
|
548
|
+
const _hoisted_4$2 = {
|
|
549
|
+
key: 0,
|
|
550
|
+
"data-testid": "call-tile-avatar",
|
|
551
|
+
class: "absolute inset-0 flex flex-col items-center justify-center gap-y-2 bg-neutral-800 px-2 text-center"
|
|
552
|
+
};
|
|
553
|
+
const _hoisted_5$2 = {
|
|
554
|
+
key: 0,
|
|
555
|
+
class: "text-label-md text-neutral-300 select-none"
|
|
556
|
+
};
|
|
557
|
+
const _hoisted_6$2 = {
|
|
558
|
+
key: 1,
|
|
559
|
+
"data-testid": "call-tile-unreachable",
|
|
560
|
+
role: "status",
|
|
561
|
+
class: "absolute inset-0 z-30 flex flex-col items-center justify-center gap-y-3 bg-neutral-900/85 px-3 text-center"
|
|
562
|
+
};
|
|
563
|
+
const _hoisted_7$2 = {
|
|
564
|
+
key: 0,
|
|
565
|
+
class: "flex size-7 shrink-0 items-center justify-center rounded-full bg-black/60 backdrop-blur-sm"
|
|
566
|
+
};
|
|
567
|
+
const _hoisted_8$2 = ["aria-label"];
|
|
568
|
+
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
|
|
569
|
+
__name: "CallTile",
|
|
570
|
+
props: {
|
|
571
|
+
tile: {},
|
|
572
|
+
participant: {},
|
|
573
|
+
stream: { default: null },
|
|
574
|
+
speaking: { type: Boolean, default: false },
|
|
575
|
+
pinned: { type: Boolean, default: false },
|
|
576
|
+
canPin: { type: Boolean, default: false },
|
|
577
|
+
compact: { type: Boolean, default: false },
|
|
578
|
+
paused: { type: Boolean, default: false },
|
|
579
|
+
isFullscreen: { type: Boolean, default: false },
|
|
580
|
+
hint: {}
|
|
581
|
+
},
|
|
582
|
+
emits: ["pin", "pause", "fullscreen", "retry", "video"],
|
|
583
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
584
|
+
const vTooltip = Tooltip;
|
|
585
|
+
const props = __props;
|
|
586
|
+
const emit = __emit;
|
|
587
|
+
const { t } = useLocalI18n(chat);
|
|
588
|
+
const root = ref(null);
|
|
589
|
+
const videoEl = ref(null);
|
|
590
|
+
onMounted(() => emit("video", videoEl.value, null));
|
|
591
|
+
onBeforeUnmount(() => emit("video", null, videoEl.value));
|
|
592
|
+
__expose({ videoEl, root });
|
|
593
|
+
const isSelf = computed(() => props.participant.isSelf);
|
|
594
|
+
const isScreen = computed(() => props.tile.kind === "screen");
|
|
595
|
+
const status = computed(() => props.participant.status);
|
|
596
|
+
const name = computed(() => props.participant.name || (isSelf.value ? t("chat.call.you") : ""));
|
|
597
|
+
const label = computed(() => {
|
|
598
|
+
if (isScreen.value)
|
|
599
|
+
return isSelf.value ? t("chat.call.yourPresentation") : t("chat.call.presentationOf", { name: name.value });
|
|
600
|
+
return isSelf.value ? t("chat.call.you") : name.value;
|
|
601
|
+
});
|
|
602
|
+
const initials = computed(() => nameInitials(props.participant.name));
|
|
603
|
+
const toneStyle = computed(() => avatarToneStyle(props.participant.name, null, "dark"));
|
|
604
|
+
const hasVideo = computed(() => {
|
|
605
|
+
var _a;
|
|
606
|
+
return !!((_a = props.stream) == null ? void 0 : _a.getVideoTracks().length);
|
|
607
|
+
});
|
|
608
|
+
const showAvatar = computed(
|
|
609
|
+
() => {
|
|
610
|
+
var _a;
|
|
611
|
+
return !isScreen.value && (((_a = props.participant.media) == null ? void 0 : _a.video) === false || !hasVideo.value);
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
const muted = computed(() => {
|
|
615
|
+
var _a;
|
|
616
|
+
return !isScreen.value && ((_a = props.participant.media) == null ? void 0 : _a.audio) === false;
|
|
617
|
+
});
|
|
618
|
+
const unreachable = computed(() => !isSelf.value && status.value === "unreachable");
|
|
619
|
+
const statusText = computed(() => {
|
|
620
|
+
if (isSelf.value) return props.hint;
|
|
621
|
+
if (status.value === "connecting") return t("chat.call.connecting");
|
|
622
|
+
if (status.value === "recovering") return t("chat.call.reconnecting");
|
|
623
|
+
return props.hint;
|
|
624
|
+
});
|
|
625
|
+
const innerTestId = computed(() => {
|
|
626
|
+
if (isSelf.value) return void 0;
|
|
627
|
+
if (isScreen.value) return "call-remote-screen";
|
|
628
|
+
return props.stream ? "call-remote-video" : void 0;
|
|
629
|
+
});
|
|
630
|
+
const pinLabel = computed(
|
|
631
|
+
() => props.pinned ? t("chat.call.controls.unpin") : t("chat.call.controls.pin")
|
|
632
|
+
);
|
|
633
|
+
const pauseLabel = computed(
|
|
634
|
+
() => props.paused ? t("chat.call.controls.playVideo") : t("chat.call.controls.pauseVideo")
|
|
635
|
+
);
|
|
636
|
+
const fullscreenLabel = computed(
|
|
637
|
+
() => props.isFullscreen ? t("chat.call.controls.exitFullscreen") : t("chat.call.controls.fullscreen")
|
|
638
|
+
);
|
|
639
|
+
return (_ctx, _cache) => {
|
|
640
|
+
return openBlock(), createElementBlock("div", {
|
|
641
|
+
ref_key: "root",
|
|
642
|
+
ref: root,
|
|
643
|
+
"data-testid": "call-tile",
|
|
644
|
+
"data-participant-id": __props.participant.id,
|
|
645
|
+
"data-kind": __props.tile.kind,
|
|
646
|
+
class: normalizeClass(["group relative min-h-0 min-w-0 overflow-hidden rounded-2xl bg-neutral-800 ring-3 ring-inset transition-shadow [clip-path:inset(0_round_var(--radius-2xl))] motion-reduce:transition-none", __props.speaking && !isScreen.value ? "ring-sky-400" : "ring-transparent"])
|
|
647
|
+
}, [
|
|
648
|
+
createElementVNode("div", {
|
|
649
|
+
class: "absolute inset-0",
|
|
650
|
+
"data-testid": innerTestId.value
|
|
651
|
+
}, [
|
|
652
|
+
createElementVNode("video", {
|
|
653
|
+
ref_key: "videoEl",
|
|
654
|
+
ref: videoEl,
|
|
655
|
+
"data-testid": __props.tile.kind === "self" ? "call-local-video" : void 0,
|
|
656
|
+
autoplay: "",
|
|
657
|
+
playsinline: "",
|
|
658
|
+
muted: isSelf.value || isScreen.value,
|
|
659
|
+
class: normalizeClass(["absolute inset-0 size-full rounded-[inherit]", [
|
|
660
|
+
isScreen.value ? "object-contain" : "object-cover",
|
|
661
|
+
__props.tile.kind === "self" && "pointer-events-none -scale-x-100"
|
|
662
|
+
]])
|
|
663
|
+
}, null, 10, _hoisted_3$2),
|
|
664
|
+
showAvatar.value ? (openBlock(), createElementBlock("div", _hoisted_4$2, [
|
|
665
|
+
createVNode(unref(Avatar), {
|
|
666
|
+
label: initials.value || void 0,
|
|
667
|
+
shape: "circle",
|
|
668
|
+
size: __props.compact ? "large" : "xlarge",
|
|
669
|
+
class: "font-semibold select-none",
|
|
670
|
+
style: normalizeStyle(toneStyle.value)
|
|
671
|
+
}, createSlots({ _: 2 }, [
|
|
672
|
+
!initials.value ? {
|
|
673
|
+
name: "icon",
|
|
674
|
+
fn: withCtx(() => [
|
|
675
|
+
createVNode(_sfc_main$5, {
|
|
676
|
+
icon: "PhUser",
|
|
677
|
+
class: "size-1/2"
|
|
678
|
+
})
|
|
679
|
+
]),
|
|
680
|
+
key: "0"
|
|
681
|
+
} : void 0
|
|
682
|
+
]), 1032, ["label", "size", "style"]),
|
|
683
|
+
statusText.value && !__props.compact ? (openBlock(), createElementBlock("p", _hoisted_5$2, toDisplayString(statusText.value), 1)) : createCommentVNode("", true)
|
|
684
|
+
])) : createCommentVNode("", true),
|
|
685
|
+
unreachable.value ? (openBlock(), createElementBlock("div", _hoisted_6$2, [
|
|
686
|
+
createElementVNode("p", {
|
|
687
|
+
class: normalizeClass(["text-label-md text-neutral-100", __props.compact && "sr-only"])
|
|
688
|
+
}, toDisplayString(unref(t)("chat.call.cantConnect", { name: name.value })), 3),
|
|
689
|
+
createVNode(unref(Button), {
|
|
690
|
+
label: __props.compact ? void 0 : unref(t)("chat.call.controls.retry"),
|
|
691
|
+
"aria-label": unref(t)("chat.call.controls.retry"),
|
|
692
|
+
dt: unref(callButtonDt),
|
|
693
|
+
severity: "contrast",
|
|
694
|
+
rounded: "",
|
|
695
|
+
size: "small",
|
|
696
|
+
"data-testid": "call-tile-retry",
|
|
697
|
+
class: normalizeClass(["min-h-11 min-w-11", unref(focusRing)]),
|
|
698
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("retry"))
|
|
699
|
+
}, {
|
|
700
|
+
icon: withCtx(() => [
|
|
701
|
+
createVNode(_sfc_main$4, {
|
|
702
|
+
name: "refresh",
|
|
703
|
+
class: "size-5"
|
|
704
|
+
})
|
|
705
|
+
]),
|
|
706
|
+
_: 1
|
|
707
|
+
}, 8, ["label", "aria-label", "dt", "class"])
|
|
708
|
+
])) : createCommentVNode("", true),
|
|
709
|
+
createElementVNode("div", {
|
|
710
|
+
class: normalizeClass(["absolute start-2 bottom-2 z-20 flex items-center gap-x-1.5", __props.compact ? "max-w-[calc(100%-3.5rem)]" : "max-w-[60%]"])
|
|
711
|
+
}, [
|
|
712
|
+
isScreen.value ? (openBlock(), createElementBlock("span", _hoisted_7$2, [
|
|
713
|
+
createVNode(_sfc_main$4, {
|
|
714
|
+
name: "presentToAll",
|
|
715
|
+
class: "size-4"
|
|
716
|
+
})
|
|
717
|
+
])) : createCommentVNode("", true),
|
|
718
|
+
muted.value ? (openBlock(), createElementBlock("span", {
|
|
719
|
+
key: 1,
|
|
720
|
+
"data-testid": "call-tile-muted",
|
|
721
|
+
role: "img",
|
|
722
|
+
"aria-label": unref(t)("chat.call.muted"),
|
|
723
|
+
class: "flex size-7 shrink-0 items-center justify-center rounded-full bg-red-500 text-white"
|
|
724
|
+
}, [
|
|
725
|
+
createVNode(_sfc_main$4, {
|
|
726
|
+
name: "micOff",
|
|
727
|
+
class: "size-4"
|
|
728
|
+
})
|
|
729
|
+
], 8, _hoisted_8$2)) : createCommentVNode("", true),
|
|
730
|
+
createElementVNode("span", {
|
|
731
|
+
class: normalizeClass(unref(nameChip))
|
|
732
|
+
}, [
|
|
733
|
+
createElementVNode("bdi", null, toDisplayString(label.value), 1)
|
|
734
|
+
], 2)
|
|
735
|
+
], 2),
|
|
736
|
+
!unreachable.value ? (openBlock(), createElementBlock("div", {
|
|
737
|
+
key: 2,
|
|
738
|
+
class: normalizeClass(unref(tileActions))
|
|
739
|
+
}, [
|
|
740
|
+
__props.canPin ? withDirectives((openBlock(), createBlock(_sfc_main$3, mergeProps({
|
|
741
|
+
key: 0,
|
|
742
|
+
icon: __props.pinned ? "keepOff" : "keep",
|
|
743
|
+
label: pinLabel.value,
|
|
744
|
+
"aria-pressed": __props.pinned
|
|
745
|
+
}, unref(tileButton), {
|
|
746
|
+
class: unref(focusRing),
|
|
747
|
+
"data-testid": "call-pin",
|
|
748
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("pin"))
|
|
749
|
+
}), null, 16, ["icon", "label", "aria-pressed", "class"])), [
|
|
750
|
+
[
|
|
751
|
+
unref(vTooltip),
|
|
752
|
+
unref(tip)(pinLabel.value),
|
|
753
|
+
void 0,
|
|
754
|
+
{ top: true }
|
|
755
|
+
]
|
|
756
|
+
]) : createCommentVNode("", true),
|
|
757
|
+
!__props.compact && !showAvatar.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
758
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
759
|
+
icon: __props.paused ? "play" : "pause",
|
|
760
|
+
label: pauseLabel.value
|
|
761
|
+
}, unref(tileButton), {
|
|
762
|
+
class: unref(focusRing),
|
|
763
|
+
onClick: _cache[2] || (_cache[2] = ($event) => emit("pause", videoEl.value))
|
|
764
|
+
}), null, 16, ["icon", "label", "class"]), [
|
|
765
|
+
[
|
|
766
|
+
unref(vTooltip),
|
|
767
|
+
unref(tip)(pauseLabel.value),
|
|
768
|
+
void 0,
|
|
769
|
+
{ top: true }
|
|
770
|
+
]
|
|
771
|
+
]),
|
|
772
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
773
|
+
icon: __props.isFullscreen ? "fullscreenExit" : "fullscreen",
|
|
774
|
+
label: fullscreenLabel.value
|
|
775
|
+
}, unref(tileButton), {
|
|
776
|
+
class: unref(focusRing),
|
|
777
|
+
onClick: _cache[3] || (_cache[3] = ($event) => emit("fullscreen", root.value))
|
|
778
|
+
}), null, 16, ["icon", "label", "class"]), [
|
|
779
|
+
[
|
|
780
|
+
unref(vTooltip),
|
|
781
|
+
unref(tip)(fullscreenLabel.value),
|
|
782
|
+
void 0,
|
|
783
|
+
{ top: true }
|
|
784
|
+
]
|
|
785
|
+
])
|
|
786
|
+
], 64)) : createCommentVNode("", true)
|
|
787
|
+
], 2)) : createCommentVNode("", true)
|
|
788
|
+
], 8, _hoisted_2$2)
|
|
789
|
+
], 10, _hoisted_1$2);
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
const _hoisted_1$1 = { class: "flex w-full items-center justify-between gap-x-2" };
|
|
794
|
+
const _hoisted_2$1 = { class: "text-title-md text-white" };
|
|
795
|
+
const _hoisted_3$1 = { class: "ms-1 text-neutral-400" };
|
|
796
|
+
const _hoisted_4$1 = { class: "flex flex-col" };
|
|
797
|
+
const _hoisted_5$1 = ["data-participant-id"];
|
|
798
|
+
const _hoisted_6$1 = { class: "min-w-0 flex-1" };
|
|
799
|
+
const _hoisted_7$1 = { class: "truncate text-body-md text-neutral-100" };
|
|
800
|
+
const _hoisted_8$1 = {
|
|
801
|
+
key: 0,
|
|
802
|
+
class: "text-neutral-400"
|
|
803
|
+
};
|
|
804
|
+
const _hoisted_9$1 = ["data-testid"];
|
|
805
|
+
const _hoisted_10$1 = {
|
|
806
|
+
key: 0,
|
|
807
|
+
class: "flex shrink-0 items-center gap-x-1.5 text-neutral-300"
|
|
808
|
+
};
|
|
809
|
+
const _hoisted_11$1 = ["aria-label"];
|
|
810
|
+
const _hoisted_12$1 = ["aria-label"];
|
|
811
|
+
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
812
|
+
__name: "CallParticipants",
|
|
813
|
+
props: /* @__PURE__ */ mergeModels({
|
|
814
|
+
participants: {}
|
|
815
|
+
}, {
|
|
816
|
+
"visible": { type: Boolean, ...{ default: false } },
|
|
817
|
+
"visibleModifiers": {}
|
|
818
|
+
}),
|
|
819
|
+
emits: ["update:visible"],
|
|
820
|
+
setup(__props) {
|
|
821
|
+
const visible = useModel(__props, "visible");
|
|
822
|
+
const { t } = useLocalI18n(chat);
|
|
823
|
+
const { dir } = useDirection();
|
|
824
|
+
const position = computed(() => dir.value === "rtl" ? "left" : "right");
|
|
825
|
+
const nameOf = (p) => p.name || (p.isSelf ? t("chat.call.you") : "");
|
|
826
|
+
const initialsOf = (p) => nameInitials(p.name);
|
|
827
|
+
const statusOf = (p) => p.isSelf ? "" : p.status === "unreachable" ? t("chat.call.cantConnect", { name: nameOf(p) }) : p.status === "recovering" ? t("chat.call.reconnecting") : p.status === "connecting" ? t("chat.call.connecting") : "";
|
|
828
|
+
return (_ctx, _cache) => {
|
|
829
|
+
return openBlock(), createBlock(unref(Drawer), {
|
|
830
|
+
visible: visible.value,
|
|
831
|
+
"onUpdate:visible": _cache[1] || (_cache[1] = ($event) => visible.value = $event),
|
|
832
|
+
position: position.value,
|
|
833
|
+
dt: unref(callDrawerDt),
|
|
834
|
+
"show-close-icon": false,
|
|
835
|
+
dir: unref(dir),
|
|
836
|
+
class: "vue-chat font-chat-family w-full! sm:w-80!",
|
|
837
|
+
"data-testid": "call-people-list"
|
|
838
|
+
}, {
|
|
839
|
+
header: withCtx(() => [
|
|
840
|
+
createElementVNode("div", _hoisted_1$1, [
|
|
841
|
+
createElementVNode("h2", _hoisted_2$1, [
|
|
842
|
+
createTextVNode(toDisplayString(unref(t)("chat.call.people")) + " ", 1),
|
|
843
|
+
createElementVNode("span", _hoisted_3$1, "(" + toDisplayString(__props.participants.length) + ")", 1)
|
|
844
|
+
]),
|
|
845
|
+
createVNode(_sfc_main$3, {
|
|
846
|
+
icon: "close",
|
|
847
|
+
label: unref(t)("chat.call.controls.closePeople"),
|
|
848
|
+
dt: unref(callButtonDt),
|
|
849
|
+
text: false,
|
|
850
|
+
"icon-class": "size-5",
|
|
851
|
+
class: normalizeClass(["size-11!", unref(focusRing)]),
|
|
852
|
+
"data-testid": "call-people-close",
|
|
853
|
+
onClick: _cache[0] || (_cache[0] = ($event) => visible.value = false)
|
|
854
|
+
}, null, 8, ["label", "dt", "class"])
|
|
855
|
+
])
|
|
856
|
+
]),
|
|
857
|
+
default: withCtx(() => [
|
|
858
|
+
createElementVNode("ul", _hoisted_4$1, [
|
|
859
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.participants, (p) => {
|
|
860
|
+
return openBlock(), createElementBlock("li", {
|
|
861
|
+
key: p.id,
|
|
862
|
+
"data-testid": "call-participant",
|
|
863
|
+
"data-participant-id": p.id,
|
|
864
|
+
class: "flex min-h-14 items-center gap-x-3 rounded-xl px-2 py-2"
|
|
865
|
+
}, [
|
|
866
|
+
createVNode(unref(Avatar), {
|
|
867
|
+
label: initialsOf(p) || void 0,
|
|
868
|
+
shape: "circle",
|
|
869
|
+
class: "shrink-0 font-semibold select-none",
|
|
870
|
+
style: normalizeStyle(unref(avatarToneStyle)(p.name, null, "dark"))
|
|
871
|
+
}, createSlots({ _: 2 }, [
|
|
872
|
+
!initialsOf(p) ? {
|
|
873
|
+
name: "icon",
|
|
874
|
+
fn: withCtx(() => [
|
|
875
|
+
createVNode(_sfc_main$5, {
|
|
876
|
+
icon: "PhUser",
|
|
877
|
+
class: "size-1/2"
|
|
878
|
+
})
|
|
879
|
+
]),
|
|
880
|
+
key: "0"
|
|
881
|
+
} : void 0
|
|
882
|
+
]), 1032, ["label", "style"]),
|
|
883
|
+
createElementVNode("div", _hoisted_6$1, [
|
|
884
|
+
createElementVNode("p", _hoisted_7$1, [
|
|
885
|
+
createElementVNode("bdi", null, toDisplayString(nameOf(p)), 1),
|
|
886
|
+
p.isSelf ? (openBlock(), createElementBlock("span", _hoisted_8$1, " (" + toDisplayString(unref(t)("chat.call.you")) + ")", 1)) : createCommentVNode("", true)
|
|
887
|
+
]),
|
|
888
|
+
statusOf(p) ? (openBlock(), createElementBlock("p", {
|
|
889
|
+
key: 0,
|
|
890
|
+
"data-testid": p.status === "unreachable" ? "call-participant-unreachable" : void 0,
|
|
891
|
+
class: normalizeClass(["truncate text-label-sm", p.status === "unreachable" ? "text-red-400" : "text-neutral-400"])
|
|
892
|
+
}, toDisplayString(statusOf(p)), 11, _hoisted_9$1)) : createCommentVNode("", true)
|
|
893
|
+
]),
|
|
894
|
+
p.media ? (openBlock(), createElementBlock("span", _hoisted_10$1, [
|
|
895
|
+
createElementVNode("span", {
|
|
896
|
+
role: "img",
|
|
897
|
+
"aria-label": p.media.audio ? unref(t)("chat.call.micOn") : unref(t)("chat.call.muted"),
|
|
898
|
+
class: normalizeClass(!p.media.audio && "text-red-400")
|
|
899
|
+
}, [
|
|
900
|
+
createVNode(_sfc_main$4, {
|
|
901
|
+
name: p.media.audio ? "mic" : "micOff",
|
|
902
|
+
class: "size-5"
|
|
903
|
+
}, null, 8, ["name"])
|
|
904
|
+
], 10, _hoisted_11$1),
|
|
905
|
+
createElementVNode("span", {
|
|
906
|
+
role: "img",
|
|
907
|
+
"aria-label": p.media.video ? unref(t)("chat.call.cameraOn") : unref(t)("chat.call.cameraOff"),
|
|
908
|
+
class: normalizeClass(!p.media.video && "text-red-400")
|
|
909
|
+
}, [
|
|
910
|
+
createVNode(_sfc_main$4, {
|
|
911
|
+
name: p.media.video ? "videocam" : "videocamOff",
|
|
912
|
+
class: "size-5"
|
|
913
|
+
}, null, 8, ["name"])
|
|
914
|
+
], 10, _hoisted_12$1)
|
|
915
|
+
])) : createCommentVNode("", true)
|
|
916
|
+
], 8, _hoisted_5$1);
|
|
917
|
+
}), 128))
|
|
918
|
+
])
|
|
919
|
+
]),
|
|
920
|
+
_: 1
|
|
921
|
+
}, 8, ["visible", "position", "dt", "dir"]);
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
const _hoisted_1 = ["dir"];
|
|
926
|
+
const _hoisted_2 = { class: "absolute inset-x-3 top-3 flex items-center justify-between" };
|
|
927
|
+
const _hoisted_3 = { class: "flex items-center gap-x-2 rounded-full bg-black/45 px-3 py-1.5 text-label-sm text-white backdrop-blur-sm select-none" };
|
|
928
|
+
const _hoisted_4 = {
|
|
929
|
+
dir: "ltr",
|
|
930
|
+
class: "tabular-nums"
|
|
931
|
+
};
|
|
932
|
+
const _hoisted_5 = { class: "absolute inset-x-3 bottom-3 flex items-center justify-between" };
|
|
933
|
+
const _hoisted_6 = { class: "flex items-center gap-1.5" };
|
|
934
|
+
const _hoisted_7 = {
|
|
935
|
+
key: 0,
|
|
936
|
+
class: "flex size-8 items-center justify-center rounded-full bg-red-500 text-white"
|
|
937
|
+
};
|
|
938
|
+
const _hoisted_8 = {
|
|
939
|
+
key: 1,
|
|
940
|
+
class: "flex size-8 items-center justify-center rounded-full bg-red-500 text-white"
|
|
941
|
+
};
|
|
942
|
+
const _hoisted_9 = ["dir"];
|
|
943
|
+
const _hoisted_10 = { class: "flex min-w-0 flex-1 items-center gap-x-3 select-none" };
|
|
944
|
+
const _hoisted_11 = { class: "truncate text-title-sm text-white" };
|
|
945
|
+
const _hoisted_12 = {
|
|
946
|
+
dir: "ltr",
|
|
947
|
+
class: "shrink-0 text-body-md text-neutral-300 tabular-nums"
|
|
948
|
+
};
|
|
949
|
+
const _hoisted_13 = {
|
|
950
|
+
"data-testid": "call-participants",
|
|
951
|
+
class: "flex shrink-0 items-center gap-x-2"
|
|
952
|
+
};
|
|
953
|
+
const _hoisted_14 = {
|
|
954
|
+
"data-testid": "call-participant-count",
|
|
955
|
+
"aria-hidden": "true",
|
|
956
|
+
class: "text-label-md tabular-nums"
|
|
957
|
+
};
|
|
958
|
+
const _hoisted_15 = { class: "max-w-full truncate rounded-full bg-black/70 px-4 py-1.5 text-label-md text-white shadow-lg backdrop-blur-sm" };
|
|
959
|
+
const _hoisted_16 = {
|
|
960
|
+
class: "sr-only",
|
|
961
|
+
"aria-live": "polite"
|
|
962
|
+
};
|
|
963
|
+
const _hoisted_17 = {
|
|
964
|
+
key: 0,
|
|
965
|
+
"data-testid": "call-waiting",
|
|
966
|
+
role: "status",
|
|
967
|
+
class: "pointer-events-none absolute inset-x-0 top-8 z-30 flex justify-center px-4"
|
|
968
|
+
};
|
|
969
|
+
const _hoisted_18 = { class: "max-w-full rounded-2xl bg-black/65 px-5 py-3 text-center shadow-lg backdrop-blur-sm" };
|
|
970
|
+
const _hoisted_19 = { class: "truncate text-title-sm text-white" };
|
|
971
|
+
const _hoisted_20 = { class: "mt-0.5 text-label-md text-neutral-200" };
|
|
972
|
+
const _hoisted_21 = { class: "flex items-center justify-center gap-x-2 sm:gap-x-3" };
|
|
973
|
+
const _hoisted_22 = {
|
|
974
|
+
key: 1,
|
|
975
|
+
class: "size-5"
|
|
976
|
+
};
|
|
977
|
+
const PIP_WIDTH = 280;
|
|
978
|
+
const PIP_HEIGHT = 160;
|
|
979
|
+
const PADDING = 16;
|
|
980
|
+
const PIP_INSET_Y = 96;
|
|
981
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
982
|
+
__name: "Call",
|
|
983
|
+
setup(__props) {
|
|
984
|
+
const vTooltip = Tooltip;
|
|
985
|
+
const callStore = useCallStore();
|
|
986
|
+
const minimizedRef = ref(null);
|
|
987
|
+
const bodyRef = ref(null);
|
|
988
|
+
const { t, locale } = useLocalI18n(chat);
|
|
989
|
+
const { dir } = useDirection();
|
|
990
|
+
const chatStore = useChatStore();
|
|
991
|
+
const callTitle = computed(() => {
|
|
992
|
+
const contact = callStore.channelId ? chatStore.getContactById(callStore.channelId) : null;
|
|
993
|
+
const name = contact ? `${contact.name} ${contact.lastName ?? ""}`.trim() : "";
|
|
994
|
+
return name || t("chat.call.title");
|
|
995
|
+
});
|
|
996
|
+
const layoutKey = ref("");
|
|
997
|
+
const {
|
|
998
|
+
toggleVideoPause,
|
|
999
|
+
toggleRemote,
|
|
1000
|
+
participantCount,
|
|
1001
|
+
participants,
|
|
1002
|
+
phase,
|
|
1003
|
+
hadOthers,
|
|
1004
|
+
endCall,
|
|
1005
|
+
toggleFullscreen,
|
|
1006
|
+
toggleFlashlight,
|
|
1007
|
+
toggleScreenShare,
|
|
1008
|
+
toggleAudio,
|
|
1009
|
+
toggleVideo,
|
|
1010
|
+
switchCamera,
|
|
1011
|
+
isFlashlightSupported,
|
|
1012
|
+
isAudioOn,
|
|
1013
|
+
isVideoOn,
|
|
1014
|
+
isFlashlightOn,
|
|
1015
|
+
isFullscreen,
|
|
1016
|
+
isScreenSharing,
|
|
1017
|
+
showControls,
|
|
1018
|
+
resetControlsTimeout,
|
|
1019
|
+
cameras,
|
|
1020
|
+
videoPaused,
|
|
1021
|
+
localStream,
|
|
1022
|
+
localVideo,
|
|
1023
|
+
localScreen,
|
|
1024
|
+
remoteRefs,
|
|
1025
|
+
remoteScreenRefs,
|
|
1026
|
+
remoteVideos,
|
|
1027
|
+
soundBlocked,
|
|
1028
|
+
enableSound,
|
|
1029
|
+
reattach,
|
|
1030
|
+
retryPeer
|
|
1031
|
+
} = useCall({ layoutKey: () => layoutKey.value });
|
|
1032
|
+
const stageRef = ref(null);
|
|
1033
|
+
const { width: stageWidth, height: stageHeight } = useElementSize(stageRef);
|
|
1034
|
+
const layout = useCallLayout({ participants, width: stageWidth, height: stageHeight });
|
|
1035
|
+
watch(layout.key, (key) => layoutKey.value = key, { immediate: true });
|
|
1036
|
+
const portrait = computed(() => layout.orientation.value === "portrait");
|
|
1037
|
+
const participantById = computed(
|
|
1038
|
+
() => new Map(participants.value.map((p) => [p.id, p]))
|
|
1039
|
+
);
|
|
1040
|
+
const participantOf = (tile) => participantById.value.get(tile.participantId);
|
|
1041
|
+
const streamOf = (tile) => {
|
|
1042
|
+
const p = participantOf(tile);
|
|
1043
|
+
return (tile.kind === "screen" ? p == null ? void 0 : p.screen : p == null ? void 0 : p.camera) ?? null;
|
|
1044
|
+
};
|
|
1045
|
+
const speakingOf = (tile) => tile.kind === "self" ? !!speaking.self : tile.kind === "camera" && !!speaking[tile.participantId];
|
|
1046
|
+
const pairRemote = computed(() => layout.tiles.value.find((t2) => t2.kind === "camera") ?? null);
|
|
1047
|
+
const selfTile = computed(() => layout.tiles.value.find((t2) => t2.kind === "self"));
|
|
1048
|
+
const canPin = computed(() => participants.value.length > 1 || isScreenSharing.value);
|
|
1049
|
+
function bindVideo(tile, el, previous) {
|
|
1050
|
+
const pid = tile.participantId;
|
|
1051
|
+
const next = (current) => el ?? (current === previous ? null : current);
|
|
1052
|
+
if (tile.kind === "self") localVideo.value = next(localVideo.value);
|
|
1053
|
+
else if (tile.id === "self_screen") localScreen.value = next(localScreen.value);
|
|
1054
|
+
else if (tile.kind === "camera") remoteRefs.value[pid] = next(remoteRefs.value[pid] ?? null);
|
|
1055
|
+
else remoteScreenRefs.value[pid] = next(remoteScreenRefs.value[pid] ?? null) ?? void 0;
|
|
1056
|
+
if (el) void reattach();
|
|
1057
|
+
}
|
|
1058
|
+
const togglePause = (tile, el) => toggleVideoPause(tile.id, el);
|
|
1059
|
+
const toggleTileFullscreen = (tile, el) => {
|
|
1060
|
+
if (el) toggleRemote(tile.id, el);
|
|
1061
|
+
};
|
|
1062
|
+
const waitingText = computed(
|
|
1063
|
+
() => hadOthers.value ? t("chat.call.everyoneLeft") : t("chat.call.waiting")
|
|
1064
|
+
);
|
|
1065
|
+
const showWaiting = computed(() => layout.mode.value === "solo" && phase.value === "waiting");
|
|
1066
|
+
const notices = useCallNotices(
|
|
1067
|
+
participants,
|
|
1068
|
+
(key, params, plural) => t(key, params, plural),
|
|
1069
|
+
() => t("chat.call.andJoin"),
|
|
1070
|
+
() => String(locale.value)
|
|
1071
|
+
);
|
|
1072
|
+
const peopleOpen = ref(false);
|
|
1073
|
+
const peopleLabel = computed(
|
|
1074
|
+
() => `${t("chat.call.controls.people")} (${t("chat.call.participants", participantCount.value)})`
|
|
1075
|
+
);
|
|
1076
|
+
const barButton = {
|
|
1077
|
+
dt: callButtonDt,
|
|
1078
|
+
text: false,
|
|
1079
|
+
size: "large",
|
|
1080
|
+
iconClass: "size-6",
|
|
1081
|
+
class: `h-12! w-12! sm:w-14! ${focusRing}`
|
|
1082
|
+
};
|
|
1083
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
1084
|
+
const keys = (key) => isMac ? `⌘ ${key}` : `Ctrl + ${key}`;
|
|
1085
|
+
const withKeys = (label, key) => `${label} (${keys(key)})`;
|
|
1086
|
+
const audioLabel = computed(
|
|
1087
|
+
() => isAudioOn.value ? t("chat.call.controls.mute") : t("chat.call.controls.unmute")
|
|
1088
|
+
);
|
|
1089
|
+
const videoLabel = computed(
|
|
1090
|
+
() => isVideoOn.value ? t("chat.call.controls.cameraOff") : t("chat.call.controls.cameraOn")
|
|
1091
|
+
);
|
|
1092
|
+
const shareLabel = computed(
|
|
1093
|
+
() => isScreenSharing.value ? t("chat.call.controls.stopSharing") : t("chat.call.controls.shareScreen")
|
|
1094
|
+
);
|
|
1095
|
+
const fullscreenLabel = computed(
|
|
1096
|
+
() => isFullscreen.value ? t("chat.call.controls.exitFullscreen") : t("chat.call.controls.fullscreen")
|
|
1097
|
+
);
|
|
1098
|
+
useEventListener(window, "keydown", (event) => {
|
|
1099
|
+
if (!callStore.isActive || callStore.isMinimized) return;
|
|
1100
|
+
if (!(isMac ? event.metaKey : event.ctrlKey) || event.altKey || event.shiftKey) return;
|
|
1101
|
+
const key = event.key.toLowerCase();
|
|
1102
|
+
if (key !== "d" && key !== "e") return;
|
|
1103
|
+
event.preventDefault();
|
|
1104
|
+
if (key === "d") toggleAudio();
|
|
1105
|
+
else toggleVideo();
|
|
1106
|
+
});
|
|
1107
|
+
const currentCameraId = ref(null);
|
|
1108
|
+
watch(
|
|
1109
|
+
localStream,
|
|
1110
|
+
(stream) => {
|
|
1111
|
+
var _a;
|
|
1112
|
+
currentCameraId.value = ((_a = stream == null ? void 0 : stream.getVideoTracks()[0]) == null ? void 0 : _a.getSettings().deviceId) ?? null;
|
|
1113
|
+
},
|
|
1114
|
+
{ immediate: true }
|
|
1115
|
+
);
|
|
1116
|
+
const cameraMenu = ref(null);
|
|
1117
|
+
const cameraItems = computed(() => [
|
|
1118
|
+
{
|
|
1119
|
+
label: t("chat.call.controls.cameras"),
|
|
1120
|
+
items: cameras.value.map((camera, index) => ({
|
|
1121
|
+
label: camera.label || `${t("chat.call.controls.chooseCamera")} ${index + 1}`,
|
|
1122
|
+
callIcon: camera.deviceId === currentCameraId.value ? "check" : void 0,
|
|
1123
|
+
command: () => {
|
|
1124
|
+
currentCameraId.value = camera.deviceId;
|
|
1125
|
+
void switchCamera(camera.deviceId);
|
|
1126
|
+
}
|
|
1127
|
+
}))
|
|
1128
|
+
}
|
|
1129
|
+
]);
|
|
1130
|
+
const moreMenu = ref(null);
|
|
1131
|
+
const moreItems = computed(() => [
|
|
1132
|
+
{
|
|
1133
|
+
label: fullscreenLabel.value,
|
|
1134
|
+
callIcon: isFullscreen.value ? "fullscreenExit" : "fullscreen",
|
|
1135
|
+
command: () => toggleFullscreen()
|
|
1136
|
+
},
|
|
1137
|
+
...isFlashlightSupported.value ? [
|
|
1138
|
+
{
|
|
1139
|
+
label: isFlashlightOn.value ? t("chat.call.controls.flashlightOff") : t("chat.call.controls.flashlightOn"),
|
|
1140
|
+
callIcon: isFlashlightOn.value ? "flashlightOff" : "flashlightOn",
|
|
1141
|
+
command: () => toggleFlashlight()
|
|
1142
|
+
}
|
|
1143
|
+
] : []
|
|
1144
|
+
]);
|
|
1145
|
+
const speaking = useSpeaking(() => ({
|
|
1146
|
+
self: isAudioOn.value ? localStream.value : null,
|
|
1147
|
+
...Object.fromEntries(
|
|
1148
|
+
Object.entries(remoteVideos.value).map(([id, remote]) => [id, remote.stream])
|
|
1149
|
+
)
|
|
1150
|
+
}));
|
|
1151
|
+
const pipVideoRef = ref(null);
|
|
1152
|
+
const activeRemoteIndex = ref(0);
|
|
1153
|
+
const remoteVideoEntries = computed(() => Object.entries(remoteVideos.value));
|
|
1154
|
+
const hasRemoteVideos = computed(() => remoteVideoEntries.value.length > 0);
|
|
1155
|
+
const activeRemoteUserId = computed(() => {
|
|
1156
|
+
const entries = remoteVideoEntries.value;
|
|
1157
|
+
if (entries.length === 0) return null;
|
|
1158
|
+
return entries[activeRemoteIndex.value % entries.length][0];
|
|
1159
|
+
});
|
|
1160
|
+
const pipStream = computed(() => {
|
|
1161
|
+
var _a;
|
|
1162
|
+
if (hasRemoteVideos.value) {
|
|
1163
|
+
const id = activeRemoteUserId.value;
|
|
1164
|
+
return id ? ((_a = remoteVideos.value[id]) == null ? void 0 : _a.stream) ?? null : null;
|
|
1165
|
+
}
|
|
1166
|
+
return localStream.value ?? null;
|
|
1167
|
+
});
|
|
1168
|
+
function cycleRemote() {
|
|
1169
|
+
const count = remoteVideoEntries.value.length;
|
|
1170
|
+
if (count === 0) return;
|
|
1171
|
+
activeRemoteIndex.value = (activeRemoteIndex.value + 1) % count;
|
|
1172
|
+
}
|
|
1173
|
+
const speakerIndex = computed(
|
|
1174
|
+
() => remoteVideoEntries.value.findIndex(([id]) => speaking[id])
|
|
1175
|
+
);
|
|
1176
|
+
let speakerTimer;
|
|
1177
|
+
watch(speakerIndex, (index) => {
|
|
1178
|
+
clearTimeout(speakerTimer);
|
|
1179
|
+
if (index < 0 || index === activeRemoteIndex.value % remoteVideoEntries.value.length) return;
|
|
1180
|
+
speakerTimer = setTimeout(() => activeRemoteIndex.value = index, 1500);
|
|
1181
|
+
});
|
|
1182
|
+
onBeforeUnmount(() => clearTimeout(speakerTimer));
|
|
1183
|
+
watch(
|
|
1184
|
+
[pipStream, () => callStore.isMinimized],
|
|
1185
|
+
async () => {
|
|
1186
|
+
await nextTick();
|
|
1187
|
+
const el = pipVideoRef.value;
|
|
1188
|
+
if (!el) return;
|
|
1189
|
+
const stream = pipStream.value;
|
|
1190
|
+
if (stream && el.srcObject !== stream) {
|
|
1191
|
+
el.srcObject = stream;
|
|
1192
|
+
el.play().catch(() => {
|
|
1193
|
+
});
|
|
1194
|
+
} else if (!stream && el.srcObject) {
|
|
1195
|
+
el.srcObject = null;
|
|
1196
|
+
}
|
|
1197
|
+
},
|
|
1198
|
+
{ immediate: true }
|
|
1199
|
+
);
|
|
1200
|
+
onMounted(() => {
|
|
1201
|
+
bodyRef.value = document.body;
|
|
1202
|
+
});
|
|
1203
|
+
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
|
1204
|
+
const { x, y, isDragging } = useDraggable(minimizedRef, {
|
|
1205
|
+
initialValue: {
|
|
1206
|
+
x: typeof window !== "undefined" ? window.innerWidth - PIP_WIDTH - PADDING : PADDING,
|
|
1207
|
+
y: PIP_INSET_Y
|
|
1208
|
+
},
|
|
1209
|
+
disabled: computed(() => !callStore.isMinimized)
|
|
1210
|
+
});
|
|
1211
|
+
watch(isDragging, (dragging) => {
|
|
1212
|
+
if (!dragging && callStore.isMinimized) {
|
|
1213
|
+
const maxX = windowWidth.value - PIP_WIDTH - PADDING;
|
|
1214
|
+
const maxY = windowHeight.value - PIP_HEIGHT - PIP_INSET_Y;
|
|
1215
|
+
x.value = x.value < windowWidth.value / 2 ? PADDING : maxX;
|
|
1216
|
+
y.value = y.value < windowHeight.value / 2 ? PIP_INSET_Y : maxY;
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
watch(
|
|
1220
|
+
() => callStore.isMinimized,
|
|
1221
|
+
(isMinimized) => {
|
|
1222
|
+
if (isMinimized) {
|
|
1223
|
+
nextTick(() => {
|
|
1224
|
+
const isRtl = dir.value === "rtl";
|
|
1225
|
+
x.value = isRtl ? PADDING : windowWidth.value - PIP_WIDTH - PADDING;
|
|
1226
|
+
y.value = PIP_INSET_Y;
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
},
|
|
1230
|
+
{ immediate: true }
|
|
1231
|
+
);
|
|
1232
|
+
const clampedStyle = computed(() => {
|
|
1233
|
+
if (!callStore.isMinimized) return {};
|
|
1234
|
+
const maxX = windowWidth.value - PIP_WIDTH - PADDING;
|
|
1235
|
+
const maxY = windowHeight.value - PIP_HEIGHT - PADDING;
|
|
1236
|
+
return {
|
|
1237
|
+
left: `${Math.max(PADDING, Math.min(x.value, maxX))}px`,
|
|
1238
|
+
top: `${Math.max(PADDING, Math.min(y.value, maxY))}px`
|
|
1239
|
+
};
|
|
1240
|
+
});
|
|
1241
|
+
const tileProps = (tile, compact = false) => ({
|
|
1242
|
+
tile,
|
|
1243
|
+
participant: participantOf(tile),
|
|
1244
|
+
stream: streamOf(tile),
|
|
1245
|
+
speaking: speakingOf(tile),
|
|
1246
|
+
pinned: layout.pinnedId.value === tile.id,
|
|
1247
|
+
canPin: canPin.value,
|
|
1248
|
+
compact,
|
|
1249
|
+
paused: !!videoPaused.value[tile.id],
|
|
1250
|
+
isFullscreen: isFullscreen.value
|
|
1251
|
+
});
|
|
1252
|
+
return (_ctx, _cache) => {
|
|
1253
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
1254
|
+
unref(callStore).isActive && unref(callStore).isMinimized ? (openBlock(), createElementBlock("div", {
|
|
1255
|
+
key: 0,
|
|
1256
|
+
ref_key: "minimizedRef",
|
|
1257
|
+
ref: minimizedRef,
|
|
1258
|
+
"data-testid": "call-pip",
|
|
1259
|
+
style: normalizeStyle(clampedStyle.value),
|
|
1260
|
+
dir: unref(dir),
|
|
1261
|
+
class: normalizeClass(["vue-chat font-chat-family fixed z-9999 h-40 w-70 cursor-move touch-none overflow-hidden rounded-2xl bg-neutral-900 shadow-2xl ring-1 ring-white/10", [!unref(isDragging) && "transition-all duration-300 ease-out motion-reduce:transition-none"]])
|
|
1262
|
+
}, [
|
|
1263
|
+
createElementVNode("video", {
|
|
1264
|
+
ref_key: "pipVideoRef",
|
|
1265
|
+
ref: pipVideoRef,
|
|
1266
|
+
muted: "",
|
|
1267
|
+
autoplay: "",
|
|
1268
|
+
playsinline: "",
|
|
1269
|
+
class: "pointer-events-none absolute inset-0 size-full object-cover"
|
|
1270
|
+
}, null, 512),
|
|
1271
|
+
_cache[17] || (_cache[17] = createElementVNode("div", { class: "pointer-events-none absolute inset-0 bg-linear-to-t from-black/60 via-transparent to-black/30" }, null, -1)),
|
|
1272
|
+
createElementVNode("div", _hoisted_2, [
|
|
1273
|
+
createElementVNode("div", _hoisted_3, [
|
|
1274
|
+
_cache[16] || (_cache[16] = createElementVNode("span", { class: "relative flex size-2.5" }, [
|
|
1275
|
+
createElementVNode("span", { class: "absolute inline-flex size-full animate-ping rounded-full bg-red-500/60 motion-reduce:animate-none" }),
|
|
1276
|
+
createElementVNode("span", { class: "relative inline-flex size-2.5 rounded-full bg-red-500" })
|
|
1277
|
+
], -1)),
|
|
1278
|
+
createElementVNode("span", _hoisted_4, toDisplayString(unref(formatDuration)(unref(callStore).elapsedTime)), 1)
|
|
1279
|
+
]),
|
|
1280
|
+
createVNode(_sfc_main$3, {
|
|
1281
|
+
icon: "callEnd",
|
|
1282
|
+
label: unref(t)("chat.call.controls.endCall"),
|
|
1283
|
+
severity: "danger",
|
|
1284
|
+
dt: unref(callButtonDt),
|
|
1285
|
+
text: false,
|
|
1286
|
+
"icon-class": "size-5",
|
|
1287
|
+
class: "h-9! w-12!",
|
|
1288
|
+
"data-testid": "call-pip-end",
|
|
1289
|
+
onPointerdown: _cache[0] || (_cache[0] = withModifiers(() => {
|
|
1290
|
+
}, ["stop"])),
|
|
1291
|
+
onClick: withModifiers(unref(endCall), ["stop"])
|
|
1292
|
+
}, null, 8, ["label", "dt", "onClick"])
|
|
1293
|
+
]),
|
|
1294
|
+
createElementVNode("div", _hoisted_5, [
|
|
1295
|
+
createElementVNode("div", _hoisted_6, [
|
|
1296
|
+
createVNode(unref(Button), {
|
|
1297
|
+
label: String(unref(participantCount)),
|
|
1298
|
+
"aria-label": unref(t)("chat.call.controls.nextParticipant"),
|
|
1299
|
+
disabled: !hasRemoteVideos.value,
|
|
1300
|
+
dt: unref(callButtonDt),
|
|
1301
|
+
severity: "secondary",
|
|
1302
|
+
size: "small",
|
|
1303
|
+
rounded: "",
|
|
1304
|
+
class: "h-8!",
|
|
1305
|
+
onPointerdown: _cache[1] || (_cache[1] = withModifiers(() => {
|
|
1306
|
+
}, ["stop"])),
|
|
1307
|
+
onClick: withModifiers(cycleRemote, ["stop"])
|
|
1308
|
+
}, {
|
|
1309
|
+
icon: withCtx(() => [
|
|
1310
|
+
createVNode(_sfc_main$4, {
|
|
1311
|
+
name: "group",
|
|
1312
|
+
class: "size-4"
|
|
1313
|
+
})
|
|
1314
|
+
]),
|
|
1315
|
+
_: 1
|
|
1316
|
+
}, 8, ["label", "aria-label", "disabled", "dt"]),
|
|
1317
|
+
!unref(isAudioOn) ? (openBlock(), createElementBlock("span", _hoisted_7, [
|
|
1318
|
+
createVNode(_sfc_main$4, {
|
|
1319
|
+
name: "micOff",
|
|
1320
|
+
class: "size-4"
|
|
1321
|
+
})
|
|
1322
|
+
])) : createCommentVNode("", true),
|
|
1323
|
+
!unref(isVideoOn) ? (openBlock(), createElementBlock("span", _hoisted_8, [
|
|
1324
|
+
createVNode(_sfc_main$4, {
|
|
1325
|
+
name: "videocamOff",
|
|
1326
|
+
class: "size-4"
|
|
1327
|
+
})
|
|
1328
|
+
])) : createCommentVNode("", true)
|
|
1329
|
+
]),
|
|
1330
|
+
createVNode(_sfc_main$3, {
|
|
1331
|
+
icon: "openInFull",
|
|
1332
|
+
label: unref(t)("chat.call.controls.maximize"),
|
|
1333
|
+
dt: unref(callButtonDt),
|
|
1334
|
+
text: false,
|
|
1335
|
+
"icon-class": "size-4.5",
|
|
1336
|
+
class: "size-9!",
|
|
1337
|
+
"data-testid": "call-maximize",
|
|
1338
|
+
onPointerdown: _cache[2] || (_cache[2] = withModifiers(() => {
|
|
1339
|
+
}, ["stop"])),
|
|
1340
|
+
onClick: _cache[3] || (_cache[3] = withModifiers(($event) => unref(callStore).maximize(), ["stop"]))
|
|
1341
|
+
}, null, 8, ["label", "dt"])
|
|
1342
|
+
])
|
|
1343
|
+
], 14, _hoisted_1)) : createCommentVNode("", true),
|
|
1344
|
+
withDirectives(createElementVNode("div", {
|
|
1345
|
+
"data-testid": "call-view",
|
|
1346
|
+
dir: unref(dir),
|
|
1347
|
+
class: "vue-chat font-chat-family fixed inset-0 z-60 flex size-full flex-col bg-neutral-900 text-white"
|
|
1348
|
+
}, [
|
|
1349
|
+
createElementVNode("div", {
|
|
1350
|
+
"data-testid": "call-top-bar",
|
|
1351
|
+
class: normalizeClass(["flex h-14 shrink-0 items-center gap-x-3 px-3 transition-opacity duration-300 motion-reduce:transition-none md:h-16 md:px-6", unref(showControls) ? "opacity-100" : "opacity-0"]),
|
|
1352
|
+
onMouseenter: _cache[5] || (_cache[5] = //@ts-ignore
|
|
1353
|
+
(...args) => unref(resetControlsTimeout) && unref(resetControlsTimeout)(...args))
|
|
1354
|
+
}, [
|
|
1355
|
+
createElementVNode("div", _hoisted_10, [
|
|
1356
|
+
createElementVNode("h1", _hoisted_11, toDisplayString(callTitle.value), 1),
|
|
1357
|
+
_cache[18] || (_cache[18] = createElementVNode("span", {
|
|
1358
|
+
"aria-hidden": "true",
|
|
1359
|
+
class: "h-4 w-px shrink-0 bg-white/30"
|
|
1360
|
+
}, null, -1)),
|
|
1361
|
+
createElementVNode("span", _hoisted_12, toDisplayString(unref(formatDuration)(unref(callStore).elapsedTime)), 1)
|
|
1362
|
+
]),
|
|
1363
|
+
createElementVNode("div", _hoisted_13, [
|
|
1364
|
+
withDirectives((openBlock(), createBlock(unref(Button), {
|
|
1365
|
+
"aria-label": peopleLabel.value,
|
|
1366
|
+
"aria-haspopup": "dialog",
|
|
1367
|
+
"aria-expanded": peopleOpen.value,
|
|
1368
|
+
dt: unref(callButtonDt),
|
|
1369
|
+
severity: "secondary",
|
|
1370
|
+
rounded: "",
|
|
1371
|
+
"data-testid": "call-people-button",
|
|
1372
|
+
class: normalizeClass(["h-11! gap-x-1.5! px-3.5!", unref(focusRing)]),
|
|
1373
|
+
onClick: _cache[4] || (_cache[4] = ($event) => peopleOpen.value = true)
|
|
1374
|
+
}, {
|
|
1375
|
+
default: withCtx(() => [
|
|
1376
|
+
createVNode(_sfc_main$4, {
|
|
1377
|
+
name: "group",
|
|
1378
|
+
class: "size-5"
|
|
1379
|
+
}),
|
|
1380
|
+
createElementVNode("span", _hoisted_14, toDisplayString(unref(participantCount)), 1)
|
|
1381
|
+
]),
|
|
1382
|
+
_: 1
|
|
1383
|
+
}, 8, ["aria-label", "aria-expanded", "dt", "class"])), [
|
|
1384
|
+
[
|
|
1385
|
+
unref(vTooltip),
|
|
1386
|
+
unref(tip)(peopleLabel.value),
|
|
1387
|
+
void 0,
|
|
1388
|
+
{ bottom: true }
|
|
1389
|
+
]
|
|
1390
|
+
]),
|
|
1391
|
+
withDirectives(createVNode(_sfc_main$3, {
|
|
1392
|
+
icon: "pictureInPicture",
|
|
1393
|
+
label: unref(t)("chat.call.controls.minimize"),
|
|
1394
|
+
dt: unref(callButtonDt),
|
|
1395
|
+
text: false,
|
|
1396
|
+
"icon-class": "size-5",
|
|
1397
|
+
class: normalizeClass(["size-11!", unref(focusRing)]),
|
|
1398
|
+
"data-testid": "call-minimize",
|
|
1399
|
+
onClick: unref(callStore).minimize
|
|
1400
|
+
}, null, 8, ["label", "dt", "class", "onClick"]), [
|
|
1401
|
+
[
|
|
1402
|
+
unref(vTooltip),
|
|
1403
|
+
unref(tip)(unref(t)("chat.call.controls.minimize")),
|
|
1404
|
+
void 0,
|
|
1405
|
+
{ bottom: true }
|
|
1406
|
+
]
|
|
1407
|
+
])
|
|
1408
|
+
])
|
|
1409
|
+
], 34),
|
|
1410
|
+
createElementVNode("div", {
|
|
1411
|
+
ref_key: "stageRef",
|
|
1412
|
+
ref: stageRef,
|
|
1413
|
+
class: "relative min-h-0 flex-1 px-2 pb-2 md:px-4 md:pb-4",
|
|
1414
|
+
style: { "--call-gap": "0.5rem" },
|
|
1415
|
+
onMousemove: _cache[10] || (_cache[10] = //@ts-ignore
|
|
1416
|
+
(...args) => unref(resetControlsTimeout) && unref(resetControlsTimeout)(...args))
|
|
1417
|
+
}, [
|
|
1418
|
+
unref(soundBlocked) ? (openBlock(), createBlock(unref(Button), {
|
|
1419
|
+
key: 0,
|
|
1420
|
+
label: unref(t)("chat.call.controls.enableSound"),
|
|
1421
|
+
dt: unref(callButtonDt),
|
|
1422
|
+
severity: "contrast",
|
|
1423
|
+
rounded: "",
|
|
1424
|
+
"data-testid": "call-enable-sound",
|
|
1425
|
+
class: "absolute! top-4 left-1/2 z-40 -translate-x-1/2 shadow-lg",
|
|
1426
|
+
onClick: unref(enableSound)
|
|
1427
|
+
}, {
|
|
1428
|
+
icon: withCtx(() => [
|
|
1429
|
+
createVNode(_sfc_main$4, {
|
|
1430
|
+
name: "volumeUp",
|
|
1431
|
+
class: "size-5"
|
|
1432
|
+
})
|
|
1433
|
+
]),
|
|
1434
|
+
_: 1
|
|
1435
|
+
}, 8, ["label", "dt", "onClick"])) : createCommentVNode("", true),
|
|
1436
|
+
createVNode(Transition, {
|
|
1437
|
+
"enter-active-class": "transition duration-200 motion-reduce:transition-none",
|
|
1438
|
+
"enter-from-class": "opacity-0 -translate-y-2",
|
|
1439
|
+
"leave-active-class": "transition duration-200 motion-reduce:transition-none",
|
|
1440
|
+
"leave-to-class": "opacity-0"
|
|
1441
|
+
}, {
|
|
1442
|
+
default: withCtx(() => [
|
|
1443
|
+
unref(notices).current.value && !unref(soundBlocked) ? (openBlock(), createElementBlock("div", {
|
|
1444
|
+
key: unref(notices).current.value.id,
|
|
1445
|
+
"data-testid": "call-notice",
|
|
1446
|
+
class: "pointer-events-none absolute inset-x-0 top-3 z-40 flex justify-center px-4"
|
|
1447
|
+
}, [
|
|
1448
|
+
createElementVNode("span", _hoisted_15, [
|
|
1449
|
+
createElementVNode("bdi", null, toDisplayString(unref(notices).current.value.text), 1)
|
|
1450
|
+
])
|
|
1451
|
+
])) : createCommentVNode("", true)
|
|
1452
|
+
]),
|
|
1453
|
+
_: 1
|
|
1454
|
+
}),
|
|
1455
|
+
createElementVNode("span", _hoisted_16, toDisplayString(unref(notices).liveText.value), 1),
|
|
1456
|
+
unref(layout).mode.value === "solo" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
1457
|
+
(openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1458
|
+
key: selfTile.value.id
|
|
1459
|
+
}, tileProps(selfTile.value), {
|
|
1460
|
+
hint: unref(t)("chat.call.cameraIsOff"),
|
|
1461
|
+
class: "size-full",
|
|
1462
|
+
onVideo: _cache[6] || (_cache[6] = (el, prev) => bindVideo(selfTile.value, el, prev)),
|
|
1463
|
+
onPause: _cache[7] || (_cache[7] = (el) => togglePause(selfTile.value, el)),
|
|
1464
|
+
onFullscreen: _cache[8] || (_cache[8] = (el) => toggleTileFullscreen(selfTile.value, el))
|
|
1465
|
+
}), null, 16, ["hint"])),
|
|
1466
|
+
showWaiting.value ? (openBlock(), createElementBlock("div", _hoisted_17, [
|
|
1467
|
+
createElementVNode("div", _hoisted_18, [
|
|
1468
|
+
createElementVNode("p", _hoisted_19, toDisplayString(callTitle.value), 1),
|
|
1469
|
+
createElementVNode("p", _hoisted_20, toDisplayString(waitingText.value), 1)
|
|
1470
|
+
])
|
|
1471
|
+
])) : createCommentVNode("", true)
|
|
1472
|
+
], 64)) : unref(layout).mode.value === "pair" && pairRemote.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
1473
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList([pairRemote.value], (tile) => {
|
|
1474
|
+
return openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1475
|
+
key: tile.id
|
|
1476
|
+
}, { ref_for: true }, tileProps(tile), {
|
|
1477
|
+
class: "size-full",
|
|
1478
|
+
onPin: ($event) => unref(layout).togglePin(tile.id),
|
|
1479
|
+
onRetry: ($event) => unref(retryPeer)(tile.participantId),
|
|
1480
|
+
onVideo: (el, prev) => bindVideo(tile, el, prev),
|
|
1481
|
+
onPause: (el) => togglePause(tile, el),
|
|
1482
|
+
onFullscreen: (el) => toggleTileFullscreen(tile, el)
|
|
1483
|
+
}), null, 16, ["onPin", "onRetry", "onVideo", "onPause", "onFullscreen"]);
|
|
1484
|
+
}), 128)),
|
|
1485
|
+
(openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1486
|
+
key: selfTile.value.id
|
|
1487
|
+
}, tileProps(selfTile.value, true), {
|
|
1488
|
+
"can-pin": false,
|
|
1489
|
+
class: "absolute! end-5 bottom-4 z-10 aspect-video w-36 shadow-xl outline outline-white/25 sm:w-56 md:end-6 md:bottom-6 md:w-64",
|
|
1490
|
+
onVideo: _cache[9] || (_cache[9] = (el, prev) => bindVideo(selfTile.value, el, prev))
|
|
1491
|
+
}), null, 16))
|
|
1492
|
+
], 64)) : unref(layout).mode.value === "grid" ? (openBlock(), createElementBlock("div", {
|
|
1493
|
+
key: 3,
|
|
1494
|
+
class: normalizeClass(unref(layout).gridClass)
|
|
1495
|
+
}, [
|
|
1496
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).gridTiles.value, (tile, index) => {
|
|
1497
|
+
return openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1498
|
+
key: tile.id
|
|
1499
|
+
}, { ref_for: true }, tileProps(tile), {
|
|
1500
|
+
class: ["size-full", unref(layout).cellClass(index)],
|
|
1501
|
+
onPin: ($event) => unref(layout).togglePin(tile.id),
|
|
1502
|
+
onRetry: ($event) => unref(retryPeer)(tile.participantId),
|
|
1503
|
+
onVideo: (el, prev) => bindVideo(tile, el, prev),
|
|
1504
|
+
onPause: (el) => togglePause(tile, el),
|
|
1505
|
+
onFullscreen: (el) => toggleTileFullscreen(tile, el)
|
|
1506
|
+
}), null, 16, ["class", "onPin", "onRetry", "onVideo", "onPause", "onFullscreen"]);
|
|
1507
|
+
}), 128))
|
|
1508
|
+
], 2)) : unref(layout).stageTile.value ? (openBlock(), createElementBlock("div", {
|
|
1509
|
+
key: 4,
|
|
1510
|
+
class: normalizeClass(["flex size-full gap-(--call-gap)", portrait.value ? "flex-col" : "flex-row"])
|
|
1511
|
+
}, [
|
|
1512
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList([unref(layout).stageTile.value], (tile) => {
|
|
1513
|
+
return openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1514
|
+
key: tile.id
|
|
1515
|
+
}, { ref_for: true }, tileProps(tile), {
|
|
1516
|
+
"data-stage": "true",
|
|
1517
|
+
class: "min-h-0 min-w-0 flex-1",
|
|
1518
|
+
onPin: ($event) => unref(layout).togglePin(tile.id),
|
|
1519
|
+
onRetry: ($event) => unref(retryPeer)(tile.participantId),
|
|
1520
|
+
onVideo: (el, prev) => bindVideo(tile, el, prev),
|
|
1521
|
+
onPause: (el) => togglePause(tile, el),
|
|
1522
|
+
onFullscreen: (el) => toggleTileFullscreen(tile, el)
|
|
1523
|
+
}), null, 16, ["onPin", "onRetry", "onVideo", "onPause", "onFullscreen"]);
|
|
1524
|
+
}), 128)),
|
|
1525
|
+
unref(layout).stripTiles.value.length ? (openBlock(), createElementBlock("div", {
|
|
1526
|
+
key: 0,
|
|
1527
|
+
"data-testid": "call-strip",
|
|
1528
|
+
class: normalizeClass(["hide-scrollbar flex shrink-0 gap-(--call-gap)", portrait.value ? "h-24 flex-row overflow-x-auto sm:h-28" : "w-40 flex-col overflow-y-auto lg:w-56"])
|
|
1529
|
+
}, [
|
|
1530
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(layout).stripTiles.value, (tile) => {
|
|
1531
|
+
return openBlock(), createBlock(_sfc_main$2, mergeProps({
|
|
1532
|
+
key: tile.id
|
|
1533
|
+
}, { ref_for: true }, tileProps(tile, true), {
|
|
1534
|
+
class: ["aspect-video shrink-0", portrait.value ? "h-full" : "w-full"],
|
|
1535
|
+
onPin: ($event) => unref(layout).togglePin(tile.id),
|
|
1536
|
+
onRetry: ($event) => unref(retryPeer)(tile.participantId),
|
|
1537
|
+
onVideo: (el, prev) => bindVideo(tile, el, prev)
|
|
1538
|
+
}), null, 16, ["class", "onPin", "onRetry", "onVideo"]);
|
|
1539
|
+
}), 128))
|
|
1540
|
+
], 2)) : createCommentVNode("", true)
|
|
1541
|
+
], 2)) : createCommentVNode("", true)
|
|
1542
|
+
], 544),
|
|
1543
|
+
createElementVNode("div", {
|
|
1544
|
+
class: normalizeClass(["flex h-20 shrink-0 items-center justify-center px-3 transition-opacity duration-300 motion-reduce:transition-none md:px-6", unref(showControls) ? "opacity-100" : "opacity-0"]),
|
|
1545
|
+
onMouseenter: _cache[13] || (_cache[13] = //@ts-ignore
|
|
1546
|
+
(...args) => unref(resetControlsTimeout) && unref(resetControlsTimeout)(...args)),
|
|
1547
|
+
onMousemove: _cache[14] || (_cache[14] = //@ts-ignore
|
|
1548
|
+
(...args) => unref(resetControlsTimeout) && unref(resetControlsTimeout)(...args))
|
|
1549
|
+
}, [
|
|
1550
|
+
createElementVNode("div", _hoisted_21, [
|
|
1551
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
1552
|
+
icon: unref(isAudioOn) ? "mic" : "micOff",
|
|
1553
|
+
label: audioLabel.value,
|
|
1554
|
+
severity: unref(isAudioOn) ? "secondary" : "danger",
|
|
1555
|
+
"aria-keyshortcuts": unref(isMac) ? "Meta+D" : "Control+D"
|
|
1556
|
+
}, barButton, {
|
|
1557
|
+
"data-testid": "call-toggle-audio",
|
|
1558
|
+
"data-active": unref(isAudioOn),
|
|
1559
|
+
onClick: unref(toggleAudio)
|
|
1560
|
+
}), null, 16, ["icon", "label", "severity", "aria-keyshortcuts", "data-active", "onClick"]), [
|
|
1561
|
+
[
|
|
1562
|
+
unref(vTooltip),
|
|
1563
|
+
unref(tip)(withKeys(audioLabel.value, "D")),
|
|
1564
|
+
void 0,
|
|
1565
|
+
{ top: true }
|
|
1566
|
+
]
|
|
1567
|
+
]),
|
|
1568
|
+
createElementVNode("div", {
|
|
1569
|
+
class: normalizeClass(["flex items-center rounded-full", unref(cameras).length > 1 && "bg-white/12"])
|
|
1570
|
+
}, [
|
|
1571
|
+
unref(cameras).length > 1 ? withDirectives((openBlock(), createBlock(_sfc_main$3, {
|
|
1572
|
+
key: 0,
|
|
1573
|
+
icon: "arrowDropUp",
|
|
1574
|
+
label: unref(t)("chat.call.controls.chooseCamera"),
|
|
1575
|
+
dt: unref(callButtonDt),
|
|
1576
|
+
text: "",
|
|
1577
|
+
severity: "secondary",
|
|
1578
|
+
"icon-class": "size-6",
|
|
1579
|
+
class: normalizeClass(["h-12! w-8! rounded-e-none! ps-1!", unref(focusRing)]),
|
|
1580
|
+
"aria-haspopup": "true",
|
|
1581
|
+
onClick: _cache[11] || (_cache[11] = ($event) => {
|
|
1582
|
+
var _a;
|
|
1583
|
+
return (_a = cameraMenu.value) == null ? void 0 : _a.toggle($event);
|
|
1584
|
+
})
|
|
1585
|
+
}, null, 8, ["label", "dt", "class"])), [
|
|
1586
|
+
[
|
|
1587
|
+
unref(vTooltip),
|
|
1588
|
+
unref(tip)(unref(t)("chat.call.controls.chooseCamera")),
|
|
1589
|
+
void 0,
|
|
1590
|
+
{ top: true }
|
|
1591
|
+
]
|
|
1592
|
+
]) : createCommentVNode("", true),
|
|
1593
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
1594
|
+
icon: unref(isVideoOn) ? "videocam" : "videocamOff",
|
|
1595
|
+
label: videoLabel.value,
|
|
1596
|
+
severity: unref(isVideoOn) ? "secondary" : "danger",
|
|
1597
|
+
"aria-keyshortcuts": unref(isMac) ? "Meta+E" : "Control+E"
|
|
1598
|
+
}, barButton, {
|
|
1599
|
+
"data-testid": "call-toggle-video",
|
|
1600
|
+
"data-active": unref(isVideoOn),
|
|
1601
|
+
onClick: unref(toggleVideo)
|
|
1602
|
+
}), null, 16, ["icon", "label", "severity", "aria-keyshortcuts", "data-active", "onClick"]), [
|
|
1603
|
+
[
|
|
1604
|
+
unref(vTooltip),
|
|
1605
|
+
unref(tip)(withKeys(videoLabel.value, "E")),
|
|
1606
|
+
void 0,
|
|
1607
|
+
{ top: true }
|
|
1608
|
+
]
|
|
1609
|
+
])
|
|
1610
|
+
], 2),
|
|
1611
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
1612
|
+
icon: unref(isScreenSharing) ? "cancelPresentation" : "presentToAll",
|
|
1613
|
+
label: shareLabel.value,
|
|
1614
|
+
severity: unref(isScreenSharing) ? "contrast" : "secondary"
|
|
1615
|
+
}, barButton, {
|
|
1616
|
+
"data-testid": "call-toggle-screen",
|
|
1617
|
+
"data-active": unref(isScreenSharing),
|
|
1618
|
+
onClick: unref(toggleScreenShare)
|
|
1619
|
+
}), null, 16, ["icon", "label", "severity", "data-active", "onClick"]), [
|
|
1620
|
+
[
|
|
1621
|
+
unref(vTooltip),
|
|
1622
|
+
unref(tip)(shareLabel.value),
|
|
1623
|
+
void 0,
|
|
1624
|
+
{ top: true }
|
|
1625
|
+
]
|
|
1626
|
+
]),
|
|
1627
|
+
withDirectives(createVNode(_sfc_main$3, mergeProps({
|
|
1628
|
+
icon: "moreVert",
|
|
1629
|
+
label: unref(t)("chat.call.controls.more")
|
|
1630
|
+
}, barButton, {
|
|
1631
|
+
class: "h-12! w-10! sm:w-12!",
|
|
1632
|
+
"aria-haspopup": "true",
|
|
1633
|
+
"data-testid": "call-more",
|
|
1634
|
+
onClick: _cache[12] || (_cache[12] = ($event) => {
|
|
1635
|
+
var _a;
|
|
1636
|
+
return (_a = moreMenu.value) == null ? void 0 : _a.toggle($event);
|
|
1637
|
+
})
|
|
1638
|
+
}), null, 16, ["label"]), [
|
|
1639
|
+
[
|
|
1640
|
+
unref(vTooltip),
|
|
1641
|
+
unref(tip)(unref(t)("chat.call.controls.more")),
|
|
1642
|
+
void 0,
|
|
1643
|
+
{ top: true }
|
|
1644
|
+
]
|
|
1645
|
+
]),
|
|
1646
|
+
withDirectives(createVNode(_sfc_main$3, {
|
|
1647
|
+
icon: "callEnd",
|
|
1648
|
+
label: unref(t)("chat.call.controls.endCall"),
|
|
1649
|
+
severity: "danger",
|
|
1650
|
+
dt: unref(callButtonDt),
|
|
1651
|
+
text: false,
|
|
1652
|
+
size: "large",
|
|
1653
|
+
"icon-class": "size-6",
|
|
1654
|
+
class: normalizeClass(["h-12! w-16! sm:w-18!", unref(focusRing)]),
|
|
1655
|
+
"data-testid": "call-end",
|
|
1656
|
+
onClick: unref(endCall)
|
|
1657
|
+
}, null, 8, ["label", "dt", "class", "onClick"]), [
|
|
1658
|
+
[
|
|
1659
|
+
unref(vTooltip),
|
|
1660
|
+
unref(tip)(unref(t)("chat.call.controls.endCall")),
|
|
1661
|
+
void 0,
|
|
1662
|
+
{ top: true }
|
|
1663
|
+
]
|
|
1664
|
+
])
|
|
1665
|
+
])
|
|
1666
|
+
], 34),
|
|
1667
|
+
createVNode(_sfc_main$1, {
|
|
1668
|
+
visible: peopleOpen.value,
|
|
1669
|
+
"onUpdate:visible": _cache[15] || (_cache[15] = ($event) => peopleOpen.value = $event),
|
|
1670
|
+
participants: unref(participants)
|
|
1671
|
+
}, null, 8, ["visible", "participants"]),
|
|
1672
|
+
createVNode(unref(Menu), {
|
|
1673
|
+
ref_key: "cameraMenu",
|
|
1674
|
+
ref: cameraMenu,
|
|
1675
|
+
model: cameraItems.value,
|
|
1676
|
+
popup: "",
|
|
1677
|
+
dir: unref(dir),
|
|
1678
|
+
dt: unref(callMenuDt),
|
|
1679
|
+
class: "vue-chat"
|
|
1680
|
+
}, {
|
|
1681
|
+
itemicon: withCtx(({ item }) => [
|
|
1682
|
+
item.callIcon ? (openBlock(), createBlock(_sfc_main$4, {
|
|
1683
|
+
key: 0,
|
|
1684
|
+
name: item.callIcon,
|
|
1685
|
+
class: "size-5 text-sky-400"
|
|
1686
|
+
}, null, 8, ["name"])) : (openBlock(), createElementBlock("span", _hoisted_22))
|
|
1687
|
+
]),
|
|
1688
|
+
_: 1
|
|
1689
|
+
}, 8, ["model", "dir", "dt"]),
|
|
1690
|
+
createVNode(unref(Menu), {
|
|
1691
|
+
ref_key: "moreMenu",
|
|
1692
|
+
ref: moreMenu,
|
|
1693
|
+
model: moreItems.value,
|
|
1694
|
+
popup: "",
|
|
1695
|
+
dir: unref(dir),
|
|
1696
|
+
dt: unref(callMenuDt),
|
|
1697
|
+
class: "vue-chat"
|
|
1698
|
+
}, {
|
|
1699
|
+
itemicon: withCtx(({ item }) => [
|
|
1700
|
+
createVNode(_sfc_main$4, {
|
|
1701
|
+
name: item.callIcon,
|
|
1702
|
+
class: "size-5 text-neutral-400"
|
|
1703
|
+
}, null, 8, ["name"])
|
|
1704
|
+
]),
|
|
1705
|
+
_: 1
|
|
1706
|
+
}, 8, ["model", "dir", "dt"])
|
|
1707
|
+
], 8, _hoisted_9), [
|
|
1708
|
+
[vShow, unref(callStore).isActive && !unref(callStore).isMinimized]
|
|
1709
|
+
])
|
|
1710
|
+
], 64);
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
export {
|
|
1715
|
+
_sfc_main as default
|
|
1716
|
+
};
|
|
1717
|
+
//# sourceMappingURL=Call-DvVJ7IsY.mjs.map
|