@skippr/live-agent-sdk 0.24.0 → 0.26.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 +20 -1
- package/dist/esm/lib-exports.js +1057 -948
- package/dist/skippr-sdk.css +1 -1
- package/dist/skippr-sdk.js +139 -139
- package/dist/types/components/AutoStartMedia.d.ts +5 -0
- package/dist/types/components/ChatHeader.d.ts +1 -5
- package/dist/types/components/ChatInput.d.ts +2 -1
- package/dist/types/components/LiveAgent.d.ts +6 -1
- package/dist/types/components/LoadingDots.d.ts +5 -0
- package/dist/types/components/Logo.d.ts +5 -0
- package/dist/types/components/MessageList.d.ts +2 -1
- package/dist/types/components/ObservingBanner.d.ts +1 -0
- package/dist/types/components/SessionAgenda.d.ts +1 -3
- package/dist/types/components/Sidebar.d.ts +7 -1
- package/dist/types/components/StartSessionPrompt.d.ts +8 -0
- package/dist/types/components/ui/tooltip.d.ts +3 -1
- package/dist/types/context/LiveAgentContext.d.ts +4 -0
- package/dist/types/hooks/useAgentVoiceState.d.ts +9 -0
- package/dist/types/hooks/useElapsedSeconds.d.ts +1 -0
- package/dist/types/hooks/useIsLocalSpeaking.d.ts +1 -0
- package/dist/types/hooks/useMediaControls.d.ts +14 -0
- package/dist/types/hooks/useSession.d.ts +1 -0
- package/dist/types/hooks/useSessionRemaining.d.ts +1 -0
- package/dist/types/lib/constants.d.ts +1 -1
- package/dist/types/lib-exports.d.ts +5 -0
- package/package.json +1 -1
- package/dist/types/components/QuickActions.d.ts +0 -7
- package/dist/types/components/SettingsView.d.ts +0 -5
- package/dist/types/hooks/useQuestionUpdates.d.ts +0 -11
package/dist/esm/lib-exports.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/components/LiveAgent.tsx
|
|
2
2
|
import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
|
|
3
|
-
import { useCallback as
|
|
3
|
+
import { useCallback as useCallback6, useEffect as useEffect12, useMemo as useMemo5, useRef as useRef6, useState as useState8 } from "react";
|
|
4
4
|
|
|
5
5
|
// src/context/LiveAgentContext.tsx
|
|
6
6
|
import { createContext } from "react";
|
|
@@ -173,6 +173,7 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
173
173
|
const [errorCode, setErrorCode] = useState2(null);
|
|
174
174
|
const [sessionId, setSessionId] = useState2(null);
|
|
175
175
|
const [bearerToken, setBearerToken] = useState2(authToken ?? null);
|
|
176
|
+
const [pendingScreenStream, setPendingScreenStream] = useState2(null);
|
|
176
177
|
useEffect2(() => {
|
|
177
178
|
let stale = false;
|
|
178
179
|
if (authToken) {
|
|
@@ -197,10 +198,18 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
197
198
|
setError("No auth token available");
|
|
198
199
|
return;
|
|
199
200
|
}
|
|
200
|
-
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
201
201
|
setIsStarting(true);
|
|
202
202
|
setError("");
|
|
203
203
|
setErrorCode(null);
|
|
204
|
+
let screenStream = null;
|
|
205
|
+
try {
|
|
206
|
+
screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
207
|
+
video: { displaySurface: "browser" }
|
|
208
|
+
});
|
|
209
|
+
} catch {
|
|
210
|
+
screenStream = null;
|
|
211
|
+
}
|
|
212
|
+
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
204
213
|
try {
|
|
205
214
|
const createResp = await fetch(`${API_URL2}/v1/sessions`, {
|
|
206
215
|
method: "POST",
|
|
@@ -230,8 +239,13 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
230
239
|
livekitUrl: conn.livekitUrl,
|
|
231
240
|
token: conn.token
|
|
232
241
|
});
|
|
242
|
+
setPendingScreenStream(screenStream);
|
|
233
243
|
setShouldConnect(true);
|
|
234
244
|
} catch (e) {
|
|
245
|
+
if (screenStream) {
|
|
246
|
+
for (const track of screenStream.getTracks())
|
|
247
|
+
track.stop();
|
|
248
|
+
}
|
|
235
249
|
setError(e instanceof Error ? e.message : "Failed to start session");
|
|
236
250
|
} finally {
|
|
237
251
|
setIsStarting(false);
|
|
@@ -248,17 +262,57 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
248
262
|
});
|
|
249
263
|
} catch {}
|
|
250
264
|
}
|
|
265
|
+
if (pendingScreenStream) {
|
|
266
|
+
for (const track of pendingScreenStream.getTracks())
|
|
267
|
+
track.stop();
|
|
268
|
+
}
|
|
251
269
|
setError("");
|
|
252
270
|
setShouldConnect(false);
|
|
253
271
|
setConnection(null);
|
|
254
272
|
setSessionId(null);
|
|
255
|
-
|
|
256
|
-
|
|
273
|
+
setPendingScreenStream(null);
|
|
274
|
+
}, [sessionId, bearerToken, pendingScreenStream]);
|
|
275
|
+
return {
|
|
276
|
+
connection,
|
|
277
|
+
shouldConnect,
|
|
278
|
+
isStarting,
|
|
279
|
+
error,
|
|
280
|
+
errorCode,
|
|
281
|
+
startSession,
|
|
282
|
+
disconnect,
|
|
283
|
+
pendingScreenStream
|
|
284
|
+
};
|
|
257
285
|
}
|
|
258
286
|
|
|
259
|
-
// src/components/
|
|
260
|
-
import {
|
|
261
|
-
import {
|
|
287
|
+
// src/components/AutoStartMedia.tsx
|
|
288
|
+
import { useConnectionState, useLocalParticipant } from "@livekit/components-react";
|
|
289
|
+
import { ConnectionState, Track } from "livekit-client";
|
|
290
|
+
import { useEffect as useEffect3, useRef } from "react";
|
|
291
|
+
function AutoStartMedia({ pendingScreenStream }) {
|
|
292
|
+
const { localParticipant } = useLocalParticipant();
|
|
293
|
+
const connectionState = useConnectionState();
|
|
294
|
+
const didStartRef = useRef(false);
|
|
295
|
+
useEffect3(() => {
|
|
296
|
+
if (didStartRef.current)
|
|
297
|
+
return;
|
|
298
|
+
if (connectionState !== ConnectionState.Connected)
|
|
299
|
+
return;
|
|
300
|
+
didStartRef.current = true;
|
|
301
|
+
localParticipant.setMicrophoneEnabled(true).catch((error) => console.error("Failed to enable microphone:", error));
|
|
302
|
+
if (pendingScreenStream) {
|
|
303
|
+
const videoTrack = pendingScreenStream.getVideoTracks()[0];
|
|
304
|
+
if (videoTrack) {
|
|
305
|
+
videoTrack.contentHint = "detail";
|
|
306
|
+
localParticipant.publishTrack(videoTrack, { source: Track.Source.ScreenShare }).catch((error) => {
|
|
307
|
+
console.error("Failed to publish screen share track:", error);
|
|
308
|
+
for (const track of pendingScreenStream.getTracks())
|
|
309
|
+
track.stop();
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}, [connectionState, localParticipant, pendingScreenStream]);
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
262
316
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
263
317
|
import { forwardRef as forwardRef2, createElement as createElement3 } from "react";
|
|
264
318
|
|
|
@@ -350,70 +404,63 @@ var createLucideIcon = (iconName, iconNode) => {
|
|
|
350
404
|
return Component;
|
|
351
405
|
};
|
|
352
406
|
|
|
407
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle-check.js
|
|
408
|
+
var __iconNode = [
|
|
409
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
410
|
+
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
411
|
+
];
|
|
412
|
+
var CircleCheck = createLucideIcon("circle-check", __iconNode);
|
|
353
413
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/loader-circle.js
|
|
354
|
-
var
|
|
355
|
-
var LoaderCircle = createLucideIcon("loader-circle",
|
|
356
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
357
|
-
var
|
|
414
|
+
var __iconNode2 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
415
|
+
var LoaderCircle = createLucideIcon("loader-circle", __iconNode2);
|
|
416
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sparkles.js
|
|
417
|
+
var __iconNode3 = [
|
|
358
418
|
[
|
|
359
419
|
"path",
|
|
360
420
|
{
|
|
361
|
-
d: "
|
|
362
|
-
key: "
|
|
421
|
+
d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
|
|
422
|
+
key: "1s2grr"
|
|
363
423
|
}
|
|
364
424
|
],
|
|
365
|
-
["path", { d: "
|
|
366
|
-
["path", { d: "
|
|
425
|
+
["path", { d: "M20 2v4", key: "1rf3ol" }],
|
|
426
|
+
["path", { d: "M22 4h-4", key: "gwowj6" }],
|
|
427
|
+
["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
|
|
367
428
|
];
|
|
368
|
-
var
|
|
369
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
370
|
-
var __iconNode3 = [
|
|
371
|
-
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
372
|
-
["path", { d: "M9 3v18", key: "fh3hqa" }]
|
|
373
|
-
];
|
|
374
|
-
var PanelLeft = createLucideIcon("panel-left", __iconNode3);
|
|
375
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send-horizontal.js
|
|
429
|
+
var Sparkles = createLucideIcon("sparkles", __iconNode3);
|
|
430
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/calendar.js
|
|
376
431
|
var __iconNode4 = [
|
|
432
|
+
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
433
|
+
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
434
|
+
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
435
|
+
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
436
|
+
];
|
|
437
|
+
var Calendar = createLucideIcon("calendar", __iconNode4);
|
|
438
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/chevron-down.js
|
|
439
|
+
var __iconNode5 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
440
|
+
var ChevronDown = createLucideIcon("chevron-down", __iconNode5);
|
|
441
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
442
|
+
var __iconNode6 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
443
|
+
var Circle = createLucideIcon("circle", __iconNode6);
|
|
444
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/eye.js
|
|
445
|
+
var __iconNode7 = [
|
|
377
446
|
[
|
|
378
447
|
"path",
|
|
379
448
|
{
|
|
380
|
-
d: "
|
|
381
|
-
key: "
|
|
449
|
+
d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
|
|
450
|
+
key: "1nclc0"
|
|
382
451
|
}
|
|
383
452
|
],
|
|
384
|
-
["
|
|
385
|
-
];
|
|
386
|
-
var SendHorizontal = createLucideIcon("send-horizontal", __iconNode4);
|
|
387
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/arrow-left.js
|
|
388
|
-
var __iconNode5 = [
|
|
389
|
-
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
390
|
-
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
391
|
-
];
|
|
392
|
-
var ArrowLeft = createLucideIcon("arrow-left", __iconNode5);
|
|
393
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
|
|
394
|
-
var __iconNode6 = [
|
|
395
|
-
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
396
|
-
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
397
|
-
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
398
|
-
["path", { d: "M20 14h2", key: "4cs60a" }],
|
|
399
|
-
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
400
|
-
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
453
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
401
454
|
];
|
|
402
|
-
var
|
|
403
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/check.js
|
|
404
|
-
var __iconNode7 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
405
|
-
var Check = createLucideIcon("check", __iconNode7);
|
|
406
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
407
|
-
var __iconNode8 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
408
|
-
var Circle = createLucideIcon("circle", __iconNode8);
|
|
455
|
+
var Eye = createLucideIcon("eye", __iconNode7);
|
|
409
456
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
|
|
410
|
-
var
|
|
457
|
+
var __iconNode8 = [
|
|
411
458
|
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
|
|
412
459
|
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
|
|
413
460
|
];
|
|
414
|
-
var Mail = createLucideIcon("mail",
|
|
461
|
+
var Mail = createLucideIcon("mail", __iconNode8);
|
|
415
462
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
|
|
416
|
-
var
|
|
463
|
+
var __iconNode9 = [
|
|
417
464
|
[
|
|
418
465
|
"path",
|
|
419
466
|
{
|
|
@@ -422,20 +469,9 @@ var __iconNode10 = [
|
|
|
422
469
|
}
|
|
423
470
|
]
|
|
424
471
|
];
|
|
425
|
-
var MessageCircle = createLucideIcon("message-circle",
|
|
426
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-square.js
|
|
427
|
-
var __iconNode11 = [
|
|
428
|
-
[
|
|
429
|
-
"path",
|
|
430
|
-
{
|
|
431
|
-
d: "M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",
|
|
432
|
-
key: "18887p"
|
|
433
|
-
}
|
|
434
|
-
]
|
|
435
|
-
];
|
|
436
|
-
var MessageSquare = createLucideIcon("message-square", __iconNode11);
|
|
472
|
+
var MessageCircle = createLucideIcon("message-circle", __iconNode9);
|
|
437
473
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
|
|
438
|
-
var
|
|
474
|
+
var __iconNode10 = [
|
|
439
475
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
440
476
|
["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
|
|
441
477
|
["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
|
|
@@ -443,38 +479,40 @@ var __iconNode12 = [
|
|
|
443
479
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
444
480
|
["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
|
|
445
481
|
];
|
|
446
|
-
var MicOff = createLucideIcon("mic-off",
|
|
482
|
+
var MicOff = createLucideIcon("mic-off", __iconNode10);
|
|
447
483
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
|
|
448
|
-
var
|
|
484
|
+
var __iconNode11 = [
|
|
449
485
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
450
486
|
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
451
487
|
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
452
488
|
];
|
|
453
|
-
var Mic = createLucideIcon("mic",
|
|
489
|
+
var Mic = createLucideIcon("mic", __iconNode11);
|
|
490
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/minimize-2.js
|
|
491
|
+
var __iconNode12 = [
|
|
492
|
+
["path", { d: "m14 10 7-7", key: "oa77jy" }],
|
|
493
|
+
["path", { d: "M20 10h-6V4", key: "mjg0md" }],
|
|
494
|
+
["path", { d: "m3 21 7-7", key: "tjx5ai" }],
|
|
495
|
+
["path", { d: "M4 14h6v6", key: "rmj7iw" }]
|
|
496
|
+
];
|
|
497
|
+
var Minimize2 = createLucideIcon("minimize-2", __iconNode12);
|
|
454
498
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
455
|
-
var
|
|
499
|
+
var __iconNode13 = [
|
|
456
500
|
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
457
501
|
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
458
502
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
459
503
|
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
460
504
|
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
461
505
|
];
|
|
462
|
-
var MonitorOff = createLucideIcon("monitor-off",
|
|
506
|
+
var MonitorOff = createLucideIcon("monitor-off", __iconNode13);
|
|
463
507
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
464
|
-
var
|
|
508
|
+
var __iconNode14 = [
|
|
465
509
|
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
466
510
|
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
467
511
|
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
468
512
|
];
|
|
469
|
-
var Monitor = createLucideIcon("monitor",
|
|
470
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-right.js
|
|
471
|
-
var __iconNode16 = [
|
|
472
|
-
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
473
|
-
["path", { d: "M15 3v18", key: "14nvp0" }]
|
|
474
|
-
];
|
|
475
|
-
var PanelRight = createLucideIcon("panel-right", __iconNode16);
|
|
513
|
+
var Monitor = createLucideIcon("monitor", __iconNode14);
|
|
476
514
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
477
|
-
var
|
|
515
|
+
var __iconNode15 = [
|
|
478
516
|
[
|
|
479
517
|
"path",
|
|
480
518
|
{
|
|
@@ -491,27 +529,32 @@ var __iconNode17 = [
|
|
|
491
529
|
}
|
|
492
530
|
]
|
|
493
531
|
];
|
|
494
|
-
var PhoneOff = createLucideIcon("phone-off",
|
|
495
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
496
|
-
var
|
|
532
|
+
var PhoneOff = createLucideIcon("phone-off", __iconNode15);
|
|
533
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send.js
|
|
534
|
+
var __iconNode16 = [
|
|
497
535
|
[
|
|
498
536
|
"path",
|
|
499
537
|
{
|
|
500
|
-
d: "
|
|
501
|
-
key: "
|
|
538
|
+
d: "M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",
|
|
539
|
+
key: "1ffxy3"
|
|
502
540
|
}
|
|
503
541
|
],
|
|
504
|
-
["
|
|
505
|
-
];
|
|
506
|
-
var Settings = createLucideIcon("settings", __iconNode18);
|
|
507
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/x.js
|
|
508
|
-
var __iconNode19 = [
|
|
509
|
-
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
510
|
-
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
542
|
+
["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
|
|
511
543
|
];
|
|
512
|
-
var
|
|
544
|
+
var Send = createLucideIcon("send", __iconNode16);
|
|
513
545
|
// src/components/MinimizedBubble.tsx
|
|
514
|
-
import {
|
|
546
|
+
import { useEffect as useEffect4 } from "react";
|
|
547
|
+
|
|
548
|
+
// src/hooks/useAgentVoiceState.ts
|
|
549
|
+
import { useVoiceAssistant } from "@livekit/components-react";
|
|
550
|
+
function useAgentVoiceState() {
|
|
551
|
+
const { state } = useVoiceAssistant();
|
|
552
|
+
return {
|
|
553
|
+
state,
|
|
554
|
+
isSpeaking: state === "speaking",
|
|
555
|
+
isListening: state === "listening"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
515
558
|
|
|
516
559
|
// src/hooks/useLiveAgent.ts
|
|
517
560
|
import { use } from "react";
|
|
@@ -524,6 +567,36 @@ function useLiveAgent() {
|
|
|
524
567
|
return publicValue;
|
|
525
568
|
}
|
|
526
569
|
|
|
570
|
+
// src/hooks/useMediaControls.ts
|
|
571
|
+
import { useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react";
|
|
572
|
+
import { ScreenSharePresets } from "livekit-client";
|
|
573
|
+
import { useCallback as useCallback3 } from "react";
|
|
574
|
+
var SCREEN_SHARE_OPTIONS = {
|
|
575
|
+
video: { displaySurface: "browser" },
|
|
576
|
+
resolution: ScreenSharePresets.h720fps30.resolution,
|
|
577
|
+
contentHint: "detail"
|
|
578
|
+
};
|
|
579
|
+
function useMediaControls() {
|
|
580
|
+
const { localParticipant } = useLocalParticipant2();
|
|
581
|
+
const isMuted = !localParticipant.isMicrophoneEnabled;
|
|
582
|
+
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
583
|
+
const toggleMute = useCallback3(async () => {
|
|
584
|
+
try {
|
|
585
|
+
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
console.error("Failed to toggle microphone:", error);
|
|
588
|
+
}
|
|
589
|
+
}, [localParticipant, isMuted]);
|
|
590
|
+
const toggleScreenShare = useCallback3(async () => {
|
|
591
|
+
try {
|
|
592
|
+
await localParticipant.setScreenShareEnabled(!isScreenSharing, SCREEN_SHARE_OPTIONS);
|
|
593
|
+
} catch (error) {
|
|
594
|
+
console.error("Failed to toggle screen share:", error);
|
|
595
|
+
}
|
|
596
|
+
}, [localParticipant, isScreenSharing]);
|
|
597
|
+
return { isMuted, toggleMute, isScreenSharing, toggleScreenShare };
|
|
598
|
+
}
|
|
599
|
+
|
|
527
600
|
// src/lib/utils.ts
|
|
528
601
|
import { clsx } from "clsx";
|
|
529
602
|
import { twMerge } from "tailwind-merge";
|
|
@@ -531,15 +604,102 @@ function cn(...inputs) {
|
|
|
531
604
|
return twMerge(clsx(inputs));
|
|
532
605
|
}
|
|
533
606
|
|
|
534
|
-
// src/components/
|
|
607
|
+
// src/components/Logo.tsx
|
|
608
|
+
import { useId } from "react";
|
|
535
609
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
536
|
-
function
|
|
537
|
-
|
|
610
|
+
function Logo({ className }) {
|
|
611
|
+
const reactId = useId().replace(/:/g, "");
|
|
612
|
+
const clipId = `skippr-logo-clip-${reactId}`;
|
|
613
|
+
const gradientId = `skippr-logo-gradient-${reactId}`;
|
|
614
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
615
|
+
width: "1em",
|
|
616
|
+
height: "1em",
|
|
617
|
+
viewBox: "0 0 30 30",
|
|
618
|
+
fill: "none",
|
|
619
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
620
|
+
role: "img",
|
|
621
|
+
"aria-label": "Skippr",
|
|
622
|
+
className,
|
|
623
|
+
children: [
|
|
624
|
+
/* @__PURE__ */ jsxs("g", {
|
|
625
|
+
clipPath: `url(#${clipId})`,
|
|
626
|
+
children: [
|
|
627
|
+
/* @__PURE__ */ jsx("path", {
|
|
628
|
+
d: "M0 10C0 4.47715 4.47715 0 10 0H20C25.5228 0 30 4.47715 30 10V20C30 25.5228 25.5228 30 20 30H10C4.47715 30 0 25.5228 0 20V10Z",
|
|
629
|
+
fill: "#2D2D3F"
|
|
630
|
+
}),
|
|
631
|
+
/* @__PURE__ */ jsx("rect", {
|
|
632
|
+
x: "7.83325",
|
|
633
|
+
y: "14.9404",
|
|
634
|
+
width: "12.4083",
|
|
635
|
+
height: "4.72833",
|
|
636
|
+
rx: "2.36417",
|
|
637
|
+
transform: "rotate(-45 7.83325 14.9404)",
|
|
638
|
+
fill: "#52FFF9"
|
|
639
|
+
}),
|
|
640
|
+
/* @__PURE__ */ jsx("path", {
|
|
641
|
+
d: "M18.8975 12.5928C20.2728 12.5928 21.3877 13.647 21.3877 14.9474C21.3877 16.2479 20.2728 17.3021 18.8975 17.3021L11.4269 17.3021C10.0516 17.3021 8.93665 16.2479 8.93665 14.9474C8.93665 13.647 10.0516 12.5928 11.4269 12.5928L18.8975 12.5928Z",
|
|
642
|
+
fill: `url(#${gradientId})`
|
|
643
|
+
}),
|
|
644
|
+
/* @__PURE__ */ jsx("rect", {
|
|
645
|
+
x: "10.1665",
|
|
646
|
+
y: "20.4404",
|
|
647
|
+
width: "12.4083",
|
|
648
|
+
height: "4.72833",
|
|
649
|
+
rx: "2.36417",
|
|
650
|
+
transform: "rotate(-45 10.1665 20.4404)",
|
|
651
|
+
fill: "white"
|
|
652
|
+
})
|
|
653
|
+
]
|
|
654
|
+
}),
|
|
655
|
+
/* @__PURE__ */ jsxs("defs", {
|
|
656
|
+
children: [
|
|
657
|
+
/* @__PURE__ */ jsxs("linearGradient", {
|
|
658
|
+
id: gradientId,
|
|
659
|
+
x1: "18.9237",
|
|
660
|
+
y1: "16.9997",
|
|
661
|
+
x2: "11.4129",
|
|
662
|
+
y2: "14.1904",
|
|
663
|
+
gradientUnits: "userSpaceOnUse",
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ jsx("stop", {
|
|
666
|
+
offset: "0.473958",
|
|
667
|
+
stopColor: "white"
|
|
668
|
+
}),
|
|
669
|
+
/* @__PURE__ */ jsx("stop", {
|
|
670
|
+
offset: "1",
|
|
671
|
+
stopColor: "#52FFF9"
|
|
672
|
+
})
|
|
673
|
+
]
|
|
674
|
+
}),
|
|
675
|
+
/* @__PURE__ */ jsx("clipPath", {
|
|
676
|
+
id: clipId,
|
|
677
|
+
children: /* @__PURE__ */ jsx("rect", {
|
|
678
|
+
width: "30",
|
|
679
|
+
height: "30",
|
|
680
|
+
fill: "white"
|
|
681
|
+
})
|
|
682
|
+
})
|
|
683
|
+
]
|
|
684
|
+
})
|
|
685
|
+
]
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/components/ui/tooltip.tsx
|
|
690
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
691
|
+
var ALIGN_CLASSES = {
|
|
692
|
+
center: "skippr:left-1/2 skippr:-translate-x-1/2",
|
|
693
|
+
start: "skippr:left-0",
|
|
694
|
+
end: "skippr:right-0"
|
|
695
|
+
};
|
|
696
|
+
function Tooltip({ label, children, position = "top", align = "center" }) {
|
|
697
|
+
return /* @__PURE__ */ jsxs2("span", {
|
|
538
698
|
className: "skippr:relative skippr:inline-flex skippr:group",
|
|
539
699
|
children: [
|
|
540
700
|
children,
|
|
541
|
-
/* @__PURE__ */
|
|
542
|
-
className: cn("skippr:pointer-events-none skippr:absolute skippr:
|
|
701
|
+
/* @__PURE__ */ jsx2("span", {
|
|
702
|
+
className: cn("skippr:pointer-events-none skippr:absolute skippr:z-10", "skippr:whitespace-nowrap skippr:rounded-md skippr:bg-foreground skippr:px-2 skippr:py-1", "skippr:text-[11px] skippr:text-background skippr:font-medium", "skippr:opacity-0 skippr:scale-95 skippr:transition-all skippr:duration-150", "skippr:group-hover:opacity-100 skippr:group-hover:scale-100", "skippr:group-focus-within:opacity-100 skippr:group-focus-within:scale-100", ALIGN_CLASSES[align], position === "top" && "skippr:bottom-full skippr:mb-1.5", position === "bottom" && "skippr:top-full skippr:mt-1.5"),
|
|
543
703
|
"aria-hidden": "true",
|
|
544
704
|
children: label
|
|
545
705
|
})
|
|
@@ -548,141 +708,111 @@ function Tooltip({ label, children, position = "top" }) {
|
|
|
548
708
|
}
|
|
549
709
|
|
|
550
710
|
// src/components/MinimizedBubble.tsx
|
|
551
|
-
import { jsx as
|
|
552
|
-
|
|
711
|
+
import { jsx as jsx3, jsxs as jsxs3, Fragment } from "react/jsx-runtime";
|
|
712
|
+
var BUBBLE_BUTTON = "skippr:flex skippr:size-12 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-[14px] skippr:shadow-[0_4px_16px_rgba(45,43,61,0.45),0_2px_4px_rgba(0,0,0,0.1)] skippr:transition-all skippr:hover:-translate-y-0.5 skippr:active:translate-y-0";
|
|
713
|
+
function AgentBubbleContent({ agentState }) {
|
|
553
714
|
if (agentState === "speaking") {
|
|
554
|
-
return /* @__PURE__ */
|
|
555
|
-
className: "skippr:flex skippr:items-
|
|
715
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
716
|
+
className: "skippr:flex skippr:h-5 skippr:items-center skippr:justify-center skippr:gap-[3px]",
|
|
556
717
|
children: [
|
|
557
|
-
/* @__PURE__ */
|
|
558
|
-
className: "skippr:w-[3px] skippr:h-
|
|
718
|
+
/* @__PURE__ */ jsx3("span", {
|
|
719
|
+
className: "skippr:w-[3px] skippr:h-2 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_infinite]"
|
|
559
720
|
}),
|
|
560
|
-
/* @__PURE__ */
|
|
561
|
-
className: "skippr:w-[3px] skippr:h-
|
|
721
|
+
/* @__PURE__ */ jsx3("span", {
|
|
722
|
+
className: "skippr:w-[3px] skippr:h-3.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.15s_infinite]"
|
|
562
723
|
}),
|
|
563
|
-
/* @__PURE__ */
|
|
564
|
-
className: "skippr:w-[3px] skippr:h-
|
|
724
|
+
/* @__PURE__ */ jsx3("span", {
|
|
725
|
+
className: "skippr:w-[3px] skippr:h-2.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.3s_infinite]"
|
|
565
726
|
}),
|
|
566
|
-
/* @__PURE__ */
|
|
567
|
-
className: "skippr:w-[3px] skippr:h-
|
|
727
|
+
/* @__PURE__ */ jsx3("span", {
|
|
728
|
+
className: "skippr:w-[3px] skippr:h-4 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.45s_infinite]"
|
|
729
|
+
}),
|
|
730
|
+
/* @__PURE__ */ jsx3("span", {
|
|
731
|
+
className: "skippr:w-[3px] skippr:h-1.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.6s_infinite]"
|
|
568
732
|
})
|
|
569
733
|
]
|
|
570
734
|
});
|
|
571
735
|
}
|
|
572
|
-
if (agentState === "listening") {
|
|
573
|
-
return /* @__PURE__ */ jsx2(Bot, {
|
|
574
|
-
className: "skippr:relative skippr:z-10 skippr:size-5 skippr:animate-skippr-breathe"
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
736
|
if (agentState === "thinking") {
|
|
578
|
-
return /* @__PURE__ */
|
|
579
|
-
className: "skippr:
|
|
737
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
738
|
+
className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-[4px]",
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ jsx3("span", {
|
|
741
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:0ms]"
|
|
742
|
+
}),
|
|
743
|
+
/* @__PURE__ */ jsx3("span", {
|
|
744
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:150ms]"
|
|
745
|
+
}),
|
|
746
|
+
/* @__PURE__ */ jsx3("span", {
|
|
747
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:300ms]"
|
|
748
|
+
})
|
|
749
|
+
]
|
|
580
750
|
});
|
|
581
751
|
}
|
|
582
|
-
return /* @__PURE__ */
|
|
583
|
-
className: "skippr:
|
|
752
|
+
return /* @__PURE__ */ jsx3(Logo, {
|
|
753
|
+
className: "skippr:size-7"
|
|
584
754
|
});
|
|
585
755
|
}
|
|
586
756
|
function ConnectedBubbleContent() {
|
|
587
|
-
const { expandPanel, disconnect } = useLiveAgent();
|
|
588
|
-
const { state: agentState } =
|
|
589
|
-
const {
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
const toggleMute = useCallback3(async () => {
|
|
593
|
-
try {
|
|
594
|
-
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
595
|
-
} catch (e) {
|
|
596
|
-
console.error("Failed to toggle microphone:", e);
|
|
597
|
-
}
|
|
598
|
-
}, [localParticipant, isMuted]);
|
|
599
|
-
const toggleScreenShare = useCallback3(async () => {
|
|
600
|
-
try {
|
|
601
|
-
await localParticipant.setScreenShareEnabled(!isScreenSharing, {
|
|
602
|
-
video: { displaySurface: "browser" },
|
|
603
|
-
resolution: ScreenSharePresets.h720fps30.resolution,
|
|
604
|
-
contentHint: "detail"
|
|
605
|
-
});
|
|
606
|
-
} catch (e) {
|
|
607
|
-
console.error("Failed to toggle screen share:", e);
|
|
608
|
-
}
|
|
609
|
-
}, [localParticipant, isScreenSharing]);
|
|
610
|
-
const isSpeaking = agentState === "speaking";
|
|
611
|
-
const isListening = agentState === "listening";
|
|
612
|
-
return /* @__PURE__ */ jsxs2(Fragment, {
|
|
757
|
+
const { expandPanel, disconnect, position } = useLiveAgent();
|
|
758
|
+
const { state: agentState } = useAgentVoiceState();
|
|
759
|
+
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
760
|
+
const tooltipAlign = position === "right" ? "end" : "start";
|
|
761
|
+
return /* @__PURE__ */ jsxs3(Fragment, {
|
|
613
762
|
children: [
|
|
614
|
-
/* @__PURE__ */
|
|
615
|
-
label: "
|
|
616
|
-
|
|
763
|
+
/* @__PURE__ */ jsx3(Tooltip, {
|
|
764
|
+
label: isMuted ? "Unmute" : "Mute",
|
|
765
|
+
align: tooltipAlign,
|
|
766
|
+
children: /* @__PURE__ */ jsx3("button", {
|
|
617
767
|
type: "button",
|
|
618
|
-
onClick:
|
|
619
|
-
|
|
620
|
-
"
|
|
621
|
-
children:
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}),
|
|
627
|
-
/* @__PURE__ */ jsx2("span", {
|
|
628
|
-
className: "skippr:absolute skippr:inset-0 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-speak-ripple-delayed"
|
|
629
|
-
})
|
|
630
|
-
]
|
|
631
|
-
}),
|
|
632
|
-
/* @__PURE__ */ jsx2(AgentAvatar, {
|
|
633
|
-
agentState
|
|
634
|
-
})
|
|
635
|
-
]
|
|
768
|
+
onClick: toggleMute,
|
|
769
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
770
|
+
className: cn(BUBBLE_BUTTON, isMuted ? "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
|
|
771
|
+
children: isMuted ? /* @__PURE__ */ jsx3(MicOff, {
|
|
772
|
+
className: "skippr:size-5"
|
|
773
|
+
}) : /* @__PURE__ */ jsx3(Mic, {
|
|
774
|
+
className: "skippr:size-5"
|
|
775
|
+
})
|
|
636
776
|
})
|
|
637
777
|
}),
|
|
638
|
-
/* @__PURE__ */
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
651
|
-
children: isMuted ? /* @__PURE__ */ jsx2(MicOff, {
|
|
652
|
-
className: "skippr:size-4"
|
|
653
|
-
}) : /* @__PURE__ */ jsx2(Mic, {
|
|
654
|
-
className: "skippr:size-4"
|
|
655
|
-
})
|
|
656
|
-
})
|
|
657
|
-
}),
|
|
658
|
-
/* @__PURE__ */ jsx2(Tooltip, {
|
|
659
|
-
label: isScreenSharing ? "Stop sharing" : "Share screen",
|
|
660
|
-
children: /* @__PURE__ */ jsx2("button", {
|
|
661
|
-
type: "button",
|
|
662
|
-
onClick: toggleScreenShare,
|
|
663
|
-
className: cn("skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center", "skippr:transition-colors skippr:cursor-pointer", isScreenSharing ? "skippr:text-foreground skippr:hover:bg-accent" : "skippr:bg-destructive skippr:text-white"),
|
|
664
|
-
"aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
|
|
665
|
-
children: isScreenSharing ? /* @__PURE__ */ jsx2(MonitorOff, {
|
|
666
|
-
className: "skippr:size-4"
|
|
667
|
-
}) : /* @__PURE__ */ jsx2(Monitor, {
|
|
668
|
-
className: "skippr:size-4"
|
|
669
|
-
})
|
|
670
|
-
})
|
|
778
|
+
/* @__PURE__ */ jsx3(Tooltip, {
|
|
779
|
+
label: isScreenSharing ? "Stop sharing" : "Share screen",
|
|
780
|
+
align: tooltipAlign,
|
|
781
|
+
children: /* @__PURE__ */ jsx3("button", {
|
|
782
|
+
type: "button",
|
|
783
|
+
onClick: toggleScreenShare,
|
|
784
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
785
|
+
className: cn(BUBBLE_BUTTON, isScreenSharing ? "skippr:bg-bubble skippr:text-white skippr:hover:brightness-110" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
|
|
786
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx3(MonitorOff, {
|
|
787
|
+
className: "skippr:size-5"
|
|
788
|
+
}) : /* @__PURE__ */ jsx3(Monitor, {
|
|
789
|
+
className: "skippr:size-5"
|
|
671
790
|
})
|
|
672
|
-
|
|
673
|
-
}),
|
|
674
|
-
/* @__PURE__ */ jsx2("div", {
|
|
675
|
-
className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
|
|
791
|
+
})
|
|
676
792
|
}),
|
|
677
|
-
/* @__PURE__ */
|
|
793
|
+
/* @__PURE__ */ jsx3(Tooltip, {
|
|
678
794
|
label: "End session",
|
|
679
|
-
|
|
795
|
+
align: tooltipAlign,
|
|
796
|
+
children: /* @__PURE__ */ jsx3("button", {
|
|
680
797
|
type: "button",
|
|
681
798
|
onClick: () => disconnect(),
|
|
682
|
-
|
|
683
|
-
"
|
|
684
|
-
children: /* @__PURE__ */
|
|
685
|
-
className: "skippr:size-
|
|
799
|
+
"aria-label": "End session",
|
|
800
|
+
className: cn(BUBBLE_BUTTON, "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90"),
|
|
801
|
+
children: /* @__PURE__ */ jsx3(PhoneOff, {
|
|
802
|
+
className: "skippr:size-5"
|
|
803
|
+
})
|
|
804
|
+
})
|
|
805
|
+
}),
|
|
806
|
+
/* @__PURE__ */ jsx3(Tooltip, {
|
|
807
|
+
label: "Open chat & transcript",
|
|
808
|
+
align: tooltipAlign,
|
|
809
|
+
children: /* @__PURE__ */ jsx3("button", {
|
|
810
|
+
type: "button",
|
|
811
|
+
onClick: expandPanel,
|
|
812
|
+
"aria-label": "Open chat & transcript",
|
|
813
|
+
className: cn(BUBBLE_BUTTON, "skippr:bg-bubble skippr:hover:brightness-110"),
|
|
814
|
+
children: /* @__PURE__ */ jsx3(AgentBubbleContent, {
|
|
815
|
+
agentState
|
|
686
816
|
})
|
|
687
817
|
})
|
|
688
818
|
})
|
|
@@ -690,123 +820,25 @@ function ConnectedBubbleContent() {
|
|
|
690
820
|
});
|
|
691
821
|
}
|
|
692
822
|
function IdleBubbleContent() {
|
|
693
|
-
const { expandPanel,
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}, [isAuthenticated, expandPanel, startSession]);
|
|
710
|
-
return /* @__PURE__ */ jsxs2("div", {
|
|
711
|
-
className: "skippr:flex skippr:items-center skippr:gap-0",
|
|
712
|
-
onMouseEnter: () => !isStarting && setShowCapabilities(true),
|
|
713
|
-
onMouseLeave: () => !isStarting && setShowCapabilities(false),
|
|
714
|
-
children: [
|
|
715
|
-
/* @__PURE__ */ jsx2("button", {
|
|
716
|
-
type: "button",
|
|
717
|
-
onClick: handleStart,
|
|
718
|
-
disabled: isStarting,
|
|
719
|
-
className: cn("skippr:relative skippr:size-11 skippr:rounded-full", "skippr:bg-primary skippr:text-primary-foreground", "skippr:flex skippr:items-center skippr:justify-center", "skippr:cursor-pointer skippr:transition-all skippr:duration-300", "skippr:hover:brightness-110", isStarting && "skippr:animate-skippr-pulse-ring skippr:cursor-not-allowed"),
|
|
720
|
-
"aria-label": "AI Agent",
|
|
721
|
-
children: /* @__PURE__ */ jsx2(Bot, {
|
|
722
|
-
className: "skippr:relative skippr:z-10 skippr:size-5"
|
|
823
|
+
const { expandPanel, position } = useLiveAgent();
|
|
824
|
+
const tooltipAlign = position === "right" ? "end" : "start";
|
|
825
|
+
return /* @__PURE__ */ jsx3(Tooltip, {
|
|
826
|
+
label: "Open Skippr assistant",
|
|
827
|
+
align: tooltipAlign,
|
|
828
|
+
children: /* @__PURE__ */ jsxs3("button", {
|
|
829
|
+
type: "button",
|
|
830
|
+
onClick: expandPanel,
|
|
831
|
+
"aria-label": "Skippr assistant",
|
|
832
|
+
className: cn(BUBBLE_BUTTON, "skippr:relative skippr:bg-bubble skippr:hover:brightness-110"),
|
|
833
|
+
children: [
|
|
834
|
+
/* @__PURE__ */ jsx3(Logo, {
|
|
835
|
+
className: "skippr:relative skippr:z-10 skippr:size-7"
|
|
836
|
+
}),
|
|
837
|
+
/* @__PURE__ */ jsx3("span", {
|
|
838
|
+
className: "skippr:absolute skippr:-inset-[3px] skippr:animate-pulse skippr:rounded-[17px] skippr:border-2 skippr:border-bubble/50"
|
|
723
839
|
})
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:ml-2 skippr:mr-1 skippr:whitespace-nowrap skippr:text-xs skippr:text-muted-foreground",
|
|
727
|
-
children: [
|
|
728
|
-
/* @__PURE__ */ jsx2("span", {
|
|
729
|
-
className: "skippr:inline-block skippr:size-1.5 skippr:rounded-full skippr:bg-primary skippr:animate-pulse"
|
|
730
|
-
}),
|
|
731
|
-
"Setting up voice & screen..."
|
|
732
|
-
]
|
|
733
|
-
}) : /* @__PURE__ */ jsxs2(Fragment, {
|
|
734
|
-
children: [
|
|
735
|
-
/* @__PURE__ */ jsx2("div", {
|
|
736
|
-
className: cn("skippr:overflow-hidden skippr:transition-all skippr:duration-500 skippr:ease-in-out", showCapabilities ? "skippr:max-w-64 skippr:opacity-100 skippr:ml-2 skippr:mr-1" : "skippr:max-w-0 skippr:opacity-0 skippr:ml-0 skippr:mr-0"),
|
|
737
|
-
"aria-hidden": !showCapabilities,
|
|
738
|
-
children: /* @__PURE__ */ jsxs2("button", {
|
|
739
|
-
type: "button",
|
|
740
|
-
onClick: handleStart,
|
|
741
|
-
tabIndex: showCapabilities ? 0 : -1,
|
|
742
|
-
className: "skippr:flex skippr:items-center skippr:gap-3 skippr:whitespace-nowrap skippr:text-xs skippr:text-muted-foreground skippr:cursor-pointer skippr:hover:text-foreground skippr:transition-colors",
|
|
743
|
-
children: [
|
|
744
|
-
/* @__PURE__ */ jsxs2("span", {
|
|
745
|
-
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
746
|
-
children: [
|
|
747
|
-
/* @__PURE__ */ jsx2(Mic, {
|
|
748
|
-
className: "skippr:size-3"
|
|
749
|
-
}),
|
|
750
|
-
"Talk"
|
|
751
|
-
]
|
|
752
|
-
}),
|
|
753
|
-
/* @__PURE__ */ jsx2("span", {
|
|
754
|
-
className: "skippr:text-border",
|
|
755
|
-
children: "·"
|
|
756
|
-
}),
|
|
757
|
-
/* @__PURE__ */ jsxs2("span", {
|
|
758
|
-
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
759
|
-
children: [
|
|
760
|
-
/* @__PURE__ */ jsx2(Monitor, {
|
|
761
|
-
className: "skippr:size-3"
|
|
762
|
-
}),
|
|
763
|
-
"Screen"
|
|
764
|
-
]
|
|
765
|
-
}),
|
|
766
|
-
/* @__PURE__ */ jsx2("span", {
|
|
767
|
-
className: "skippr:text-border",
|
|
768
|
-
children: "·"
|
|
769
|
-
}),
|
|
770
|
-
/* @__PURE__ */ jsxs2("span", {
|
|
771
|
-
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
772
|
-
children: [
|
|
773
|
-
/* @__PURE__ */ jsx2(MessageSquare, {
|
|
774
|
-
className: "skippr:size-3"
|
|
775
|
-
}),
|
|
776
|
-
"Chat"
|
|
777
|
-
]
|
|
778
|
-
})
|
|
779
|
-
]
|
|
780
|
-
})
|
|
781
|
-
}),
|
|
782
|
-
/* @__PURE__ */ jsx2("div", {
|
|
783
|
-
className: cn("skippr:overflow-hidden skippr:transition-all skippr:duration-500 skippr:ease-in-out", showCapabilities ? "skippr:max-w-0 skippr:opacity-0" : "skippr:max-w-12 skippr:opacity-100"),
|
|
784
|
-
"aria-hidden": showCapabilities,
|
|
785
|
-
children: /* @__PURE__ */ jsxs2("div", {
|
|
786
|
-
className: "skippr:flex skippr:items-center",
|
|
787
|
-
children: [
|
|
788
|
-
/* @__PURE__ */ jsx2("div", {
|
|
789
|
-
className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
|
|
790
|
-
}),
|
|
791
|
-
/* @__PURE__ */ jsx2(Tooltip, {
|
|
792
|
-
label: "Start session",
|
|
793
|
-
children: /* @__PURE__ */ jsx2("button", {
|
|
794
|
-
type: "button",
|
|
795
|
-
onClick: handleStart,
|
|
796
|
-
tabIndex: showCapabilities ? -1 : 0,
|
|
797
|
-
className: "skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center skippr:transition-colors skippr:cursor-pointer skippr:bg-primary skippr:text-primary-foreground skippr:hover:brightness-110",
|
|
798
|
-
"aria-label": "Start session",
|
|
799
|
-
children: /* @__PURE__ */ jsx2(Monitor, {
|
|
800
|
-
className: "skippr:size-4"
|
|
801
|
-
})
|
|
802
|
-
})
|
|
803
|
-
})
|
|
804
|
-
]
|
|
805
|
-
})
|
|
806
|
-
})
|
|
807
|
-
]
|
|
808
|
-
})
|
|
809
|
-
]
|
|
840
|
+
]
|
|
841
|
+
})
|
|
810
842
|
});
|
|
811
843
|
}
|
|
812
844
|
function WelcomeBubble({
|
|
@@ -814,18 +846,18 @@ function WelcomeBubble({
|
|
|
814
846
|
position,
|
|
815
847
|
onDismiss
|
|
816
848
|
}) {
|
|
817
|
-
|
|
849
|
+
useEffect4(() => {
|
|
818
850
|
const timer = setTimeout(onDismiss, 5000);
|
|
819
851
|
return () => clearTimeout(timer);
|
|
820
852
|
}, [onDismiss]);
|
|
821
|
-
return /* @__PURE__ */
|
|
853
|
+
return /* @__PURE__ */ jsxs3("button", {
|
|
822
854
|
type: "button",
|
|
823
855
|
className: cn("skippr:absolute skippr:bottom-full skippr:mb-3", "skippr:max-w-64 skippr:rounded-xl skippr:bg-card skippr:shadow-lg", "skippr:border skippr:border-border skippr:px-4 skippr:py-3", "skippr:text-sm skippr:text-foreground skippr:leading-relaxed skippr:text-left", "skippr:animate-[skippr-fade-in_0.3s_ease-out]", "skippr:cursor-pointer", position === "right" ? "skippr:right-0" : "skippr:left-0"),
|
|
824
856
|
onClick: onDismiss,
|
|
825
857
|
"aria-label": "Dismiss",
|
|
826
858
|
children: [
|
|
827
859
|
message,
|
|
828
|
-
/* @__PURE__ */
|
|
860
|
+
/* @__PURE__ */ jsx3("span", {
|
|
829
861
|
className: cn("skippr:absolute skippr:top-full skippr:size-2.5", "skippr:border-l skippr:border-t skippr:border-border skippr:bg-card", "skippr:rotate-[225deg]", position === "right" ? "skippr:right-5" : "skippr:left-5", "skippr:-mt-[5px]")
|
|
830
862
|
})
|
|
831
863
|
]
|
|
@@ -836,31 +868,63 @@ function MinimizedBubble({
|
|
|
836
868
|
welcomeDismissed,
|
|
837
869
|
onDismissWelcome
|
|
838
870
|
}) {
|
|
839
|
-
const { isConnected, position } = useLiveAgent();
|
|
840
|
-
|
|
841
|
-
|
|
871
|
+
const { isConnected, isStarting, position } = useLiveAgent();
|
|
872
|
+
const inSession = isConnected || isStarting;
|
|
873
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
874
|
+
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-2", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
842
875
|
children: [
|
|
843
|
-
welcomeMessage && !
|
|
876
|
+
welcomeMessage && !inSession && !welcomeDismissed && /* @__PURE__ */ jsx3(WelcomeBubble, {
|
|
844
877
|
message: welcomeMessage,
|
|
845
878
|
position,
|
|
846
879
|
onDismiss: onDismissWelcome
|
|
847
880
|
}),
|
|
848
|
-
|
|
881
|
+
inSession ? /* @__PURE__ */ jsx3(ConnectedBubbleContent, {}) : /* @__PURE__ */ jsx3(IdleBubbleContent, {})
|
|
849
882
|
]
|
|
850
883
|
});
|
|
851
884
|
}
|
|
852
885
|
|
|
886
|
+
// src/components/ObservingBanner.tsx
|
|
887
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
888
|
+
function ObservingBanner() {
|
|
889
|
+
const { isConnected } = useLiveAgent();
|
|
890
|
+
const { isScreenSharing } = useMediaControls();
|
|
891
|
+
if (!isConnected || !isScreenSharing)
|
|
892
|
+
return null;
|
|
893
|
+
return /* @__PURE__ */ jsx4("div", {
|
|
894
|
+
className: "skippr:fixed skippr:top-0 skippr:left-0 skippr:right-0 skippr:z-[2147483647] skippr:flex skippr:justify-center skippr:pointer-events-none",
|
|
895
|
+
children: /* @__PURE__ */ jsxs4("div", {
|
|
896
|
+
className: "skippr:pointer-events-auto skippr:flex skippr:items-center skippr:gap-2 skippr:bg-indigo-500/95 skippr:backdrop-blur-sm skippr:text-white skippr:text-xs skippr:font-medium skippr:px-4 skippr:py-1.5 skippr:rounded-b-lg skippr:shadow-lg",
|
|
897
|
+
children: [
|
|
898
|
+
/* @__PURE__ */ jsxs4("span", {
|
|
899
|
+
className: "skippr:relative skippr:flex skippr:size-1.5",
|
|
900
|
+
children: [
|
|
901
|
+
/* @__PURE__ */ jsx4("span", {
|
|
902
|
+
className: "skippr:absolute skippr:inline-flex skippr:size-full skippr:animate-ping skippr:rounded-full skippr:bg-emerald-400 skippr:opacity-75"
|
|
903
|
+
}),
|
|
904
|
+
/* @__PURE__ */ jsx4("span", {
|
|
905
|
+
className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-emerald-400"
|
|
906
|
+
})
|
|
907
|
+
]
|
|
908
|
+
}),
|
|
909
|
+
/* @__PURE__ */ jsx4(Eye, {
|
|
910
|
+
className: "skippr:size-3.5"
|
|
911
|
+
}),
|
|
912
|
+
/* @__PURE__ */ jsx4("span", {
|
|
913
|
+
children: "Skippr is observing this page"
|
|
914
|
+
})
|
|
915
|
+
]
|
|
916
|
+
})
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
|
|
853
920
|
// src/components/Sidebar.tsx
|
|
854
|
-
import {
|
|
855
|
-
import { ConnectionState } from "livekit-client";
|
|
856
|
-
import { useEffect as useEffect8, useState as useState8 } from "react";
|
|
921
|
+
import { useEffect as useEffect11 } from "react";
|
|
857
922
|
|
|
858
923
|
// src/hooks/useCombinedMessages.ts
|
|
859
|
-
import { useVoiceAssistant as useVoiceAssistant2 } from "@livekit/components-react";
|
|
860
924
|
import { useMemo as useMemo4 } from "react";
|
|
861
925
|
|
|
862
926
|
// src/hooks/useChatMessages.ts
|
|
863
|
-
import { useChat, useLocalParticipant as
|
|
927
|
+
import { useChat, useLocalParticipant as useLocalParticipant3 } from "@livekit/components-react";
|
|
864
928
|
import { useMemo as useMemo2 } from "react";
|
|
865
929
|
|
|
866
930
|
// src/lib/filterSystemMessages.ts
|
|
@@ -872,7 +936,7 @@ function filterSystemMessages(messages) {
|
|
|
872
936
|
// src/hooks/useChatMessages.ts
|
|
873
937
|
function useChatMessages() {
|
|
874
938
|
const { chatMessages: rawMessages, send, isSending } = useChat();
|
|
875
|
-
const { localParticipant } =
|
|
939
|
+
const { localParticipant } = useLocalParticipant3();
|
|
876
940
|
const localIdentity = localParticipant.identity;
|
|
877
941
|
const chatMessages = useMemo2(() => {
|
|
878
942
|
const sortedMessages = rawMessages.map((msg) => ({
|
|
@@ -888,11 +952,11 @@ function useChatMessages() {
|
|
|
888
952
|
}
|
|
889
953
|
|
|
890
954
|
// src/hooks/useStreamingTranscript.ts
|
|
891
|
-
import { useLocalParticipant as
|
|
955
|
+
import { useLocalParticipant as useLocalParticipant4, useTranscriptions } from "@livekit/components-react";
|
|
892
956
|
import { useMemo as useMemo3 } from "react";
|
|
893
957
|
function useStreamingTranscript() {
|
|
894
958
|
const transcriptions = useTranscriptions();
|
|
895
|
-
const { localParticipant } =
|
|
959
|
+
const { localParticipant } = useLocalParticipant4();
|
|
896
960
|
const localIdentity = localParticipant.identity;
|
|
897
961
|
const transcriptMessages = useMemo3(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
|
|
898
962
|
id: stream.streamInfo.id,
|
|
@@ -924,7 +988,7 @@ function mergeChatsIntoTranscripts(transcripts, chats) {
|
|
|
924
988
|
function useCombinedMessages() {
|
|
925
989
|
const { transcriptMessages } = useStreamingTranscript();
|
|
926
990
|
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
927
|
-
const { state: agentState } =
|
|
991
|
+
const { state: agentState } = useAgentVoiceState();
|
|
928
992
|
const allMessages = useMemo4(() => {
|
|
929
993
|
if (chatMessages.length === 0)
|
|
930
994
|
return transcriptMessages;
|
|
@@ -940,11 +1004,11 @@ import { useCallback as useCallback4 } from "react";
|
|
|
940
1004
|
|
|
941
1005
|
// src/hooks/useAgentState.ts
|
|
942
1006
|
import { useRemoteParticipants } from "@livekit/components-react";
|
|
943
|
-
import { useEffect as
|
|
1007
|
+
import { useEffect as useEffect5, useState as useState3 } from "react";
|
|
944
1008
|
function useAgentState(attributeKey, parse, initial) {
|
|
945
|
-
const [value, setValue] =
|
|
1009
|
+
const [value, setValue] = useState3(initial);
|
|
946
1010
|
const remoteParticipants = useRemoteParticipants();
|
|
947
|
-
|
|
1011
|
+
useEffect5(() => {
|
|
948
1012
|
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
949
1013
|
if (agentParticipant) {
|
|
950
1014
|
const attr = agentParticipant.attributes?.[attributeKey];
|
|
@@ -995,30 +1059,152 @@ function usePhaseUpdates() {
|
|
|
995
1059
|
return { phases };
|
|
996
1060
|
}
|
|
997
1061
|
|
|
998
|
-
// src/hooks/
|
|
999
|
-
import {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1062
|
+
// src/hooks/useSessionRemaining.ts
|
|
1063
|
+
import { useEffect as useEffect6, useRef as useRef2, useState as useState4 } from "react";
|
|
1064
|
+
|
|
1065
|
+
// src/lib/format.ts
|
|
1066
|
+
function formatTime(seconds) {
|
|
1067
|
+
const m = Math.floor(seconds / 60).toString().padStart(2, "0");
|
|
1068
|
+
const s = (seconds % 60).toString().padStart(2, "0");
|
|
1069
|
+
return `${m}:${s}`;
|
|
1070
|
+
}
|
|
1071
|
+
function parseNumber(s) {
|
|
1072
|
+
const n = Number(s);
|
|
1073
|
+
return n > 0 ? n : null;
|
|
1008
1074
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1075
|
+
|
|
1076
|
+
// src/hooks/useSessionRemaining.ts
|
|
1077
|
+
function useSessionRemaining() {
|
|
1078
|
+
const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
|
|
1079
|
+
const endTimeRef = useRef2(null);
|
|
1080
|
+
const [remaining, setRemaining] = useState4(null);
|
|
1081
|
+
useEffect6(() => {
|
|
1082
|
+
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
1083
|
+
return;
|
|
1084
|
+
const endTime = Date.now() + maxCallDuration * 1000;
|
|
1085
|
+
endTimeRef.current = endTime;
|
|
1086
|
+
const tick = () => {
|
|
1087
|
+
const secs = Math.ceil((endTime - Date.now()) / 1000);
|
|
1088
|
+
setRemaining(Math.max(secs, 0));
|
|
1089
|
+
};
|
|
1090
|
+
tick();
|
|
1091
|
+
const id = setInterval(tick, 1000);
|
|
1092
|
+
return () => clearInterval(id);
|
|
1093
|
+
}, [maxCallDuration]);
|
|
1094
|
+
return remaining;
|
|
1013
1095
|
}
|
|
1014
1096
|
|
|
1015
1097
|
// src/lib/constants.ts
|
|
1016
|
-
var SIDEBAR_WIDTH =
|
|
1098
|
+
var SIDEBAR_WIDTH = 360;
|
|
1017
1099
|
|
|
1018
|
-
// src/
|
|
1019
|
-
import {
|
|
1020
|
-
|
|
1021
|
-
|
|
1100
|
+
// src/hooks/useElapsedSeconds.ts
|
|
1101
|
+
import { useEffect as useEffect7, useState as useState5 } from "react";
|
|
1102
|
+
function useElapsedSeconds(isRunning) {
|
|
1103
|
+
const [elapsed, setElapsed] = useState5(0);
|
|
1104
|
+
useEffect7(() => {
|
|
1105
|
+
if (!isRunning) {
|
|
1106
|
+
setElapsed(0);
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
const startedAt = Date.now();
|
|
1110
|
+
setElapsed(0);
|
|
1111
|
+
const id = setInterval(() => {
|
|
1112
|
+
setElapsed(Math.floor((Date.now() - startedAt) / 1000));
|
|
1113
|
+
}, 1000);
|
|
1114
|
+
return () => clearInterval(id);
|
|
1115
|
+
}, [isRunning]);
|
|
1116
|
+
return elapsed;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// src/components/ChatHeader.tsx
|
|
1120
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1121
|
+
function ChatHeader() {
|
|
1122
|
+
const { isConnected, minimizePanel, minimizable } = useLiveAgent();
|
|
1123
|
+
const elapsed = useElapsedSeconds(isConnected);
|
|
1124
|
+
return /* @__PURE__ */ jsxs5("header", {
|
|
1125
|
+
className: "skippr:sticky skippr:top-0 skippr:z-10 skippr:flex skippr:shrink-0 skippr:items-center skippr:justify-between skippr:border-b skippr:border-border skippr:bg-primary skippr:px-4 skippr:py-3",
|
|
1126
|
+
children: [
|
|
1127
|
+
/* @__PURE__ */ jsx5("p", {
|
|
1128
|
+
className: "skippr:text-sm skippr:font-semibold skippr:text-primary-foreground",
|
|
1129
|
+
children: "Skippr"
|
|
1130
|
+
}),
|
|
1131
|
+
/* @__PURE__ */ jsxs5("div", {
|
|
1132
|
+
className: "skippr:flex skippr:items-center skippr:gap-2",
|
|
1133
|
+
children: [
|
|
1134
|
+
isConnected && /* @__PURE__ */ jsxs5("div", {
|
|
1135
|
+
className: "skippr:flex skippr:items-center skippr:gap-1.5 skippr:rounded-full skippr:bg-primary-foreground/20 skippr:px-2.5 skippr:py-1",
|
|
1136
|
+
children: [
|
|
1137
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
1138
|
+
className: "skippr:relative skippr:flex skippr:size-1.5",
|
|
1139
|
+
children: [
|
|
1140
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1141
|
+
className: "skippr:absolute skippr:inline-flex skippr:h-full skippr:w-full skippr:animate-ping skippr:rounded-full skippr:bg-red-400 skippr:opacity-75"
|
|
1142
|
+
}),
|
|
1143
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1144
|
+
className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-red-400"
|
|
1145
|
+
})
|
|
1146
|
+
]
|
|
1147
|
+
}),
|
|
1148
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1149
|
+
className: "skippr:text-[10px] skippr:font-medium skippr:text-primary-foreground",
|
|
1150
|
+
children: "REC"
|
|
1151
|
+
}),
|
|
1152
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1153
|
+
className: "skippr:text-[10px] skippr:font-mono skippr:text-primary-foreground",
|
|
1154
|
+
children: formatTime(elapsed)
|
|
1155
|
+
})
|
|
1156
|
+
]
|
|
1157
|
+
}),
|
|
1158
|
+
minimizable && /* @__PURE__ */ jsx5("button", {
|
|
1159
|
+
type: "button",
|
|
1160
|
+
onClick: minimizePanel,
|
|
1161
|
+
"aria-label": "Minimize",
|
|
1162
|
+
className: "skippr:flex skippr:size-6 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-md skippr:text-primary-foreground/70 skippr:transition-colors skippr:hover:bg-primary-foreground/10 skippr:hover:text-primary-foreground",
|
|
1163
|
+
children: /* @__PURE__ */ jsx5(Minimize2, {
|
|
1164
|
+
className: "skippr:size-3.5"
|
|
1165
|
+
})
|
|
1166
|
+
})
|
|
1167
|
+
]
|
|
1168
|
+
})
|
|
1169
|
+
]
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// src/components/LoadingDots.tsx
|
|
1174
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1175
|
+
function LoadingDots({ label }) {
|
|
1176
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
1177
|
+
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:py-4",
|
|
1178
|
+
children: [
|
|
1179
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1180
|
+
className: "skippr:flex skippr:gap-1",
|
|
1181
|
+
children: [
|
|
1182
|
+
/* @__PURE__ */ jsx6("span", {
|
|
1183
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:0ms]"
|
|
1184
|
+
}),
|
|
1185
|
+
/* @__PURE__ */ jsx6("span", {
|
|
1186
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:150ms]"
|
|
1187
|
+
}),
|
|
1188
|
+
/* @__PURE__ */ jsx6("span", {
|
|
1189
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:300ms]"
|
|
1190
|
+
})
|
|
1191
|
+
]
|
|
1192
|
+
}),
|
|
1193
|
+
/* @__PURE__ */ jsx6("p", {
|
|
1194
|
+
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1195
|
+
children: label
|
|
1196
|
+
})
|
|
1197
|
+
]
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// src/components/LoginFlow.tsx
|
|
1202
|
+
import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef3, useState as useState6 } from "react";
|
|
1203
|
+
|
|
1204
|
+
// src/components/ui/button.tsx
|
|
1205
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
1206
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1207
|
+
var variantClasses = {
|
|
1022
1208
|
default: "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90",
|
|
1023
1209
|
destructive: "skippr:bg-destructive skippr:text-white skippr:hover:bg-destructive/90",
|
|
1024
1210
|
outline: "skippr:border skippr:border-input skippr:bg-background skippr:shadow-xs skippr:hover:bg-accent skippr:hover:text-accent-foreground",
|
|
@@ -1036,7 +1222,7 @@ var sizeClasses = {
|
|
|
1036
1222
|
"icon-lg": "skippr:size-10"
|
|
1037
1223
|
};
|
|
1038
1224
|
var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
1039
|
-
return /* @__PURE__ */
|
|
1225
|
+
return /* @__PURE__ */ jsx7("button", {
|
|
1040
1226
|
className: cn("skippr:inline-flex skippr:items-center skippr:justify-center skippr:gap-2 skippr:whitespace-nowrap skippr:rounded-md skippr:text-sm skippr:font-medium skippr:ring-offset-background skippr:transition-all skippr:cursor-pointer skippr:focus-visible:outline-none skippr:focus-visible:ring-2 skippr:focus-visible:ring-ring skippr:focus-visible:ring-offset-2 skippr:disabled:pointer-events-none skippr:disabled:opacity-50 skippr:shrink-0 skippr:[&_svg]:pointer-events-none skippr:[&_svg:not([class*='size-'])]:size-4 skippr:[&_svg]:shrink-0", variantClasses[variant], sizeClasses[size], className),
|
|
1041
1227
|
ref,
|
|
1042
1228
|
...props
|
|
@@ -1044,79 +1230,29 @@ var Button = forwardRef3(({ className, variant = "default", size = "default", ..
|
|
|
1044
1230
|
});
|
|
1045
1231
|
Button.displayName = "Button";
|
|
1046
1232
|
|
|
1047
|
-
// src/components/ChatHeader.tsx
|
|
1048
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1049
|
-
function ChatHeader({ onOpenSettings }) {
|
|
1050
|
-
const { closePanel, minimizePanel, minimizable } = useLiveAgent();
|
|
1051
|
-
return /* @__PURE__ */ jsxs3("div", {
|
|
1052
|
-
className: "skippr:flex skippr:items-center skippr:gap-3 skippr:bg-primary skippr:px-4 skippr:py-3 skippr:text-primary-foreground",
|
|
1053
|
-
children: [
|
|
1054
|
-
/* @__PURE__ */ jsx4("div", {
|
|
1055
|
-
className: "skippr:flex skippr:size-6 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary-foreground/20",
|
|
1056
|
-
children: /* @__PURE__ */ jsx4(Bot, {
|
|
1057
|
-
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1058
|
-
})
|
|
1059
|
-
}),
|
|
1060
|
-
/* @__PURE__ */ jsx4("div", {
|
|
1061
|
-
className: "skippr:flex-1",
|
|
1062
|
-
children: /* @__PURE__ */ jsx4("p", {
|
|
1063
|
-
className: "skippr:text-sm skippr:font-semibold skippr:leading-none",
|
|
1064
|
-
children: "AI Agent"
|
|
1065
|
-
})
|
|
1066
|
-
}),
|
|
1067
|
-
/* @__PURE__ */ jsxs3("div", {
|
|
1068
|
-
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
1069
|
-
children: [
|
|
1070
|
-
/* @__PURE__ */ jsx4(Button, {
|
|
1071
|
-
variant: "ghost",
|
|
1072
|
-
size: "icon-xs",
|
|
1073
|
-
onClick: onOpenSettings,
|
|
1074
|
-
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
|
|
1075
|
-
"aria-label": "Settings",
|
|
1076
|
-
children: /* @__PURE__ */ jsx4(Settings, {
|
|
1077
|
-
className: "skippr:size-4"
|
|
1078
|
-
})
|
|
1079
|
-
}),
|
|
1080
|
-
/* @__PURE__ */ jsx4(Button, {
|
|
1081
|
-
variant: "ghost",
|
|
1082
|
-
size: "icon-xs",
|
|
1083
|
-
onClick: minimizable ? minimizePanel : closePanel,
|
|
1084
|
-
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
|
|
1085
|
-
"aria-label": "Close",
|
|
1086
|
-
children: /* @__PURE__ */ jsx4(X, {
|
|
1087
|
-
className: "skippr:size-4"
|
|
1088
|
-
})
|
|
1089
|
-
})
|
|
1090
|
-
]
|
|
1091
|
-
})
|
|
1092
|
-
]
|
|
1093
|
-
});
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
1233
|
// src/components/LoginFlow.tsx
|
|
1097
|
-
import {
|
|
1098
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1234
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1099
1235
|
var OTP_LENGTH = 6;
|
|
1100
1236
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
1101
1237
|
function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
1102
|
-
const [step, setStep] =
|
|
1103
|
-
const [email, setEmail] =
|
|
1104
|
-
const handleRequestOtp =
|
|
1238
|
+
const [step, setStep] = useState6("email");
|
|
1239
|
+
const [email, setEmail] = useState6("");
|
|
1240
|
+
const handleRequestOtp = useCallback5(async (emailValue) => {
|
|
1105
1241
|
const success = await requestOtp(emailValue);
|
|
1106
1242
|
if (success)
|
|
1107
1243
|
setStep("otp");
|
|
1108
1244
|
}, [requestOtp]);
|
|
1109
|
-
const handleVerifyOtp =
|
|
1245
|
+
const handleVerifyOtp = useCallback5(async (code) => {
|
|
1110
1246
|
await verifyOtp(email, code);
|
|
1111
1247
|
}, [verifyOtp, email]);
|
|
1112
|
-
const handleBack =
|
|
1248
|
+
const handleBack = useCallback5(() => {
|
|
1113
1249
|
setStep("email");
|
|
1114
1250
|
}, []);
|
|
1115
|
-
const handleResend =
|
|
1251
|
+
const handleResend = useCallback5(async () => {
|
|
1116
1252
|
await requestOtp(email);
|
|
1117
1253
|
}, [requestOtp, email]);
|
|
1118
1254
|
if (step === "otp") {
|
|
1119
|
-
return /* @__PURE__ */
|
|
1255
|
+
return /* @__PURE__ */ jsx8(OtpStep, {
|
|
1120
1256
|
email,
|
|
1121
1257
|
onSubmit: handleVerifyOtp,
|
|
1122
1258
|
onResend: handleResend,
|
|
@@ -1125,7 +1261,7 @@ function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
|
1125
1261
|
isSubmitting
|
|
1126
1262
|
});
|
|
1127
1263
|
}
|
|
1128
|
-
return /* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsx8(EmailStep, {
|
|
1129
1265
|
email,
|
|
1130
1266
|
onEmailChange: setEmail,
|
|
1131
1267
|
onSubmit: handleRequestOtp,
|
|
@@ -1139,30 +1275,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1139
1275
|
if (email.trim())
|
|
1140
1276
|
onSubmit(email.trim());
|
|
1141
1277
|
}
|
|
1142
|
-
return /* @__PURE__ */
|
|
1278
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1143
1279
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
1144
1280
|
children: [
|
|
1145
|
-
/* @__PURE__ */
|
|
1281
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1146
1282
|
className: "skippr:mb-4 skippr:text-center",
|
|
1147
1283
|
children: [
|
|
1148
|
-
/* @__PURE__ */
|
|
1284
|
+
/* @__PURE__ */ jsx8(Mail, {
|
|
1149
1285
|
className: "skippr:mx-auto skippr:mb-2 skippr:size-6 skippr:text-primary"
|
|
1150
1286
|
}),
|
|
1151
|
-
/* @__PURE__ */
|
|
1287
|
+
/* @__PURE__ */ jsx8("p", {
|
|
1152
1288
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
1153
1289
|
children: "Sign in to continue"
|
|
1154
1290
|
}),
|
|
1155
|
-
/* @__PURE__ */
|
|
1291
|
+
/* @__PURE__ */ jsx8("p", {
|
|
1156
1292
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
1157
1293
|
children: "Your email will be used to identify you across sessions"
|
|
1158
1294
|
})
|
|
1159
1295
|
]
|
|
1160
1296
|
}),
|
|
1161
|
-
/* @__PURE__ */
|
|
1297
|
+
/* @__PURE__ */ jsxs7("form", {
|
|
1162
1298
|
onSubmit: handleSubmit,
|
|
1163
1299
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
1164
1300
|
children: [
|
|
1165
|
-
/* @__PURE__ */
|
|
1301
|
+
/* @__PURE__ */ jsx8("input", {
|
|
1166
1302
|
type: "email",
|
|
1167
1303
|
placeholder: "you@example.com",
|
|
1168
1304
|
value: email,
|
|
@@ -1171,15 +1307,15 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1171
1307
|
required: true,
|
|
1172
1308
|
className: "skippr:w-full skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:px-3 skippr:py-2 skippr:text-sm skippr:text-foreground skippr:placeholder-muted-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
|
|
1173
1309
|
}),
|
|
1174
|
-
/* @__PURE__ */
|
|
1310
|
+
/* @__PURE__ */ jsx8(Button, {
|
|
1175
1311
|
type: "submit",
|
|
1176
1312
|
disabled: isSubmitting || !email.trim(),
|
|
1177
1313
|
className: "skippr:w-full",
|
|
1178
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1314
|
+
children: isSubmitting ? /* @__PURE__ */ jsx8(LoaderCircle, {
|
|
1179
1315
|
className: "skippr:size-4 skippr:animate-spin"
|
|
1180
1316
|
}) : "Continue"
|
|
1181
1317
|
}),
|
|
1182
|
-
error && /* @__PURE__ */
|
|
1318
|
+
error && /* @__PURE__ */ jsx8("p", {
|
|
1183
1319
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
1184
1320
|
children: error
|
|
1185
1321
|
})
|
|
@@ -1189,30 +1325,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1189
1325
|
});
|
|
1190
1326
|
}
|
|
1191
1327
|
function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
1192
|
-
const [digits, setDigits] =
|
|
1193
|
-
const [resendCooldown, setResendCooldown] =
|
|
1194
|
-
const inputRefs =
|
|
1195
|
-
const submittedRef =
|
|
1196
|
-
|
|
1328
|
+
const [digits, setDigits] = useState6(Array(OTP_LENGTH).fill(""));
|
|
1329
|
+
const [resendCooldown, setResendCooldown] = useState6(0);
|
|
1330
|
+
const inputRefs = useRef3([]);
|
|
1331
|
+
const submittedRef = useRef3(false);
|
|
1332
|
+
useEffect8(() => {
|
|
1197
1333
|
inputRefs.current[0]?.focus();
|
|
1198
1334
|
}, []);
|
|
1199
|
-
|
|
1335
|
+
useEffect8(() => {
|
|
1200
1336
|
if (error)
|
|
1201
1337
|
submittedRef.current = false;
|
|
1202
1338
|
}, [error]);
|
|
1203
|
-
|
|
1339
|
+
useEffect8(() => {
|
|
1204
1340
|
if (resendCooldown <= 0)
|
|
1205
1341
|
return;
|
|
1206
1342
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
1207
1343
|
return () => clearTimeout(timer);
|
|
1208
1344
|
}, [resendCooldown]);
|
|
1209
|
-
const submitCode =
|
|
1345
|
+
const submitCode = useCallback5((code) => {
|
|
1210
1346
|
if (submittedRef.current || isSubmitting)
|
|
1211
1347
|
return;
|
|
1212
1348
|
submittedRef.current = true;
|
|
1213
1349
|
onSubmit(code);
|
|
1214
1350
|
}, [onSubmit, isSubmitting]);
|
|
1215
|
-
const handleDigitChange =
|
|
1351
|
+
const handleDigitChange = useCallback5((index2, value) => {
|
|
1216
1352
|
const digit = value.replace(/\D/g, "").slice(-1);
|
|
1217
1353
|
const newDigits = [...digits];
|
|
1218
1354
|
newDigits[index2] = digit;
|
|
@@ -1226,12 +1362,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1226
1362
|
submitCode(code);
|
|
1227
1363
|
}
|
|
1228
1364
|
}, [digits, submitCode]);
|
|
1229
|
-
const handleKeyDown =
|
|
1365
|
+
const handleKeyDown = useCallback5((index2, e) => {
|
|
1230
1366
|
if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
|
|
1231
1367
|
inputRefs.current[index2 - 1]?.focus();
|
|
1232
1368
|
}
|
|
1233
1369
|
}, [digits]);
|
|
1234
|
-
const handlePaste =
|
|
1370
|
+
const handlePaste = useCallback5((e) => {
|
|
1235
1371
|
e.preventDefault();
|
|
1236
1372
|
const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
|
|
1237
1373
|
if (pasted.length > 0) {
|
|
@@ -1259,22 +1395,22 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1259
1395
|
submittedRef.current = false;
|
|
1260
1396
|
inputRefs.current[0]?.focus();
|
|
1261
1397
|
}
|
|
1262
|
-
return /* @__PURE__ */
|
|
1398
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1263
1399
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
1264
1400
|
children: [
|
|
1265
|
-
/* @__PURE__ */
|
|
1401
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1266
1402
|
className: "skippr:mb-4 skippr:text-center",
|
|
1267
1403
|
children: [
|
|
1268
|
-
/* @__PURE__ */
|
|
1404
|
+
/* @__PURE__ */ jsx8("p", {
|
|
1269
1405
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
1270
1406
|
children: "Enter verification code"
|
|
1271
1407
|
}),
|
|
1272
|
-
/* @__PURE__ */
|
|
1408
|
+
/* @__PURE__ */ jsxs7("p", {
|
|
1273
1409
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
1274
1410
|
children: [
|
|
1275
1411
|
"We sent a 6-digit code to",
|
|
1276
1412
|
" ",
|
|
1277
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsx8("span", {
|
|
1278
1414
|
className: "skippr:font-medium skippr:text-foreground",
|
|
1279
1415
|
children: email
|
|
1280
1416
|
})
|
|
@@ -1282,13 +1418,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1282
1418
|
})
|
|
1283
1419
|
]
|
|
1284
1420
|
}),
|
|
1285
|
-
/* @__PURE__ */
|
|
1421
|
+
/* @__PURE__ */ jsxs7("form", {
|
|
1286
1422
|
onSubmit: handleSubmit,
|
|
1287
1423
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
1288
1424
|
children: [
|
|
1289
|
-
/* @__PURE__ */
|
|
1425
|
+
/* @__PURE__ */ jsx8("div", {
|
|
1290
1426
|
className: "skippr:flex skippr:justify-center skippr:gap-1.5",
|
|
1291
|
-
children: digits.map((digit, index2) => /* @__PURE__ */
|
|
1427
|
+
children: digits.map((digit, index2) => /* @__PURE__ */ jsx8("input", {
|
|
1292
1428
|
ref: (el) => {
|
|
1293
1429
|
inputRefs.current[index2] = el;
|
|
1294
1430
|
},
|
|
@@ -1303,29 +1439,29 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1303
1439
|
className: "skippr:h-10 skippr:w-10 skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:text-center skippr:text-sm skippr:font-semibold skippr:text-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
|
|
1304
1440
|
}, DIGIT_KEYS[index2]))
|
|
1305
1441
|
}),
|
|
1306
|
-
error && /* @__PURE__ */
|
|
1442
|
+
error && /* @__PURE__ */ jsx8("p", {
|
|
1307
1443
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
1308
1444
|
children: error
|
|
1309
1445
|
}),
|
|
1310
|
-
/* @__PURE__ */
|
|
1446
|
+
/* @__PURE__ */ jsx8(Button, {
|
|
1311
1447
|
type: "submit",
|
|
1312
1448
|
disabled: isSubmitting || digits.join("").length !== OTP_LENGTH,
|
|
1313
1449
|
className: "skippr:w-full",
|
|
1314
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1450
|
+
children: isSubmitting ? /* @__PURE__ */ jsx8(LoaderCircle, {
|
|
1315
1451
|
className: "skippr:size-4 skippr:animate-spin"
|
|
1316
1452
|
}) : "Verify"
|
|
1317
1453
|
}),
|
|
1318
|
-
/* @__PURE__ */
|
|
1454
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1319
1455
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:text-xs",
|
|
1320
1456
|
children: [
|
|
1321
|
-
/* @__PURE__ */
|
|
1457
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1322
1458
|
type: "button",
|
|
1323
1459
|
onClick: onBack,
|
|
1324
1460
|
disabled: isSubmitting,
|
|
1325
1461
|
className: "skippr:text-muted-foreground hover:skippr:text-foreground skippr:transition-colors disabled:skippr:opacity-50",
|
|
1326
1462
|
children: "Change email"
|
|
1327
1463
|
}),
|
|
1328
|
-
/* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1329
1465
|
type: "button",
|
|
1330
1466
|
onClick: handleResend,
|
|
1331
1467
|
disabled: isSubmitting || resendCooldown > 0,
|
|
@@ -1341,476 +1477,351 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1341
1477
|
}
|
|
1342
1478
|
|
|
1343
1479
|
// src/components/MeetingControls.tsx
|
|
1344
|
-
import {
|
|
1345
|
-
|
|
1346
|
-
import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef3, useState as useState6 } from "react";
|
|
1347
|
-
|
|
1348
|
-
// src/lib/format.ts
|
|
1349
|
-
function formatTime(seconds) {
|
|
1350
|
-
const m = Math.floor(seconds / 60).toString().padStart(2, "0");
|
|
1351
|
-
const s = (seconds % 60).toString().padStart(2, "0");
|
|
1352
|
-
return `${m}:${s}`;
|
|
1353
|
-
}
|
|
1354
|
-
function parseNumber(s) {
|
|
1355
|
-
const n = Number(s);
|
|
1356
|
-
return n > 0 ? n : null;
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
|
-
// src/components/SessionWarningBanner.tsx
|
|
1360
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1361
|
-
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
1362
|
-
function SessionWarningBanner({ remaining }) {
|
|
1363
|
-
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
1364
|
-
return null;
|
|
1365
|
-
return /* @__PURE__ */ jsx6("div", {
|
|
1366
|
-
"data-testid": "session-warning-banner",
|
|
1367
|
-
className: "skippr:bg-red-50 skippr:px-4 skippr:py-1.5 skippr:text-center skippr:text-xs skippr:font-medium skippr:text-red-700",
|
|
1368
|
-
children: "Session ending soon"
|
|
1369
|
-
});
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
// src/components/MeetingControls.tsx
|
|
1373
|
-
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1480
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1481
|
+
var CONTROL_BUTTON = "skippr:flex skippr:size-11 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-full skippr:transition-colors";
|
|
1374
1482
|
function MeetingControls({ onHangUp }) {
|
|
1375
|
-
const
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
1379
|
-
const endTimeRef = useRef3(null);
|
|
1380
|
-
const [remaining, setRemaining] = useState6(null);
|
|
1381
|
-
useEffect6(() => {
|
|
1382
|
-
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
1383
|
-
return;
|
|
1384
|
-
endTimeRef.current = Date.now() + maxCallDuration * 1000;
|
|
1385
|
-
const tick = () => {
|
|
1386
|
-
const secs = Math.ceil((endTimeRef.current - Date.now()) / 1000);
|
|
1387
|
-
setRemaining(Math.max(secs, 0));
|
|
1388
|
-
};
|
|
1389
|
-
tick();
|
|
1390
|
-
const id = setInterval(tick, 1000);
|
|
1391
|
-
return () => clearInterval(id);
|
|
1392
|
-
}, [maxCallDuration]);
|
|
1393
|
-
const toggleMute = useCallback7(async () => {
|
|
1394
|
-
try {
|
|
1395
|
-
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
1396
|
-
} catch (e) {
|
|
1397
|
-
console.error("Failed to toggle microphone:", e);
|
|
1398
|
-
}
|
|
1399
|
-
}, [localParticipant, isMuted]);
|
|
1400
|
-
const toggleScreenShare = useCallback7(async () => {
|
|
1401
|
-
try {
|
|
1402
|
-
await localParticipant.setScreenShareEnabled(!isScreenSharing, {
|
|
1403
|
-
video: { displaySurface: "browser" },
|
|
1404
|
-
resolution: ScreenSharePresets2.h720fps30.resolution,
|
|
1405
|
-
contentHint: "detail"
|
|
1406
|
-
});
|
|
1407
|
-
} catch (e) {
|
|
1408
|
-
console.error("Failed to toggle screen share:", e);
|
|
1409
|
-
}
|
|
1410
|
-
}, [localParticipant, isScreenSharing]);
|
|
1411
|
-
useEffect6(() => {
|
|
1412
|
-
toggleMute().then(() => toggleScreenShare());
|
|
1413
|
-
}, []);
|
|
1414
|
-
return /* @__PURE__ */ jsxs5("div", {
|
|
1483
|
+
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
1484
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1485
|
+
className: "skippr:shrink-0 skippr:border-t skippr:border-border skippr:bg-background skippr:px-4 skippr:py-4",
|
|
1415
1486
|
children: [
|
|
1416
|
-
/* @__PURE__ */
|
|
1417
|
-
|
|
1418
|
-
}),
|
|
1419
|
-
/* @__PURE__ */ jsxs5("div", {
|
|
1420
|
-
className: "skippr:flex skippr:items-center skippr:justify-between skippr:border-b skippr:px-4 skippr:py-3",
|
|
1487
|
+
/* @__PURE__ */ jsxs8("div", {
|
|
1488
|
+
className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-3",
|
|
1421
1489
|
children: [
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
children: isMuted ? /* @__PURE__ */ jsx7(MicOff, {
|
|
1433
|
-
className: "skippr:size-4"
|
|
1434
|
-
}) : /* @__PURE__ */ jsx7(Mic, {
|
|
1435
|
-
className: "skippr:size-4"
|
|
1436
|
-
})
|
|
1437
|
-
})
|
|
1438
|
-
}),
|
|
1439
|
-
/* @__PURE__ */ jsx7(Tooltip, {
|
|
1440
|
-
label: isScreenSharing ? "Stop sharing" : "Share screen",
|
|
1441
|
-
children: /* @__PURE__ */ jsx7(Button, {
|
|
1442
|
-
size: "icon-sm",
|
|
1443
|
-
variant: isScreenSharing ? "outline" : "destructive",
|
|
1444
|
-
onClick: toggleScreenShare,
|
|
1445
|
-
"aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
|
|
1446
|
-
children: isScreenSharing ? /* @__PURE__ */ jsx7(MonitorOff, {
|
|
1447
|
-
className: "skippr:size-4"
|
|
1448
|
-
}) : /* @__PURE__ */ jsx7(Monitor, {
|
|
1449
|
-
className: "skippr:size-4"
|
|
1450
|
-
})
|
|
1451
|
-
})
|
|
1452
|
-
})
|
|
1453
|
-
]
|
|
1490
|
+
/* @__PURE__ */ jsx9("button", {
|
|
1491
|
+
type: "button",
|
|
1492
|
+
onClick: toggleMute,
|
|
1493
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
1494
|
+
className: cn(CONTROL_BUTTON, isMuted ? "skippr:bg-destructive/15 skippr:text-destructive skippr:hover:bg-destructive/25" : "skippr:bg-muted skippr:text-foreground skippr:hover:bg-muted/80"),
|
|
1495
|
+
children: isMuted ? /* @__PURE__ */ jsx9(MicOff, {
|
|
1496
|
+
className: "skippr:size-5"
|
|
1497
|
+
}) : /* @__PURE__ */ jsx9(Mic, {
|
|
1498
|
+
className: "skippr:size-5"
|
|
1499
|
+
})
|
|
1454
1500
|
}),
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1501
|
+
/* @__PURE__ */ jsx9("button", {
|
|
1502
|
+
type: "button",
|
|
1503
|
+
onClick: toggleScreenShare,
|
|
1504
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
1505
|
+
className: cn(CONTROL_BUTTON, isScreenSharing ? "skippr:bg-bubble skippr:text-white skippr:hover:brightness-110" : "skippr:bg-muted skippr:text-foreground skippr:hover:bg-muted/80"),
|
|
1506
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx9(MonitorOff, {
|
|
1507
|
+
className: "skippr:size-5"
|
|
1508
|
+
}) : /* @__PURE__ */ jsx9(Monitor, {
|
|
1509
|
+
className: "skippr:size-5"
|
|
1510
|
+
})
|
|
1458
1511
|
}),
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
children: /* @__PURE__ */ jsx7(PhoneOff, {
|
|
1467
|
-
className: "skippr:size-4"
|
|
1468
|
-
})
|
|
1512
|
+
/* @__PURE__ */ jsx9("button", {
|
|
1513
|
+
type: "button",
|
|
1514
|
+
onClick: onHangUp,
|
|
1515
|
+
"aria-label": "End session",
|
|
1516
|
+
className: cn(CONTROL_BUTTON, "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90"),
|
|
1517
|
+
children: /* @__PURE__ */ jsx9(PhoneOff, {
|
|
1518
|
+
className: "skippr:size-5"
|
|
1469
1519
|
})
|
|
1470
1520
|
})
|
|
1471
1521
|
]
|
|
1522
|
+
}),
|
|
1523
|
+
/* @__PURE__ */ jsx9("p", {
|
|
1524
|
+
className: "skippr:mt-3 skippr:text-center skippr:text-[10px] skippr:text-muted-foreground",
|
|
1525
|
+
children: "Powered by Skippr"
|
|
1472
1526
|
})
|
|
1473
1527
|
]
|
|
1474
1528
|
});
|
|
1475
1529
|
}
|
|
1476
1530
|
|
|
1477
1531
|
// src/components/MessageList.tsx
|
|
1478
|
-
import { useEffect as
|
|
1532
|
+
import { useEffect as useEffect10, useRef as useRef5 } from "react";
|
|
1479
1533
|
|
|
1480
1534
|
// src/components/ChatInput.tsx
|
|
1481
|
-
import { useState as useState7 } from "react";
|
|
1482
|
-
import { jsx as
|
|
1483
|
-
|
|
1535
|
+
import { useEffect as useEffect9, useRef as useRef4, useState as useState7 } from "react";
|
|
1536
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1537
|
+
var MAX_INPUT_HEIGHT = 60;
|
|
1538
|
+
function ChatInput({ sendChatMessage, isSendingChat, autoFocus = false }) {
|
|
1484
1539
|
const [inputText, setInputText] = useState7("");
|
|
1540
|
+
const textareaRef = useRef4(null);
|
|
1485
1541
|
const canSend = inputText.trim().length > 0 && !isSendingChat;
|
|
1542
|
+
useEffect9(() => {
|
|
1543
|
+
if (autoFocus)
|
|
1544
|
+
textareaRef.current?.focus();
|
|
1545
|
+
}, [autoFocus]);
|
|
1546
|
+
function resizeTextarea() {
|
|
1547
|
+
const el = textareaRef.current;
|
|
1548
|
+
if (!el)
|
|
1549
|
+
return;
|
|
1550
|
+
el.style.height = "auto";
|
|
1551
|
+
el.style.height = `${Math.min(el.scrollHeight, MAX_INPUT_HEIGHT)}px`;
|
|
1552
|
+
}
|
|
1553
|
+
function handleChange(e) {
|
|
1554
|
+
setInputText(e.target.value);
|
|
1555
|
+
resizeTextarea();
|
|
1556
|
+
}
|
|
1486
1557
|
function handleSubmit(e) {
|
|
1487
1558
|
e.preventDefault();
|
|
1488
1559
|
const text = inputText.trim();
|
|
1489
1560
|
if (!text || isSendingChat)
|
|
1490
1561
|
return;
|
|
1491
1562
|
setInputText("");
|
|
1563
|
+
resizeTextarea();
|
|
1492
1564
|
sendChatMessage(text).catch(() => setInputText(text));
|
|
1565
|
+
textareaRef.current?.focus();
|
|
1566
|
+
}
|
|
1567
|
+
function handleKeyDown(e) {
|
|
1568
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1569
|
+
e.preventDefault();
|
|
1570
|
+
handleSubmit(e);
|
|
1571
|
+
}
|
|
1493
1572
|
}
|
|
1494
|
-
return /* @__PURE__ */
|
|
1573
|
+
return /* @__PURE__ */ jsx10("form", {
|
|
1495
1574
|
onSubmit: handleSubmit,
|
|
1496
|
-
className: "skippr:
|
|
1497
|
-
children:
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1575
|
+
className: "skippr:border-t skippr:border-border skippr:p-3",
|
|
1576
|
+
children: /* @__PURE__ */ jsxs9("div", {
|
|
1577
|
+
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:rounded-xl skippr:bg-background skippr:ring-1 skippr:ring-foreground/10 skippr:px-3 skippr:py-2",
|
|
1578
|
+
children: [
|
|
1579
|
+
/* @__PURE__ */ jsx10("textarea", {
|
|
1580
|
+
ref: textareaRef,
|
|
1581
|
+
rows: 1,
|
|
1582
|
+
value: inputText,
|
|
1583
|
+
onChange: handleChange,
|
|
1584
|
+
onKeyDown: handleKeyDown,
|
|
1585
|
+
placeholder: "Type a message...",
|
|
1586
|
+
className: "skippr:flex-1 skippr:resize-none skippr:overflow-y-auto skippr:bg-transparent skippr:text-sm skippr:leading-5 skippr:text-foreground skippr:placeholder:text-muted-foreground skippr:outline-none",
|
|
1587
|
+
style: { maxHeight: `${MAX_INPUT_HEIGHT}px` }
|
|
1588
|
+
}),
|
|
1589
|
+
/* @__PURE__ */ jsx10("button", {
|
|
1590
|
+
type: "submit",
|
|
1591
|
+
disabled: !canSend,
|
|
1592
|
+
"aria-label": "Send message",
|
|
1593
|
+
className: cn("skippr:flex skippr:size-8 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-lg skippr:transition-colors", canSend ? "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90" : "skippr:bg-muted-foreground/20 skippr:text-muted-foreground/60"),
|
|
1594
|
+
children: /* @__PURE__ */ jsx10(Send, {
|
|
1595
|
+
className: "skippr:size-3.5"
|
|
1596
|
+
})
|
|
1513
1597
|
})
|
|
1514
|
-
|
|
1515
|
-
|
|
1598
|
+
]
|
|
1599
|
+
})
|
|
1516
1600
|
});
|
|
1517
1601
|
}
|
|
1518
1602
|
|
|
1519
1603
|
// src/components/ChatMessage.tsx
|
|
1520
|
-
import { jsx as
|
|
1604
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1605
|
+
function formatTimestamp(ts) {
|
|
1606
|
+
return new Date(ts).toLocaleTimeString("en-US", {
|
|
1607
|
+
hour: "numeric",
|
|
1608
|
+
minute: "2-digit",
|
|
1609
|
+
hour12: true
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1521
1612
|
function ChatMessage({ message }) {
|
|
1522
|
-
const
|
|
1523
|
-
return /* @__PURE__ */
|
|
1524
|
-
className: cn("skippr:flex skippr:
|
|
1525
|
-
children:
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1613
|
+
const isAgent = message.role === "assistant";
|
|
1614
|
+
return /* @__PURE__ */ jsxs10("div", {
|
|
1615
|
+
className: cn("skippr:flex skippr:gap-2", isAgent ? "skippr:items-start" : "skippr:justify-end"),
|
|
1616
|
+
children: [
|
|
1617
|
+
isAgent && /* @__PURE__ */ jsx11("div", {
|
|
1618
|
+
className: "skippr:mt-0.5 skippr:flex skippr:size-7 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-md skippr:bg-primary",
|
|
1619
|
+
children: /* @__PURE__ */ jsx11(Sparkles, {
|
|
1620
|
+
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1621
|
+
})
|
|
1622
|
+
}),
|
|
1623
|
+
/* @__PURE__ */ jsxs10("div", {
|
|
1624
|
+
className: cn("skippr:flex skippr:max-w-[80%] skippr:flex-col", isAgent ? "skippr:items-start" : "skippr:items-end"),
|
|
1625
|
+
children: [
|
|
1626
|
+
/* @__PURE__ */ jsx11("div", {
|
|
1627
|
+
className: cn("skippr:rounded-2xl skippr:px-4 skippr:py-2.5 skippr:text-sm skippr:leading-relaxed", isAgent ? "skippr:border skippr:border-border skippr:bg-card skippr:text-foreground" : "skippr:bg-primary skippr:text-primary-foreground"),
|
|
1628
|
+
children: message.content
|
|
1629
|
+
}),
|
|
1630
|
+
message.timestamp && /* @__PURE__ */ jsx11("span", {
|
|
1631
|
+
className: "skippr:mt-1 skippr:px-1 skippr:text-[10px] skippr:text-muted-foreground/60",
|
|
1632
|
+
children: formatTimestamp(message.timestamp)
|
|
1633
|
+
})
|
|
1634
|
+
]
|
|
1635
|
+
})
|
|
1636
|
+
]
|
|
1529
1637
|
});
|
|
1530
1638
|
}
|
|
1531
1639
|
|
|
1532
1640
|
// src/components/TypingIndicator.tsx
|
|
1533
|
-
import { jsx as
|
|
1641
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1534
1642
|
function TypingIndicator() {
|
|
1535
|
-
return /* @__PURE__ */
|
|
1536
|
-
className: "skippr:flex skippr:items-
|
|
1537
|
-
children:
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
/* @__PURE__ */
|
|
1541
|
-
className: "skippr:size-
|
|
1542
|
-
}),
|
|
1543
|
-
/* @__PURE__ */ jsx10("span", {
|
|
1544
|
-
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:150ms]"
|
|
1545
|
-
}),
|
|
1546
|
-
/* @__PURE__ */ jsx10("span", {
|
|
1547
|
-
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:300ms]"
|
|
1643
|
+
return /* @__PURE__ */ jsxs11("div", {
|
|
1644
|
+
className: "skippr:flex skippr:items-start skippr:gap-2 skippr:animate-skippr-tab-fade",
|
|
1645
|
+
children: [
|
|
1646
|
+
/* @__PURE__ */ jsx12("div", {
|
|
1647
|
+
className: "skippr:mt-0.5 skippr:flex skippr:size-7 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-md skippr:bg-primary",
|
|
1648
|
+
children: /* @__PURE__ */ jsx12(Sparkles, {
|
|
1649
|
+
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1548
1650
|
})
|
|
1549
|
-
|
|
1550
|
-
|
|
1651
|
+
}),
|
|
1652
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1653
|
+
className: "skippr:inline-flex skippr:items-center skippr:gap-1 skippr:rounded-2xl skippr:border skippr:border-primary/20 skippr:bg-primary/10 skippr:px-4 skippr:py-2 skippr:text-xs skippr:text-primary",
|
|
1654
|
+
children: [
|
|
1655
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1656
|
+
children: "Agent is analyzing your screen"
|
|
1657
|
+
}),
|
|
1658
|
+
/* @__PURE__ */ jsxs11("span", {
|
|
1659
|
+
className: "skippr:inline-flex skippr:items-center skippr:gap-[2px]",
|
|
1660
|
+
children: [
|
|
1661
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1662
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:0ms]"
|
|
1663
|
+
}),
|
|
1664
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1665
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:200ms]"
|
|
1666
|
+
}),
|
|
1667
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1668
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:400ms]"
|
|
1669
|
+
})
|
|
1670
|
+
]
|
|
1671
|
+
})
|
|
1672
|
+
]
|
|
1673
|
+
})
|
|
1674
|
+
]
|
|
1551
1675
|
});
|
|
1552
1676
|
}
|
|
1553
1677
|
|
|
1554
1678
|
// src/components/MessageList.tsx
|
|
1555
|
-
import { jsx as
|
|
1679
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1556
1680
|
function MessageList({
|
|
1557
1681
|
messages,
|
|
1558
1682
|
isStreaming,
|
|
1559
1683
|
sendChatMessage,
|
|
1560
|
-
isSendingChat
|
|
1684
|
+
isSendingChat,
|
|
1685
|
+
autoFocus = false
|
|
1561
1686
|
}) {
|
|
1562
|
-
const scrollRef =
|
|
1687
|
+
const scrollRef = useRef5(null);
|
|
1563
1688
|
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
1564
|
-
|
|
1689
|
+
useEffect10(() => {
|
|
1565
1690
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1566
1691
|
}, [messages.length, lastMessage?.content]);
|
|
1567
1692
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
1568
|
-
return /* @__PURE__ */
|
|
1693
|
+
return /* @__PURE__ */ jsxs12("div", {
|
|
1569
1694
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1570
1695
|
children: [
|
|
1571
|
-
/* @__PURE__ */
|
|
1572
|
-
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto",
|
|
1573
|
-
children: /* @__PURE__ */ jsxs8("div", {
|
|
1574
|
-
className: "skippr:flex skippr:flex-col skippr:gap-1 skippr:py-3",
|
|
1575
|
-
children: [
|
|
1576
|
-
messages.length === 0 && !showTyping && /* @__PURE__ */ jsxs8("div", {
|
|
1577
|
-
className: "skippr:flex skippr:flex-col skippr:items-center skippr:justify-center skippr:gap-3 skippr:py-10 skippr:text-center skippr:px-4",
|
|
1578
|
-
children: [
|
|
1579
|
-
/* @__PURE__ */ jsxs8("div", {
|
|
1580
|
-
className: "skippr:flex skippr:items-end skippr:justify-center skippr:gap-[3px] skippr:h-5",
|
|
1581
|
-
children: [
|
|
1582
|
-
/* @__PURE__ */ jsx11("span", {
|
|
1583
|
-
className: "skippr:w-[3px] skippr:rounded-full skippr:bg-primary/40 skippr:animate-[skippr-wave_1.2s_ease-in-out_infinite] skippr:h-2"
|
|
1584
|
-
}),
|
|
1585
|
-
/* @__PURE__ */ jsx11("span", {
|
|
1586
|
-
className: "skippr:w-[3px] skippr:rounded-full skippr:bg-primary/40 skippr:animate-[skippr-wave_1.2s_ease-in-out_0.15s_infinite] skippr:h-3"
|
|
1587
|
-
}),
|
|
1588
|
-
/* @__PURE__ */ jsx11("span", {
|
|
1589
|
-
className: "skippr:w-[3px] skippr:rounded-full skippr:bg-primary/40 skippr:animate-[skippr-wave_1.2s_ease-in-out_0.3s_infinite] skippr:h-4"
|
|
1590
|
-
}),
|
|
1591
|
-
/* @__PURE__ */ jsx11("span", {
|
|
1592
|
-
className: "skippr:w-[3px] skippr:rounded-full skippr:bg-primary/40 skippr:animate-[skippr-wave_1.2s_ease-in-out_0.45s_infinite] skippr:h-3"
|
|
1593
|
-
}),
|
|
1594
|
-
/* @__PURE__ */ jsx11("span", {
|
|
1595
|
-
className: "skippr:w-[3px] skippr:rounded-full skippr:bg-primary/40 skippr:animate-[skippr-wave_1.2s_ease-in-out_0.6s_infinite] skippr:h-2"
|
|
1596
|
-
})
|
|
1597
|
-
]
|
|
1598
|
-
}),
|
|
1599
|
-
/* @__PURE__ */ jsx11("p", {
|
|
1600
|
-
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1601
|
-
children: "Agent is getting ready..."
|
|
1602
|
-
})
|
|
1603
|
-
]
|
|
1604
|
-
}),
|
|
1605
|
-
messages.map((message) => /* @__PURE__ */ jsx11(ChatMessage, {
|
|
1606
|
-
message
|
|
1607
|
-
}, message.id)),
|
|
1608
|
-
showTyping && /* @__PURE__ */ jsx11(TypingIndicator, {}),
|
|
1609
|
-
/* @__PURE__ */ jsx11("div", {
|
|
1610
|
-
ref: scrollRef
|
|
1611
|
-
})
|
|
1612
|
-
]
|
|
1613
|
-
})
|
|
1614
|
-
}),
|
|
1615
|
-
/* @__PURE__ */ jsx11(ChatInput, {
|
|
1616
|
-
sendChatMessage,
|
|
1617
|
-
isSendingChat
|
|
1618
|
-
})
|
|
1619
|
-
]
|
|
1620
|
-
});
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
// src/components/QuickActions.tsx
|
|
1624
|
-
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1625
|
-
function QuickActions({ onStartSession, isStarting, error }) {
|
|
1626
|
-
return /* @__PURE__ */ jsxs9("div", {
|
|
1627
|
-
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-6 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
|
|
1628
|
-
children: [
|
|
1629
|
-
/* @__PURE__ */ jsx12("p", {
|
|
1630
|
-
className: "skippr:mb-1 skippr:text-sm skippr:text-muted-foreground",
|
|
1631
|
-
children: "How can I help you today?"
|
|
1632
|
-
}),
|
|
1633
|
-
/* @__PURE__ */ jsxs9(Button, {
|
|
1634
|
-
variant: "outline",
|
|
1635
|
-
className: "skippr:h-auto skippr:flex-col skippr:gap-1.5 skippr:whitespace-normal skippr:py-3 skippr:text-xs",
|
|
1636
|
-
onClick: onStartSession,
|
|
1637
|
-
disabled: isStarting,
|
|
1696
|
+
/* @__PURE__ */ jsxs12("div", {
|
|
1697
|
+
className: "skippr:min-h-0 skippr:flex-1 skippr:space-y-4 skippr:overflow-y-auto skippr:p-4",
|
|
1638
1698
|
children: [
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
}) : /* @__PURE__ */ jsx12(MessageCircleQuestionMark, {
|
|
1642
|
-
className: "skippr:size-4 skippr:text-primary"
|
|
1699
|
+
messages.length === 0 && !showTyping && /* @__PURE__ */ jsx13(LoadingDots, {
|
|
1700
|
+
label: "Waiting for conversation to begin..."
|
|
1643
1701
|
}),
|
|
1644
|
-
|
|
1702
|
+
messages.map((message) => /* @__PURE__ */ jsx13(ChatMessage, {
|
|
1703
|
+
message
|
|
1704
|
+
}, message.id)),
|
|
1705
|
+
showTyping && /* @__PURE__ */ jsx13(TypingIndicator, {}),
|
|
1706
|
+
/* @__PURE__ */ jsx13("div", {
|
|
1707
|
+
ref: scrollRef
|
|
1708
|
+
})
|
|
1645
1709
|
]
|
|
1646
1710
|
}),
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1711
|
+
/* @__PURE__ */ jsx13(ChatInput, {
|
|
1712
|
+
sendChatMessage,
|
|
1713
|
+
isSendingChat,
|
|
1714
|
+
autoFocus
|
|
1650
1715
|
})
|
|
1651
1716
|
]
|
|
1652
1717
|
});
|
|
1653
1718
|
}
|
|
1654
1719
|
|
|
1655
1720
|
// src/components/SessionAgenda.tsx
|
|
1656
|
-
import { jsx as
|
|
1657
|
-
function SessionAgenda({ phases
|
|
1721
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1722
|
+
function SessionAgenda({ phases }) {
|
|
1658
1723
|
if (phases.length === 0) {
|
|
1659
|
-
return /* @__PURE__ */
|
|
1660
|
-
className: "skippr:flex skippr:flex-
|
|
1661
|
-
children:
|
|
1662
|
-
|
|
1663
|
-
className: "skippr:text-sm skippr:font-semibold",
|
|
1664
|
-
children: "Agenda"
|
|
1665
|
-
}),
|
|
1666
|
-
/* @__PURE__ */ jsx13("p", {
|
|
1667
|
-
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1668
|
-
children: "Waiting for session..."
|
|
1669
|
-
})
|
|
1670
|
-
]
|
|
1671
|
-
});
|
|
1672
|
-
}
|
|
1673
|
-
return /* @__PURE__ */ jsxs10("div", {
|
|
1674
|
-
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1675
|
-
children: [
|
|
1676
|
-
/* @__PURE__ */ jsx13("h3", {
|
|
1677
|
-
className: "skippr:text-sm skippr:font-semibold",
|
|
1678
|
-
children: "Agenda"
|
|
1679
|
-
}),
|
|
1680
|
-
/* @__PURE__ */ jsx13("ul", {
|
|
1681
|
-
className: "skippr:flex skippr:flex-col skippr:gap-2",
|
|
1682
|
-
children: phases.map((phase) => {
|
|
1683
|
-
const phaseQuestions = questions.filter((q) => q.phaseName === phase.name);
|
|
1684
|
-
const answeredCount = phaseQuestions.filter((q) => q.status === "answered").length;
|
|
1685
|
-
const totalCount = phaseQuestions.length;
|
|
1686
|
-
return /* @__PURE__ */ jsxs10("li", {
|
|
1687
|
-
className: "skippr:flex skippr:flex-col skippr:gap-0.5",
|
|
1688
|
-
children: [
|
|
1689
|
-
/* @__PURE__ */ jsxs10("div", {
|
|
1690
|
-
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:text-sm",
|
|
1691
|
-
children: [
|
|
1692
|
-
/* @__PURE__ */ jsx13(PhaseIcon, {
|
|
1693
|
-
status: phase.status
|
|
1694
|
-
}),
|
|
1695
|
-
/* @__PURE__ */ jsx13("span", {
|
|
1696
|
-
className: cn(phase.status === "completed" && "skippr:text-muted-foreground skippr:line-through", phase.status === "active" && "skippr:font-medium skippr:text-primary"),
|
|
1697
|
-
children: phase.name
|
|
1698
|
-
})
|
|
1699
|
-
]
|
|
1700
|
-
}),
|
|
1701
|
-
totalCount > 0 && /* @__PURE__ */ jsxs10("span", {
|
|
1702
|
-
className: "skippr:ml-6 skippr:text-xs skippr:text-muted-foreground",
|
|
1703
|
-
children: [
|
|
1704
|
-
answeredCount,
|
|
1705
|
-
"/",
|
|
1706
|
-
totalCount,
|
|
1707
|
-
" answered"
|
|
1708
|
-
]
|
|
1709
|
-
})
|
|
1710
|
-
]
|
|
1711
|
-
}, phase.name);
|
|
1712
|
-
})
|
|
1713
|
-
})
|
|
1714
|
-
]
|
|
1715
|
-
});
|
|
1716
|
-
}
|
|
1717
|
-
function PhaseIcon({ status }) {
|
|
1718
|
-
if (status === "completed") {
|
|
1719
|
-
return /* @__PURE__ */ jsx13("div", {
|
|
1720
|
-
className: "skippr:flex skippr:size-4 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary",
|
|
1721
|
-
children: /* @__PURE__ */ jsx13(Check, {
|
|
1722
|
-
className: "skippr:size-2.5 skippr:text-primary-foreground",
|
|
1723
|
-
strokeWidth: 3
|
|
1724
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1725
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1726
|
+
children: /* @__PURE__ */ jsx14(LoadingDots, {
|
|
1727
|
+
label: "Waiting for agenda to load..."
|
|
1724
1728
|
})
|
|
1725
1729
|
});
|
|
1726
1730
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
// src/components/SettingsView.tsx
|
|
1738
|
-
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1739
|
-
function SettingsView({ onBack }) {
|
|
1740
|
-
const { position, setPosition } = useLiveAgent();
|
|
1741
|
-
return /* @__PURE__ */ jsxs11("div", {
|
|
1742
|
-
className: "skippr:flex skippr:flex-1 skippr:flex-col",
|
|
1743
|
-
children: [
|
|
1744
|
-
/* @__PURE__ */ jsxs11("div", {
|
|
1745
|
-
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-b skippr:border-border skippr:px-4 skippr:py-3",
|
|
1746
|
-
children: [
|
|
1747
|
-
/* @__PURE__ */ jsx14(Button, {
|
|
1748
|
-
variant: "ghost",
|
|
1749
|
-
size: "icon-xs",
|
|
1750
|
-
onClick: onBack,
|
|
1751
|
-
"aria-label": "Back",
|
|
1752
|
-
children: /* @__PURE__ */ jsx14(ArrowLeft, {
|
|
1753
|
-
className: "skippr:size-4"
|
|
1754
|
-
})
|
|
1755
|
-
}),
|
|
1756
|
-
/* @__PURE__ */ jsx14("p", {
|
|
1757
|
-
className: "skippr:text-sm skippr:font-semibold",
|
|
1758
|
-
children: "Settings"
|
|
1759
|
-
})
|
|
1760
|
-
]
|
|
1761
|
-
}),
|
|
1762
|
-
/* @__PURE__ */ jsx14("div", {
|
|
1763
|
-
className: "skippr:flex-1 skippr:overflow-y-auto skippr:p-4",
|
|
1764
|
-
children: /* @__PURE__ */ jsxs11("div", {
|
|
1765
|
-
className: "skippr:mb-4",
|
|
1731
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1732
|
+
className: "skippr:flex-1 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
|
|
1733
|
+
children: /* @__PURE__ */ jsx14("div", {
|
|
1734
|
+
className: "skippr:space-y-1",
|
|
1735
|
+
children: phases.map((phase) => {
|
|
1736
|
+
const isActive = phase.status === "active";
|
|
1737
|
+
const isCompleted = phase.status === "completed";
|
|
1738
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
1739
|
+
className: cn("skippr:flex skippr:items-start skippr:gap-2.5 skippr:rounded-lg skippr:p-2 skippr:transition-colors", isActive && "skippr:bg-primary/10"),
|
|
1766
1740
|
children: [
|
|
1767
|
-
/* @__PURE__ */ jsx14("
|
|
1768
|
-
className: "skippr:
|
|
1769
|
-
children:
|
|
1741
|
+
/* @__PURE__ */ jsx14("div", {
|
|
1742
|
+
className: "skippr:mt-0.5",
|
|
1743
|
+
children: isCompleted ? /* @__PURE__ */ jsx14(CircleCheck, {
|
|
1744
|
+
className: "skippr:size-4 skippr:text-chart-3"
|
|
1745
|
+
}) : isActive ? /* @__PURE__ */ jsx14(Circle, {
|
|
1746
|
+
className: "skippr:size-4 skippr:fill-primary/30 skippr:text-primary"
|
|
1747
|
+
}) : /* @__PURE__ */ jsx14(Circle, {
|
|
1748
|
+
className: "skippr:size-4 skippr:text-muted-foreground/30"
|
|
1749
|
+
})
|
|
1770
1750
|
}),
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
className: "skippr:
|
|
1751
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
1752
|
+
className: "skippr:min-w-0 skippr:flex-1",
|
|
1773
1753
|
children: [
|
|
1774
|
-
/* @__PURE__ */
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
className: cn("skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-2 skippr:rounded-lg skippr:border skippr:p-3 skippr:cursor-pointer skippr:transition-colors", position === "left" ? "skippr:border-primary skippr:bg-primary/5 skippr:text-primary" : "skippr:border-border skippr:text-muted-foreground skippr:hover:border-primary/40"),
|
|
1778
|
-
children: [
|
|
1779
|
-
/* @__PURE__ */ jsx14(PanelLeft, {
|
|
1780
|
-
className: "skippr:size-5"
|
|
1781
|
-
}),
|
|
1782
|
-
/* @__PURE__ */ jsx14("span", {
|
|
1783
|
-
className: "skippr:text-xs skippr:font-medium",
|
|
1784
|
-
children: "Left"
|
|
1785
|
-
})
|
|
1786
|
-
]
|
|
1754
|
+
/* @__PURE__ */ jsx14("p", {
|
|
1755
|
+
className: cn("skippr:text-sm", isCompleted && "skippr:text-muted-foreground skippr:line-through", isActive && "skippr:font-medium skippr:text-foreground", phase.status === "pending" && "skippr:text-muted-foreground"),
|
|
1756
|
+
children: phase.name
|
|
1787
1757
|
}),
|
|
1788
|
-
/* @__PURE__ */
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
})
|
|
1800
|
-
]
|
|
1758
|
+
phase.highlights.length > 0 && /* @__PURE__ */ jsx14("ul", {
|
|
1759
|
+
className: "skippr:mt-1 skippr:space-y-0.5",
|
|
1760
|
+
children: phase.highlights.map((text) => /* @__PURE__ */ jsxs13("li", {
|
|
1761
|
+
className: cn("skippr:flex skippr:items-center skippr:gap-1.5 skippr:text-[11px] skippr:leading-tight", isCompleted ? "skippr:text-muted-foreground/40 skippr:line-through" : "skippr:text-muted-foreground/70"),
|
|
1762
|
+
children: [
|
|
1763
|
+
/* @__PURE__ */ jsx14("span", {
|
|
1764
|
+
className: "skippr:size-1 skippr:shrink-0 skippr:rounded-full skippr:bg-current"
|
|
1765
|
+
}),
|
|
1766
|
+
text
|
|
1767
|
+
]
|
|
1768
|
+
}, text))
|
|
1801
1769
|
})
|
|
1802
1770
|
]
|
|
1803
1771
|
})
|
|
1804
1772
|
]
|
|
1805
|
-
})
|
|
1773
|
+
}, phase.name);
|
|
1774
|
+
})
|
|
1775
|
+
})
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
// src/components/SessionWarningBanner.tsx
|
|
1780
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1781
|
+
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
1782
|
+
function SessionWarningBanner({ remaining }) {
|
|
1783
|
+
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
1784
|
+
return null;
|
|
1785
|
+
return /* @__PURE__ */ jsx15("div", {
|
|
1786
|
+
"data-testid": "session-warning-banner",
|
|
1787
|
+
className: "skippr:bg-red-50 skippr:px-4 skippr:py-1.5 skippr:text-center skippr:text-xs skippr:font-medium skippr:text-red-700",
|
|
1788
|
+
children: "Session ending soon"
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// src/components/StartSessionPrompt.tsx
|
|
1793
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1794
|
+
function StartSessionPrompt({
|
|
1795
|
+
onStartSession,
|
|
1796
|
+
isStarting,
|
|
1797
|
+
error,
|
|
1798
|
+
label = "Talk to Skippr"
|
|
1799
|
+
}) {
|
|
1800
|
+
return /* @__PURE__ */ jsxs14("div", {
|
|
1801
|
+
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:justify-center skippr:gap-3 skippr:px-4",
|
|
1802
|
+
children: [
|
|
1803
|
+
/* @__PURE__ */ jsx16("button", {
|
|
1804
|
+
type: "button",
|
|
1805
|
+
onClick: onStartSession,
|
|
1806
|
+
disabled: isStarting,
|
|
1807
|
+
className: "skippr:cursor-pointer skippr:rounded-xl skippr:bg-primary skippr:px-8 skippr:py-3 skippr:text-sm skippr:font-medium skippr:text-primary-foreground skippr:transition-all skippr:hover:bg-primary/90 skippr:disabled:cursor-not-allowed skippr:disabled:opacity-60",
|
|
1808
|
+
children: isStarting ? "Starting..." : label
|
|
1809
|
+
}),
|
|
1810
|
+
error && /* @__PURE__ */ jsx16("p", {
|
|
1811
|
+
className: "skippr:text-xs skippr:text-destructive",
|
|
1812
|
+
children: error
|
|
1806
1813
|
})
|
|
1807
1814
|
]
|
|
1808
1815
|
});
|
|
1809
1816
|
}
|
|
1810
1817
|
|
|
1811
1818
|
// src/components/Sidebar.tsx
|
|
1812
|
-
import { jsx as
|
|
1813
|
-
function Sidebar(
|
|
1819
|
+
import { jsx as jsx17, jsxs as jsxs15, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
1820
|
+
function Sidebar({
|
|
1821
|
+
hideControls = false,
|
|
1822
|
+
hideHeader = false,
|
|
1823
|
+
startSessionLabel = "Talk to Skippr"
|
|
1824
|
+
}) {
|
|
1814
1825
|
const {
|
|
1815
1826
|
variant,
|
|
1816
1827
|
isConnected,
|
|
@@ -1825,12 +1836,14 @@ function Sidebar() {
|
|
|
1825
1836
|
authError,
|
|
1826
1837
|
requestOtp,
|
|
1827
1838
|
verifyOtp,
|
|
1828
|
-
isAuthSubmitting
|
|
1839
|
+
isAuthSubmitting,
|
|
1840
|
+
sidebarTab: activeTab,
|
|
1841
|
+
setSidebarTab: setActiveTab,
|
|
1842
|
+
autoFocusChat
|
|
1829
1843
|
} = useLiveAgent();
|
|
1830
|
-
const [view, setView] = useState8("main");
|
|
1831
1844
|
const isFloating = variant === "floating";
|
|
1832
1845
|
const isSidebar = variant === "sidebar";
|
|
1833
|
-
|
|
1846
|
+
useEffect11(() => {
|
|
1834
1847
|
if (!isSidebar)
|
|
1835
1848
|
return;
|
|
1836
1849
|
const prop = position === "right" ? "marginRight" : "marginLeft";
|
|
@@ -1844,105 +1857,160 @@ function Sidebar() {
|
|
|
1844
1857
|
document.body.style.transition = "";
|
|
1845
1858
|
};
|
|
1846
1859
|
}, [isSidebar, isPanelOpen, position]);
|
|
1847
|
-
return /* @__PURE__ */
|
|
1848
|
-
className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-
|
|
1860
|
+
return /* @__PURE__ */ jsxs15("div", {
|
|
1861
|
+
className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-card", "skippr:flex skippr:flex-col", "skippr:overflow-hidden", isFloating && "skippr:border skippr:border-border skippr:bottom-[88px] skippr:h-[calc(100vh-112px)] skippr:rounded-2xl skippr:shadow-[0_8px_30px_rgba(0,0,0,0.16),0_4px_12px_rgba(0,0,0,0.08)]", isFloating && (position === "right" ? "skippr:right-6" : "skippr:left-6"), isFloating && "skippr:transition-[opacity,transform] skippr:duration-300 skippr:ease-in-out", isFloating && (position === "right" ? "skippr:origin-bottom-right" : "skippr:origin-bottom-left"), isFloating && !isPanelOpen && "skippr:scale-0 skippr:opacity-0 skippr:pointer-events-none", isFloating && isPanelOpen && "skippr:scale-100 skippr:opacity-100", isSidebar && "skippr:top-0 skippr:h-full", isSidebar && "skippr:transition-[width] skippr:duration-300 skippr:ease-in-out", isSidebar && position === "right" && "skippr:right-0 skippr:border-l skippr:border-l-border", isSidebar && position === "left" && "skippr:left-0 skippr:border-r skippr:border-r-border", isSidebar && !isPanelOpen && "skippr:w-0 skippr:border-0"),
|
|
1849
1862
|
style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
|
|
1850
|
-
children:
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
/* @__PURE__ */
|
|
1855
|
-
|
|
1856
|
-
}),
|
|
1857
|
-
isConnected ? /* @__PURE__ */ jsx15(ConnectedContent, {
|
|
1858
|
-
onDisconnect: disconnect
|
|
1859
|
-
}) : isValidating ? /* @__PURE__ */ jsx15("div", {
|
|
1860
|
-
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1861
|
-
children: /* @__PURE__ */ jsx15("p", {
|
|
1862
|
-
className: "skippr:text-sm skippr:text-muted-foreground",
|
|
1863
|
-
children: "Loading..."
|
|
1864
|
-
})
|
|
1865
|
-
}) : isAuthenticated ? /* @__PURE__ */ jsx15(QuickActions, {
|
|
1866
|
-
onStartSession: startSession,
|
|
1867
|
-
isStarting,
|
|
1868
|
-
error
|
|
1869
|
-
}) : /* @__PURE__ */ jsx15(LoginFlow, {
|
|
1870
|
-
requestOtp,
|
|
1871
|
-
verifyOtp,
|
|
1872
|
-
error: authError,
|
|
1873
|
-
isSubmitting: isAuthSubmitting
|
|
1863
|
+
children: [
|
|
1864
|
+
!hideHeader && /* @__PURE__ */ jsx17(ChatHeader, {}),
|
|
1865
|
+
!isAuthenticated && isValidating ? /* @__PURE__ */ jsx17("div", {
|
|
1866
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1867
|
+
children: /* @__PURE__ */ jsx17(LoadingDots, {
|
|
1868
|
+
label: "Loading..."
|
|
1874
1869
|
})
|
|
1875
|
-
|
|
1876
|
-
|
|
1870
|
+
}) : !isAuthenticated ? /* @__PURE__ */ jsx17(LoginFlow, {
|
|
1871
|
+
requestOtp,
|
|
1872
|
+
verifyOtp,
|
|
1873
|
+
error: authError,
|
|
1874
|
+
isSubmitting: isAuthSubmitting
|
|
1875
|
+
}) : /* @__PURE__ */ jsx17(AuthenticatedContent, {
|
|
1876
|
+
isConnected,
|
|
1877
|
+
onStartSession: startSession,
|
|
1878
|
+
onDisconnect: disconnect,
|
|
1879
|
+
isStarting,
|
|
1880
|
+
error,
|
|
1881
|
+
activeTab,
|
|
1882
|
+
onTabChange: setActiveTab,
|
|
1883
|
+
hideControls,
|
|
1884
|
+
startSessionLabel,
|
|
1885
|
+
autoFocusChat
|
|
1886
|
+
})
|
|
1887
|
+
]
|
|
1877
1888
|
});
|
|
1878
1889
|
}
|
|
1879
|
-
function
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
});
|
|
1893
|
-
}
|
|
1894
|
-
const isAgentSpeaking = agentState === "speaking";
|
|
1895
|
-
return /* @__PURE__ */ jsxs12(Fragment2, {
|
|
1890
|
+
function AuthenticatedContent({
|
|
1891
|
+
isConnected,
|
|
1892
|
+
onStartSession,
|
|
1893
|
+
onDisconnect,
|
|
1894
|
+
isStarting,
|
|
1895
|
+
error,
|
|
1896
|
+
activeTab,
|
|
1897
|
+
onTabChange,
|
|
1898
|
+
hideControls,
|
|
1899
|
+
startSessionLabel,
|
|
1900
|
+
autoFocusChat
|
|
1901
|
+
}) {
|
|
1902
|
+
return /* @__PURE__ */ jsxs15(Fragment2, {
|
|
1896
1903
|
children: [
|
|
1897
|
-
/* @__PURE__ */
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
/* @__PURE__ */ jsxs12("div", {
|
|
1901
|
-
className: "skippr:flex skippr:min-h-0 skippr:flex-1",
|
|
1904
|
+
isConnected && /* @__PURE__ */ jsx17(ConnectedBanner, {}),
|
|
1905
|
+
/* @__PURE__ */ jsxs15("div", {
|
|
1906
|
+
className: "skippr:flex skippr:gap-2 skippr:border-b skippr:border-border skippr:px-3 skippr:py-2",
|
|
1902
1907
|
children: [
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1908
|
+
/* @__PURE__ */ jsxs15("button", {
|
|
1909
|
+
type: "button",
|
|
1910
|
+
className: cn("skippr:relative skippr:inline-flex skippr:cursor-pointer skippr:items-center skippr:gap-1.5 skippr:rounded-lg skippr:px-3 skippr:py-2 skippr:text-sm skippr:font-medium skippr:transition-all", activeTab === "chat" ? "skippr:text-foreground" : "skippr:text-muted-foreground skippr:hover:text-foreground"),
|
|
1911
|
+
onClick: () => onTabChange("chat"),
|
|
1912
|
+
children: [
|
|
1913
|
+
/* @__PURE__ */ jsx17(MessageCircle, {
|
|
1914
|
+
className: "skippr:size-3.5"
|
|
1915
|
+
}),
|
|
1916
|
+
"Chat",
|
|
1917
|
+
activeTab === "chat" && /* @__PURE__ */ jsx17("span", {
|
|
1918
|
+
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
1919
|
+
})
|
|
1920
|
+
]
|
|
1909
1921
|
}),
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1922
|
+
/* @__PURE__ */ jsxs15("button", {
|
|
1923
|
+
type: "button",
|
|
1924
|
+
className: cn("skippr:relative skippr:inline-flex skippr:cursor-pointer skippr:items-center skippr:gap-1.5 skippr:rounded-lg skippr:px-3 skippr:py-2 skippr:text-sm skippr:font-medium skippr:transition-all", activeTab === "agenda" ? "skippr:text-foreground" : "skippr:text-muted-foreground skippr:hover:text-foreground"),
|
|
1925
|
+
onClick: () => onTabChange("agenda"),
|
|
1926
|
+
children: [
|
|
1927
|
+
/* @__PURE__ */ jsx17(Calendar, {
|
|
1928
|
+
className: "skippr:size-3.5"
|
|
1929
|
+
}),
|
|
1930
|
+
"Agenda",
|
|
1931
|
+
activeTab === "agenda" && /* @__PURE__ */ jsx17("span", {
|
|
1932
|
+
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
1933
|
+
})
|
|
1934
|
+
]
|
|
1918
1935
|
})
|
|
1919
1936
|
]
|
|
1937
|
+
}),
|
|
1938
|
+
/* @__PURE__ */ jsx17("div", {
|
|
1939
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1940
|
+
children: isConnected ? /* @__PURE__ */ jsx17(ConnectedBody, {
|
|
1941
|
+
activeTab,
|
|
1942
|
+
autoFocusChat
|
|
1943
|
+
}) : /* @__PURE__ */ jsx17("div", {
|
|
1944
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
1945
|
+
children: /* @__PURE__ */ jsx17(StartSessionPrompt, {
|
|
1946
|
+
onStartSession,
|
|
1947
|
+
isStarting,
|
|
1948
|
+
error,
|
|
1949
|
+
label: startSessionLabel
|
|
1950
|
+
})
|
|
1951
|
+
}, `${activeTab}-empty`)
|
|
1952
|
+
}),
|
|
1953
|
+
isConnected && !hideControls && /* @__PURE__ */ jsx17(MeetingControls, {
|
|
1954
|
+
onHangUp: onDisconnect
|
|
1920
1955
|
})
|
|
1921
1956
|
]
|
|
1922
1957
|
});
|
|
1923
1958
|
}
|
|
1959
|
+
function ConnectedBanner() {
|
|
1960
|
+
const remaining = useSessionRemaining();
|
|
1961
|
+
return /* @__PURE__ */ jsx17(SessionWarningBanner, {
|
|
1962
|
+
remaining
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
function ConnectedBody({
|
|
1966
|
+
activeTab,
|
|
1967
|
+
autoFocusChat
|
|
1968
|
+
}) {
|
|
1969
|
+
const { allMessages, agentState, sendChatMessage, isSendingChat } = useCombinedMessages();
|
|
1970
|
+
const { phases } = usePhaseUpdates();
|
|
1971
|
+
if (activeTab === "agenda") {
|
|
1972
|
+
return /* @__PURE__ */ jsx17("div", {
|
|
1973
|
+
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto skippr:animate-skippr-tab-fade",
|
|
1974
|
+
children: /* @__PURE__ */ jsx17(SessionAgenda, {
|
|
1975
|
+
phases
|
|
1976
|
+
})
|
|
1977
|
+
}, "agenda");
|
|
1978
|
+
}
|
|
1979
|
+
return /* @__PURE__ */ jsx17("div", {
|
|
1980
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
1981
|
+
children: /* @__PURE__ */ jsx17(MessageList, {
|
|
1982
|
+
messages: allMessages,
|
|
1983
|
+
isStreaming: agentState === "speaking",
|
|
1984
|
+
sendChatMessage,
|
|
1985
|
+
isSendingChat,
|
|
1986
|
+
autoFocus: autoFocusChat
|
|
1987
|
+
})
|
|
1988
|
+
}, "chat");
|
|
1989
|
+
}
|
|
1924
1990
|
|
|
1925
1991
|
// src/components/SidebarTrigger.tsx
|
|
1926
|
-
import { jsx as
|
|
1992
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1927
1993
|
function SidebarTrigger() {
|
|
1928
|
-
const { isPanelOpen, togglePanel, position, isMinimized } = useLiveAgent();
|
|
1994
|
+
const { isPanelOpen, togglePanel, minimizePanel, minimizable, position, isMinimized } = useLiveAgent();
|
|
1929
1995
|
if (isMinimized)
|
|
1930
1996
|
return null;
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
title: isPanelOpen ? "Close chat" : "
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
className: "skippr:size-
|
|
1997
|
+
const handleClick = isPanelOpen && minimizable ? minimizePanel : togglePanel;
|
|
1998
|
+
return /* @__PURE__ */ jsx18("button", {
|
|
1999
|
+
type: "button",
|
|
2000
|
+
onClick: handleClick,
|
|
2001
|
+
title: isPanelOpen ? "Close chat" : "Open chat",
|
|
2002
|
+
"aria-label": isPanelOpen ? "Close chat" : "Open chat",
|
|
2003
|
+
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9998]", "skippr:flex skippr:size-12 skippr:items-center skippr:justify-center", "skippr:rounded-[14px] skippr:bg-bubble skippr:text-white", "skippr:shadow-[0_4px_16px_rgba(45,43,61,0.45),0_2px_4px_rgba(0,0,0,0.1)] skippr:transition-all", "skippr:cursor-pointer skippr:hover:brightness-110 skippr:hover:-translate-y-0.5 skippr:active:translate-y-0", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
2004
|
+
children: isPanelOpen ? /* @__PURE__ */ jsx18(ChevronDown, {
|
|
2005
|
+
className: "skippr:size-5"
|
|
2006
|
+
}) : /* @__PURE__ */ jsx18(Logo, {
|
|
2007
|
+
className: "skippr:size-7"
|
|
1940
2008
|
})
|
|
1941
2009
|
});
|
|
1942
2010
|
}
|
|
1943
2011
|
|
|
1944
2012
|
// src/components/LiveAgent.tsx
|
|
1945
|
-
import { jsx as
|
|
2013
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1946
2014
|
function LiveAgent({
|
|
1947
2015
|
agentId,
|
|
1948
2016
|
authToken: authTokenProp,
|
|
@@ -1953,21 +2021,36 @@ function LiveAgent({
|
|
|
1953
2021
|
minimizable = true,
|
|
1954
2022
|
defaultOpen = false,
|
|
1955
2023
|
welcomeMessage,
|
|
2024
|
+
hideControls = false,
|
|
2025
|
+
hideHeader = false,
|
|
2026
|
+
startSessionLabel = "Talk to Skippr",
|
|
2027
|
+
autoFocusChat = true,
|
|
2028
|
+
showObservingBanner = true,
|
|
1956
2029
|
children
|
|
1957
2030
|
}) {
|
|
1958
2031
|
const auth = useAuth({ appKey });
|
|
1959
2032
|
const effectiveAuthToken = authTokenProp || auth.authToken || undefined;
|
|
1960
|
-
const {
|
|
2033
|
+
const {
|
|
2034
|
+
connection,
|
|
2035
|
+
shouldConnect,
|
|
2036
|
+
isStarting,
|
|
2037
|
+
error,
|
|
2038
|
+
errorCode,
|
|
2039
|
+
startSession,
|
|
2040
|
+
disconnect,
|
|
2041
|
+
pendingScreenStream
|
|
2042
|
+
} = useSession({
|
|
1961
2043
|
agentId,
|
|
1962
2044
|
authToken: effectiveAuthToken,
|
|
1963
2045
|
appKey,
|
|
1964
2046
|
userToken
|
|
1965
2047
|
});
|
|
1966
|
-
const [isPanelOpen, setIsPanelOpen] =
|
|
1967
|
-
const [isMinimized, setIsMinimized] =
|
|
1968
|
-
const [
|
|
1969
|
-
const
|
|
1970
|
-
const
|
|
2048
|
+
const [isPanelOpen, setIsPanelOpen] = useState8(defaultOpen);
|
|
2049
|
+
const [isMinimized, setIsMinimized] = useState8(minimizable && !defaultOpen);
|
|
2050
|
+
const [sidebarTab, setSidebarTab] = useState8("agenda");
|
|
2051
|
+
const [welcomeDismissed, setWelcomeDismissed] = useState8(false);
|
|
2052
|
+
const dismissWelcome = useCallback6(() => setWelcomeDismissed(true), []);
|
|
2053
|
+
const [currentPosition, setCurrentPosition] = useState8(() => {
|
|
1971
2054
|
try {
|
|
1972
2055
|
const saved = localStorage.getItem("skippr_widget_position");
|
|
1973
2056
|
if (saved === "left" || saved === "right")
|
|
@@ -1975,20 +2058,20 @@ function LiveAgent({
|
|
|
1975
2058
|
} catch {}
|
|
1976
2059
|
return position;
|
|
1977
2060
|
});
|
|
1978
|
-
const setPositionWithPersist =
|
|
2061
|
+
const setPositionWithPersist = useCallback6((pos) => {
|
|
1979
2062
|
setCurrentPosition(pos);
|
|
1980
2063
|
try {
|
|
1981
2064
|
localStorage.setItem("skippr_widget_position", pos);
|
|
1982
2065
|
} catch {}
|
|
1983
2066
|
}, []);
|
|
1984
|
-
const openPanel =
|
|
1985
|
-
const closePanel =
|
|
1986
|
-
const togglePanel =
|
|
1987
|
-
const expandPanel =
|
|
2067
|
+
const openPanel = useCallback6(() => setIsPanelOpen(true), []);
|
|
2068
|
+
const closePanel = useCallback6(() => setIsPanelOpen(false), []);
|
|
2069
|
+
const togglePanel = useCallback6(() => setIsPanelOpen((prev) => !prev), []);
|
|
2070
|
+
const expandPanel = useCallback6(() => {
|
|
1988
2071
|
setIsMinimized(false);
|
|
1989
2072
|
setIsPanelOpen(true);
|
|
1990
2073
|
}, []);
|
|
1991
|
-
const minimizePanel =
|
|
2074
|
+
const minimizePanel = useCallback6(() => {
|
|
1992
2075
|
if (!minimizable)
|
|
1993
2076
|
return;
|
|
1994
2077
|
setIsMinimized(true);
|
|
@@ -1996,8 +2079,8 @@ function LiveAgent({
|
|
|
1996
2079
|
}, [minimizable]);
|
|
1997
2080
|
const isConnected = connection !== null;
|
|
1998
2081
|
const isAuthenticated = !!userToken || !!authTokenProp || auth.isAuthenticated;
|
|
1999
|
-
const prevConnectionRef =
|
|
2000
|
-
|
|
2082
|
+
const prevConnectionRef = useRef6(connection);
|
|
2083
|
+
useEffect12(() => {
|
|
2001
2084
|
const connectionChanged = prevConnectionRef.current !== connection;
|
|
2002
2085
|
prevConnectionRef.current = connection;
|
|
2003
2086
|
if (connectionChanged && minimizable) {
|
|
@@ -2031,7 +2114,10 @@ function LiveAgent({
|
|
|
2031
2114
|
requestOtp: auth.requestOtp,
|
|
2032
2115
|
verifyOtp: auth.verifyOtp,
|
|
2033
2116
|
logoutAuth: auth.logout,
|
|
2034
|
-
isAuthSubmitting: auth.isSubmitting
|
|
2117
|
+
isAuthSubmitting: auth.isSubmitting,
|
|
2118
|
+
sidebarTab,
|
|
2119
|
+
setSidebarTab,
|
|
2120
|
+
autoFocusChat
|
|
2035
2121
|
}), [
|
|
2036
2122
|
connection,
|
|
2037
2123
|
shouldConnect,
|
|
@@ -2058,31 +2144,54 @@ function LiveAgent({
|
|
|
2058
2144
|
auth.requestOtp,
|
|
2059
2145
|
auth.verifyOtp,
|
|
2060
2146
|
auth.logout,
|
|
2061
|
-
auth.isSubmitting
|
|
2147
|
+
auth.isSubmitting,
|
|
2148
|
+
sidebarTab,
|
|
2149
|
+
autoFocusChat
|
|
2062
2150
|
]);
|
|
2063
|
-
return /* @__PURE__ */
|
|
2151
|
+
return /* @__PURE__ */ jsx19(LiveAgentContext.Provider, {
|
|
2064
2152
|
value: ctx,
|
|
2065
|
-
children: /* @__PURE__ */
|
|
2153
|
+
children: /* @__PURE__ */ jsxs16(LiveKitRoom, {
|
|
2066
2154
|
serverUrl: connection?.livekitUrl,
|
|
2067
2155
|
token: connection?.token,
|
|
2068
2156
|
connect: shouldConnect,
|
|
2069
2157
|
audio: true,
|
|
2070
2158
|
onDisconnected: disconnect,
|
|
2071
2159
|
children: [
|
|
2072
|
-
connection && /* @__PURE__ */
|
|
2073
|
-
|
|
2160
|
+
connection && /* @__PURE__ */ jsx19(RoomAudioRenderer, {}),
|
|
2161
|
+
showObservingBanner && /* @__PURE__ */ jsx19(ObservingBanner, {}),
|
|
2162
|
+
connection && /* @__PURE__ */ jsx19(AutoStartMedia, {
|
|
2163
|
+
pendingScreenStream
|
|
2164
|
+
}),
|
|
2165
|
+
isMinimized && /* @__PURE__ */ jsx19(MinimizedBubble, {
|
|
2074
2166
|
welcomeMessage,
|
|
2075
2167
|
welcomeDismissed,
|
|
2076
2168
|
onDismissWelcome: dismissWelcome
|
|
2077
2169
|
}),
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2170
|
+
/* @__PURE__ */ jsx19(SidebarTrigger, {}),
|
|
2171
|
+
/* @__PURE__ */ jsx19(Sidebar, {
|
|
2172
|
+
hideControls,
|
|
2173
|
+
hideHeader,
|
|
2174
|
+
startSessionLabel
|
|
2175
|
+
}),
|
|
2080
2176
|
children
|
|
2081
2177
|
]
|
|
2082
2178
|
})
|
|
2083
2179
|
});
|
|
2084
2180
|
}
|
|
2181
|
+
// src/hooks/useIsLocalSpeaking.ts
|
|
2182
|
+
import { useIsSpeaking, useLocalParticipant as useLocalParticipant5 } from "@livekit/components-react";
|
|
2183
|
+
function useIsLocalSpeaking() {
|
|
2184
|
+
const { localParticipant } = useLocalParticipant5();
|
|
2185
|
+
return useIsSpeaking(localParticipant);
|
|
2186
|
+
}
|
|
2085
2187
|
export {
|
|
2188
|
+
useMediaControls,
|
|
2086
2189
|
useLiveAgent,
|
|
2190
|
+
useIsLocalSpeaking,
|
|
2191
|
+
useElapsedSeconds,
|
|
2192
|
+
useAgentVoiceState,
|
|
2193
|
+
parseNumber,
|
|
2194
|
+
formatTime,
|
|
2195
|
+
SCREEN_SHARE_OPTIONS,
|
|
2087
2196
|
LiveAgent
|
|
2088
2197
|
};
|