glitchgrab 1.22.0 → 1.23.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/dist/index.d.mts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +1097 -282
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1102 -283
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -319,7 +319,7 @@ async function sendReport(payload, baseUrl) {
|
|
|
319
319
|
return null;
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
|
-
async function enhanceText(text, token, baseUrl) {
|
|
322
|
+
async function enhanceText(text, token, baseUrl, screenshot, context) {
|
|
323
323
|
var _a;
|
|
324
324
|
try {
|
|
325
325
|
const trimmed = text.trim();
|
|
@@ -331,7 +331,11 @@ async function enhanceText(text, token, baseUrl) {
|
|
|
331
331
|
"Content-Type": "application/json",
|
|
332
332
|
Authorization: `Bearer ${token}`
|
|
333
333
|
},
|
|
334
|
-
body: JSON.stringify({
|
|
334
|
+
body: JSON.stringify({
|
|
335
|
+
text: trimmed,
|
|
336
|
+
...screenshot ? { screenshot } : {},
|
|
337
|
+
...context ? { context } : {}
|
|
338
|
+
})
|
|
335
339
|
});
|
|
336
340
|
if (!response.ok) return text;
|
|
337
341
|
const envelope = await response.json();
|
|
@@ -343,6 +347,28 @@ async function enhanceText(text, token, baseUrl) {
|
|
|
343
347
|
return text;
|
|
344
348
|
}
|
|
345
349
|
}
|
|
350
|
+
async function transcribeAudio(blob, token, baseUrl) {
|
|
351
|
+
var _a;
|
|
352
|
+
try {
|
|
353
|
+
if (blob.size === 0) return "";
|
|
354
|
+
const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/sdk/stt`;
|
|
355
|
+
const form = new FormData();
|
|
356
|
+
form.append("file", blob, "audio.webm");
|
|
357
|
+
const response = await fetch(url, {
|
|
358
|
+
method: "POST",
|
|
359
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
360
|
+
body: form
|
|
361
|
+
});
|
|
362
|
+
if (!response.ok) return "";
|
|
363
|
+
const envelope = await response.json();
|
|
364
|
+
if ((envelope == null ? void 0 : envelope.success) && typeof ((_a = envelope.data) == null ? void 0 : _a.transcript) === "string") {
|
|
365
|
+
return envelope.data.transcript;
|
|
366
|
+
}
|
|
367
|
+
return "";
|
|
368
|
+
} catch (e) {
|
|
369
|
+
return "";
|
|
370
|
+
}
|
|
371
|
+
}
|
|
346
372
|
|
|
347
373
|
// src/dedup.ts
|
|
348
374
|
var DEFAULT_WINDOW_MS = 5 * 60 * 1e3;
|
|
@@ -481,11 +507,17 @@ function useIsDark() {
|
|
|
481
507
|
try {
|
|
482
508
|
for (const el of [document.body, document.documentElement]) {
|
|
483
509
|
const bg = getComputedStyle(el).backgroundColor;
|
|
484
|
-
const match = bg.match(
|
|
510
|
+
const match = bg.match(
|
|
511
|
+
/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/
|
|
512
|
+
);
|
|
485
513
|
if (match) {
|
|
486
514
|
const alpha = match[4] !== void 0 ? parseFloat(match[4]) : 1;
|
|
487
515
|
if (alpha < 0.05) continue;
|
|
488
|
-
const [r, g, b] = [
|
|
516
|
+
const [r, g, b] = [
|
|
517
|
+
Number(match[1]),
|
|
518
|
+
Number(match[2]),
|
|
519
|
+
Number(match[3])
|
|
520
|
+
];
|
|
489
521
|
return (r * 299 + g * 587 + b * 114) / 1e3 < 128;
|
|
490
522
|
}
|
|
491
523
|
}
|
|
@@ -511,14 +543,26 @@ function parseColorToRgb(value) {
|
|
|
511
543
|
const hexMatch = trimmed.match(/^#([0-9a-f]{3,8})$/i);
|
|
512
544
|
if (hexMatch) {
|
|
513
545
|
let hex = hexMatch[1];
|
|
514
|
-
if (hex.length === 3)
|
|
515
|
-
|
|
546
|
+
if (hex.length === 3)
|
|
547
|
+
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
548
|
+
return [
|
|
549
|
+
parseInt(hex.slice(0, 2), 16),
|
|
550
|
+
parseInt(hex.slice(2, 4), 16),
|
|
551
|
+
parseInt(hex.slice(4, 6), 16)
|
|
552
|
+
];
|
|
516
553
|
}
|
|
517
554
|
const rgbMatch = trimmed.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
|
|
518
|
-
if (rgbMatch)
|
|
519
|
-
|
|
555
|
+
if (rgbMatch)
|
|
556
|
+
return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];
|
|
557
|
+
const hslMatch = trimmed.match(
|
|
558
|
+
/hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%/
|
|
559
|
+
);
|
|
520
560
|
if (hslMatch) {
|
|
521
|
-
const hex = hslToHex(
|
|
561
|
+
const hex = hslToHex(
|
|
562
|
+
Number(hslMatch[1]),
|
|
563
|
+
Number(hslMatch[2]),
|
|
564
|
+
Number(hslMatch[3])
|
|
565
|
+
);
|
|
522
566
|
return parseColorToRgb(hex);
|
|
523
567
|
}
|
|
524
568
|
return null;
|
|
@@ -548,9 +592,16 @@ function detectHostAccent() {
|
|
|
548
592
|
if (!raw) continue;
|
|
549
593
|
const hslSpaceMatch = raw.match(/^([\d.]+)\s+([\d.]+)%\s+([\d.]+)%$/);
|
|
550
594
|
if (hslSpaceMatch) {
|
|
551
|
-
const hex = hslToHex(
|
|
595
|
+
const hex = hslToHex(
|
|
596
|
+
Number(hslSpaceMatch[1]),
|
|
597
|
+
Number(hslSpaceMatch[2]),
|
|
598
|
+
Number(hslSpaceMatch[3])
|
|
599
|
+
);
|
|
552
600
|
const rgb2 = parseColorToRgb(hex);
|
|
553
|
-
return {
|
|
601
|
+
return {
|
|
602
|
+
accent: hex,
|
|
603
|
+
accentText: rgb2 ? getContrastText(...rgb2) : "#ffffff"
|
|
604
|
+
};
|
|
554
605
|
}
|
|
555
606
|
const rgb = parseColorToRgb(raw);
|
|
556
607
|
if (rgb) {
|
|
@@ -565,7 +616,27 @@ function detectHostAccent() {
|
|
|
565
616
|
}
|
|
566
617
|
function getTheme(dark) {
|
|
567
618
|
const hostAccent = detectHostAccent();
|
|
568
|
-
const defaults = dark ? {
|
|
619
|
+
const defaults = dark ? {
|
|
620
|
+
bg: "#1c1c1e",
|
|
621
|
+
bgSecondary: "#27272a",
|
|
622
|
+
border: "#2c2c2e",
|
|
623
|
+
text: "#fafafa",
|
|
624
|
+
textMuted: "#a1a1aa",
|
|
625
|
+
accent: "#22d3ee",
|
|
626
|
+
accentText: "#09090b",
|
|
627
|
+
inputBg: "#27272a",
|
|
628
|
+
inputBorder: "#3f3f46"
|
|
629
|
+
} : {
|
|
630
|
+
bg: "#ffffff",
|
|
631
|
+
bgSecondary: "#f4f4f5",
|
|
632
|
+
border: "#e4e4e7",
|
|
633
|
+
text: "#18181b",
|
|
634
|
+
textMuted: "#71717a",
|
|
635
|
+
accent: "#0891b2",
|
|
636
|
+
accentText: "#ffffff",
|
|
637
|
+
inputBg: "#fafafa",
|
|
638
|
+
inputBorder: "#d4d4d8"
|
|
639
|
+
};
|
|
569
640
|
if (hostAccent) {
|
|
570
641
|
defaults.accent = hostAccent.accent;
|
|
571
642
|
defaults.accentText = hostAccent.accentText;
|
|
@@ -615,10 +686,18 @@ function isLowQualityText(text) {
|
|
|
615
686
|
function ReportDialog({
|
|
616
687
|
report,
|
|
617
688
|
enhanceText: enhanceText2,
|
|
689
|
+
transcribeAudio: transcribeAudio2,
|
|
618
690
|
types,
|
|
619
691
|
showSeverity = true
|
|
620
692
|
}) {
|
|
621
693
|
const [isEnhancing, setIsEnhancing] = (0, import_react.useState)(false);
|
|
694
|
+
const [isEnhanced, setIsEnhanced] = (0, import_react.useState)(false);
|
|
695
|
+
const [originalDescription, setOriginalDescription] = (0, import_react.useState)(
|
|
696
|
+
null
|
|
697
|
+
);
|
|
698
|
+
const [isListening, setIsListening] = (0, import_react.useState)(false);
|
|
699
|
+
const [isTranscribing, setIsTranscribing] = (0, import_react.useState)(false);
|
|
700
|
+
const [voiceError, setVoiceError] = (0, import_react.useState)(null);
|
|
622
701
|
const [screenshotDragOver, setScreenshotDragOver] = (0, import_react.useState)(false);
|
|
623
702
|
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
624
703
|
(0, import_react.useEffect)(() => {
|
|
@@ -632,10 +711,22 @@ function ReportDialog({
|
|
|
632
711
|
const [previewOpen, setPreviewOpen] = (0, import_react.useState)(false);
|
|
633
712
|
const fileInputRef = (0, import_react.useRef)(null);
|
|
634
713
|
const modalRef = (0, import_react.useRef)(null);
|
|
714
|
+
const textareaRef = (0, import_react.useRef)(null);
|
|
715
|
+
const recognitionRef = (0, import_react.useRef)(null);
|
|
716
|
+
const voiceBaseRef = (0, import_react.useRef)("");
|
|
717
|
+
const usingWebSpeechRef = (0, import_react.useRef)(false);
|
|
718
|
+
const textBeforeVoiceRef = (0, import_react.useRef)("");
|
|
719
|
+
const mediaRecorderRef = (0, import_react.useRef)(null);
|
|
720
|
+
const streamRef = (0, import_react.useRef)(null);
|
|
721
|
+
const sarvamChunksRef = (0, import_react.useRef)([]);
|
|
722
|
+
const spaceTimerRef = (0, import_react.useRef)(null);
|
|
723
|
+
const isPushToTalkRef = (0, import_react.useRef)(false);
|
|
635
724
|
(0, import_react.useEffect)(() => {
|
|
636
725
|
if (!isOpen) return;
|
|
637
726
|
const dialogs = Array.from(
|
|
638
|
-
document.querySelectorAll(
|
|
727
|
+
document.querySelectorAll(
|
|
728
|
+
'[role="dialog"][data-state="open"]'
|
|
729
|
+
)
|
|
639
730
|
);
|
|
640
731
|
dialogs.forEach((d) => d.setAttribute("inert", ""));
|
|
641
732
|
return () => dialogs.forEach((d) => d.removeAttribute("inert"));
|
|
@@ -644,7 +735,13 @@ function ReportDialog({
|
|
|
644
735
|
const [reportType, setReportType] = (0, import_react.useState)("BUG");
|
|
645
736
|
const [severity, setSeverity] = (0, import_react.useState)("medium");
|
|
646
737
|
const [validationError, setValidationError] = (0, import_react.useState)(null);
|
|
647
|
-
const
|
|
738
|
+
const [placeholderIdx, setPlaceholderIdx] = (0, import_react.useState)(0);
|
|
739
|
+
const availableTypes = types != null ? types : [
|
|
740
|
+
"BUG",
|
|
741
|
+
"FEATURE_REQUEST",
|
|
742
|
+
"QUESTION",
|
|
743
|
+
"OTHER"
|
|
744
|
+
];
|
|
648
745
|
const isDark = useIsDark();
|
|
649
746
|
const t = getTheme(isDark);
|
|
650
747
|
const handleFileUpload = (e) => {
|
|
@@ -744,12 +841,185 @@ function ReportDialog({
|
|
|
744
841
|
window.addEventListener("paste", handlePaste);
|
|
745
842
|
return () => window.removeEventListener("paste", handlePaste);
|
|
746
843
|
}, [isOpen]);
|
|
844
|
+
(0, import_react.useEffect)(() => {
|
|
845
|
+
if (!isOpen || !transcribeAudio2) return;
|
|
846
|
+
const id = setInterval(() => {
|
|
847
|
+
setPlaceholderIdx((i) => (i + 1) % 2);
|
|
848
|
+
}, 3e3);
|
|
849
|
+
return () => clearInterval(id);
|
|
850
|
+
}, [isOpen, transcribeAudio2]);
|
|
851
|
+
const stopVoice = () => {
|
|
852
|
+
var _a, _b;
|
|
853
|
+
usingWebSpeechRef.current = false;
|
|
854
|
+
(_a = recognitionRef.current) == null ? void 0 : _a.stop();
|
|
855
|
+
recognitionRef.current = null;
|
|
856
|
+
sarvamChunksRef.current = [];
|
|
857
|
+
const stream = streamRef.current;
|
|
858
|
+
streamRef.current = null;
|
|
859
|
+
stream == null ? void 0 : stream.getTracks().forEach((t2) => t2.stop());
|
|
860
|
+
try {
|
|
861
|
+
(_b = mediaRecorderRef.current) == null ? void 0 : _b.stop();
|
|
862
|
+
} catch (e) {
|
|
863
|
+
}
|
|
864
|
+
mediaRecorderRef.current = null;
|
|
865
|
+
setIsListening(false);
|
|
866
|
+
setIsTranscribing(false);
|
|
867
|
+
};
|
|
868
|
+
const stopListeningAndTranscribe = () => {
|
|
869
|
+
var _a, _b;
|
|
870
|
+
usingWebSpeechRef.current = false;
|
|
871
|
+
(_a = recognitionRef.current) == null ? void 0 : _a.stop();
|
|
872
|
+
recognitionRef.current = null;
|
|
873
|
+
setIsListening(false);
|
|
874
|
+
try {
|
|
875
|
+
(_b = mediaRecorderRef.current) == null ? void 0 : _b.stop();
|
|
876
|
+
} catch (e) {
|
|
877
|
+
}
|
|
878
|
+
};
|
|
747
879
|
const handleClose = () => {
|
|
880
|
+
stopVoice();
|
|
748
881
|
setIsOpen(false);
|
|
749
882
|
setStep(1);
|
|
750
883
|
setReportType("BUG");
|
|
751
884
|
setSeverity("medium");
|
|
752
885
|
setValidationError(null);
|
|
886
|
+
setVoiceError(null);
|
|
887
|
+
setIsEnhanced(false);
|
|
888
|
+
setOriginalDescription(null);
|
|
889
|
+
};
|
|
890
|
+
const toggleVoice = async () => {
|
|
891
|
+
if (isListening) {
|
|
892
|
+
stopListeningAndTranscribe();
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
const SpeechRec = typeof window !== "undefined" ? window.SpeechRecognition || window.webkitSpeechRecognition : void 0;
|
|
896
|
+
let stream = null;
|
|
897
|
+
try {
|
|
898
|
+
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
899
|
+
} catch (e) {
|
|
900
|
+
if (!SpeechRec) {
|
|
901
|
+
setVoiceError("Microphone access denied");
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if (stream && transcribeAudio2) {
|
|
906
|
+
streamRef.current = stream;
|
|
907
|
+
sarvamChunksRef.current = [];
|
|
908
|
+
textBeforeVoiceRef.current = description;
|
|
909
|
+
const rec = new MediaRecorder(stream);
|
|
910
|
+
mediaRecorderRef.current = rec;
|
|
911
|
+
rec.ondataavailable = (e) => {
|
|
912
|
+
if (e.data.size > 0) sarvamChunksRef.current.push(e.data);
|
|
913
|
+
};
|
|
914
|
+
rec.onstop = async () => {
|
|
915
|
+
stream.getTracks().forEach((t2) => t2.stop());
|
|
916
|
+
if (streamRef.current === stream) streamRef.current = null;
|
|
917
|
+
mediaRecorderRef.current = null;
|
|
918
|
+
const chunks = sarvamChunksRef.current;
|
|
919
|
+
sarvamChunksRef.current = [];
|
|
920
|
+
if (!chunks.length || !transcribeAudio2) return;
|
|
921
|
+
setIsTranscribing(true);
|
|
922
|
+
try {
|
|
923
|
+
const blob = new Blob(chunks, { type: rec.mimeType || "audio/webm" });
|
|
924
|
+
const text = await transcribeAudio2(blob);
|
|
925
|
+
if (text.trim()) {
|
|
926
|
+
const sep = textBeforeVoiceRef.current.trim() ? " " : "";
|
|
927
|
+
setDescription(textBeforeVoiceRef.current + sep + text.trim());
|
|
928
|
+
setValidationError(null);
|
|
929
|
+
setIsEnhanced(false);
|
|
930
|
+
setOriginalDescription(null);
|
|
931
|
+
}
|
|
932
|
+
} catch (e) {
|
|
933
|
+
}
|
|
934
|
+
setIsTranscribing(false);
|
|
935
|
+
};
|
|
936
|
+
rec.start();
|
|
937
|
+
}
|
|
938
|
+
if (SpeechRec) {
|
|
939
|
+
setVoiceError(null);
|
|
940
|
+
usingWebSpeechRef.current = true;
|
|
941
|
+
voiceBaseRef.current = description;
|
|
942
|
+
textBeforeVoiceRef.current = description;
|
|
943
|
+
const recognition = new SpeechRec();
|
|
944
|
+
recognition.lang = "en-IN";
|
|
945
|
+
recognition.interimResults = true;
|
|
946
|
+
recognition.continuous = true;
|
|
947
|
+
recognitionRef.current = recognition;
|
|
948
|
+
recognition.onstart = () => setIsListening(true);
|
|
949
|
+
recognition.onresult = (event) => {
|
|
950
|
+
let finalText = "";
|
|
951
|
+
let interimText = "";
|
|
952
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
953
|
+
const text = event.results[i][0].transcript;
|
|
954
|
+
if (event.results[i].isFinal) finalText += text;
|
|
955
|
+
else interimText += text;
|
|
956
|
+
}
|
|
957
|
+
if (finalText) {
|
|
958
|
+
const sep = voiceBaseRef.current.trim() ? " " : "";
|
|
959
|
+
voiceBaseRef.current += sep + finalText.trim();
|
|
960
|
+
}
|
|
961
|
+
const liveText = interimText ? voiceBaseRef.current + (voiceBaseRef.current.trim() ? " " : "") + interimText : voiceBaseRef.current;
|
|
962
|
+
setDescription(liveText);
|
|
963
|
+
setValidationError(null);
|
|
964
|
+
};
|
|
965
|
+
recognition.onend = () => {
|
|
966
|
+
if (usingWebSpeechRef.current && recognitionRef.current === recognition) {
|
|
967
|
+
try {
|
|
968
|
+
recognition.start();
|
|
969
|
+
} catch (e) {
|
|
970
|
+
}
|
|
971
|
+
} else {
|
|
972
|
+
setIsListening(false);
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
recognition.onerror = (event) => {
|
|
976
|
+
if (event.error === "aborted" || event.error === "no-speech") return;
|
|
977
|
+
setVoiceError("Speech recognition not available \u2014 try Chrome");
|
|
978
|
+
usingWebSpeechRef.current = false;
|
|
979
|
+
recognitionRef.current = null;
|
|
980
|
+
setIsListening(false);
|
|
981
|
+
};
|
|
982
|
+
recognition.start();
|
|
983
|
+
} else if (stream) {
|
|
984
|
+
setVoiceError(null);
|
|
985
|
+
setIsListening(true);
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
const handleSpaceDown = (e) => {
|
|
989
|
+
if (e.code !== "Space") return;
|
|
990
|
+
if (spaceTimerRef.current || isListening || isPushToTalkRef.current) {
|
|
991
|
+
e.preventDefault();
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
if (e.repeat || !transcribeAudio2 || isTranscribing) return;
|
|
995
|
+
e.preventDefault();
|
|
996
|
+
spaceTimerRef.current = setTimeout(() => {
|
|
997
|
+
isPushToTalkRef.current = true;
|
|
998
|
+
void toggleVoice();
|
|
999
|
+
}, 400);
|
|
1000
|
+
};
|
|
1001
|
+
const handleSpaceUp = (e) => {
|
|
1002
|
+
var _a;
|
|
1003
|
+
if (e.code !== "Space") return;
|
|
1004
|
+
if (spaceTimerRef.current) {
|
|
1005
|
+
clearTimeout(spaceTimerRef.current);
|
|
1006
|
+
spaceTimerRef.current = null;
|
|
1007
|
+
if (!isPushToTalkRef.current) {
|
|
1008
|
+
const ta = textareaRef.current;
|
|
1009
|
+
const pos = ta ? (_a = ta.selectionStart) != null ? _a : description.length : description.length;
|
|
1010
|
+
setDescription((prev) => prev.slice(0, pos) + " " + prev.slice(pos));
|
|
1011
|
+
requestAnimationFrame(() => {
|
|
1012
|
+
if (textareaRef.current) {
|
|
1013
|
+
textareaRef.current.selectionStart = pos + 1;
|
|
1014
|
+
textareaRef.current.selectionEnd = pos + 1;
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (isPushToTalkRef.current) {
|
|
1020
|
+
isPushToTalkRef.current = false;
|
|
1021
|
+
stopListeningAndTranscribe();
|
|
1022
|
+
}
|
|
753
1023
|
};
|
|
754
1024
|
const handleSubmit = async () => {
|
|
755
1025
|
try {
|
|
@@ -766,7 +1036,11 @@ function ReportDialog({
|
|
|
766
1036
|
if (showSeverity && reportType === "BUG") {
|
|
767
1037
|
metadata.severity = severity;
|
|
768
1038
|
}
|
|
769
|
-
const result = await report(
|
|
1039
|
+
const result = await report(
|
|
1040
|
+
reportType,
|
|
1041
|
+
description.trim(),
|
|
1042
|
+
Object.keys(metadata).length > 0 ? metadata : void 0
|
|
1043
|
+
);
|
|
770
1044
|
if (result) {
|
|
771
1045
|
setSubmitted(true);
|
|
772
1046
|
setDescription("");
|
|
@@ -783,6 +1057,16 @@ function ReportDialog({
|
|
|
783
1057
|
};
|
|
784
1058
|
if (!mounted) return null;
|
|
785
1059
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1060
|
+
isOpen && (0, import_react_dom.createPortal)(
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
1062
|
+
@keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}
|
|
1063
|
+
@keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}
|
|
1064
|
+
@keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}
|
|
1065
|
+
@keyframes gg-b3{0%,100%{height:4px}30%{height:14px}70%{height:5px}}
|
|
1066
|
+
@keyframes gg-b4{0%,100%{height:6px}60%{height:13px}}
|
|
1067
|
+
` }),
|
|
1068
|
+
document.body
|
|
1069
|
+
),
|
|
786
1070
|
isOpen && (0, import_react_dom.createPortal)(
|
|
787
1071
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
788
1072
|
"div",
|
|
@@ -839,36 +1123,64 @@ function ReportDialog({
|
|
|
839
1123
|
alignItems: "center"
|
|
840
1124
|
},
|
|
841
1125
|
children: [
|
|
842
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
{
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1126
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1127
|
+
"div",
|
|
1128
|
+
{
|
|
1129
|
+
style: {
|
|
1130
|
+
display: "flex",
|
|
1131
|
+
alignItems: "center",
|
|
1132
|
+
gap: "8px"
|
|
1133
|
+
},
|
|
1134
|
+
children: [
|
|
1135
|
+
step > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1136
|
+
"button",
|
|
1137
|
+
{
|
|
1138
|
+
type: "button",
|
|
1139
|
+
onClick: () => setStep((s) => s - 1),
|
|
1140
|
+
style: {
|
|
1141
|
+
background: "none",
|
|
1142
|
+
border: "none",
|
|
1143
|
+
cursor: "pointer",
|
|
1144
|
+
padding: "2px",
|
|
1145
|
+
display: "flex",
|
|
1146
|
+
alignItems: "center"
|
|
1147
|
+
},
|
|
1148
|
+
"aria-label": "Back",
|
|
1149
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1150
|
+
"svg",
|
|
1151
|
+
{
|
|
1152
|
+
width: "16",
|
|
1153
|
+
height: "16",
|
|
1154
|
+
viewBox: "0 0 16 16",
|
|
1155
|
+
fill: "none",
|
|
1156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1157
|
+
"path",
|
|
1158
|
+
{
|
|
1159
|
+
d: "M10 3L5 8L10 13",
|
|
1160
|
+
stroke: t.textMuted,
|
|
1161
|
+
strokeWidth: "2",
|
|
1162
|
+
strokeLinecap: "round",
|
|
1163
|
+
strokeLinejoin: "round"
|
|
1164
|
+
}
|
|
1165
|
+
)
|
|
1166
|
+
}
|
|
1167
|
+
)
|
|
1168
|
+
}
|
|
1169
|
+
),
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1171
|
+
"span",
|
|
1172
|
+
{
|
|
1173
|
+
style: {
|
|
1174
|
+
fontSize: "15px",
|
|
1175
|
+
fontWeight: 600,
|
|
1176
|
+
color: t.text
|
|
1177
|
+
},
|
|
1178
|
+
children: step === 1 ? "What's on your mind?" : "Tell us more"
|
|
1179
|
+
}
|
|
1180
|
+
)
|
|
1181
|
+
]
|
|
1182
|
+
}
|
|
1183
|
+
),
|
|
872
1184
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
873
1185
|
"button",
|
|
874
1186
|
{
|
|
@@ -884,27 +1196,74 @@ function ReportDialog({
|
|
|
884
1196
|
justifyContent: "center"
|
|
885
1197
|
},
|
|
886
1198
|
"aria-label": "Close",
|
|
887
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1200
|
+
"svg",
|
|
1201
|
+
{
|
|
1202
|
+
width: "16",
|
|
1203
|
+
height: "16",
|
|
1204
|
+
viewBox: "0 0 16 16",
|
|
1205
|
+
fill: "none",
|
|
1206
|
+
style: { display: "block" },
|
|
1207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1208
|
+
"path",
|
|
1209
|
+
{
|
|
1210
|
+
d: "M4 4L12 12M12 4L4 12",
|
|
1211
|
+
stroke: t.textMuted,
|
|
1212
|
+
strokeWidth: "2",
|
|
1213
|
+
strokeLinecap: "round"
|
|
1214
|
+
}
|
|
1215
|
+
)
|
|
1216
|
+
}
|
|
1217
|
+
)
|
|
888
1218
|
}
|
|
889
1219
|
)
|
|
890
1220
|
]
|
|
891
1221
|
}
|
|
892
1222
|
),
|
|
893
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1224
|
+
"div",
|
|
1225
|
+
{
|
|
1226
|
+
style: {
|
|
1227
|
+
display: "flex",
|
|
1228
|
+
alignItems: "center",
|
|
1229
|
+
justifyContent: "center",
|
|
1230
|
+
gap: "0",
|
|
1231
|
+
marginTop: "12px"
|
|
1232
|
+
},
|
|
1233
|
+
children: [1, 2].map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1234
|
+
"div",
|
|
1235
|
+
{
|
|
1236
|
+
style: { display: "flex", alignItems: "center" },
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1239
|
+
"div",
|
|
1240
|
+
{
|
|
1241
|
+
style: {
|
|
1242
|
+
width: "8px",
|
|
1243
|
+
height: "8px",
|
|
1244
|
+
borderRadius: "50%",
|
|
1245
|
+
backgroundColor: s <= step ? t.accent : t.inputBorder,
|
|
1246
|
+
transition: "background-color 0.2s ease"
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
),
|
|
1250
|
+
i < 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1251
|
+
"div",
|
|
1252
|
+
{
|
|
1253
|
+
style: {
|
|
1254
|
+
width: "40px",
|
|
1255
|
+
height: "2px",
|
|
1256
|
+
backgroundColor: s < step ? t.accent : t.inputBorder,
|
|
1257
|
+
transition: "background-color 0.2s ease"
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
)
|
|
1261
|
+
]
|
|
1262
|
+
},
|
|
1263
|
+
s
|
|
1264
|
+
))
|
|
1265
|
+
}
|
|
1266
|
+
)
|
|
908
1267
|
]
|
|
909
1268
|
}
|
|
910
1269
|
),
|
|
@@ -924,76 +1283,185 @@ function ReportDialog({
|
|
|
924
1283
|
]
|
|
925
1284
|
}
|
|
926
1285
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
927
|
-
step === 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
928
|
-
"
|
|
1286
|
+
step === 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1287
|
+
"div",
|
|
929
1288
|
{
|
|
930
|
-
type: "button",
|
|
931
|
-
onClick: () => {
|
|
932
|
-
setReportType(type);
|
|
933
|
-
setStep(2);
|
|
934
|
-
},
|
|
935
1289
|
style: {
|
|
936
|
-
display: "
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
gap: "8px",
|
|
940
|
-
padding: "16px 8px",
|
|
941
|
-
borderRadius: "8px",
|
|
942
|
-
border: `1px solid ${t.inputBorder}`,
|
|
943
|
-
background: t.inputBg,
|
|
944
|
-
cursor: "pointer",
|
|
945
|
-
color: t.text,
|
|
946
|
-
fontFamily: "inherit",
|
|
947
|
-
transition: "border-color 0.15s ease"
|
|
948
|
-
},
|
|
949
|
-
onMouseEnter: (e) => {
|
|
950
|
-
e.currentTarget.style.borderColor = t.accent;
|
|
951
|
-
},
|
|
952
|
-
onMouseLeave: (e) => {
|
|
953
|
-
e.currentTarget.style.borderColor = t.inputBorder;
|
|
1290
|
+
display: "grid",
|
|
1291
|
+
gridTemplateColumns: "1fr 1fr",
|
|
1292
|
+
gap: "8px"
|
|
954
1293
|
},
|
|
955
|
-
children:
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1294
|
+
children: availableTypes.map((type) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1295
|
+
"button",
|
|
1296
|
+
{
|
|
1297
|
+
type: "button",
|
|
1298
|
+
onClick: () => {
|
|
1299
|
+
setReportType(type);
|
|
1300
|
+
setStep(2);
|
|
1301
|
+
},
|
|
1302
|
+
style: {
|
|
1303
|
+
display: "flex",
|
|
1304
|
+
flexDirection: "column",
|
|
1305
|
+
alignItems: "center",
|
|
1306
|
+
gap: "8px",
|
|
1307
|
+
padding: "16px 8px",
|
|
1308
|
+
borderRadius: "8px",
|
|
1309
|
+
border: `1px solid ${t.inputBorder}`,
|
|
1310
|
+
background: t.inputBg,
|
|
1311
|
+
cursor: "pointer",
|
|
1312
|
+
color: t.text,
|
|
1313
|
+
fontFamily: "inherit",
|
|
1314
|
+
transition: "border-color 0.15s ease"
|
|
1315
|
+
},
|
|
1316
|
+
onMouseEnter: (e) => {
|
|
1317
|
+
e.currentTarget.style.borderColor = t.accent;
|
|
1318
|
+
},
|
|
1319
|
+
onMouseLeave: (e) => {
|
|
1320
|
+
e.currentTarget.style.borderColor = t.inputBorder;
|
|
1321
|
+
},
|
|
1322
|
+
children: [
|
|
1323
|
+
getTypeIcon(type, t.accent),
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1326
|
+
"span",
|
|
1327
|
+
{
|
|
1328
|
+
style: {
|
|
1329
|
+
fontSize: "11px",
|
|
1330
|
+
color: t.textMuted,
|
|
1331
|
+
lineHeight: "1.3"
|
|
1332
|
+
},
|
|
1333
|
+
children: getTypeSubtitle(type)
|
|
1334
|
+
}
|
|
1335
|
+
)
|
|
1336
|
+
]
|
|
1337
|
+
},
|
|
1338
|
+
type
|
|
1339
|
+
))
|
|
1340
|
+
}
|
|
1341
|
+
),
|
|
963
1342
|
step === 2 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
964
1343
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, children: [
|
|
965
1344
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
966
1345
|
"textarea",
|
|
967
1346
|
{
|
|
1347
|
+
ref: textareaRef,
|
|
968
1348
|
value: description,
|
|
969
1349
|
onChange: (e) => {
|
|
970
1350
|
setDescription(e.target.value);
|
|
971
1351
|
if (validationError) setValidationError(null);
|
|
1352
|
+
if (isEnhanced) {
|
|
1353
|
+
setIsEnhanced(false);
|
|
1354
|
+
setOriginalDescription(null);
|
|
1355
|
+
}
|
|
972
1356
|
},
|
|
973
|
-
placeholder: getPlaceholder(reportType),
|
|
1357
|
+
placeholder: isTranscribing ? "Transcribing your speech\u2026" : isListening ? "Listening\u2026 speak now" : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio2),
|
|
974
1358
|
style: {
|
|
975
1359
|
width: "100%",
|
|
976
1360
|
minHeight: "100px",
|
|
977
|
-
padding: enhanceText2 ? "28px 12px 10px" : "10px 12px",
|
|
1361
|
+
padding: enhanceText2 ? "28px 12px 36px" : transcribeAudio2 ? "10px 12px 36px" : "10px 12px",
|
|
978
1362
|
borderRadius: "8px",
|
|
979
|
-
border: `1px solid ${t.inputBorder}`,
|
|
1363
|
+
border: `1px solid ${isTranscribing ? "#f59e0b" : isListening ? t.accent : t.inputBorder}`,
|
|
980
1364
|
fontSize: "14px",
|
|
981
1365
|
fontFamily: "inherit",
|
|
982
|
-
resize: "
|
|
1366
|
+
resize: "none",
|
|
983
1367
|
outline: "none",
|
|
984
1368
|
boxSizing: "border-box",
|
|
985
1369
|
color: t.text,
|
|
986
|
-
backgroundColor: t.inputBg
|
|
1370
|
+
backgroundColor: t.inputBg,
|
|
1371
|
+
transition: "border-color 0.2s ease"
|
|
987
1372
|
},
|
|
1373
|
+
onKeyDown: handleSpaceDown,
|
|
1374
|
+
onKeyUp: handleSpaceUp,
|
|
988
1375
|
onFocus: (e) => {
|
|
989
1376
|
e.target.style.borderColor = t.accent;
|
|
990
1377
|
},
|
|
991
1378
|
onBlur: (e) => {
|
|
992
|
-
|
|
1379
|
+
if (!isListening && !isTranscribing)
|
|
1380
|
+
e.target.style.borderColor = t.inputBorder;
|
|
993
1381
|
},
|
|
994
1382
|
autoFocus: true
|
|
995
1383
|
}
|
|
996
1384
|
),
|
|
1385
|
+
(isListening || isTranscribing) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1386
|
+
"span",
|
|
1387
|
+
{
|
|
1388
|
+
style: {
|
|
1389
|
+
position: "absolute",
|
|
1390
|
+
bottom: "10px",
|
|
1391
|
+
left: "10px",
|
|
1392
|
+
display: "inline-flex",
|
|
1393
|
+
alignItems: "center",
|
|
1394
|
+
gap: "4px",
|
|
1395
|
+
fontSize: "10px",
|
|
1396
|
+
fontWeight: 700,
|
|
1397
|
+
letterSpacing: "0.04em",
|
|
1398
|
+
color: isTranscribing ? "#f59e0b" : "#ef4444",
|
|
1399
|
+
pointerEvents: "none",
|
|
1400
|
+
zIndex: 1
|
|
1401
|
+
},
|
|
1402
|
+
children: [
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1404
|
+
"span",
|
|
1405
|
+
{
|
|
1406
|
+
style: {
|
|
1407
|
+
width: "6px",
|
|
1408
|
+
height: "6px",
|
|
1409
|
+
borderRadius: "50%",
|
|
1410
|
+
backgroundColor: "currentColor",
|
|
1411
|
+
animation: "gg-pulse 1.2s ease-in-out infinite",
|
|
1412
|
+
display: "inline-block",
|
|
1413
|
+
flexShrink: 0
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
),
|
|
1417
|
+
isTranscribing ? "Transcribing\u2026" : "REC",
|
|
1418
|
+
isListening && !isTranscribing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1419
|
+
"span",
|
|
1420
|
+
{
|
|
1421
|
+
style: {
|
|
1422
|
+
display: "inline-flex",
|
|
1423
|
+
alignItems: "flex-end",
|
|
1424
|
+
gap: "2px",
|
|
1425
|
+
height: "14px",
|
|
1426
|
+
marginLeft: "3px"
|
|
1427
|
+
},
|
|
1428
|
+
children: [
|
|
1429
|
+
{ anim: "gg-b1", dur: "0.6s", delay: "0s" },
|
|
1430
|
+
{
|
|
1431
|
+
anim: "gg-b2",
|
|
1432
|
+
dur: "0.5s",
|
|
1433
|
+
delay: "0.1s"
|
|
1434
|
+
},
|
|
1435
|
+
{
|
|
1436
|
+
anim: "gg-b3",
|
|
1437
|
+
dur: "0.7s",
|
|
1438
|
+
delay: "0.05s"
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
anim: "gg-b4",
|
|
1442
|
+
dur: "0.55s",
|
|
1443
|
+
delay: "0.15s"
|
|
1444
|
+
}
|
|
1445
|
+
].map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1446
|
+
"span",
|
|
1447
|
+
{
|
|
1448
|
+
style: {
|
|
1449
|
+
width: "2.5px",
|
|
1450
|
+
height: "4px",
|
|
1451
|
+
borderRadius: "1px",
|
|
1452
|
+
backgroundColor: "#ef4444",
|
|
1453
|
+
animation: `${b.anim} ${b.dur} ease-in-out ${b.delay} infinite`,
|
|
1454
|
+
display: "inline-block",
|
|
1455
|
+
alignSelf: "center"
|
|
1456
|
+
}
|
|
1457
|
+
},
|
|
1458
|
+
i
|
|
1459
|
+
))
|
|
1460
|
+
}
|
|
1461
|
+
)
|
|
1462
|
+
]
|
|
1463
|
+
}
|
|
1464
|
+
),
|
|
997
1465
|
enhanceText2 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
998
1466
|
"button",
|
|
999
1467
|
{
|
|
@@ -1002,16 +1470,22 @@ function ReportDialog({
|
|
|
1002
1470
|
if (!description.trim() || isEnhancing) return;
|
|
1003
1471
|
setIsEnhancing(true);
|
|
1004
1472
|
try {
|
|
1005
|
-
const polished = await enhanceText2(
|
|
1473
|
+
const polished = await enhanceText2(
|
|
1474
|
+
description,
|
|
1475
|
+
screenshot
|
|
1476
|
+
);
|
|
1006
1477
|
if (polished && polished !== description) {
|
|
1478
|
+
setOriginalDescription(description);
|
|
1007
1479
|
setDescription(polished);
|
|
1008
|
-
|
|
1480
|
+
setIsEnhanced(true);
|
|
1481
|
+
if (validationError)
|
|
1482
|
+
setValidationError(null);
|
|
1009
1483
|
}
|
|
1010
1484
|
} finally {
|
|
1011
1485
|
setIsEnhancing(false);
|
|
1012
1486
|
}
|
|
1013
1487
|
},
|
|
1014
|
-
disabled: !description.trim() || isEnhancing,
|
|
1488
|
+
disabled: !description.trim() || isEnhancing || isEnhanced,
|
|
1015
1489
|
style: {
|
|
1016
1490
|
position: "absolute",
|
|
1017
1491
|
top: "6px",
|
|
@@ -1032,105 +1506,393 @@ function ReportDialog({
|
|
|
1032
1506
|
},
|
|
1033
1507
|
title: "Polish grammar \u2014 preserves your meaning",
|
|
1034
1508
|
children: [
|
|
1035
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1509
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1510
|
+
"svg",
|
|
1511
|
+
{
|
|
1512
|
+
width: "11",
|
|
1513
|
+
height: "11",
|
|
1514
|
+
viewBox: "0 0 24 24",
|
|
1515
|
+
fill: "none",
|
|
1516
|
+
"aria-hidden": "true",
|
|
1517
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1518
|
+
"path",
|
|
1519
|
+
{
|
|
1520
|
+
d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z",
|
|
1521
|
+
stroke: t.textMuted,
|
|
1522
|
+
strokeWidth: "1.5",
|
|
1523
|
+
strokeLinejoin: "round"
|
|
1524
|
+
}
|
|
1525
|
+
)
|
|
1526
|
+
}
|
|
1527
|
+
),
|
|
1036
1528
|
isEnhancing ? "Enhancing..." : "AI enhance"
|
|
1037
1529
|
]
|
|
1038
1530
|
}
|
|
1531
|
+
),
|
|
1532
|
+
transcribeAudio2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1533
|
+
"button",
|
|
1534
|
+
{
|
|
1535
|
+
type: "button",
|
|
1536
|
+
onClick: () => {
|
|
1537
|
+
void toggleVoice();
|
|
1538
|
+
},
|
|
1539
|
+
title: isListening ? "Stop recording" : "Speak your report",
|
|
1540
|
+
style: {
|
|
1541
|
+
position: "absolute",
|
|
1542
|
+
bottom: "14px",
|
|
1543
|
+
right: "7px",
|
|
1544
|
+
width: "26px",
|
|
1545
|
+
height: "26px",
|
|
1546
|
+
display: "flex",
|
|
1547
|
+
alignItems: "center",
|
|
1548
|
+
justifyContent: "center",
|
|
1549
|
+
background: "transparent",
|
|
1550
|
+
border: `1.5px solid ${isListening ? "#ef4444" : t.inputBorder}`,
|
|
1551
|
+
borderRadius: "6px",
|
|
1552
|
+
color: isListening ? "#ef4444" : t.textMuted,
|
|
1553
|
+
cursor: "pointer",
|
|
1554
|
+
zIndex: 1,
|
|
1555
|
+
padding: 0,
|
|
1556
|
+
transition: "border-color 0.2s ease, color 0.2s ease"
|
|
1557
|
+
},
|
|
1558
|
+
children: isListening ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1559
|
+
"svg",
|
|
1560
|
+
{
|
|
1561
|
+
width: "12",
|
|
1562
|
+
height: "12",
|
|
1563
|
+
viewBox: "0 0 24 24",
|
|
1564
|
+
fill: "currentColor",
|
|
1565
|
+
"aria-hidden": "true",
|
|
1566
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1567
|
+
"rect",
|
|
1568
|
+
{
|
|
1569
|
+
x: "6",
|
|
1570
|
+
y: "6",
|
|
1571
|
+
width: "12",
|
|
1572
|
+
height: "12",
|
|
1573
|
+
rx: "2"
|
|
1574
|
+
}
|
|
1575
|
+
)
|
|
1576
|
+
}
|
|
1577
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1578
|
+
"svg",
|
|
1579
|
+
{
|
|
1580
|
+
width: "13",
|
|
1581
|
+
height: "13",
|
|
1582
|
+
viewBox: "0 0 24 24",
|
|
1583
|
+
fill: "none",
|
|
1584
|
+
"aria-hidden": "true",
|
|
1585
|
+
children: [
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1587
|
+
"rect",
|
|
1588
|
+
{
|
|
1589
|
+
x: "9",
|
|
1590
|
+
y: "2",
|
|
1591
|
+
width: "6",
|
|
1592
|
+
height: "12",
|
|
1593
|
+
rx: "3",
|
|
1594
|
+
stroke: "currentColor",
|
|
1595
|
+
strokeWidth: "1.8"
|
|
1596
|
+
}
|
|
1597
|
+
),
|
|
1598
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1599
|
+
"path",
|
|
1600
|
+
{
|
|
1601
|
+
d: "M5 10a7 7 0 0014 0M12 19v3M9 22h6",
|
|
1602
|
+
stroke: "currentColor",
|
|
1603
|
+
strokeWidth: "1.8",
|
|
1604
|
+
strokeLinecap: "round"
|
|
1605
|
+
}
|
|
1606
|
+
)
|
|
1607
|
+
]
|
|
1608
|
+
}
|
|
1609
|
+
)
|
|
1610
|
+
}
|
|
1039
1611
|
)
|
|
1040
1612
|
] }),
|
|
1041
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1613
|
+
transcribeAudio2 && !isListening && !isTranscribing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1614
|
+
"div",
|
|
1615
|
+
{
|
|
1616
|
+
style: {
|
|
1617
|
+
display: "flex",
|
|
1618
|
+
alignItems: "center",
|
|
1619
|
+
gap: "5px",
|
|
1620
|
+
marginTop: "5px",
|
|
1621
|
+
fontSize: "11px",
|
|
1622
|
+
color: t.text,
|
|
1623
|
+
opacity: 0.55,
|
|
1624
|
+
userSelect: "none"
|
|
1625
|
+
},
|
|
1626
|
+
children: [
|
|
1627
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
|
|
1631
|
+
] }),
|
|
1632
|
+
"Hold Space to speak \u2014 we'll transcribe it"
|
|
1633
|
+
]
|
|
1634
|
+
}
|
|
1635
|
+
),
|
|
1636
|
+
isEnhanced && originalDescription !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1637
|
+
"div",
|
|
1638
|
+
{
|
|
1639
|
+
style: {
|
|
1640
|
+
display: "flex",
|
|
1641
|
+
alignItems: "center",
|
|
1642
|
+
gap: "6px",
|
|
1643
|
+
marginTop: "6px",
|
|
1644
|
+
padding: "6px 8px",
|
|
1645
|
+
borderRadius: "6px",
|
|
1646
|
+
background: isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.05)",
|
|
1647
|
+
border: `1px solid ${t.accent}40`
|
|
1648
|
+
},
|
|
1649
|
+
children: [
|
|
1045
1650
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1046
|
-
"
|
|
1651
|
+
"svg",
|
|
1652
|
+
{
|
|
1653
|
+
width: "12",
|
|
1654
|
+
height: "12",
|
|
1655
|
+
viewBox: "0 0 24 24",
|
|
1656
|
+
fill: "none",
|
|
1657
|
+
style: { flexShrink: 0 },
|
|
1658
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1659
|
+
"path",
|
|
1660
|
+
{
|
|
1661
|
+
d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z",
|
|
1662
|
+
stroke: t.accent,
|
|
1663
|
+
strokeWidth: "1.5",
|
|
1664
|
+
strokeLinejoin: "round"
|
|
1665
|
+
}
|
|
1666
|
+
)
|
|
1667
|
+
}
|
|
1668
|
+
),
|
|
1669
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1670
|
+
"span",
|
|
1047
1671
|
{
|
|
1048
|
-
src: screenshot,
|
|
1049
|
-
alt: "Page screenshot",
|
|
1050
|
-
onClick: () => setPreviewOpen(true),
|
|
1051
1672
|
style: {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
objectPosition: "top",
|
|
1058
|
-
cursor: "zoom-in",
|
|
1059
|
-
display: "block"
|
|
1060
|
-
}
|
|
1673
|
+
fontSize: "11px",
|
|
1674
|
+
color: t.textMuted,
|
|
1675
|
+
flex: 1
|
|
1676
|
+
},
|
|
1677
|
+
children: "AI enhanced"
|
|
1061
1678
|
}
|
|
1062
1679
|
),
|
|
1063
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1064
|
-
position: "absolute",
|
|
1065
|
-
bottom: "5px",
|
|
1066
|
-
left: "6px",
|
|
1067
|
-
background: "rgba(0,0,0,0.55)",
|
|
1068
|
-
color: "#fff",
|
|
1069
|
-
fontSize: "10px",
|
|
1070
|
-
padding: "1px 5px",
|
|
1071
|
-
borderRadius: "3px",
|
|
1072
|
-
pointerEvents: "none"
|
|
1073
|
-
}, children: "click to preview" })
|
|
1074
|
-
] }),
|
|
1075
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "6px", marginTop: "6px" }, children: [
|
|
1076
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1077
1681
|
"button",
|
|
1078
1682
|
{
|
|
1079
1683
|
type: "button",
|
|
1080
|
-
onClick: () =>
|
|
1684
|
+
onClick: () => {
|
|
1685
|
+
setIsEnhanced(false);
|
|
1686
|
+
setOriginalDescription(null);
|
|
1687
|
+
},
|
|
1081
1688
|
style: {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
fontWeight: 500,
|
|
1689
|
+
padding: "2px 8px",
|
|
1690
|
+
borderRadius: "4px",
|
|
1691
|
+
border: `1px solid ${t.accent}`,
|
|
1692
|
+
background: t.accent,
|
|
1693
|
+
color: t.accentText,
|
|
1694
|
+
fontSize: "11px",
|
|
1695
|
+
fontWeight: 600,
|
|
1090
1696
|
cursor: "pointer",
|
|
1091
|
-
fontFamily: "inherit"
|
|
1092
|
-
display: "flex",
|
|
1093
|
-
alignItems: "center",
|
|
1094
|
-
justifyContent: "center",
|
|
1095
|
-
gap: "4px"
|
|
1697
|
+
fontFamily: "inherit"
|
|
1096
1698
|
},
|
|
1097
|
-
children:
|
|
1098
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "11", height: "11", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }),
|
|
1099
|
-
"Remove"
|
|
1100
|
-
]
|
|
1699
|
+
children: "Keep"
|
|
1101
1700
|
}
|
|
1102
1701
|
),
|
|
1103
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1104
1703
|
"button",
|
|
1105
1704
|
{
|
|
1106
1705
|
type: "button",
|
|
1107
1706
|
onClick: () => {
|
|
1108
|
-
|
|
1109
|
-
|
|
1707
|
+
setDescription(originalDescription);
|
|
1708
|
+
setIsEnhanced(false);
|
|
1709
|
+
setOriginalDescription(null);
|
|
1110
1710
|
},
|
|
1111
1711
|
style: {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
borderRadius: "6px",
|
|
1712
|
+
padding: "2px 8px",
|
|
1713
|
+
borderRadius: "4px",
|
|
1115
1714
|
border: `1px solid ${t.inputBorder}`,
|
|
1116
1715
|
background: "transparent",
|
|
1117
1716
|
color: t.textMuted,
|
|
1118
|
-
fontSize: "
|
|
1119
|
-
fontWeight:
|
|
1717
|
+
fontSize: "11px",
|
|
1718
|
+
fontWeight: 600,
|
|
1120
1719
|
cursor: "pointer",
|
|
1121
|
-
fontFamily: "inherit"
|
|
1122
|
-
display: "flex",
|
|
1123
|
-
alignItems: "center",
|
|
1124
|
-
justifyContent: "center",
|
|
1125
|
-
gap: "4px"
|
|
1720
|
+
fontFamily: "inherit"
|
|
1126
1721
|
},
|
|
1127
|
-
children:
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1722
|
+
children: "Restore"
|
|
1723
|
+
}
|
|
1724
|
+
)
|
|
1725
|
+
]
|
|
1726
|
+
}
|
|
1727
|
+
),
|
|
1728
|
+
voiceError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1729
|
+
"p",
|
|
1730
|
+
{
|
|
1731
|
+
style: {
|
|
1732
|
+
color: "#ef4444",
|
|
1733
|
+
fontSize: "11px",
|
|
1734
|
+
marginTop: "4px",
|
|
1735
|
+
marginBottom: 0
|
|
1736
|
+
},
|
|
1737
|
+
children: voiceError
|
|
1738
|
+
}
|
|
1739
|
+
),
|
|
1740
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "10px" }, children: [
|
|
1741
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1742
|
+
"span",
|
|
1743
|
+
{
|
|
1744
|
+
style: {
|
|
1745
|
+
fontSize: "12px",
|
|
1746
|
+
color: t.textMuted,
|
|
1747
|
+
marginBottom: "6px",
|
|
1748
|
+
display: "block",
|
|
1749
|
+
fontWeight: 500
|
|
1750
|
+
},
|
|
1751
|
+
children: "Screenshot"
|
|
1752
|
+
}
|
|
1753
|
+
),
|
|
1754
|
+
screenshot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1755
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, children: [
|
|
1756
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1757
|
+
"img",
|
|
1758
|
+
{
|
|
1759
|
+
src: screenshot,
|
|
1760
|
+
alt: "Page screenshot",
|
|
1761
|
+
onClick: () => setPreviewOpen(true),
|
|
1762
|
+
style: {
|
|
1763
|
+
width: "100%",
|
|
1764
|
+
borderRadius: "6px",
|
|
1765
|
+
border: `1px solid ${t.border}`,
|
|
1766
|
+
maxHeight: "64px",
|
|
1767
|
+
objectFit: "cover",
|
|
1768
|
+
objectPosition: "top",
|
|
1769
|
+
cursor: "zoom-in",
|
|
1770
|
+
display: "block"
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
),
|
|
1774
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1775
|
+
"span",
|
|
1776
|
+
{
|
|
1777
|
+
style: {
|
|
1778
|
+
position: "absolute",
|
|
1779
|
+
bottom: "5px",
|
|
1780
|
+
left: "6px",
|
|
1781
|
+
background: "rgba(0,0,0,0.55)",
|
|
1782
|
+
color: "#fff",
|
|
1783
|
+
fontSize: "10px",
|
|
1784
|
+
padding: "1px 5px",
|
|
1785
|
+
borderRadius: "3px",
|
|
1786
|
+
pointerEvents: "none"
|
|
1787
|
+
},
|
|
1788
|
+
children: "click to preview"
|
|
1131
1789
|
}
|
|
1132
1790
|
)
|
|
1133
|
-
] })
|
|
1791
|
+
] }),
|
|
1792
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1793
|
+
"div",
|
|
1794
|
+
{
|
|
1795
|
+
style: {
|
|
1796
|
+
display: "flex",
|
|
1797
|
+
gap: "6px",
|
|
1798
|
+
marginTop: "6px"
|
|
1799
|
+
},
|
|
1800
|
+
children: [
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1802
|
+
"button",
|
|
1803
|
+
{
|
|
1804
|
+
type: "button",
|
|
1805
|
+
onClick: () => setScreenshot(null),
|
|
1806
|
+
style: {
|
|
1807
|
+
flex: 1,
|
|
1808
|
+
padding: "6px 0",
|
|
1809
|
+
borderRadius: "6px",
|
|
1810
|
+
border: `1px solid ${t.inputBorder}`,
|
|
1811
|
+
background: "transparent",
|
|
1812
|
+
color: "#ef4444",
|
|
1813
|
+
fontSize: "12px",
|
|
1814
|
+
fontWeight: 500,
|
|
1815
|
+
cursor: "pointer",
|
|
1816
|
+
fontFamily: "inherit",
|
|
1817
|
+
display: "flex",
|
|
1818
|
+
alignItems: "center",
|
|
1819
|
+
justifyContent: "center",
|
|
1820
|
+
gap: "4px"
|
|
1821
|
+
},
|
|
1822
|
+
children: [
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1824
|
+
"svg",
|
|
1825
|
+
{
|
|
1826
|
+
width: "11",
|
|
1827
|
+
height: "11",
|
|
1828
|
+
viewBox: "0 0 10 10",
|
|
1829
|
+
fill: "none",
|
|
1830
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1831
|
+
"path",
|
|
1832
|
+
{
|
|
1833
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
1834
|
+
stroke: "currentColor",
|
|
1835
|
+
strokeWidth: "1.5",
|
|
1836
|
+
strokeLinecap: "round"
|
|
1837
|
+
}
|
|
1838
|
+
)
|
|
1839
|
+
}
|
|
1840
|
+
),
|
|
1841
|
+
"Remove"
|
|
1842
|
+
]
|
|
1843
|
+
}
|
|
1844
|
+
),
|
|
1845
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1846
|
+
"button",
|
|
1847
|
+
{
|
|
1848
|
+
type: "button",
|
|
1849
|
+
onClick: () => {
|
|
1850
|
+
var _a;
|
|
1851
|
+
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
1852
|
+
},
|
|
1853
|
+
style: {
|
|
1854
|
+
flex: 1,
|
|
1855
|
+
padding: "6px 0",
|
|
1856
|
+
borderRadius: "6px",
|
|
1857
|
+
border: `1px solid ${t.inputBorder}`,
|
|
1858
|
+
background: "transparent",
|
|
1859
|
+
color: t.textMuted,
|
|
1860
|
+
fontSize: "12px",
|
|
1861
|
+
fontWeight: 500,
|
|
1862
|
+
cursor: "pointer",
|
|
1863
|
+
fontFamily: "inherit",
|
|
1864
|
+
display: "flex",
|
|
1865
|
+
alignItems: "center",
|
|
1866
|
+
justifyContent: "center",
|
|
1867
|
+
gap: "4px"
|
|
1868
|
+
},
|
|
1869
|
+
children: [
|
|
1870
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1871
|
+
"svg",
|
|
1872
|
+
{
|
|
1873
|
+
width: "11",
|
|
1874
|
+
height: "11",
|
|
1875
|
+
viewBox: "0 0 24 24",
|
|
1876
|
+
fill: "none",
|
|
1877
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1878
|
+
"path",
|
|
1879
|
+
{
|
|
1880
|
+
d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12",
|
|
1881
|
+
stroke: "currentColor",
|
|
1882
|
+
strokeWidth: "2",
|
|
1883
|
+
strokeLinecap: "round",
|
|
1884
|
+
strokeLinejoin: "round"
|
|
1885
|
+
}
|
|
1886
|
+
)
|
|
1887
|
+
}
|
|
1888
|
+
),
|
|
1889
|
+
"Replace"
|
|
1890
|
+
]
|
|
1891
|
+
}
|
|
1892
|
+
)
|
|
1893
|
+
]
|
|
1894
|
+
}
|
|
1895
|
+
)
|
|
1134
1896
|
] }) : (
|
|
1135
1897
|
/* Drop zone */
|
|
1136
1898
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -1143,7 +1905,9 @@ function ReportDialog({
|
|
|
1143
1905
|
onDrop: (e) => {
|
|
1144
1906
|
e.preventDefault();
|
|
1145
1907
|
setScreenshotDragOver(false);
|
|
1146
|
-
const file = Array.from(
|
|
1908
|
+
const file = Array.from(
|
|
1909
|
+
e.dataTransfer.files
|
|
1910
|
+
).find((f) => f.type.startsWith("image/"));
|
|
1147
1911
|
if (!file) return;
|
|
1148
1912
|
const reader = new FileReader();
|
|
1149
1913
|
reader.onload = () => setScreenshot(reader.result);
|
|
@@ -1164,20 +1928,95 @@ function ReportDialog({
|
|
|
1164
1928
|
transition: "border-color 0.15s ease, background 0.15s ease"
|
|
1165
1929
|
},
|
|
1166
1930
|
children: [
|
|
1167
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1931
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1932
|
+
"svg",
|
|
1933
|
+
{
|
|
1934
|
+
width: "22",
|
|
1935
|
+
height: "22",
|
|
1936
|
+
viewBox: "0 0 24 24",
|
|
1937
|
+
fill: "none",
|
|
1938
|
+
style: {
|
|
1939
|
+
margin: "0 auto 6px",
|
|
1940
|
+
display: "block",
|
|
1941
|
+
opacity: 0.45
|
|
1942
|
+
},
|
|
1943
|
+
children: [
|
|
1944
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1945
|
+
"rect",
|
|
1946
|
+
{
|
|
1947
|
+
x: "3",
|
|
1948
|
+
y: "3",
|
|
1949
|
+
width: "18",
|
|
1950
|
+
height: "18",
|
|
1951
|
+
rx: "2",
|
|
1952
|
+
stroke: t.textMuted,
|
|
1953
|
+
strokeWidth: "1.5"
|
|
1954
|
+
}
|
|
1955
|
+
),
|
|
1956
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1957
|
+
"circle",
|
|
1958
|
+
{
|
|
1959
|
+
cx: "8.5",
|
|
1960
|
+
cy: "8.5",
|
|
1961
|
+
r: "1.5",
|
|
1962
|
+
stroke: t.textMuted,
|
|
1963
|
+
strokeWidth: "1.5"
|
|
1964
|
+
}
|
|
1965
|
+
),
|
|
1966
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1967
|
+
"path",
|
|
1968
|
+
{
|
|
1969
|
+
d: "M21 15l-5-5L5 21",
|
|
1970
|
+
stroke: t.textMuted,
|
|
1971
|
+
strokeWidth: "1.5",
|
|
1972
|
+
strokeLinecap: "round",
|
|
1973
|
+
strokeLinejoin: "round"
|
|
1974
|
+
}
|
|
1975
|
+
)
|
|
1976
|
+
]
|
|
1977
|
+
}
|
|
1978
|
+
),
|
|
1979
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1980
|
+
"p",
|
|
1981
|
+
{
|
|
1982
|
+
style: {
|
|
1983
|
+
margin: 0,
|
|
1984
|
+
fontSize: "12px",
|
|
1985
|
+
fontWeight: 600,
|
|
1986
|
+
color: t.text
|
|
1987
|
+
},
|
|
1988
|
+
children: screenshotDragOver ? "Drop to attach" : "Add a screenshot"
|
|
1989
|
+
}
|
|
1990
|
+
),
|
|
1991
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1992
|
+
"p",
|
|
1993
|
+
{
|
|
1994
|
+
style: {
|
|
1995
|
+
margin: "3px 0 0",
|
|
1996
|
+
fontSize: "11px",
|
|
1997
|
+
color: t.textMuted
|
|
1998
|
+
},
|
|
1999
|
+
children: "Drag & drop \xB7 Paste \u2318V / Ctrl+V \xB7 Click to browse"
|
|
2000
|
+
}
|
|
2001
|
+
)
|
|
1174
2002
|
]
|
|
1175
2003
|
}
|
|
1176
2004
|
)
|
|
1177
2005
|
)
|
|
1178
2006
|
] }),
|
|
1179
2007
|
showSeverity && reportType === "BUG" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "10px" }, children: [
|
|
1180
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2008
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2009
|
+
"span",
|
|
2010
|
+
{
|
|
2011
|
+
style: {
|
|
2012
|
+
fontSize: "12px",
|
|
2013
|
+
color: t.textMuted,
|
|
2014
|
+
marginBottom: "6px",
|
|
2015
|
+
display: "block"
|
|
2016
|
+
},
|
|
2017
|
+
children: "Severity"
|
|
2018
|
+
}
|
|
2019
|
+
),
|
|
1181
2020
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1182
2021
|
"button",
|
|
1183
2022
|
{
|
|
@@ -1202,114 +2041,34 @@ function ReportDialog({
|
|
|
1202
2041
|
s
|
|
1203
2042
|
)) })
|
|
1204
2043
|
] }),
|
|
1205
|
-
validationError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1206
|
-
|
|
1207
|
-
"button",
|
|
2044
|
+
validationError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2045
|
+
"p",
|
|
1208
2046
|
{
|
|
1209
|
-
type: "button",
|
|
1210
|
-
onClick: () => {
|
|
1211
|
-
const err = isLowQualityText(description);
|
|
1212
|
-
if (err) {
|
|
1213
|
-
setValidationError(err);
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
setValidationError(null);
|
|
1217
|
-
setStep(3);
|
|
1218
|
-
},
|
|
1219
|
-
disabled: !description.trim(),
|
|
1220
2047
|
style: {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
borderRadius: "8px",
|
|
1225
|
-
border: "none",
|
|
1226
|
-
backgroundColor: !description.trim() ? t.bgSecondary : t.accent,
|
|
1227
|
-
color: !description.trim() ? t.textMuted : t.accentText,
|
|
1228
|
-
fontSize: "14px",
|
|
1229
|
-
fontWeight: 600,
|
|
1230
|
-
cursor: !description.trim() ? "not-allowed" : "pointer",
|
|
1231
|
-
fontFamily: "inherit",
|
|
1232
|
-
transition: "background-color 0.15s ease"
|
|
2048
|
+
color: "#ef4444",
|
|
2049
|
+
fontSize: "12px",
|
|
2050
|
+
marginTop: "6px"
|
|
1233
2051
|
},
|
|
1234
|
-
children:
|
|
2052
|
+
children: validationError
|
|
1235
2053
|
}
|
|
1236
|
-
)
|
|
1237
|
-
] }),
|
|
1238
|
-
step === 3 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1239
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap", marginBottom: "12px" }, children: [
|
|
1240
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: {
|
|
1241
|
-
display: "inline-flex",
|
|
1242
|
-
alignItems: "center",
|
|
1243
|
-
gap: "4px",
|
|
1244
|
-
padding: "4px 10px",
|
|
1245
|
-
borderRadius: "12px",
|
|
1246
|
-
fontSize: "12px",
|
|
1247
|
-
fontWeight: 600,
|
|
1248
|
-
backgroundColor: t.bgSecondary,
|
|
1249
|
-
color: t.text,
|
|
1250
|
-
border: `1px solid ${t.border}`
|
|
1251
|
-
}, children: [
|
|
1252
|
-
getTypeIcon(reportType, t.accent, 12),
|
|
1253
|
-
getTypeLabel(reportType)
|
|
1254
|
-
] }),
|
|
1255
|
-
showSeverity && reportType === "BUG" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
|
|
1256
|
-
display: "inline-flex",
|
|
1257
|
-
alignItems: "center",
|
|
1258
|
-
padding: "4px 10px",
|
|
1259
|
-
borderRadius: "12px",
|
|
1260
|
-
fontSize: "12px",
|
|
1261
|
-
fontWeight: 600,
|
|
1262
|
-
backgroundColor: severity === "high" ? "#fef2f2" : severity === "medium" ? "#fffbeb" : "#f0fdf4",
|
|
1263
|
-
color: severity === "high" ? "#dc2626" : severity === "medium" ? "#d97706" : "#16a34a",
|
|
1264
|
-
border: `1px solid ${severity === "high" ? "#fecaca" : severity === "medium" ? "#fde68a" : "#bbf7d0"}`,
|
|
1265
|
-
textTransform: "capitalize"
|
|
1266
|
-
}, children: severity })
|
|
1267
|
-
] }),
|
|
1268
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
1269
|
-
padding: "10px 12px",
|
|
1270
|
-
borderRadius: "8px",
|
|
1271
|
-
border: `1px solid ${t.inputBorder}`,
|
|
1272
|
-
backgroundColor: t.inputBg,
|
|
1273
|
-
fontSize: "13px",
|
|
1274
|
-
color: t.text,
|
|
1275
|
-
marginBottom: "10px",
|
|
1276
|
-
maxHeight: "80px",
|
|
1277
|
-
overflow: "hidden",
|
|
1278
|
-
lineHeight: "1.4"
|
|
1279
|
-
}, children: description.length > 200 ? description.slice(0, 200) + "..." : description }),
|
|
1280
|
-
screenshot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: "10px", position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1281
|
-
"img",
|
|
1282
|
-
{
|
|
1283
|
-
src: screenshot,
|
|
1284
|
-
alt: "Page screenshot",
|
|
1285
|
-
onClick: () => setPreviewOpen(true),
|
|
1286
|
-
style: {
|
|
1287
|
-
width: "100%",
|
|
1288
|
-
borderRadius: "6px",
|
|
1289
|
-
border: `1px solid ${t.border}`,
|
|
1290
|
-
maxHeight: "80px",
|
|
1291
|
-
objectFit: "cover",
|
|
1292
|
-
objectPosition: "top",
|
|
1293
|
-
cursor: "pointer"
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
) }),
|
|
2054
|
+
),
|
|
1297
2055
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1298
2056
|
"button",
|
|
1299
2057
|
{
|
|
1300
2058
|
type: "button",
|
|
1301
2059
|
onClick: handleSubmit,
|
|
1302
|
-
disabled: isSubmitting,
|
|
2060
|
+
disabled: !description.trim() || isSubmitting,
|
|
1303
2061
|
style: {
|
|
2062
|
+
marginTop: "12px",
|
|
1304
2063
|
width: "100%",
|
|
1305
2064
|
padding: "10px",
|
|
1306
2065
|
borderRadius: "8px",
|
|
1307
2066
|
border: "none",
|
|
1308
|
-
backgroundColor: isSubmitting ? t.bgSecondary : t.accent,
|
|
1309
|
-
color: isSubmitting ? t.textMuted : t.accentText,
|
|
2067
|
+
backgroundColor: !description.trim() || isSubmitting ? t.bgSecondary : t.accent,
|
|
2068
|
+
color: !description.trim() || isSubmitting ? t.textMuted : t.accentText,
|
|
1310
2069
|
fontSize: "14px",
|
|
1311
2070
|
fontWeight: 600,
|
|
1312
|
-
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
2071
|
+
cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
|
|
1313
2072
|
fontFamily: "inherit",
|
|
1314
2073
|
transition: "background-color 0.15s ease"
|
|
1315
2074
|
},
|
|
@@ -1425,10 +2184,11 @@ function getTypeSubtitle(type) {
|
|
|
1425
2184
|
return "General feedback";
|
|
1426
2185
|
}
|
|
1427
2186
|
}
|
|
1428
|
-
function getPlaceholder(type) {
|
|
2187
|
+
function getPlaceholder(type, idx = 0, hasVoice = false) {
|
|
2188
|
+
if (hasVoice && idx === 1) return "Hold Space to speak \u2014 we'll transcribe it";
|
|
1429
2189
|
switch (type) {
|
|
1430
2190
|
case "BUG":
|
|
1431
|
-
return "What went wrong?";
|
|
2191
|
+
return "What went wrong? Describe it or paste an error...";
|
|
1432
2192
|
case "FEATURE_REQUEST":
|
|
1433
2193
|
return "Describe the feature you'd like...";
|
|
1434
2194
|
case "QUESTION":
|
|
@@ -1438,19 +2198,58 @@ function getPlaceholder(type) {
|
|
|
1438
2198
|
}
|
|
1439
2199
|
}
|
|
1440
2200
|
function getTypeIcon(type, color, size = 24) {
|
|
1441
|
-
const props = {
|
|
2201
|
+
const props = {
|
|
2202
|
+
width: size,
|
|
2203
|
+
height: size,
|
|
2204
|
+
viewBox: "0 0 24 24",
|
|
2205
|
+
fill: "none",
|
|
2206
|
+
style: { flexShrink: 0 }
|
|
2207
|
+
};
|
|
1442
2208
|
switch (type) {
|
|
1443
2209
|
case "BUG":
|
|
1444
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2210
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2211
|
+
"path",
|
|
2212
|
+
{
|
|
2213
|
+
d: "M8 2L6.5 3.5M16 2L17.5 3.5M3 9H7M17 9H21M12 2a5 5 0 015 5v4a5 5 0 01-10 0V7a5 5 0 015-5zM7 16l-2 3M17 16l2 3",
|
|
2214
|
+
stroke: color,
|
|
2215
|
+
strokeWidth: "1.5",
|
|
2216
|
+
strokeLinecap: "round"
|
|
2217
|
+
}
|
|
2218
|
+
) });
|
|
1445
2219
|
case "FEATURE_REQUEST":
|
|
1446
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2221
|
+
"path",
|
|
2222
|
+
{
|
|
2223
|
+
d: "M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2z",
|
|
2224
|
+
stroke: color,
|
|
2225
|
+
strokeWidth: "1.5",
|
|
2226
|
+
strokeLinejoin: "round"
|
|
2227
|
+
}
|
|
2228
|
+
) });
|
|
1447
2229
|
case "QUESTION":
|
|
1448
2230
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
1449
2231
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
|
|
1450
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2233
|
+
"path",
|
|
2234
|
+
{
|
|
2235
|
+
d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01",
|
|
2236
|
+
stroke: color,
|
|
2237
|
+
strokeWidth: "1.5",
|
|
2238
|
+
strokeLinecap: "round",
|
|
2239
|
+
strokeLinejoin: "round"
|
|
2240
|
+
}
|
|
2241
|
+
)
|
|
1451
2242
|
] });
|
|
1452
2243
|
case "OTHER":
|
|
1453
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2245
|
+
"path",
|
|
2246
|
+
{
|
|
2247
|
+
d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z",
|
|
2248
|
+
stroke: color,
|
|
2249
|
+
strokeWidth: "1.5",
|
|
2250
|
+
strokeLinejoin: "round"
|
|
2251
|
+
}
|
|
2252
|
+
) });
|
|
1454
2253
|
}
|
|
1455
2254
|
}
|
|
1456
2255
|
|
|
@@ -1672,15 +2471,31 @@ function GlitchgrabProviderInner({
|
|
|
1672
2471
|
[]
|
|
1673
2472
|
);
|
|
1674
2473
|
const enhance = (0, import_react2.useCallback)(
|
|
1675
|
-
async (text) => {
|
|
2474
|
+
async (text, screenshot) => {
|
|
1676
2475
|
try {
|
|
1677
|
-
|
|
2476
|
+
const ctx = captureContext(visitedPagesRef.current);
|
|
2477
|
+
const context = {
|
|
2478
|
+
url: ctx.url,
|
|
2479
|
+
visitedPages: ctx.visitedPages.slice(-5),
|
|
2480
|
+
breadcrumbs: ctx.breadcrumbs.slice(-10).map((b) => ({ type: b.type, message: b.message }))
|
|
2481
|
+
};
|
|
2482
|
+
return await enhanceText(text, token, baseUrl, screenshot, context);
|
|
1678
2483
|
} catch (e) {
|
|
1679
2484
|
return text;
|
|
1680
2485
|
}
|
|
1681
2486
|
},
|
|
1682
2487
|
[token, baseUrl]
|
|
1683
2488
|
);
|
|
2489
|
+
const transcribe = (0, import_react2.useCallback)(
|
|
2490
|
+
async (blob) => {
|
|
2491
|
+
try {
|
|
2492
|
+
return await transcribeAudio(blob, token, baseUrl);
|
|
2493
|
+
} catch (e) {
|
|
2494
|
+
return "";
|
|
2495
|
+
}
|
|
2496
|
+
},
|
|
2497
|
+
[token, baseUrl]
|
|
2498
|
+
);
|
|
1684
2499
|
const openReportDialog = (0, import_react2.useCallback)((options) => {
|
|
1685
2500
|
if (typeof window !== "undefined") {
|
|
1686
2501
|
window.dispatchEvent(new CustomEvent("glitchgrab:open-report", { detail: options }));
|
|
@@ -1725,7 +2540,7 @@ function GlitchgrabProviderInner({
|
|
|
1725
2540
|
children
|
|
1726
2541
|
}
|
|
1727
2542
|
),
|
|
1728
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReportDialog, { report, enhanceText: enhance, types, showSeverity })
|
|
2543
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReportDialog, { report, enhanceText: enhance, transcribeAudio: transcribe, types, showSeverity })
|
|
1729
2544
|
]
|
|
1730
2545
|
}
|
|
1731
2546
|
);
|