@skippr/live-agent-sdk 0.24.0 → 0.25.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 +979 -940
- package/dist/esm/logo-icon-cn8fyke6.png +0 -0
- package/dist/logo-icon-cn8fyke6.png +0 -0
- 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/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/assets.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,42 @@ 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
|
+
|
|
600
|
+
// src/assets/logo-icon.png
|
|
601
|
+
var logo_icon_default = "./logo-icon-cn8fyke6.png";
|
|
602
|
+
|
|
603
|
+
// src/lib/assets.ts
|
|
604
|
+
var LOGO_URL = logo_icon_default;
|
|
605
|
+
|
|
527
606
|
// src/lib/utils.ts
|
|
528
607
|
import { clsx } from "clsx";
|
|
529
608
|
import { twMerge } from "tailwind-merge";
|
|
@@ -533,13 +612,18 @@ function cn(...inputs) {
|
|
|
533
612
|
|
|
534
613
|
// src/components/ui/tooltip.tsx
|
|
535
614
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
536
|
-
|
|
615
|
+
var ALIGN_CLASSES = {
|
|
616
|
+
center: "skippr:left-1/2 skippr:-translate-x-1/2",
|
|
617
|
+
start: "skippr:left-0",
|
|
618
|
+
end: "skippr:right-0"
|
|
619
|
+
};
|
|
620
|
+
function Tooltip({ label, children, position = "top", align = "center" }) {
|
|
537
621
|
return /* @__PURE__ */ jsxs("span", {
|
|
538
622
|
className: "skippr:relative skippr:inline-flex skippr:group",
|
|
539
623
|
children: [
|
|
540
624
|
children,
|
|
541
625
|
/* @__PURE__ */ jsx("span", {
|
|
542
|
-
className: cn("skippr:pointer-events-none skippr:absolute skippr:
|
|
626
|
+
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
627
|
"aria-hidden": "true",
|
|
544
628
|
children: label
|
|
545
629
|
})
|
|
@@ -549,140 +633,112 @@ function Tooltip({ label, children, position = "top" }) {
|
|
|
549
633
|
|
|
550
634
|
// src/components/MinimizedBubble.tsx
|
|
551
635
|
import { jsx as jsx2, jsxs as jsxs2, Fragment } from "react/jsx-runtime";
|
|
552
|
-
|
|
636
|
+
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";
|
|
637
|
+
function AgentBubbleContent({ agentState }) {
|
|
553
638
|
if (agentState === "speaking") {
|
|
554
639
|
return /* @__PURE__ */ jsxs2("div", {
|
|
555
|
-
className: "skippr:flex skippr:items-
|
|
640
|
+
className: "skippr:flex skippr:h-5 skippr:items-center skippr:justify-center skippr:gap-[3px]",
|
|
556
641
|
children: [
|
|
557
642
|
/* @__PURE__ */ jsx2("span", {
|
|
558
|
-
className: "skippr:w-[3px] skippr:h-
|
|
643
|
+
className: "skippr:w-[3px] skippr:h-2 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_infinite]"
|
|
644
|
+
}),
|
|
645
|
+
/* @__PURE__ */ jsx2("span", {
|
|
646
|
+
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]"
|
|
559
647
|
}),
|
|
560
648
|
/* @__PURE__ */ jsx2("span", {
|
|
561
|
-
className: "skippr:w-[3px] skippr:h-
|
|
649
|
+
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]"
|
|
562
650
|
}),
|
|
563
651
|
/* @__PURE__ */ jsx2("span", {
|
|
564
|
-
className: "skippr:w-[3px] skippr:h-
|
|
652
|
+
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]"
|
|
565
653
|
}),
|
|
566
654
|
/* @__PURE__ */ jsx2("span", {
|
|
567
|
-
className: "skippr:w-[3px] skippr:h-
|
|
655
|
+
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
656
|
})
|
|
569
657
|
]
|
|
570
658
|
});
|
|
571
659
|
}
|
|
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
660
|
if (agentState === "thinking") {
|
|
578
|
-
return /* @__PURE__ */
|
|
579
|
-
className: "skippr:
|
|
661
|
+
return /* @__PURE__ */ jsxs2("div", {
|
|
662
|
+
className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-[4px]",
|
|
663
|
+
children: [
|
|
664
|
+
/* @__PURE__ */ jsx2("span", {
|
|
665
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:0ms]"
|
|
666
|
+
}),
|
|
667
|
+
/* @__PURE__ */ jsx2("span", {
|
|
668
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:150ms]"
|
|
669
|
+
}),
|
|
670
|
+
/* @__PURE__ */ jsx2("span", {
|
|
671
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:300ms]"
|
|
672
|
+
})
|
|
673
|
+
]
|
|
580
674
|
});
|
|
581
675
|
}
|
|
582
|
-
return /* @__PURE__ */ jsx2(
|
|
583
|
-
|
|
676
|
+
return /* @__PURE__ */ jsx2("img", {
|
|
677
|
+
src: LOGO_URL,
|
|
678
|
+
alt: "Skippr",
|
|
679
|
+
className: "skippr:size-7"
|
|
584
680
|
});
|
|
585
681
|
}
|
|
586
682
|
function ConnectedBubbleContent() {
|
|
587
|
-
const { expandPanel, disconnect } = useLiveAgent();
|
|
588
|
-
const { state: agentState } =
|
|
589
|
-
const {
|
|
590
|
-
const
|
|
591
|
-
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
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";
|
|
683
|
+
const { expandPanel, disconnect, position } = useLiveAgent();
|
|
684
|
+
const { state: agentState } = useAgentVoiceState();
|
|
685
|
+
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
686
|
+
const tooltipAlign = position === "right" ? "end" : "start";
|
|
612
687
|
return /* @__PURE__ */ jsxs2(Fragment, {
|
|
613
688
|
children: [
|
|
614
689
|
/* @__PURE__ */ jsx2(Tooltip, {
|
|
615
|
-
label: "
|
|
616
|
-
|
|
690
|
+
label: isMuted ? "Unmute" : "Mute",
|
|
691
|
+
align: tooltipAlign,
|
|
692
|
+
children: /* @__PURE__ */ jsx2("button", {
|
|
617
693
|
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
|
-
]
|
|
694
|
+
onClick: toggleMute,
|
|
695
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
696
|
+
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"),
|
|
697
|
+
children: isMuted ? /* @__PURE__ */ jsx2(MicOff, {
|
|
698
|
+
className: "skippr:size-5"
|
|
699
|
+
}) : /* @__PURE__ */ jsx2(Mic, {
|
|
700
|
+
className: "skippr:size-5"
|
|
701
|
+
})
|
|
636
702
|
})
|
|
637
703
|
}),
|
|
638
|
-
/* @__PURE__ */ jsx2(
|
|
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
|
-
})
|
|
704
|
+
/* @__PURE__ */ jsx2(Tooltip, {
|
|
705
|
+
label: isScreenSharing ? "Stop sharing" : "Share screen",
|
|
706
|
+
align: tooltipAlign,
|
|
707
|
+
children: /* @__PURE__ */ jsx2("button", {
|
|
708
|
+
type: "button",
|
|
709
|
+
onClick: toggleScreenShare,
|
|
710
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
711
|
+
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"),
|
|
712
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx2(MonitorOff, {
|
|
713
|
+
className: "skippr:size-5"
|
|
714
|
+
}) : /* @__PURE__ */ jsx2(Monitor, {
|
|
715
|
+
className: "skippr:size-5"
|
|
671
716
|
})
|
|
672
|
-
|
|
673
|
-
}),
|
|
674
|
-
/* @__PURE__ */ jsx2("div", {
|
|
675
|
-
className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
|
|
717
|
+
})
|
|
676
718
|
}),
|
|
677
719
|
/* @__PURE__ */ jsx2(Tooltip, {
|
|
678
720
|
label: "End session",
|
|
721
|
+
align: tooltipAlign,
|
|
679
722
|
children: /* @__PURE__ */ jsx2("button", {
|
|
680
723
|
type: "button",
|
|
681
724
|
onClick: () => disconnect(),
|
|
682
|
-
|
|
683
|
-
"
|
|
725
|
+
"aria-label": "End session",
|
|
726
|
+
className: cn(BUBBLE_BUTTON, "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90"),
|
|
684
727
|
children: /* @__PURE__ */ jsx2(PhoneOff, {
|
|
685
|
-
className: "skippr:size-
|
|
728
|
+
className: "skippr:size-5"
|
|
729
|
+
})
|
|
730
|
+
})
|
|
731
|
+
}),
|
|
732
|
+
/* @__PURE__ */ jsx2(Tooltip, {
|
|
733
|
+
label: "Open chat & transcript",
|
|
734
|
+
align: tooltipAlign,
|
|
735
|
+
children: /* @__PURE__ */ jsx2("button", {
|
|
736
|
+
type: "button",
|
|
737
|
+
onClick: expandPanel,
|
|
738
|
+
"aria-label": "Open chat & transcript",
|
|
739
|
+
className: cn(BUBBLE_BUTTON, "skippr:bg-bubble skippr:hover:brightness-110"),
|
|
740
|
+
children: /* @__PURE__ */ jsx2(AgentBubbleContent, {
|
|
741
|
+
agentState
|
|
686
742
|
})
|
|
687
743
|
})
|
|
688
744
|
})
|
|
@@ -690,123 +746,27 @@ function ConnectedBubbleContent() {
|
|
|
690
746
|
});
|
|
691
747
|
}
|
|
692
748
|
function IdleBubbleContent() {
|
|
693
|
-
const { expandPanel,
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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"
|
|
749
|
+
const { expandPanel, position } = useLiveAgent();
|
|
750
|
+
const tooltipAlign = position === "right" ? "end" : "start";
|
|
751
|
+
return /* @__PURE__ */ jsx2(Tooltip, {
|
|
752
|
+
label: "Open Skippr assistant",
|
|
753
|
+
align: tooltipAlign,
|
|
754
|
+
children: /* @__PURE__ */ jsxs2("button", {
|
|
755
|
+
type: "button",
|
|
756
|
+
onClick: expandPanel,
|
|
757
|
+
"aria-label": "Skippr assistant",
|
|
758
|
+
className: cn(BUBBLE_BUTTON, "skippr:relative skippr:bg-bubble skippr:hover:brightness-110"),
|
|
759
|
+
children: [
|
|
760
|
+
/* @__PURE__ */ jsx2("img", {
|
|
761
|
+
src: LOGO_URL,
|
|
762
|
+
alt: "Skippr",
|
|
763
|
+
className: "skippr:relative skippr:z-10 skippr:size-7"
|
|
764
|
+
}),
|
|
765
|
+
/* @__PURE__ */ jsx2("span", {
|
|
766
|
+
className: "skippr:absolute skippr:-inset-[3px] skippr:animate-pulse skippr:rounded-[17px] skippr:border-2 skippr:border-bubble/50"
|
|
723
767
|
})
|
|
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
|
-
]
|
|
768
|
+
]
|
|
769
|
+
})
|
|
810
770
|
});
|
|
811
771
|
}
|
|
812
772
|
function WelcomeBubble({
|
|
@@ -814,7 +774,7 @@ function WelcomeBubble({
|
|
|
814
774
|
position,
|
|
815
775
|
onDismiss
|
|
816
776
|
}) {
|
|
817
|
-
|
|
777
|
+
useEffect4(() => {
|
|
818
778
|
const timer = setTimeout(onDismiss, 5000);
|
|
819
779
|
return () => clearTimeout(timer);
|
|
820
780
|
}, [onDismiss]);
|
|
@@ -836,31 +796,63 @@ function MinimizedBubble({
|
|
|
836
796
|
welcomeDismissed,
|
|
837
797
|
onDismissWelcome
|
|
838
798
|
}) {
|
|
839
|
-
const { isConnected, position } = useLiveAgent();
|
|
799
|
+
const { isConnected, isStarting, position } = useLiveAgent();
|
|
800
|
+
const inSession = isConnected || isStarting;
|
|
840
801
|
return /* @__PURE__ */ jsxs2("div", {
|
|
841
|
-
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-
|
|
802
|
+
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
803
|
children: [
|
|
843
|
-
welcomeMessage && !
|
|
804
|
+
welcomeMessage && !inSession && !welcomeDismissed && /* @__PURE__ */ jsx2(WelcomeBubble, {
|
|
844
805
|
message: welcomeMessage,
|
|
845
806
|
position,
|
|
846
807
|
onDismiss: onDismissWelcome
|
|
847
808
|
}),
|
|
848
|
-
|
|
809
|
+
inSession ? /* @__PURE__ */ jsx2(ConnectedBubbleContent, {}) : /* @__PURE__ */ jsx2(IdleBubbleContent, {})
|
|
849
810
|
]
|
|
850
811
|
});
|
|
851
812
|
}
|
|
852
813
|
|
|
814
|
+
// src/components/ObservingBanner.tsx
|
|
815
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
816
|
+
function ObservingBanner() {
|
|
817
|
+
const { isConnected } = useLiveAgent();
|
|
818
|
+
const { isScreenSharing } = useMediaControls();
|
|
819
|
+
if (!isConnected || !isScreenSharing)
|
|
820
|
+
return null;
|
|
821
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
822
|
+
className: "skippr:fixed skippr:top-0 skippr:left-0 skippr:right-0 skippr:z-[2147483647] skippr:flex skippr:justify-center skippr:pointer-events-none",
|
|
823
|
+
children: /* @__PURE__ */ jsxs3("div", {
|
|
824
|
+
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",
|
|
825
|
+
children: [
|
|
826
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
827
|
+
className: "skippr:relative skippr:flex skippr:size-1.5",
|
|
828
|
+
children: [
|
|
829
|
+
/* @__PURE__ */ jsx3("span", {
|
|
830
|
+
className: "skippr:absolute skippr:inline-flex skippr:size-full skippr:animate-ping skippr:rounded-full skippr:bg-emerald-400 skippr:opacity-75"
|
|
831
|
+
}),
|
|
832
|
+
/* @__PURE__ */ jsx3("span", {
|
|
833
|
+
className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-emerald-400"
|
|
834
|
+
})
|
|
835
|
+
]
|
|
836
|
+
}),
|
|
837
|
+
/* @__PURE__ */ jsx3(Eye, {
|
|
838
|
+
className: "skippr:size-3.5"
|
|
839
|
+
}),
|
|
840
|
+
/* @__PURE__ */ jsx3("span", {
|
|
841
|
+
children: "Skippr is observing this page"
|
|
842
|
+
})
|
|
843
|
+
]
|
|
844
|
+
})
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
|
|
853
848
|
// src/components/Sidebar.tsx
|
|
854
|
-
import {
|
|
855
|
-
import { ConnectionState } from "livekit-client";
|
|
856
|
-
import { useEffect as useEffect8, useState as useState8 } from "react";
|
|
849
|
+
import { useEffect as useEffect11 } from "react";
|
|
857
850
|
|
|
858
851
|
// src/hooks/useCombinedMessages.ts
|
|
859
|
-
import { useVoiceAssistant as useVoiceAssistant2 } from "@livekit/components-react";
|
|
860
852
|
import { useMemo as useMemo4 } from "react";
|
|
861
853
|
|
|
862
854
|
// src/hooks/useChatMessages.ts
|
|
863
|
-
import { useChat, useLocalParticipant as
|
|
855
|
+
import { useChat, useLocalParticipant as useLocalParticipant3 } from "@livekit/components-react";
|
|
864
856
|
import { useMemo as useMemo2 } from "react";
|
|
865
857
|
|
|
866
858
|
// src/lib/filterSystemMessages.ts
|
|
@@ -872,7 +864,7 @@ function filterSystemMessages(messages) {
|
|
|
872
864
|
// src/hooks/useChatMessages.ts
|
|
873
865
|
function useChatMessages() {
|
|
874
866
|
const { chatMessages: rawMessages, send, isSending } = useChat();
|
|
875
|
-
const { localParticipant } =
|
|
867
|
+
const { localParticipant } = useLocalParticipant3();
|
|
876
868
|
const localIdentity = localParticipant.identity;
|
|
877
869
|
const chatMessages = useMemo2(() => {
|
|
878
870
|
const sortedMessages = rawMessages.map((msg) => ({
|
|
@@ -888,11 +880,11 @@ function useChatMessages() {
|
|
|
888
880
|
}
|
|
889
881
|
|
|
890
882
|
// src/hooks/useStreamingTranscript.ts
|
|
891
|
-
import { useLocalParticipant as
|
|
883
|
+
import { useLocalParticipant as useLocalParticipant4, useTranscriptions } from "@livekit/components-react";
|
|
892
884
|
import { useMemo as useMemo3 } from "react";
|
|
893
885
|
function useStreamingTranscript() {
|
|
894
886
|
const transcriptions = useTranscriptions();
|
|
895
|
-
const { localParticipant } =
|
|
887
|
+
const { localParticipant } = useLocalParticipant4();
|
|
896
888
|
const localIdentity = localParticipant.identity;
|
|
897
889
|
const transcriptMessages = useMemo3(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
|
|
898
890
|
id: stream.streamInfo.id,
|
|
@@ -924,7 +916,7 @@ function mergeChatsIntoTranscripts(transcripts, chats) {
|
|
|
924
916
|
function useCombinedMessages() {
|
|
925
917
|
const { transcriptMessages } = useStreamingTranscript();
|
|
926
918
|
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
927
|
-
const { state: agentState } =
|
|
919
|
+
const { state: agentState } = useAgentVoiceState();
|
|
928
920
|
const allMessages = useMemo4(() => {
|
|
929
921
|
if (chatMessages.length === 0)
|
|
930
922
|
return transcriptMessages;
|
|
@@ -940,11 +932,11 @@ import { useCallback as useCallback4 } from "react";
|
|
|
940
932
|
|
|
941
933
|
// src/hooks/useAgentState.ts
|
|
942
934
|
import { useRemoteParticipants } from "@livekit/components-react";
|
|
943
|
-
import { useEffect as
|
|
935
|
+
import { useEffect as useEffect5, useState as useState3 } from "react";
|
|
944
936
|
function useAgentState(attributeKey, parse, initial) {
|
|
945
|
-
const [value, setValue] =
|
|
937
|
+
const [value, setValue] = useState3(initial);
|
|
946
938
|
const remoteParticipants = useRemoteParticipants();
|
|
947
|
-
|
|
939
|
+
useEffect5(() => {
|
|
948
940
|
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
949
941
|
if (agentParticipant) {
|
|
950
942
|
const attr = agentParticipant.attributes?.[attributeKey];
|
|
@@ -995,96 +987,109 @@ function usePhaseUpdates() {
|
|
|
995
987
|
return { phases };
|
|
996
988
|
}
|
|
997
989
|
|
|
998
|
-
// src/hooks/
|
|
999
|
-
import {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
} catch {}
|
|
1007
|
-
return null;
|
|
990
|
+
// src/hooks/useSessionRemaining.ts
|
|
991
|
+
import { useEffect as useEffect6, useRef as useRef2, useState as useState4 } from "react";
|
|
992
|
+
|
|
993
|
+
// src/lib/format.ts
|
|
994
|
+
function formatTime(seconds) {
|
|
995
|
+
const m = Math.floor(seconds / 60).toString().padStart(2, "0");
|
|
996
|
+
const s = (seconds % 60).toString().padStart(2, "0");
|
|
997
|
+
return `${m}:${s}`;
|
|
1008
998
|
}
|
|
1009
|
-
function
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
999
|
+
function parseNumber(s) {
|
|
1000
|
+
const n = Number(s);
|
|
1001
|
+
return n > 0 ? n : null;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// src/hooks/useSessionRemaining.ts
|
|
1005
|
+
function useSessionRemaining() {
|
|
1006
|
+
const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
|
|
1007
|
+
const endTimeRef = useRef2(null);
|
|
1008
|
+
const [remaining, setRemaining] = useState4(null);
|
|
1009
|
+
useEffect6(() => {
|
|
1010
|
+
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
1011
|
+
return;
|
|
1012
|
+
const endTime = Date.now() + maxCallDuration * 1000;
|
|
1013
|
+
endTimeRef.current = endTime;
|
|
1014
|
+
const tick = () => {
|
|
1015
|
+
const secs = Math.ceil((endTime - Date.now()) / 1000);
|
|
1016
|
+
setRemaining(Math.max(secs, 0));
|
|
1017
|
+
};
|
|
1018
|
+
tick();
|
|
1019
|
+
const id = setInterval(tick, 1000);
|
|
1020
|
+
return () => clearInterval(id);
|
|
1021
|
+
}, [maxCallDuration]);
|
|
1022
|
+
return remaining;
|
|
1013
1023
|
}
|
|
1014
1024
|
|
|
1015
1025
|
// src/lib/constants.ts
|
|
1016
|
-
var SIDEBAR_WIDTH =
|
|
1026
|
+
var SIDEBAR_WIDTH = 360;
|
|
1017
1027
|
|
|
1018
|
-
// src/
|
|
1019
|
-
import {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
"icon-lg": "skippr:size-10"
|
|
1037
|
-
};
|
|
1038
|
-
var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
1039
|
-
return /* @__PURE__ */ jsx3("button", {
|
|
1040
|
-
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
|
-
ref,
|
|
1042
|
-
...props
|
|
1043
|
-
});
|
|
1044
|
-
});
|
|
1045
|
-
Button.displayName = "Button";
|
|
1028
|
+
// src/hooks/useElapsedSeconds.ts
|
|
1029
|
+
import { useEffect as useEffect7, useState as useState5 } from "react";
|
|
1030
|
+
function useElapsedSeconds(isRunning) {
|
|
1031
|
+
const [elapsed, setElapsed] = useState5(0);
|
|
1032
|
+
useEffect7(() => {
|
|
1033
|
+
if (!isRunning) {
|
|
1034
|
+
setElapsed(0);
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
const startedAt = Date.now();
|
|
1038
|
+
setElapsed(0);
|
|
1039
|
+
const id = setInterval(() => {
|
|
1040
|
+
setElapsed(Math.floor((Date.now() - startedAt) / 1000));
|
|
1041
|
+
}, 1000);
|
|
1042
|
+
return () => clearInterval(id);
|
|
1043
|
+
}, [isRunning]);
|
|
1044
|
+
return elapsed;
|
|
1045
|
+
}
|
|
1046
1046
|
|
|
1047
1047
|
// src/components/ChatHeader.tsx
|
|
1048
|
-
import { jsx as jsx4, jsxs as
|
|
1049
|
-
function ChatHeader(
|
|
1050
|
-
const {
|
|
1051
|
-
|
|
1052
|
-
|
|
1048
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1049
|
+
function ChatHeader() {
|
|
1050
|
+
const { isConnected, minimizePanel, minimizable } = useLiveAgent();
|
|
1051
|
+
const elapsed = useElapsedSeconds(isConnected);
|
|
1052
|
+
return /* @__PURE__ */ jsxs4("header", {
|
|
1053
|
+
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",
|
|
1053
1054
|
children: [
|
|
1054
|
-
/* @__PURE__ */ jsx4("
|
|
1055
|
-
className: "skippr:
|
|
1056
|
-
children:
|
|
1057
|
-
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1058
|
-
})
|
|
1055
|
+
/* @__PURE__ */ jsx4("p", {
|
|
1056
|
+
className: "skippr:text-sm skippr:font-semibold skippr:text-primary-foreground",
|
|
1057
|
+
children: "Skippr"
|
|
1059
1058
|
}),
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
className: "skippr:flex-
|
|
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",
|
|
1059
|
+
/* @__PURE__ */ jsxs4("div", {
|
|
1060
|
+
className: "skippr:flex skippr:items-center skippr:gap-2",
|
|
1069
1061
|
children: [
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1062
|
+
isConnected && /* @__PURE__ */ jsxs4("div", {
|
|
1063
|
+
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",
|
|
1064
|
+
children: [
|
|
1065
|
+
/* @__PURE__ */ jsxs4("span", {
|
|
1066
|
+
className: "skippr:relative skippr:flex skippr:size-1.5",
|
|
1067
|
+
children: [
|
|
1068
|
+
/* @__PURE__ */ jsx4("span", {
|
|
1069
|
+
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"
|
|
1070
|
+
}),
|
|
1071
|
+
/* @__PURE__ */ jsx4("span", {
|
|
1072
|
+
className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-red-400"
|
|
1073
|
+
})
|
|
1074
|
+
]
|
|
1075
|
+
}),
|
|
1076
|
+
/* @__PURE__ */ jsx4("span", {
|
|
1077
|
+
className: "skippr:text-[10px] skippr:font-medium skippr:text-primary-foreground",
|
|
1078
|
+
children: "REC"
|
|
1079
|
+
}),
|
|
1080
|
+
/* @__PURE__ */ jsx4("span", {
|
|
1081
|
+
className: "skippr:text-[10px] skippr:font-mono skippr:text-primary-foreground",
|
|
1082
|
+
children: formatTime(elapsed)
|
|
1083
|
+
})
|
|
1084
|
+
]
|
|
1079
1085
|
}),
|
|
1080
|
-
/* @__PURE__ */ jsx4(
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
className: "skippr:size-4"
|
|
1086
|
+
minimizable && /* @__PURE__ */ jsx4("button", {
|
|
1087
|
+
type: "button",
|
|
1088
|
+
onClick: minimizePanel,
|
|
1089
|
+
"aria-label": "Minimize",
|
|
1090
|
+
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",
|
|
1091
|
+
children: /* @__PURE__ */ jsx4(Minimize2, {
|
|
1092
|
+
className: "skippr:size-3.5"
|
|
1088
1093
|
})
|
|
1089
1094
|
})
|
|
1090
1095
|
]
|
|
@@ -1093,30 +1098,89 @@ function ChatHeader({ onOpenSettings }) {
|
|
|
1093
1098
|
});
|
|
1094
1099
|
}
|
|
1095
1100
|
|
|
1101
|
+
// src/components/LoadingDots.tsx
|
|
1102
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1103
|
+
function LoadingDots({ label }) {
|
|
1104
|
+
return /* @__PURE__ */ jsxs5("div", {
|
|
1105
|
+
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:py-4",
|
|
1106
|
+
children: [
|
|
1107
|
+
/* @__PURE__ */ jsxs5("div", {
|
|
1108
|
+
className: "skippr:flex skippr:gap-1",
|
|
1109
|
+
children: [
|
|
1110
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1111
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:0ms]"
|
|
1112
|
+
}),
|
|
1113
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1114
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:150ms]"
|
|
1115
|
+
}),
|
|
1116
|
+
/* @__PURE__ */ jsx5("span", {
|
|
1117
|
+
className: "skippr:size-1.5 skippr:rounded-full skippr:bg-muted-foreground/40 skippr:animate-bounce skippr:[animation-delay:300ms]"
|
|
1118
|
+
})
|
|
1119
|
+
]
|
|
1120
|
+
}),
|
|
1121
|
+
/* @__PURE__ */ jsx5("p", {
|
|
1122
|
+
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1123
|
+
children: label
|
|
1124
|
+
})
|
|
1125
|
+
]
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// src/components/LoginFlow.tsx
|
|
1130
|
+
import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef3, useState as useState6 } from "react";
|
|
1131
|
+
|
|
1132
|
+
// src/components/ui/button.tsx
|
|
1133
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
1134
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1135
|
+
var variantClasses = {
|
|
1136
|
+
default: "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90",
|
|
1137
|
+
destructive: "skippr:bg-destructive skippr:text-white skippr:hover:bg-destructive/90",
|
|
1138
|
+
outline: "skippr:border skippr:border-input skippr:bg-background skippr:shadow-xs skippr:hover:bg-accent skippr:hover:text-accent-foreground",
|
|
1139
|
+
secondary: "skippr:bg-secondary skippr:text-secondary-foreground skippr:hover:bg-secondary/80",
|
|
1140
|
+
ghost: "skippr:hover:bg-accent skippr:hover:text-accent-foreground"
|
|
1141
|
+
};
|
|
1142
|
+
var sizeClasses = {
|
|
1143
|
+
default: "skippr:h-9 skippr:px-4 skippr:py-2",
|
|
1144
|
+
xs: "skippr:h-6 skippr:gap-1 skippr:rounded-md skippr:px-2 skippr:text-xs",
|
|
1145
|
+
sm: "skippr:h-8 skippr:gap-1.5 skippr:rounded-md skippr:px-3",
|
|
1146
|
+
lg: "skippr:h-10 skippr:rounded-md skippr:px-6",
|
|
1147
|
+
icon: "skippr:size-9",
|
|
1148
|
+
"icon-xs": "skippr:size-6",
|
|
1149
|
+
"icon-sm": "skippr:size-8",
|
|
1150
|
+
"icon-lg": "skippr:size-10"
|
|
1151
|
+
};
|
|
1152
|
+
var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
1153
|
+
return /* @__PURE__ */ jsx6("button", {
|
|
1154
|
+
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),
|
|
1155
|
+
ref,
|
|
1156
|
+
...props
|
|
1157
|
+
});
|
|
1158
|
+
});
|
|
1159
|
+
Button.displayName = "Button";
|
|
1160
|
+
|
|
1096
1161
|
// src/components/LoginFlow.tsx
|
|
1097
|
-
import {
|
|
1098
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1162
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1099
1163
|
var OTP_LENGTH = 6;
|
|
1100
1164
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
1101
1165
|
function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
1102
|
-
const [step, setStep] =
|
|
1103
|
-
const [email, setEmail] =
|
|
1104
|
-
const handleRequestOtp =
|
|
1166
|
+
const [step, setStep] = useState6("email");
|
|
1167
|
+
const [email, setEmail] = useState6("");
|
|
1168
|
+
const handleRequestOtp = useCallback5(async (emailValue) => {
|
|
1105
1169
|
const success = await requestOtp(emailValue);
|
|
1106
1170
|
if (success)
|
|
1107
1171
|
setStep("otp");
|
|
1108
1172
|
}, [requestOtp]);
|
|
1109
|
-
const handleVerifyOtp =
|
|
1173
|
+
const handleVerifyOtp = useCallback5(async (code) => {
|
|
1110
1174
|
await verifyOtp(email, code);
|
|
1111
1175
|
}, [verifyOtp, email]);
|
|
1112
|
-
const handleBack =
|
|
1176
|
+
const handleBack = useCallback5(() => {
|
|
1113
1177
|
setStep("email");
|
|
1114
1178
|
}, []);
|
|
1115
|
-
const handleResend =
|
|
1179
|
+
const handleResend = useCallback5(async () => {
|
|
1116
1180
|
await requestOtp(email);
|
|
1117
1181
|
}, [requestOtp, email]);
|
|
1118
1182
|
if (step === "otp") {
|
|
1119
|
-
return /* @__PURE__ */
|
|
1183
|
+
return /* @__PURE__ */ jsx7(OtpStep, {
|
|
1120
1184
|
email,
|
|
1121
1185
|
onSubmit: handleVerifyOtp,
|
|
1122
1186
|
onResend: handleResend,
|
|
@@ -1125,7 +1189,7 @@ function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
|
1125
1189
|
isSubmitting
|
|
1126
1190
|
});
|
|
1127
1191
|
}
|
|
1128
|
-
return /* @__PURE__ */
|
|
1192
|
+
return /* @__PURE__ */ jsx7(EmailStep, {
|
|
1129
1193
|
email,
|
|
1130
1194
|
onEmailChange: setEmail,
|
|
1131
1195
|
onSubmit: handleRequestOtp,
|
|
@@ -1139,30 +1203,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1139
1203
|
if (email.trim())
|
|
1140
1204
|
onSubmit(email.trim());
|
|
1141
1205
|
}
|
|
1142
|
-
return /* @__PURE__ */
|
|
1206
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
1143
1207
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
1144
1208
|
children: [
|
|
1145
|
-
/* @__PURE__ */
|
|
1209
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1146
1210
|
className: "skippr:mb-4 skippr:text-center",
|
|
1147
1211
|
children: [
|
|
1148
|
-
/* @__PURE__ */
|
|
1212
|
+
/* @__PURE__ */ jsx7(Mail, {
|
|
1149
1213
|
className: "skippr:mx-auto skippr:mb-2 skippr:size-6 skippr:text-primary"
|
|
1150
1214
|
}),
|
|
1151
|
-
/* @__PURE__ */
|
|
1215
|
+
/* @__PURE__ */ jsx7("p", {
|
|
1152
1216
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
1153
1217
|
children: "Sign in to continue"
|
|
1154
1218
|
}),
|
|
1155
|
-
/* @__PURE__ */
|
|
1219
|
+
/* @__PURE__ */ jsx7("p", {
|
|
1156
1220
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
1157
1221
|
children: "Your email will be used to identify you across sessions"
|
|
1158
1222
|
})
|
|
1159
1223
|
]
|
|
1160
1224
|
}),
|
|
1161
|
-
/* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsxs6("form", {
|
|
1162
1226
|
onSubmit: handleSubmit,
|
|
1163
1227
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
1164
1228
|
children: [
|
|
1165
|
-
/* @__PURE__ */
|
|
1229
|
+
/* @__PURE__ */ jsx7("input", {
|
|
1166
1230
|
type: "email",
|
|
1167
1231
|
placeholder: "you@example.com",
|
|
1168
1232
|
value: email,
|
|
@@ -1171,15 +1235,15 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1171
1235
|
required: true,
|
|
1172
1236
|
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
1237
|
}),
|
|
1174
|
-
/* @__PURE__ */
|
|
1238
|
+
/* @__PURE__ */ jsx7(Button, {
|
|
1175
1239
|
type: "submit",
|
|
1176
1240
|
disabled: isSubmitting || !email.trim(),
|
|
1177
1241
|
className: "skippr:w-full",
|
|
1178
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1242
|
+
children: isSubmitting ? /* @__PURE__ */ jsx7(LoaderCircle, {
|
|
1179
1243
|
className: "skippr:size-4 skippr:animate-spin"
|
|
1180
1244
|
}) : "Continue"
|
|
1181
1245
|
}),
|
|
1182
|
-
error && /* @__PURE__ */
|
|
1246
|
+
error && /* @__PURE__ */ jsx7("p", {
|
|
1183
1247
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
1184
1248
|
children: error
|
|
1185
1249
|
})
|
|
@@ -1189,30 +1253,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
1189
1253
|
});
|
|
1190
1254
|
}
|
|
1191
1255
|
function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
1192
|
-
const [digits, setDigits] =
|
|
1193
|
-
const [resendCooldown, setResendCooldown] =
|
|
1194
|
-
const inputRefs =
|
|
1195
|
-
const submittedRef =
|
|
1196
|
-
|
|
1256
|
+
const [digits, setDigits] = useState6(Array(OTP_LENGTH).fill(""));
|
|
1257
|
+
const [resendCooldown, setResendCooldown] = useState6(0);
|
|
1258
|
+
const inputRefs = useRef3([]);
|
|
1259
|
+
const submittedRef = useRef3(false);
|
|
1260
|
+
useEffect8(() => {
|
|
1197
1261
|
inputRefs.current[0]?.focus();
|
|
1198
1262
|
}, []);
|
|
1199
|
-
|
|
1263
|
+
useEffect8(() => {
|
|
1200
1264
|
if (error)
|
|
1201
1265
|
submittedRef.current = false;
|
|
1202
1266
|
}, [error]);
|
|
1203
|
-
|
|
1267
|
+
useEffect8(() => {
|
|
1204
1268
|
if (resendCooldown <= 0)
|
|
1205
1269
|
return;
|
|
1206
1270
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
1207
1271
|
return () => clearTimeout(timer);
|
|
1208
1272
|
}, [resendCooldown]);
|
|
1209
|
-
const submitCode =
|
|
1273
|
+
const submitCode = useCallback5((code) => {
|
|
1210
1274
|
if (submittedRef.current || isSubmitting)
|
|
1211
1275
|
return;
|
|
1212
1276
|
submittedRef.current = true;
|
|
1213
1277
|
onSubmit(code);
|
|
1214
1278
|
}, [onSubmit, isSubmitting]);
|
|
1215
|
-
const handleDigitChange =
|
|
1279
|
+
const handleDigitChange = useCallback5((index2, value) => {
|
|
1216
1280
|
const digit = value.replace(/\D/g, "").slice(-1);
|
|
1217
1281
|
const newDigits = [...digits];
|
|
1218
1282
|
newDigits[index2] = digit;
|
|
@@ -1226,12 +1290,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1226
1290
|
submitCode(code);
|
|
1227
1291
|
}
|
|
1228
1292
|
}, [digits, submitCode]);
|
|
1229
|
-
const handleKeyDown =
|
|
1293
|
+
const handleKeyDown = useCallback5((index2, e) => {
|
|
1230
1294
|
if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
|
|
1231
1295
|
inputRefs.current[index2 - 1]?.focus();
|
|
1232
1296
|
}
|
|
1233
1297
|
}, [digits]);
|
|
1234
|
-
const handlePaste =
|
|
1298
|
+
const handlePaste = useCallback5((e) => {
|
|
1235
1299
|
e.preventDefault();
|
|
1236
1300
|
const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
|
|
1237
1301
|
if (pasted.length > 0) {
|
|
@@ -1259,22 +1323,22 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1259
1323
|
submittedRef.current = false;
|
|
1260
1324
|
inputRefs.current[0]?.focus();
|
|
1261
1325
|
}
|
|
1262
|
-
return /* @__PURE__ */
|
|
1326
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
1263
1327
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
1264
1328
|
children: [
|
|
1265
|
-
/* @__PURE__ */
|
|
1329
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1266
1330
|
className: "skippr:mb-4 skippr:text-center",
|
|
1267
1331
|
children: [
|
|
1268
|
-
/* @__PURE__ */
|
|
1332
|
+
/* @__PURE__ */ jsx7("p", {
|
|
1269
1333
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
1270
1334
|
children: "Enter verification code"
|
|
1271
1335
|
}),
|
|
1272
|
-
/* @__PURE__ */
|
|
1336
|
+
/* @__PURE__ */ jsxs6("p", {
|
|
1273
1337
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
1274
1338
|
children: [
|
|
1275
1339
|
"We sent a 6-digit code to",
|
|
1276
1340
|
" ",
|
|
1277
|
-
/* @__PURE__ */
|
|
1341
|
+
/* @__PURE__ */ jsx7("span", {
|
|
1278
1342
|
className: "skippr:font-medium skippr:text-foreground",
|
|
1279
1343
|
children: email
|
|
1280
1344
|
})
|
|
@@ -1282,13 +1346,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1282
1346
|
})
|
|
1283
1347
|
]
|
|
1284
1348
|
}),
|
|
1285
|
-
/* @__PURE__ */
|
|
1349
|
+
/* @__PURE__ */ jsxs6("form", {
|
|
1286
1350
|
onSubmit: handleSubmit,
|
|
1287
1351
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
1288
1352
|
children: [
|
|
1289
|
-
/* @__PURE__ */
|
|
1353
|
+
/* @__PURE__ */ jsx7("div", {
|
|
1290
1354
|
className: "skippr:flex skippr:justify-center skippr:gap-1.5",
|
|
1291
|
-
children: digits.map((digit, index2) => /* @__PURE__ */
|
|
1355
|
+
children: digits.map((digit, index2) => /* @__PURE__ */ jsx7("input", {
|
|
1292
1356
|
ref: (el) => {
|
|
1293
1357
|
inputRefs.current[index2] = el;
|
|
1294
1358
|
},
|
|
@@ -1303,29 +1367,29 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1303
1367
|
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
1368
|
}, DIGIT_KEYS[index2]))
|
|
1305
1369
|
}),
|
|
1306
|
-
error && /* @__PURE__ */
|
|
1370
|
+
error && /* @__PURE__ */ jsx7("p", {
|
|
1307
1371
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
1308
1372
|
children: error
|
|
1309
1373
|
}),
|
|
1310
|
-
/* @__PURE__ */
|
|
1374
|
+
/* @__PURE__ */ jsx7(Button, {
|
|
1311
1375
|
type: "submit",
|
|
1312
1376
|
disabled: isSubmitting || digits.join("").length !== OTP_LENGTH,
|
|
1313
1377
|
className: "skippr:w-full",
|
|
1314
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1378
|
+
children: isSubmitting ? /* @__PURE__ */ jsx7(LoaderCircle, {
|
|
1315
1379
|
className: "skippr:size-4 skippr:animate-spin"
|
|
1316
1380
|
}) : "Verify"
|
|
1317
1381
|
}),
|
|
1318
|
-
/* @__PURE__ */
|
|
1382
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1319
1383
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:text-xs",
|
|
1320
1384
|
children: [
|
|
1321
|
-
/* @__PURE__ */
|
|
1385
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1322
1386
|
type: "button",
|
|
1323
1387
|
onClick: onBack,
|
|
1324
1388
|
disabled: isSubmitting,
|
|
1325
1389
|
className: "skippr:text-muted-foreground hover:skippr:text-foreground skippr:transition-colors disabled:skippr:opacity-50",
|
|
1326
1390
|
children: "Change email"
|
|
1327
1391
|
}),
|
|
1328
|
-
/* @__PURE__ */
|
|
1392
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1329
1393
|
type: "button",
|
|
1330
1394
|
onClick: handleResend,
|
|
1331
1395
|
disabled: isSubmitting || resendCooldown > 0,
|
|
@@ -1341,476 +1405,351 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
1341
1405
|
}
|
|
1342
1406
|
|
|
1343
1407
|
// 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";
|
|
1408
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1409
|
+
var CONTROL_BUTTON = "skippr:flex skippr:size-11 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-full skippr:transition-colors";
|
|
1374
1410
|
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", {
|
|
1411
|
+
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
1412
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1413
|
+
className: "skippr:shrink-0 skippr:border-t skippr:border-border skippr:bg-background skippr:px-4 skippr:py-4",
|
|
1415
1414
|
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",
|
|
1415
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1416
|
+
className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-3",
|
|
1421
1417
|
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
|
-
]
|
|
1418
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1419
|
+
type: "button",
|
|
1420
|
+
onClick: toggleMute,
|
|
1421
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
1422
|
+
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"),
|
|
1423
|
+
children: isMuted ? /* @__PURE__ */ jsx8(MicOff, {
|
|
1424
|
+
className: "skippr:size-5"
|
|
1425
|
+
}) : /* @__PURE__ */ jsx8(Mic, {
|
|
1426
|
+
className: "skippr:size-5"
|
|
1427
|
+
})
|
|
1454
1428
|
}),
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1429
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1430
|
+
type: "button",
|
|
1431
|
+
onClick: toggleScreenShare,
|
|
1432
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
1433
|
+
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"),
|
|
1434
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx8(MonitorOff, {
|
|
1435
|
+
className: "skippr:size-5"
|
|
1436
|
+
}) : /* @__PURE__ */ jsx8(Monitor, {
|
|
1437
|
+
className: "skippr:size-5"
|
|
1438
|
+
})
|
|
1458
1439
|
}),
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
children: /* @__PURE__ */ jsx7(PhoneOff, {
|
|
1467
|
-
className: "skippr:size-4"
|
|
1468
|
-
})
|
|
1440
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1441
|
+
type: "button",
|
|
1442
|
+
onClick: onHangUp,
|
|
1443
|
+
"aria-label": "End session",
|
|
1444
|
+
className: cn(CONTROL_BUTTON, "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90"),
|
|
1445
|
+
children: /* @__PURE__ */ jsx8(PhoneOff, {
|
|
1446
|
+
className: "skippr:size-5"
|
|
1469
1447
|
})
|
|
1470
1448
|
})
|
|
1471
1449
|
]
|
|
1450
|
+
}),
|
|
1451
|
+
/* @__PURE__ */ jsx8("p", {
|
|
1452
|
+
className: "skippr:mt-3 skippr:text-center skippr:text-[10px] skippr:text-muted-foreground",
|
|
1453
|
+
children: "Powered by Skippr"
|
|
1472
1454
|
})
|
|
1473
1455
|
]
|
|
1474
1456
|
});
|
|
1475
1457
|
}
|
|
1476
1458
|
|
|
1477
1459
|
// src/components/MessageList.tsx
|
|
1478
|
-
import { useEffect as
|
|
1460
|
+
import { useEffect as useEffect10, useRef as useRef5 } from "react";
|
|
1479
1461
|
|
|
1480
1462
|
// src/components/ChatInput.tsx
|
|
1481
|
-
import { useState as useState7 } from "react";
|
|
1482
|
-
import { jsx as
|
|
1483
|
-
|
|
1463
|
+
import { useEffect as useEffect9, useRef as useRef4, useState as useState7 } from "react";
|
|
1464
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1465
|
+
var MAX_INPUT_HEIGHT = 60;
|
|
1466
|
+
function ChatInput({ sendChatMessage, isSendingChat, autoFocus = false }) {
|
|
1484
1467
|
const [inputText, setInputText] = useState7("");
|
|
1468
|
+
const textareaRef = useRef4(null);
|
|
1485
1469
|
const canSend = inputText.trim().length > 0 && !isSendingChat;
|
|
1470
|
+
useEffect9(() => {
|
|
1471
|
+
if (autoFocus)
|
|
1472
|
+
textareaRef.current?.focus();
|
|
1473
|
+
}, [autoFocus]);
|
|
1474
|
+
function resizeTextarea() {
|
|
1475
|
+
const el = textareaRef.current;
|
|
1476
|
+
if (!el)
|
|
1477
|
+
return;
|
|
1478
|
+
el.style.height = "auto";
|
|
1479
|
+
el.style.height = `${Math.min(el.scrollHeight, MAX_INPUT_HEIGHT)}px`;
|
|
1480
|
+
}
|
|
1481
|
+
function handleChange(e) {
|
|
1482
|
+
setInputText(e.target.value);
|
|
1483
|
+
resizeTextarea();
|
|
1484
|
+
}
|
|
1486
1485
|
function handleSubmit(e) {
|
|
1487
1486
|
e.preventDefault();
|
|
1488
1487
|
const text = inputText.trim();
|
|
1489
1488
|
if (!text || isSendingChat)
|
|
1490
1489
|
return;
|
|
1491
1490
|
setInputText("");
|
|
1491
|
+
resizeTextarea();
|
|
1492
1492
|
sendChatMessage(text).catch(() => setInputText(text));
|
|
1493
|
+
textareaRef.current?.focus();
|
|
1493
1494
|
}
|
|
1494
|
-
|
|
1495
|
+
function handleKeyDown(e) {
|
|
1496
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1497
|
+
e.preventDefault();
|
|
1498
|
+
handleSubmit(e);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
return /* @__PURE__ */ jsx9("form", {
|
|
1495
1502
|
onSubmit: handleSubmit,
|
|
1496
|
-
className: "skippr:
|
|
1497
|
-
children:
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1503
|
+
className: "skippr:border-t skippr:border-border skippr:p-3",
|
|
1504
|
+
children: /* @__PURE__ */ jsxs8("div", {
|
|
1505
|
+
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",
|
|
1506
|
+
children: [
|
|
1507
|
+
/* @__PURE__ */ jsx9("textarea", {
|
|
1508
|
+
ref: textareaRef,
|
|
1509
|
+
rows: 1,
|
|
1510
|
+
value: inputText,
|
|
1511
|
+
onChange: handleChange,
|
|
1512
|
+
onKeyDown: handleKeyDown,
|
|
1513
|
+
placeholder: "Type a message...",
|
|
1514
|
+
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",
|
|
1515
|
+
style: { maxHeight: `${MAX_INPUT_HEIGHT}px` }
|
|
1516
|
+
}),
|
|
1517
|
+
/* @__PURE__ */ jsx9("button", {
|
|
1518
|
+
type: "submit",
|
|
1519
|
+
disabled: !canSend,
|
|
1520
|
+
"aria-label": "Send message",
|
|
1521
|
+
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"),
|
|
1522
|
+
children: /* @__PURE__ */ jsx9(Send, {
|
|
1523
|
+
className: "skippr:size-3.5"
|
|
1524
|
+
})
|
|
1513
1525
|
})
|
|
1514
|
-
|
|
1515
|
-
|
|
1526
|
+
]
|
|
1527
|
+
})
|
|
1516
1528
|
});
|
|
1517
1529
|
}
|
|
1518
1530
|
|
|
1519
1531
|
// src/components/ChatMessage.tsx
|
|
1520
|
-
import { jsx as
|
|
1532
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1533
|
+
function formatTimestamp(ts) {
|
|
1534
|
+
return new Date(ts).toLocaleTimeString("en-US", {
|
|
1535
|
+
hour: "numeric",
|
|
1536
|
+
minute: "2-digit",
|
|
1537
|
+
hour12: true
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1521
1540
|
function ChatMessage({ message }) {
|
|
1522
|
-
const
|
|
1523
|
-
return /* @__PURE__ */
|
|
1524
|
-
className: cn("skippr:flex skippr:
|
|
1525
|
-
children:
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1541
|
+
const isAgent = message.role === "assistant";
|
|
1542
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1543
|
+
className: cn("skippr:flex skippr:gap-2", isAgent ? "skippr:items-start" : "skippr:justify-end"),
|
|
1544
|
+
children: [
|
|
1545
|
+
isAgent && /* @__PURE__ */ jsx10("div", {
|
|
1546
|
+
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",
|
|
1547
|
+
children: /* @__PURE__ */ jsx10(Sparkles, {
|
|
1548
|
+
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1549
|
+
})
|
|
1550
|
+
}),
|
|
1551
|
+
/* @__PURE__ */ jsxs9("div", {
|
|
1552
|
+
className: cn("skippr:flex skippr:max-w-[80%] skippr:flex-col", isAgent ? "skippr:items-start" : "skippr:items-end"),
|
|
1553
|
+
children: [
|
|
1554
|
+
/* @__PURE__ */ jsx10("div", {
|
|
1555
|
+
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"),
|
|
1556
|
+
children: message.content
|
|
1557
|
+
}),
|
|
1558
|
+
message.timestamp && /* @__PURE__ */ jsx10("span", {
|
|
1559
|
+
className: "skippr:mt-1 skippr:px-1 skippr:text-[10px] skippr:text-muted-foreground/60",
|
|
1560
|
+
children: formatTimestamp(message.timestamp)
|
|
1561
|
+
})
|
|
1562
|
+
]
|
|
1563
|
+
})
|
|
1564
|
+
]
|
|
1529
1565
|
});
|
|
1530
1566
|
}
|
|
1531
1567
|
|
|
1532
1568
|
// src/components/TypingIndicator.tsx
|
|
1533
|
-
import { jsx as
|
|
1569
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1534
1570
|
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]"
|
|
1571
|
+
return /* @__PURE__ */ jsxs10("div", {
|
|
1572
|
+
className: "skippr:flex skippr:items-start skippr:gap-2 skippr:animate-skippr-tab-fade",
|
|
1573
|
+
children: [
|
|
1574
|
+
/* @__PURE__ */ jsx11("div", {
|
|
1575
|
+
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",
|
|
1576
|
+
children: /* @__PURE__ */ jsx11(Sparkles, {
|
|
1577
|
+
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
1548
1578
|
})
|
|
1549
|
-
|
|
1550
|
-
|
|
1579
|
+
}),
|
|
1580
|
+
/* @__PURE__ */ jsxs10("div", {
|
|
1581
|
+
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",
|
|
1582
|
+
children: [
|
|
1583
|
+
/* @__PURE__ */ jsx11("span", {
|
|
1584
|
+
children: "Agent is analyzing your screen"
|
|
1585
|
+
}),
|
|
1586
|
+
/* @__PURE__ */ jsxs10("span", {
|
|
1587
|
+
className: "skippr:inline-flex skippr:items-center skippr:gap-[2px]",
|
|
1588
|
+
children: [
|
|
1589
|
+
/* @__PURE__ */ jsx11("span", {
|
|
1590
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:0ms]"
|
|
1591
|
+
}),
|
|
1592
|
+
/* @__PURE__ */ jsx11("span", {
|
|
1593
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:200ms]"
|
|
1594
|
+
}),
|
|
1595
|
+
/* @__PURE__ */ jsx11("span", {
|
|
1596
|
+
className: "skippr:size-1 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-thinking-dot skippr:[animation-delay:400ms]"
|
|
1597
|
+
})
|
|
1598
|
+
]
|
|
1599
|
+
})
|
|
1600
|
+
]
|
|
1601
|
+
})
|
|
1602
|
+
]
|
|
1551
1603
|
});
|
|
1552
1604
|
}
|
|
1553
1605
|
|
|
1554
1606
|
// src/components/MessageList.tsx
|
|
1555
|
-
import { jsx as
|
|
1607
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1556
1608
|
function MessageList({
|
|
1557
1609
|
messages,
|
|
1558
1610
|
isStreaming,
|
|
1559
1611
|
sendChatMessage,
|
|
1560
|
-
isSendingChat
|
|
1612
|
+
isSendingChat,
|
|
1613
|
+
autoFocus = false
|
|
1561
1614
|
}) {
|
|
1562
|
-
const scrollRef =
|
|
1615
|
+
const scrollRef = useRef5(null);
|
|
1563
1616
|
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
1564
|
-
|
|
1617
|
+
useEffect10(() => {
|
|
1565
1618
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1566
1619
|
}, [messages.length, lastMessage?.content]);
|
|
1567
1620
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
1568
|
-
return /* @__PURE__ */
|
|
1621
|
+
return /* @__PURE__ */ jsxs11("div", {
|
|
1569
1622
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1570
1623
|
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,
|
|
1624
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1625
|
+
className: "skippr:min-h-0 skippr:flex-1 skippr:space-y-4 skippr:overflow-y-auto skippr:p-4",
|
|
1638
1626
|
children: [
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
}) : /* @__PURE__ */ jsx12(MessageCircleQuestionMark, {
|
|
1642
|
-
className: "skippr:size-4 skippr:text-primary"
|
|
1627
|
+
messages.length === 0 && !showTyping && /* @__PURE__ */ jsx12(LoadingDots, {
|
|
1628
|
+
label: "Waiting for conversation to begin..."
|
|
1643
1629
|
}),
|
|
1644
|
-
|
|
1630
|
+
messages.map((message) => /* @__PURE__ */ jsx12(ChatMessage, {
|
|
1631
|
+
message
|
|
1632
|
+
}, message.id)),
|
|
1633
|
+
showTyping && /* @__PURE__ */ jsx12(TypingIndicator, {}),
|
|
1634
|
+
/* @__PURE__ */ jsx12("div", {
|
|
1635
|
+
ref: scrollRef
|
|
1636
|
+
})
|
|
1645
1637
|
]
|
|
1646
1638
|
}),
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1639
|
+
/* @__PURE__ */ jsx12(ChatInput, {
|
|
1640
|
+
sendChatMessage,
|
|
1641
|
+
isSendingChat,
|
|
1642
|
+
autoFocus
|
|
1650
1643
|
})
|
|
1651
1644
|
]
|
|
1652
1645
|
});
|
|
1653
1646
|
}
|
|
1654
1647
|
|
|
1655
1648
|
// src/components/SessionAgenda.tsx
|
|
1656
|
-
import { jsx as jsx13, jsxs as
|
|
1657
|
-
function SessionAgenda({ phases
|
|
1649
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1650
|
+
function SessionAgenda({ phases }) {
|
|
1658
1651
|
if (phases.length === 0) {
|
|
1659
|
-
return /* @__PURE__ */ jsxs10("div", {
|
|
1660
|
-
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1661
|
-
children: [
|
|
1662
|
-
/* @__PURE__ */ jsx13("h3", {
|
|
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
1652
|
return /* @__PURE__ */ jsx13("div", {
|
|
1720
|
-
className: "skippr:flex skippr:
|
|
1721
|
-
children: /* @__PURE__ */ jsx13(
|
|
1722
|
-
|
|
1723
|
-
strokeWidth: 3
|
|
1653
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1654
|
+
children: /* @__PURE__ */ jsx13(LoadingDots, {
|
|
1655
|
+
label: "Waiting for agenda to load..."
|
|
1724
1656
|
})
|
|
1725
1657
|
});
|
|
1726
1658
|
}
|
|
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",
|
|
1659
|
+
return /* @__PURE__ */ jsx13("div", {
|
|
1660
|
+
className: "skippr:flex-1 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
|
|
1661
|
+
children: /* @__PURE__ */ jsx13("div", {
|
|
1662
|
+
className: "skippr:space-y-1",
|
|
1663
|
+
children: phases.map((phase) => {
|
|
1664
|
+
const isActive = phase.status === "active";
|
|
1665
|
+
const isCompleted = phase.status === "completed";
|
|
1666
|
+
return /* @__PURE__ */ jsxs12("div", {
|
|
1667
|
+
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
1668
|
children: [
|
|
1767
|
-
/* @__PURE__ */
|
|
1768
|
-
className: "skippr:
|
|
1769
|
-
children:
|
|
1669
|
+
/* @__PURE__ */ jsx13("div", {
|
|
1670
|
+
className: "skippr:mt-0.5",
|
|
1671
|
+
children: isCompleted ? /* @__PURE__ */ jsx13(CircleCheck, {
|
|
1672
|
+
className: "skippr:size-4 skippr:text-chart-3"
|
|
1673
|
+
}) : isActive ? /* @__PURE__ */ jsx13(Circle, {
|
|
1674
|
+
className: "skippr:size-4 skippr:fill-primary/30 skippr:text-primary"
|
|
1675
|
+
}) : /* @__PURE__ */ jsx13(Circle, {
|
|
1676
|
+
className: "skippr:size-4 skippr:text-muted-foreground/30"
|
|
1677
|
+
})
|
|
1770
1678
|
}),
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
className: "skippr:
|
|
1679
|
+
/* @__PURE__ */ jsxs12("div", {
|
|
1680
|
+
className: "skippr:min-w-0 skippr:flex-1",
|
|
1773
1681
|
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
|
-
]
|
|
1682
|
+
/* @__PURE__ */ jsx13("p", {
|
|
1683
|
+
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"),
|
|
1684
|
+
children: phase.name
|
|
1787
1685
|
}),
|
|
1788
|
-
/* @__PURE__ */
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
})
|
|
1800
|
-
]
|
|
1686
|
+
phase.highlights.length > 0 && /* @__PURE__ */ jsx13("ul", {
|
|
1687
|
+
className: "skippr:mt-1 skippr:space-y-0.5",
|
|
1688
|
+
children: phase.highlights.map((text) => /* @__PURE__ */ jsxs12("li", {
|
|
1689
|
+
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"),
|
|
1690
|
+
children: [
|
|
1691
|
+
/* @__PURE__ */ jsx13("span", {
|
|
1692
|
+
className: "skippr:size-1 skippr:shrink-0 skippr:rounded-full skippr:bg-current"
|
|
1693
|
+
}),
|
|
1694
|
+
text
|
|
1695
|
+
]
|
|
1696
|
+
}, text))
|
|
1801
1697
|
})
|
|
1802
1698
|
]
|
|
1803
1699
|
})
|
|
1804
1700
|
]
|
|
1805
|
-
})
|
|
1701
|
+
}, phase.name);
|
|
1702
|
+
})
|
|
1703
|
+
})
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// src/components/SessionWarningBanner.tsx
|
|
1708
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1709
|
+
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
1710
|
+
function SessionWarningBanner({ remaining }) {
|
|
1711
|
+
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
1712
|
+
return null;
|
|
1713
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1714
|
+
"data-testid": "session-warning-banner",
|
|
1715
|
+
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",
|
|
1716
|
+
children: "Session ending soon"
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// src/components/StartSessionPrompt.tsx
|
|
1721
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1722
|
+
function StartSessionPrompt({
|
|
1723
|
+
onStartSession,
|
|
1724
|
+
isStarting,
|
|
1725
|
+
error,
|
|
1726
|
+
label = "Talk to Skippr"
|
|
1727
|
+
}) {
|
|
1728
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
1729
|
+
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:justify-center skippr:gap-3 skippr:px-4",
|
|
1730
|
+
children: [
|
|
1731
|
+
/* @__PURE__ */ jsx15("button", {
|
|
1732
|
+
type: "button",
|
|
1733
|
+
onClick: onStartSession,
|
|
1734
|
+
disabled: isStarting,
|
|
1735
|
+
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",
|
|
1736
|
+
children: isStarting ? "Starting..." : label
|
|
1737
|
+
}),
|
|
1738
|
+
error && /* @__PURE__ */ jsx15("p", {
|
|
1739
|
+
className: "skippr:text-xs skippr:text-destructive",
|
|
1740
|
+
children: error
|
|
1806
1741
|
})
|
|
1807
1742
|
]
|
|
1808
1743
|
});
|
|
1809
1744
|
}
|
|
1810
1745
|
|
|
1811
1746
|
// src/components/Sidebar.tsx
|
|
1812
|
-
import { jsx as
|
|
1813
|
-
function Sidebar(
|
|
1747
|
+
import { jsx as jsx16, jsxs as jsxs14, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
1748
|
+
function Sidebar({
|
|
1749
|
+
hideControls = false,
|
|
1750
|
+
hideHeader = false,
|
|
1751
|
+
startSessionLabel = "Talk to Skippr"
|
|
1752
|
+
}) {
|
|
1814
1753
|
const {
|
|
1815
1754
|
variant,
|
|
1816
1755
|
isConnected,
|
|
@@ -1825,12 +1764,14 @@ function Sidebar() {
|
|
|
1825
1764
|
authError,
|
|
1826
1765
|
requestOtp,
|
|
1827
1766
|
verifyOtp,
|
|
1828
|
-
isAuthSubmitting
|
|
1767
|
+
isAuthSubmitting,
|
|
1768
|
+
sidebarTab: activeTab,
|
|
1769
|
+
setSidebarTab: setActiveTab,
|
|
1770
|
+
autoFocusChat
|
|
1829
1771
|
} = useLiveAgent();
|
|
1830
|
-
const [view, setView] = useState8("main");
|
|
1831
1772
|
const isFloating = variant === "floating";
|
|
1832
1773
|
const isSidebar = variant === "sidebar";
|
|
1833
|
-
|
|
1774
|
+
useEffect11(() => {
|
|
1834
1775
|
if (!isSidebar)
|
|
1835
1776
|
return;
|
|
1836
1777
|
const prop = position === "right" ? "marginRight" : "marginLeft";
|
|
@@ -1844,105 +1785,162 @@ function Sidebar() {
|
|
|
1844
1785
|
document.body.style.transition = "";
|
|
1845
1786
|
};
|
|
1846
1787
|
}, [isSidebar, isPanelOpen, position]);
|
|
1847
|
-
return /* @__PURE__ */
|
|
1848
|
-
className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-
|
|
1788
|
+
return /* @__PURE__ */ jsxs14("div", {
|
|
1789
|
+
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
1790
|
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
|
|
1791
|
+
children: [
|
|
1792
|
+
!hideHeader && /* @__PURE__ */ jsx16(ChatHeader, {}),
|
|
1793
|
+
!isAuthenticated && isValidating ? /* @__PURE__ */ jsx16("div", {
|
|
1794
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1795
|
+
children: /* @__PURE__ */ jsx16(LoadingDots, {
|
|
1796
|
+
label: "Loading..."
|
|
1874
1797
|
})
|
|
1875
|
-
|
|
1876
|
-
|
|
1798
|
+
}) : !isAuthenticated ? /* @__PURE__ */ jsx16(LoginFlow, {
|
|
1799
|
+
requestOtp,
|
|
1800
|
+
verifyOtp,
|
|
1801
|
+
error: authError,
|
|
1802
|
+
isSubmitting: isAuthSubmitting
|
|
1803
|
+
}) : /* @__PURE__ */ jsx16(AuthenticatedContent, {
|
|
1804
|
+
isConnected,
|
|
1805
|
+
onStartSession: startSession,
|
|
1806
|
+
onDisconnect: disconnect,
|
|
1807
|
+
isStarting,
|
|
1808
|
+
error,
|
|
1809
|
+
activeTab,
|
|
1810
|
+
onTabChange: setActiveTab,
|
|
1811
|
+
hideControls,
|
|
1812
|
+
startSessionLabel,
|
|
1813
|
+
autoFocusChat
|
|
1814
|
+
})
|
|
1815
|
+
]
|
|
1877
1816
|
});
|
|
1878
1817
|
}
|
|
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, {
|
|
1818
|
+
function AuthenticatedContent({
|
|
1819
|
+
isConnected,
|
|
1820
|
+
onStartSession,
|
|
1821
|
+
onDisconnect,
|
|
1822
|
+
isStarting,
|
|
1823
|
+
error,
|
|
1824
|
+
activeTab,
|
|
1825
|
+
onTabChange,
|
|
1826
|
+
hideControls,
|
|
1827
|
+
startSessionLabel,
|
|
1828
|
+
autoFocusChat
|
|
1829
|
+
}) {
|
|
1830
|
+
return /* @__PURE__ */ jsxs14(Fragment2, {
|
|
1896
1831
|
children: [
|
|
1897
|
-
/* @__PURE__ */
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
/* @__PURE__ */ jsxs12("div", {
|
|
1901
|
-
className: "skippr:flex skippr:min-h-0 skippr:flex-1",
|
|
1832
|
+
isConnected && /* @__PURE__ */ jsx16(ConnectedBanner, {}),
|
|
1833
|
+
/* @__PURE__ */ jsxs14("div", {
|
|
1834
|
+
className: "skippr:flex skippr:gap-2 skippr:border-b skippr:border-border skippr:px-3 skippr:py-2",
|
|
1902
1835
|
children: [
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1836
|
+
/* @__PURE__ */ jsxs14("button", {
|
|
1837
|
+
type: "button",
|
|
1838
|
+
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"),
|
|
1839
|
+
onClick: () => onTabChange("chat"),
|
|
1840
|
+
children: [
|
|
1841
|
+
/* @__PURE__ */ jsx16(MessageCircle, {
|
|
1842
|
+
className: "skippr:size-3.5"
|
|
1843
|
+
}),
|
|
1844
|
+
"Chat",
|
|
1845
|
+
activeTab === "chat" && /* @__PURE__ */ jsx16("span", {
|
|
1846
|
+
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
1847
|
+
})
|
|
1848
|
+
]
|
|
1909
1849
|
}),
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1850
|
+
/* @__PURE__ */ jsxs14("button", {
|
|
1851
|
+
type: "button",
|
|
1852
|
+
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"),
|
|
1853
|
+
onClick: () => onTabChange("agenda"),
|
|
1854
|
+
children: [
|
|
1855
|
+
/* @__PURE__ */ jsx16(Calendar, {
|
|
1856
|
+
className: "skippr:size-3.5"
|
|
1857
|
+
}),
|
|
1858
|
+
"Agenda",
|
|
1859
|
+
activeTab === "agenda" && /* @__PURE__ */ jsx16("span", {
|
|
1860
|
+
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
1861
|
+
})
|
|
1862
|
+
]
|
|
1918
1863
|
})
|
|
1919
1864
|
]
|
|
1865
|
+
}),
|
|
1866
|
+
/* @__PURE__ */ jsx16("div", {
|
|
1867
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1868
|
+
children: isConnected ? /* @__PURE__ */ jsx16(ConnectedBody, {
|
|
1869
|
+
activeTab,
|
|
1870
|
+
autoFocusChat
|
|
1871
|
+
}) : /* @__PURE__ */ jsx16("div", {
|
|
1872
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
1873
|
+
children: /* @__PURE__ */ jsx16(StartSessionPrompt, {
|
|
1874
|
+
onStartSession,
|
|
1875
|
+
isStarting,
|
|
1876
|
+
error,
|
|
1877
|
+
label: startSessionLabel
|
|
1878
|
+
})
|
|
1879
|
+
}, `${activeTab}-empty`)
|
|
1880
|
+
}),
|
|
1881
|
+
isConnected && !hideControls && /* @__PURE__ */ jsx16(MeetingControls, {
|
|
1882
|
+
onHangUp: onDisconnect
|
|
1920
1883
|
})
|
|
1921
1884
|
]
|
|
1922
1885
|
});
|
|
1923
1886
|
}
|
|
1887
|
+
function ConnectedBanner() {
|
|
1888
|
+
const remaining = useSessionRemaining();
|
|
1889
|
+
return /* @__PURE__ */ jsx16(SessionWarningBanner, {
|
|
1890
|
+
remaining
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
function ConnectedBody({
|
|
1894
|
+
activeTab,
|
|
1895
|
+
autoFocusChat
|
|
1896
|
+
}) {
|
|
1897
|
+
const { allMessages, agentState, sendChatMessage, isSendingChat } = useCombinedMessages();
|
|
1898
|
+
const { phases } = usePhaseUpdates();
|
|
1899
|
+
if (activeTab === "agenda") {
|
|
1900
|
+
return /* @__PURE__ */ jsx16("div", {
|
|
1901
|
+
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto skippr:animate-skippr-tab-fade",
|
|
1902
|
+
children: /* @__PURE__ */ jsx16(SessionAgenda, {
|
|
1903
|
+
phases
|
|
1904
|
+
})
|
|
1905
|
+
}, "agenda");
|
|
1906
|
+
}
|
|
1907
|
+
return /* @__PURE__ */ jsx16("div", {
|
|
1908
|
+
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
1909
|
+
children: /* @__PURE__ */ jsx16(MessageList, {
|
|
1910
|
+
messages: allMessages,
|
|
1911
|
+
isStreaming: agentState === "speaking",
|
|
1912
|
+
sendChatMessage,
|
|
1913
|
+
isSendingChat,
|
|
1914
|
+
autoFocus: autoFocusChat
|
|
1915
|
+
})
|
|
1916
|
+
}, "chat");
|
|
1917
|
+
}
|
|
1924
1918
|
|
|
1925
1919
|
// src/components/SidebarTrigger.tsx
|
|
1926
|
-
import { jsx as
|
|
1920
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1927
1921
|
function SidebarTrigger() {
|
|
1928
|
-
const { isPanelOpen, togglePanel, position, isMinimized } = useLiveAgent();
|
|
1922
|
+
const { isPanelOpen, togglePanel, minimizePanel, minimizable, position, isMinimized } = useLiveAgent();
|
|
1929
1923
|
if (isMinimized)
|
|
1930
1924
|
return null;
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
title: isPanelOpen ? "Close chat" : "
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
className: "skippr:size-
|
|
1925
|
+
const handleClick = isPanelOpen && minimizable ? minimizePanel : togglePanel;
|
|
1926
|
+
return /* @__PURE__ */ jsx17("button", {
|
|
1927
|
+
type: "button",
|
|
1928
|
+
onClick: handleClick,
|
|
1929
|
+
title: isPanelOpen ? "Close chat" : "Open chat",
|
|
1930
|
+
"aria-label": isPanelOpen ? "Close chat" : "Open chat",
|
|
1931
|
+
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"),
|
|
1932
|
+
children: isPanelOpen ? /* @__PURE__ */ jsx17(ChevronDown, {
|
|
1933
|
+
className: "skippr:size-5"
|
|
1934
|
+
}) : /* @__PURE__ */ jsx17("img", {
|
|
1935
|
+
src: LOGO_URL,
|
|
1936
|
+
alt: "Skippr",
|
|
1937
|
+
className: "skippr:size-7"
|
|
1940
1938
|
})
|
|
1941
1939
|
});
|
|
1942
1940
|
}
|
|
1943
1941
|
|
|
1944
1942
|
// src/components/LiveAgent.tsx
|
|
1945
|
-
import { jsx as
|
|
1943
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1946
1944
|
function LiveAgent({
|
|
1947
1945
|
agentId,
|
|
1948
1946
|
authToken: authTokenProp,
|
|
@@ -1953,21 +1951,36 @@ function LiveAgent({
|
|
|
1953
1951
|
minimizable = true,
|
|
1954
1952
|
defaultOpen = false,
|
|
1955
1953
|
welcomeMessage,
|
|
1954
|
+
hideControls = false,
|
|
1955
|
+
hideHeader = false,
|
|
1956
|
+
startSessionLabel = "Talk to Skippr",
|
|
1957
|
+
autoFocusChat = true,
|
|
1958
|
+
showObservingBanner = true,
|
|
1956
1959
|
children
|
|
1957
1960
|
}) {
|
|
1958
1961
|
const auth = useAuth({ appKey });
|
|
1959
1962
|
const effectiveAuthToken = authTokenProp || auth.authToken || undefined;
|
|
1960
|
-
const {
|
|
1963
|
+
const {
|
|
1964
|
+
connection,
|
|
1965
|
+
shouldConnect,
|
|
1966
|
+
isStarting,
|
|
1967
|
+
error,
|
|
1968
|
+
errorCode,
|
|
1969
|
+
startSession,
|
|
1970
|
+
disconnect,
|
|
1971
|
+
pendingScreenStream
|
|
1972
|
+
} = useSession({
|
|
1961
1973
|
agentId,
|
|
1962
1974
|
authToken: effectiveAuthToken,
|
|
1963
1975
|
appKey,
|
|
1964
1976
|
userToken
|
|
1965
1977
|
});
|
|
1966
|
-
const [isPanelOpen, setIsPanelOpen] =
|
|
1967
|
-
const [isMinimized, setIsMinimized] =
|
|
1968
|
-
const [
|
|
1969
|
-
const
|
|
1970
|
-
const
|
|
1978
|
+
const [isPanelOpen, setIsPanelOpen] = useState8(defaultOpen);
|
|
1979
|
+
const [isMinimized, setIsMinimized] = useState8(minimizable && !defaultOpen);
|
|
1980
|
+
const [sidebarTab, setSidebarTab] = useState8("agenda");
|
|
1981
|
+
const [welcomeDismissed, setWelcomeDismissed] = useState8(false);
|
|
1982
|
+
const dismissWelcome = useCallback6(() => setWelcomeDismissed(true), []);
|
|
1983
|
+
const [currentPosition, setCurrentPosition] = useState8(() => {
|
|
1971
1984
|
try {
|
|
1972
1985
|
const saved = localStorage.getItem("skippr_widget_position");
|
|
1973
1986
|
if (saved === "left" || saved === "right")
|
|
@@ -1975,20 +1988,20 @@ function LiveAgent({
|
|
|
1975
1988
|
} catch {}
|
|
1976
1989
|
return position;
|
|
1977
1990
|
});
|
|
1978
|
-
const setPositionWithPersist =
|
|
1991
|
+
const setPositionWithPersist = useCallback6((pos) => {
|
|
1979
1992
|
setCurrentPosition(pos);
|
|
1980
1993
|
try {
|
|
1981
1994
|
localStorage.setItem("skippr_widget_position", pos);
|
|
1982
1995
|
} catch {}
|
|
1983
1996
|
}, []);
|
|
1984
|
-
const openPanel =
|
|
1985
|
-
const closePanel =
|
|
1986
|
-
const togglePanel =
|
|
1987
|
-
const expandPanel =
|
|
1997
|
+
const openPanel = useCallback6(() => setIsPanelOpen(true), []);
|
|
1998
|
+
const closePanel = useCallback6(() => setIsPanelOpen(false), []);
|
|
1999
|
+
const togglePanel = useCallback6(() => setIsPanelOpen((prev) => !prev), []);
|
|
2000
|
+
const expandPanel = useCallback6(() => {
|
|
1988
2001
|
setIsMinimized(false);
|
|
1989
2002
|
setIsPanelOpen(true);
|
|
1990
2003
|
}, []);
|
|
1991
|
-
const minimizePanel =
|
|
2004
|
+
const minimizePanel = useCallback6(() => {
|
|
1992
2005
|
if (!minimizable)
|
|
1993
2006
|
return;
|
|
1994
2007
|
setIsMinimized(true);
|
|
@@ -1996,8 +2009,8 @@ function LiveAgent({
|
|
|
1996
2009
|
}, [minimizable]);
|
|
1997
2010
|
const isConnected = connection !== null;
|
|
1998
2011
|
const isAuthenticated = !!userToken || !!authTokenProp || auth.isAuthenticated;
|
|
1999
|
-
const prevConnectionRef =
|
|
2000
|
-
|
|
2012
|
+
const prevConnectionRef = useRef6(connection);
|
|
2013
|
+
useEffect12(() => {
|
|
2001
2014
|
const connectionChanged = prevConnectionRef.current !== connection;
|
|
2002
2015
|
prevConnectionRef.current = connection;
|
|
2003
2016
|
if (connectionChanged && minimizable) {
|
|
@@ -2031,7 +2044,10 @@ function LiveAgent({
|
|
|
2031
2044
|
requestOtp: auth.requestOtp,
|
|
2032
2045
|
verifyOtp: auth.verifyOtp,
|
|
2033
2046
|
logoutAuth: auth.logout,
|
|
2034
|
-
isAuthSubmitting: auth.isSubmitting
|
|
2047
|
+
isAuthSubmitting: auth.isSubmitting,
|
|
2048
|
+
sidebarTab,
|
|
2049
|
+
setSidebarTab,
|
|
2050
|
+
autoFocusChat
|
|
2035
2051
|
}), [
|
|
2036
2052
|
connection,
|
|
2037
2053
|
shouldConnect,
|
|
@@ -2058,31 +2074,54 @@ function LiveAgent({
|
|
|
2058
2074
|
auth.requestOtp,
|
|
2059
2075
|
auth.verifyOtp,
|
|
2060
2076
|
auth.logout,
|
|
2061
|
-
auth.isSubmitting
|
|
2077
|
+
auth.isSubmitting,
|
|
2078
|
+
sidebarTab,
|
|
2079
|
+
autoFocusChat
|
|
2062
2080
|
]);
|
|
2063
|
-
return /* @__PURE__ */
|
|
2081
|
+
return /* @__PURE__ */ jsx18(LiveAgentContext.Provider, {
|
|
2064
2082
|
value: ctx,
|
|
2065
|
-
children: /* @__PURE__ */
|
|
2083
|
+
children: /* @__PURE__ */ jsxs15(LiveKitRoom, {
|
|
2066
2084
|
serverUrl: connection?.livekitUrl,
|
|
2067
2085
|
token: connection?.token,
|
|
2068
2086
|
connect: shouldConnect,
|
|
2069
2087
|
audio: true,
|
|
2070
2088
|
onDisconnected: disconnect,
|
|
2071
2089
|
children: [
|
|
2072
|
-
connection && /* @__PURE__ */
|
|
2073
|
-
|
|
2090
|
+
connection && /* @__PURE__ */ jsx18(RoomAudioRenderer, {}),
|
|
2091
|
+
showObservingBanner && /* @__PURE__ */ jsx18(ObservingBanner, {}),
|
|
2092
|
+
connection && /* @__PURE__ */ jsx18(AutoStartMedia, {
|
|
2093
|
+
pendingScreenStream
|
|
2094
|
+
}),
|
|
2095
|
+
isMinimized && /* @__PURE__ */ jsx18(MinimizedBubble, {
|
|
2074
2096
|
welcomeMessage,
|
|
2075
2097
|
welcomeDismissed,
|
|
2076
2098
|
onDismissWelcome: dismissWelcome
|
|
2077
2099
|
}),
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2100
|
+
/* @__PURE__ */ jsx18(SidebarTrigger, {}),
|
|
2101
|
+
/* @__PURE__ */ jsx18(Sidebar, {
|
|
2102
|
+
hideControls,
|
|
2103
|
+
hideHeader,
|
|
2104
|
+
startSessionLabel
|
|
2105
|
+
}),
|
|
2080
2106
|
children
|
|
2081
2107
|
]
|
|
2082
2108
|
})
|
|
2083
2109
|
});
|
|
2084
2110
|
}
|
|
2111
|
+
// src/hooks/useIsLocalSpeaking.ts
|
|
2112
|
+
import { useIsSpeaking, useLocalParticipant as useLocalParticipant5 } from "@livekit/components-react";
|
|
2113
|
+
function useIsLocalSpeaking() {
|
|
2114
|
+
const { localParticipant } = useLocalParticipant5();
|
|
2115
|
+
return useIsSpeaking(localParticipant);
|
|
2116
|
+
}
|
|
2085
2117
|
export {
|
|
2118
|
+
useMediaControls,
|
|
2086
2119
|
useLiveAgent,
|
|
2120
|
+
useIsLocalSpeaking,
|
|
2121
|
+
useElapsedSeconds,
|
|
2122
|
+
useAgentVoiceState,
|
|
2123
|
+
parseNumber,
|
|
2124
|
+
formatTime,
|
|
2125
|
+
SCREEN_SHARE_OPTIONS,
|
|
2087
2126
|
LiveAgent
|
|
2088
2127
|
};
|