glitchgrab 1.27.0 → 1.29.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.mjs CHANGED
@@ -6,7 +6,8 @@ import {
6
6
  useContext,
7
7
  useRef as useRef3,
8
8
  useEffect as useEffect3,
9
- useCallback
9
+ useCallback,
10
+ useState as useState3
10
11
  } from "react";
11
12
 
12
13
  // src/error-boundary.tsx
@@ -738,6 +739,24 @@ function AnnotationCanvas({ imageSrc, onSave, onCancel }) {
738
739
  );
739
740
  }
740
741
 
742
+ // src/shortcut.ts
743
+ var GLITCHGRAB_SHORTCUT = "Ctrl+Shift+G";
744
+ var GLITCHGRAB_SHORTCUT_MAC = "\u2318\u21E7G";
745
+ function isMac() {
746
+ try {
747
+ if (typeof navigator === "undefined") return false;
748
+ return /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);
749
+ } catch (e) {
750
+ return false;
751
+ }
752
+ }
753
+ function getShortcutLabel() {
754
+ return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;
755
+ }
756
+ function matchesShortcut(e) {
757
+ return (e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "g";
758
+ }
759
+
741
760
  // src/report-dialog.tsx
742
761
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
743
762
  function useIsDark() {
@@ -1367,6 +1386,9 @@ function ReportDialog({
1367
1386
  zIndex: 2147483647,
1368
1387
  width: "340px",
1369
1388
  maxWidth: "calc(100% - 32px)",
1389
+ maxHeight: "calc(100dvh - 32px)",
1390
+ display: "flex",
1391
+ flexDirection: "column",
1370
1392
  backgroundColor: t.bg,
1371
1393
  borderRadius: "12px",
1372
1394
  boxShadow: "0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)",
@@ -1380,6 +1402,7 @@ function ReportDialog({
1380
1402
  "div",
1381
1403
  {
1382
1404
  style: {
1405
+ flexShrink: 0,
1383
1406
  padding: "16px 16px 12px",
1384
1407
  borderBottom: `1px solid ${t.border}`
1385
1408
  },
@@ -1447,6 +1470,24 @@ function ReportDialog({
1447
1470
  },
1448
1471
  children: step === 1 ? "What's on your mind?" : "Tell us more"
1449
1472
  }
1473
+ ),
1474
+ step === 1 && /* @__PURE__ */ jsx2(
1475
+ "span",
1476
+ {
1477
+ title: "Press this anywhere to open Glitchgrab",
1478
+ style: {
1479
+ fontSize: "10px",
1480
+ fontWeight: 600,
1481
+ lineHeight: 1,
1482
+ padding: "3px 6px",
1483
+ borderRadius: "4px",
1484
+ border: `1px solid ${t.inputBorder}`,
1485
+ background: t.inputBg,
1486
+ color: t.textMuted,
1487
+ whiteSpace: "nowrap"
1488
+ },
1489
+ children: getShortcutLabel()
1490
+ }
1450
1491
  )
1451
1492
  ]
1452
1493
  }
@@ -1537,824 +1578,835 @@ function ReportDialog({
1537
1578
  ]
1538
1579
  }
1539
1580
  ),
1540
- /* @__PURE__ */ jsx2("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ jsxs2(
1581
+ /* @__PURE__ */ jsx2(
1541
1582
  "div",
1542
1583
  {
1543
1584
  style: {
1544
- textAlign: "center",
1545
- padding: "20px 0",
1546
- color: t.accent,
1547
- fontSize: "14px",
1548
- fontWeight: 500
1585
+ padding: "16px",
1586
+ overflowY: "auto",
1587
+ flex: "1 1 auto",
1588
+ minHeight: 0
1549
1589
  },
1550
- children: [
1551
- getTypeLabel(reportType),
1552
- " sent. Thank you!"
1553
- ]
1554
- }
1555
- ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1556
- step === 1 && /* @__PURE__ */ jsx2(
1557
- "div",
1558
- {
1559
- style: {
1560
- display: "grid",
1561
- gridTemplateColumns: "1fr 1fr",
1562
- gap: "8px"
1563
- },
1564
- children: availableTypes.map((type) => /* @__PURE__ */ jsxs2(
1565
- "button",
1566
- {
1567
- type: "button",
1568
- onClick: () => {
1569
- setReportType(type);
1570
- setStep(2);
1571
- },
1572
- style: {
1573
- display: "flex",
1574
- flexDirection: "column",
1575
- alignItems: "center",
1576
- gap: "8px",
1577
- padding: "16px 8px",
1578
- borderRadius: "8px",
1579
- border: `1px solid ${t.inputBorder}`,
1580
- background: t.inputBg,
1581
- cursor: "pointer",
1582
- color: t.text,
1583
- fontFamily: "inherit",
1584
- transition: "border-color 0.15s ease"
1585
- },
1586
- onMouseEnter: (e) => {
1587
- e.currentTarget.style.borderColor = t.accent;
1588
- },
1589
- onMouseLeave: (e) => {
1590
- e.currentTarget.style.borderColor = t.inputBorder;
1591
- },
1592
- children: [
1593
- getTypeIcon(type, t.accent),
1594
- /* @__PURE__ */ jsx2("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
1595
- /* @__PURE__ */ jsx2(
1596
- "span",
1597
- {
1598
- style: {
1599
- fontSize: "11px",
1600
- color: t.textMuted,
1601
- lineHeight: "1.3"
1602
- },
1603
- children: getTypeSubtitle(type)
1604
- }
1605
- )
1606
- ]
1590
+ children: submitted ? /* @__PURE__ */ jsxs2(
1591
+ "div",
1592
+ {
1593
+ style: {
1594
+ textAlign: "center",
1595
+ padding: "20px 0",
1596
+ color: t.accent,
1597
+ fontSize: "14px",
1598
+ fontWeight: 500
1607
1599
  },
1608
- type
1609
- ))
1610
- }
1611
- ),
1612
- step === 2 && /* @__PURE__ */ jsxs2(Fragment, { children: [
1613
- /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1614
- /* @__PURE__ */ jsx2(
1615
- "textarea",
1616
- {
1617
- ref: textareaRef,
1618
- value: description,
1619
- onChange: (e) => {
1620
- setDescription(e.target.value);
1621
- if (validationError) setValidationError(null);
1622
- if (isEnhanced) {
1623
- setIsEnhanced(false);
1624
- setOriginalDescription(null);
1625
- }
1626
- },
1627
- placeholder: isTranscribing ? "Transcribing your speech\u2026" : isListening ? "Listening\u2026 speak now" : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio2),
1628
- style: {
1629
- width: "100%",
1630
- minHeight: "100px",
1631
- padding: enhanceText2 ? "28px 12px 36px" : transcribeAudio2 ? "10px 12px 36px" : "10px 12px",
1632
- borderRadius: "8px",
1633
- border: `1px solid ${isTranscribing ? "#f59e0b" : isListening ? t.accent : t.inputBorder}`,
1634
- fontSize: "14px",
1635
- fontFamily: "inherit",
1636
- resize: "none",
1637
- outline: "none",
1638
- boxSizing: "border-box",
1639
- color: t.text,
1640
- backgroundColor: t.inputBg,
1641
- transition: "border-color 0.2s ease"
1642
- },
1643
- onKeyDown: handleSpaceDown,
1644
- onKeyUp: handleSpaceUp,
1645
- onFocus: (e) => {
1646
- e.target.style.borderColor = t.accent;
1647
- },
1648
- onBlur: (e) => {
1649
- if (!isListening && !isTranscribing)
1650
- e.target.style.borderColor = t.inputBorder;
1651
- },
1652
- autoFocus: true
1653
- }
1654
- ),
1655
- (isListening || isTranscribing) && /* @__PURE__ */ jsxs2(
1656
- "span",
1600
+ children: [
1601
+ getTypeLabel(reportType),
1602
+ " sent. Thank you!"
1603
+ ]
1604
+ }
1605
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1606
+ step === 1 && /* @__PURE__ */ jsx2(
1607
+ "div",
1657
1608
  {
1658
1609
  style: {
1659
- position: "absolute",
1660
- bottom: "10px",
1661
- left: "10px",
1662
- display: "inline-flex",
1663
- alignItems: "center",
1664
- gap: "4px",
1665
- fontSize: "10px",
1666
- fontWeight: 700,
1667
- letterSpacing: "0.04em",
1668
- color: isTranscribing ? "#f59e0b" : "#ef4444",
1669
- pointerEvents: "none",
1670
- zIndex: 1
1610
+ display: "grid",
1611
+ gridTemplateColumns: "1fr 1fr",
1612
+ gap: "8px"
1671
1613
  },
1672
- children: [
1673
- /* @__PURE__ */ jsx2(
1674
- "span",
1675
- {
1676
- style: {
1677
- width: "6px",
1678
- height: "6px",
1679
- borderRadius: "50%",
1680
- backgroundColor: "currentColor",
1681
- animation: "gg-pulse 1.2s ease-in-out infinite",
1682
- display: "inline-block",
1683
- flexShrink: 0
1684
- }
1685
- }
1686
- ),
1687
- isTranscribing ? "Transcribing\u2026" : "REC",
1688
- isListening && !isTranscribing && /* @__PURE__ */ jsx2(
1689
- "span",
1690
- {
1691
- style: {
1692
- display: "inline-flex",
1693
- alignItems: "flex-end",
1694
- gap: "2px",
1695
- height: "14px",
1696
- marginLeft: "3px"
1697
- },
1698
- children: [
1699
- { anim: "gg-b1", dur: "0.6s", delay: "0s" },
1700
- {
1701
- anim: "gg-b2",
1702
- dur: "0.5s",
1703
- delay: "0.1s"
1704
- },
1705
- {
1706
- anim: "gg-b3",
1707
- dur: "0.7s",
1708
- delay: "0.05s"
1709
- },
1710
- {
1711
- anim: "gg-b4",
1712
- dur: "0.55s",
1713
- delay: "0.15s"
1714
- }
1715
- ].map((b, i) => /* @__PURE__ */ jsx2(
1614
+ children: availableTypes.map((type) => /* @__PURE__ */ jsxs2(
1615
+ "button",
1616
+ {
1617
+ type: "button",
1618
+ onClick: () => {
1619
+ setReportType(type);
1620
+ setStep(2);
1621
+ },
1622
+ style: {
1623
+ display: "flex",
1624
+ flexDirection: "column",
1625
+ alignItems: "center",
1626
+ gap: "8px",
1627
+ padding: "16px 8px",
1628
+ borderRadius: "8px",
1629
+ border: `1px solid ${t.inputBorder}`,
1630
+ background: t.inputBg,
1631
+ cursor: "pointer",
1632
+ color: t.text,
1633
+ fontFamily: "inherit",
1634
+ transition: "border-color 0.15s ease"
1635
+ },
1636
+ onMouseEnter: (e) => {
1637
+ e.currentTarget.style.borderColor = t.accent;
1638
+ },
1639
+ onMouseLeave: (e) => {
1640
+ e.currentTarget.style.borderColor = t.inputBorder;
1641
+ },
1642
+ children: [
1643
+ getTypeIcon(type, t.accent),
1644
+ /* @__PURE__ */ jsx2("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
1645
+ /* @__PURE__ */ jsx2(
1716
1646
  "span",
1717
1647
  {
1718
1648
  style: {
1719
- width: "2.5px",
1720
- height: "4px",
1721
- borderRadius: "1px",
1722
- backgroundColor: "#ef4444",
1723
- animation: `${b.anim} ${b.dur} ease-in-out ${b.delay} infinite`,
1724
- display: "inline-block",
1725
- alignSelf: "center"
1726
- }
1727
- },
1728
- i
1729
- ))
1730
- }
1731
- )
1732
- ]
1733
- }
1734
- ),
1735
- enhanceText2 && /* @__PURE__ */ jsxs2(
1736
- "button",
1737
- {
1738
- type: "button",
1739
- onClick: async () => {
1740
- var _a;
1741
- if (!description.trim() || isEnhancing) return;
1742
- setIsEnhancing(true);
1743
- try {
1744
- const polished = await enhanceText2(
1745
- description,
1746
- (_a = screenshots[0]) != null ? _a : null
1747
- );
1748
- if (polished && polished !== description) {
1749
- setOriginalDescription(description);
1750
- setDescription(polished);
1751
- setIsEnhanced(true);
1752
- if (validationError)
1753
- setValidationError(null);
1754
- }
1755
- } finally {
1756
- setIsEnhancing(false);
1757
- }
1758
- },
1759
- disabled: !description.trim() || isEnhancing || isEnhanced,
1760
- style: {
1761
- position: "absolute",
1762
- top: "6px",
1763
- right: "6px",
1764
- display: "inline-flex",
1765
- alignItems: "center",
1766
- gap: "4px",
1767
- background: t.inputBg,
1768
- border: "none",
1769
- padding: "2px 6px",
1770
- borderRadius: "4px",
1771
- fontFamily: "inherit",
1772
- fontSize: "11px",
1773
- color: t.textMuted,
1774
- cursor: !description.trim() || isEnhancing ? "default" : "pointer",
1775
- opacity: !description.trim() ? 0.5 : 1,
1776
- zIndex: 1
1777
- },
1778
- title: "Polish grammar \u2014 preserves your meaning",
1779
- children: [
1780
- /* @__PURE__ */ jsx2(
1781
- "svg",
1782
- {
1783
- width: "11",
1784
- height: "11",
1785
- viewBox: "0 0 24 24",
1786
- fill: "none",
1787
- "aria-hidden": "true",
1788
- children: /* @__PURE__ */ jsx2(
1789
- "path",
1790
- {
1791
- 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",
1792
- stroke: t.textMuted,
1793
- strokeWidth: "1.5",
1794
- strokeLinejoin: "round"
1649
+ fontSize: "11px",
1650
+ color: t.textMuted,
1651
+ lineHeight: "1.3"
1652
+ },
1653
+ children: getTypeSubtitle(type)
1795
1654
  }
1796
1655
  )
1797
- }
1798
- ),
1799
- isEnhancing ? "Enhancing..." : "AI enhance"
1800
- ]
1656
+ ]
1657
+ },
1658
+ type
1659
+ ))
1801
1660
  }
1802
1661
  ),
1803
- transcribeAudio2 && /* @__PURE__ */ jsx2(
1804
- "button",
1805
- {
1806
- type: "button",
1807
- onClick: () => {
1808
- void toggleVoice();
1809
- },
1810
- title: isListening ? "Stop recording" : "Speak your report",
1811
- style: {
1812
- position: "absolute",
1813
- bottom: "14px",
1814
- right: "7px",
1815
- width: "26px",
1816
- height: "26px",
1817
- display: "flex",
1818
- alignItems: "center",
1819
- justifyContent: "center",
1820
- background: "transparent",
1821
- border: `1.5px solid ${isListening ? "#ef4444" : t.inputBorder}`,
1822
- borderRadius: "6px",
1823
- color: isListening ? "#ef4444" : t.textMuted,
1824
- cursor: "pointer",
1825
- zIndex: 1,
1826
- padding: 0,
1827
- transition: "border-color 0.2s ease, color 0.2s ease"
1828
- },
1829
- children: isListening ? /* @__PURE__ */ jsx2(
1830
- "svg",
1662
+ step === 2 && /* @__PURE__ */ jsxs2(Fragment, { children: [
1663
+ /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1664
+ /* @__PURE__ */ jsx2(
1665
+ "textarea",
1831
1666
  {
1832
- width: "12",
1833
- height: "12",
1834
- viewBox: "0 0 24 24",
1835
- fill: "currentColor",
1836
- "aria-hidden": "true",
1837
- children: /* @__PURE__ */ jsx2(
1838
- "rect",
1839
- {
1840
- x: "6",
1841
- y: "6",
1842
- width: "12",
1843
- height: "12",
1844
- rx: "2"
1667
+ ref: textareaRef,
1668
+ value: description,
1669
+ onChange: (e) => {
1670
+ setDescription(e.target.value);
1671
+ if (validationError) setValidationError(null);
1672
+ if (isEnhanced) {
1673
+ setIsEnhanced(false);
1674
+ setOriginalDescription(null);
1845
1675
  }
1846
- )
1676
+ },
1677
+ placeholder: isTranscribing ? "Transcribing your speech\u2026" : isListening ? "Listening\u2026 speak now" : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio2),
1678
+ style: {
1679
+ width: "100%",
1680
+ minHeight: "100px",
1681
+ padding: enhanceText2 ? "28px 12px 36px" : transcribeAudio2 ? "10px 12px 36px" : "10px 12px",
1682
+ borderRadius: "8px",
1683
+ border: `1px solid ${isTranscribing ? "#f59e0b" : isListening ? t.accent : t.inputBorder}`,
1684
+ fontSize: "14px",
1685
+ fontFamily: "inherit",
1686
+ resize: "none",
1687
+ outline: "none",
1688
+ boxSizing: "border-box",
1689
+ color: t.text,
1690
+ backgroundColor: t.inputBg,
1691
+ transition: "border-color 0.2s ease"
1692
+ },
1693
+ onKeyDown: handleSpaceDown,
1694
+ onKeyUp: handleSpaceUp,
1695
+ onFocus: (e) => {
1696
+ e.target.style.borderColor = t.accent;
1697
+ },
1698
+ onBlur: (e) => {
1699
+ if (!isListening && !isTranscribing)
1700
+ e.target.style.borderColor = t.inputBorder;
1701
+ },
1702
+ autoFocus: true
1847
1703
  }
1848
- ) : /* @__PURE__ */ jsxs2(
1849
- "svg",
1704
+ ),
1705
+ (isListening || isTranscribing) && /* @__PURE__ */ jsxs2(
1706
+ "span",
1850
1707
  {
1851
- width: "13",
1852
- height: "13",
1853
- viewBox: "0 0 24 24",
1854
- fill: "none",
1855
- "aria-hidden": "true",
1708
+ style: {
1709
+ position: "absolute",
1710
+ bottom: "10px",
1711
+ left: "10px",
1712
+ display: "inline-flex",
1713
+ alignItems: "center",
1714
+ gap: "4px",
1715
+ fontSize: "10px",
1716
+ fontWeight: 700,
1717
+ letterSpacing: "0.04em",
1718
+ color: isTranscribing ? "#f59e0b" : "#ef4444",
1719
+ pointerEvents: "none",
1720
+ zIndex: 1
1721
+ },
1856
1722
  children: [
1857
1723
  /* @__PURE__ */ jsx2(
1858
- "rect",
1724
+ "span",
1859
1725
  {
1860
- x: "9",
1861
- y: "2",
1862
- width: "6",
1863
- height: "12",
1864
- rx: "3",
1865
- stroke: "currentColor",
1866
- strokeWidth: "1.8"
1726
+ style: {
1727
+ width: "6px",
1728
+ height: "6px",
1729
+ borderRadius: "50%",
1730
+ backgroundColor: "currentColor",
1731
+ animation: "gg-pulse 1.2s ease-in-out infinite",
1732
+ display: "inline-block",
1733
+ flexShrink: 0
1734
+ }
1867
1735
  }
1868
1736
  ),
1869
- /* @__PURE__ */ jsx2(
1870
- "path",
1737
+ isTranscribing ? "Transcribing\u2026" : "REC",
1738
+ isListening && !isTranscribing && /* @__PURE__ */ jsx2(
1739
+ "span",
1871
1740
  {
1872
- d: "M5 10a7 7 0 0014 0M12 19v3M9 22h6",
1873
- stroke: "currentColor",
1874
- strokeWidth: "1.8",
1875
- strokeLinecap: "round"
1741
+ style: {
1742
+ display: "inline-flex",
1743
+ alignItems: "flex-end",
1744
+ gap: "2px",
1745
+ height: "14px",
1746
+ marginLeft: "3px"
1747
+ },
1748
+ children: [
1749
+ { anim: "gg-b1", dur: "0.6s", delay: "0s" },
1750
+ {
1751
+ anim: "gg-b2",
1752
+ dur: "0.5s",
1753
+ delay: "0.1s"
1754
+ },
1755
+ {
1756
+ anim: "gg-b3",
1757
+ dur: "0.7s",
1758
+ delay: "0.05s"
1759
+ },
1760
+ {
1761
+ anim: "gg-b4",
1762
+ dur: "0.55s",
1763
+ delay: "0.15s"
1764
+ }
1765
+ ].map((b, i) => /* @__PURE__ */ jsx2(
1766
+ "span",
1767
+ {
1768
+ style: {
1769
+ width: "2.5px",
1770
+ height: "4px",
1771
+ borderRadius: "1px",
1772
+ backgroundColor: "#ef4444",
1773
+ animation: `${b.anim} ${b.dur} ease-in-out ${b.delay} infinite`,
1774
+ display: "inline-block",
1775
+ alignSelf: "center"
1776
+ }
1777
+ },
1778
+ i
1779
+ ))
1876
1780
  }
1877
1781
  )
1878
1782
  ]
1879
1783
  }
1880
- )
1881
- }
1882
- )
1883
- ] }),
1884
- transcribeAudio2 && !isListening && !isTranscribing && /* @__PURE__ */ jsxs2(
1885
- "div",
1886
- {
1887
- style: {
1888
- display: "flex",
1889
- alignItems: "center",
1890
- gap: "5px",
1891
- marginTop: "5px",
1892
- fontSize: "11px",
1893
- color: t.text,
1894
- opacity: 0.55,
1895
- userSelect: "none"
1896
- },
1897
- children: [
1898
- /* @__PURE__ */ jsxs2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1899
- /* @__PURE__ */ jsx2("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
1900
- /* @__PURE__ */ jsx2("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1901
- /* @__PURE__ */ jsx2("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
1902
- ] }),
1903
- "Hold Space to speak \u2014 we'll transcribe it"
1904
- ]
1905
- }
1906
- ),
1907
- isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs2(
1908
- "div",
1909
- {
1910
- style: {
1911
- display: "flex",
1912
- alignItems: "center",
1913
- gap: "6px",
1914
- marginTop: "6px",
1915
- padding: "6px 8px",
1916
- borderRadius: "6px",
1917
- background: isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.05)",
1918
- border: `1px solid ${t.accent}40`
1919
- },
1920
- children: [
1921
- /* @__PURE__ */ jsx2(
1922
- "svg",
1923
- {
1924
- width: "12",
1925
- height: "12",
1926
- viewBox: "0 0 24 24",
1927
- fill: "none",
1928
- style: { flexShrink: 0 },
1929
- children: /* @__PURE__ */ jsx2(
1930
- "path",
1931
- {
1932
- d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z",
1933
- stroke: t.accent,
1934
- strokeWidth: "1.5",
1935
- strokeLinejoin: "round"
1936
- }
1937
- )
1938
- }
1939
1784
  ),
1940
- /* @__PURE__ */ jsx2(
1941
- "span",
1942
- {
1943
- style: {
1944
- fontSize: "11px",
1945
- color: t.textMuted,
1946
- flex: 1
1947
- },
1948
- children: "AI enhanced"
1949
- }
1950
- ),
1951
- /* @__PURE__ */ jsx2(
1785
+ enhanceText2 && /* @__PURE__ */ jsxs2(
1952
1786
  "button",
1953
1787
  {
1954
1788
  type: "button",
1955
- onClick: () => {
1956
- setIsEnhanced(false);
1957
- setOriginalDescription(null);
1789
+ onClick: async () => {
1790
+ var _a;
1791
+ if (!description.trim() || isEnhancing) return;
1792
+ setIsEnhancing(true);
1793
+ try {
1794
+ const polished = await enhanceText2(
1795
+ description,
1796
+ (_a = screenshots[0]) != null ? _a : null
1797
+ );
1798
+ if (polished && polished !== description) {
1799
+ setOriginalDescription(description);
1800
+ setDescription(polished);
1801
+ setIsEnhanced(true);
1802
+ if (validationError)
1803
+ setValidationError(null);
1804
+ }
1805
+ } finally {
1806
+ setIsEnhancing(false);
1807
+ }
1958
1808
  },
1809
+ disabled: !description.trim() || isEnhancing || isEnhanced,
1959
1810
  style: {
1960
- padding: "2px 8px",
1811
+ position: "absolute",
1812
+ top: "6px",
1813
+ right: "6px",
1814
+ display: "inline-flex",
1815
+ alignItems: "center",
1816
+ gap: "4px",
1817
+ background: t.inputBg,
1818
+ border: "none",
1819
+ padding: "2px 6px",
1961
1820
  borderRadius: "4px",
1962
- border: `1px solid ${t.accent}`,
1963
- background: t.accent,
1964
- color: t.accentText,
1821
+ fontFamily: "inherit",
1965
1822
  fontSize: "11px",
1966
- fontWeight: 600,
1967
- cursor: "pointer",
1968
- fontFamily: "inherit"
1823
+ color: t.textMuted,
1824
+ cursor: !description.trim() || isEnhancing ? "default" : "pointer",
1825
+ opacity: !description.trim() ? 0.5 : 1,
1826
+ zIndex: 1
1969
1827
  },
1970
- children: "Keep"
1828
+ title: "Polish grammar \u2014 preserves your meaning",
1829
+ children: [
1830
+ /* @__PURE__ */ jsx2(
1831
+ "svg",
1832
+ {
1833
+ width: "11",
1834
+ height: "11",
1835
+ viewBox: "0 0 24 24",
1836
+ fill: "none",
1837
+ "aria-hidden": "true",
1838
+ children: /* @__PURE__ */ jsx2(
1839
+ "path",
1840
+ {
1841
+ 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",
1842
+ stroke: t.textMuted,
1843
+ strokeWidth: "1.5",
1844
+ strokeLinejoin: "round"
1845
+ }
1846
+ )
1847
+ }
1848
+ ),
1849
+ isEnhancing ? "Enhancing..." : "AI enhance"
1850
+ ]
1971
1851
  }
1972
1852
  ),
1973
- /* @__PURE__ */ jsx2(
1853
+ transcribeAudio2 && /* @__PURE__ */ jsx2(
1974
1854
  "button",
1975
1855
  {
1976
1856
  type: "button",
1977
1857
  onClick: () => {
1978
- setDescription(originalDescription);
1979
- setIsEnhanced(false);
1980
- setOriginalDescription(null);
1858
+ void toggleVoice();
1981
1859
  },
1860
+ title: isListening ? "Stop recording" : "Speak your report",
1982
1861
  style: {
1983
- padding: "2px 8px",
1984
- borderRadius: "4px",
1985
- border: `1px solid ${t.inputBorder}`,
1862
+ position: "absolute",
1863
+ bottom: "14px",
1864
+ right: "7px",
1865
+ width: "26px",
1866
+ height: "26px",
1867
+ display: "flex",
1868
+ alignItems: "center",
1869
+ justifyContent: "center",
1986
1870
  background: "transparent",
1987
- color: t.textMuted,
1988
- fontSize: "11px",
1989
- fontWeight: 600,
1871
+ border: `1.5px solid ${isListening ? "#ef4444" : t.inputBorder}`,
1872
+ borderRadius: "6px",
1873
+ color: isListening ? "#ef4444" : t.textMuted,
1990
1874
  cursor: "pointer",
1991
- fontFamily: "inherit"
1875
+ zIndex: 1,
1876
+ padding: 0,
1877
+ transition: "border-color 0.2s ease, color 0.2s ease"
1992
1878
  },
1993
- children: "Restore"
1879
+ children: isListening ? /* @__PURE__ */ jsx2(
1880
+ "svg",
1881
+ {
1882
+ width: "12",
1883
+ height: "12",
1884
+ viewBox: "0 0 24 24",
1885
+ fill: "currentColor",
1886
+ "aria-hidden": "true",
1887
+ children: /* @__PURE__ */ jsx2(
1888
+ "rect",
1889
+ {
1890
+ x: "6",
1891
+ y: "6",
1892
+ width: "12",
1893
+ height: "12",
1894
+ rx: "2"
1895
+ }
1896
+ )
1897
+ }
1898
+ ) : /* @__PURE__ */ jsxs2(
1899
+ "svg",
1900
+ {
1901
+ width: "13",
1902
+ height: "13",
1903
+ viewBox: "0 0 24 24",
1904
+ fill: "none",
1905
+ "aria-hidden": "true",
1906
+ children: [
1907
+ /* @__PURE__ */ jsx2(
1908
+ "rect",
1909
+ {
1910
+ x: "9",
1911
+ y: "2",
1912
+ width: "6",
1913
+ height: "12",
1914
+ rx: "3",
1915
+ stroke: "currentColor",
1916
+ strokeWidth: "1.8"
1917
+ }
1918
+ ),
1919
+ /* @__PURE__ */ jsx2(
1920
+ "path",
1921
+ {
1922
+ d: "M5 10a7 7 0 0014 0M12 19v3M9 22h6",
1923
+ stroke: "currentColor",
1924
+ strokeWidth: "1.8",
1925
+ strokeLinecap: "round"
1926
+ }
1927
+ )
1928
+ ]
1929
+ }
1930
+ )
1994
1931
  }
1995
1932
  )
1996
- ]
1997
- }
1998
- ),
1999
- voiceError && /* @__PURE__ */ jsx2(
2000
- "p",
2001
- {
2002
- style: {
2003
- color: "#ef4444",
2004
- fontSize: "11px",
2005
- marginTop: "4px",
2006
- marginBottom: 0
2007
- },
2008
- children: voiceError
2009
- }
2010
- ),
2011
- /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2012
- /* @__PURE__ */ jsxs2(
2013
- "span",
2014
- {
2015
- style: {
2016
- fontSize: "12px",
2017
- color: t.textMuted,
2018
- marginBottom: "6px",
2019
- display: "block",
2020
- fontWeight: 500
2021
- },
2022
- children: [
2023
- "Screenshots",
2024
- screenshots.length > 0 ? ` (${screenshots.length})` : ""
2025
- ]
2026
- }
2027
- ),
2028
- screenshots.length > 0 && /* @__PURE__ */ jsx2(
2029
- "div",
2030
- {
2031
- style: {
2032
- display: "flex",
2033
- flexWrap: "wrap",
2034
- gap: "8px",
2035
- marginBottom: "8px"
2036
- },
2037
- children: screenshots.map((src, i) => /* @__PURE__ */ jsxs2(
2038
- "div",
1933
+ ] }),
1934
+ transcribeAudio2 && !isListening && !isTranscribing && /* @__PURE__ */ jsxs2(
1935
+ "div",
1936
+ {
1937
+ style: {
1938
+ display: "flex",
1939
+ alignItems: "center",
1940
+ gap: "5px",
1941
+ marginTop: "5px",
1942
+ fontSize: "11px",
1943
+ color: t.text,
1944
+ opacity: 0.55,
1945
+ userSelect: "none"
1946
+ },
1947
+ children: [
1948
+ /* @__PURE__ */ jsxs2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1949
+ /* @__PURE__ */ jsx2("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
1950
+ /* @__PURE__ */ jsx2("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1951
+ /* @__PURE__ */ jsx2("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
1952
+ ] }),
1953
+ "Hold Space to speak \u2014 we'll transcribe it"
1954
+ ]
1955
+ }
1956
+ ),
1957
+ isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs2(
1958
+ "div",
1959
+ {
1960
+ style: {
1961
+ display: "flex",
1962
+ alignItems: "center",
1963
+ gap: "6px",
1964
+ marginTop: "6px",
1965
+ padding: "6px 8px",
1966
+ borderRadius: "6px",
1967
+ background: isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.05)",
1968
+ border: `1px solid ${t.accent}40`
1969
+ },
1970
+ children: [
1971
+ /* @__PURE__ */ jsx2(
1972
+ "svg",
1973
+ {
1974
+ width: "12",
1975
+ height: "12",
1976
+ viewBox: "0 0 24 24",
1977
+ fill: "none",
1978
+ style: { flexShrink: 0 },
1979
+ children: /* @__PURE__ */ jsx2(
1980
+ "path",
1981
+ {
1982
+ d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z",
1983
+ stroke: t.accent,
1984
+ strokeWidth: "1.5",
1985
+ strokeLinejoin: "round"
1986
+ }
1987
+ )
1988
+ }
1989
+ ),
1990
+ /* @__PURE__ */ jsx2(
1991
+ "span",
1992
+ {
1993
+ style: {
1994
+ fontSize: "11px",
1995
+ color: t.textMuted,
1996
+ flex: 1
1997
+ },
1998
+ children: "AI enhanced"
1999
+ }
2000
+ ),
2001
+ /* @__PURE__ */ jsx2(
2002
+ "button",
2003
+ {
2004
+ type: "button",
2005
+ onClick: () => {
2006
+ setIsEnhanced(false);
2007
+ setOriginalDescription(null);
2008
+ },
2009
+ style: {
2010
+ padding: "2px 8px",
2011
+ borderRadius: "4px",
2012
+ border: `1px solid ${t.accent}`,
2013
+ background: t.accent,
2014
+ color: t.accentText,
2015
+ fontSize: "11px",
2016
+ fontWeight: 600,
2017
+ cursor: "pointer",
2018
+ fontFamily: "inherit"
2019
+ },
2020
+ children: "Keep"
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ jsx2(
2024
+ "button",
2025
+ {
2026
+ type: "button",
2027
+ onClick: () => {
2028
+ setDescription(originalDescription);
2029
+ setIsEnhanced(false);
2030
+ setOriginalDescription(null);
2031
+ },
2032
+ style: {
2033
+ padding: "2px 8px",
2034
+ borderRadius: "4px",
2035
+ border: `1px solid ${t.inputBorder}`,
2036
+ background: "transparent",
2037
+ color: t.textMuted,
2038
+ fontSize: "11px",
2039
+ fontWeight: 600,
2040
+ cursor: "pointer",
2041
+ fontFamily: "inherit"
2042
+ },
2043
+ children: "Restore"
2044
+ }
2045
+ )
2046
+ ]
2047
+ }
2048
+ ),
2049
+ voiceError && /* @__PURE__ */ jsx2(
2050
+ "p",
2051
+ {
2052
+ style: {
2053
+ color: "#ef4444",
2054
+ fontSize: "11px",
2055
+ marginTop: "4px",
2056
+ marginBottom: 0
2057
+ },
2058
+ children: voiceError
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2062
+ /* @__PURE__ */ jsxs2(
2063
+ "span",
2039
2064
  {
2040
2065
  style: {
2041
- position: "relative",
2042
- width: "56px",
2043
- height: "56px"
2066
+ fontSize: "12px",
2067
+ color: t.textMuted,
2068
+ marginBottom: "6px",
2069
+ display: "block",
2070
+ fontWeight: 500
2044
2071
  },
2045
2072
  children: [
2046
- /* @__PURE__ */ jsx2(
2047
- "img",
2048
- {
2049
- src,
2050
- alt: `Screenshot ${i + 1}`,
2051
- onClick: () => setPreviewIndex(i),
2052
- style: {
2053
- width: "100%",
2054
- height: "100%",
2055
- borderRadius: "6px",
2056
- border: `1px solid ${t.border}`,
2057
- objectFit: "cover",
2058
- objectPosition: "top",
2059
- cursor: "zoom-in",
2060
- display: "block"
2061
- }
2062
- }
2063
- ),
2064
- /* @__PURE__ */ jsx2(
2065
- "button",
2066
- {
2067
- type: "button",
2068
- onClick: () => setScreenshots(
2069
- (prev) => prev.filter((_, idx) => idx !== i)
2073
+ "Screenshots",
2074
+ screenshots.length > 0 ? ` (${screenshots.length})` : ""
2075
+ ]
2076
+ }
2077
+ ),
2078
+ screenshots.length > 0 && /* @__PURE__ */ jsx2(
2079
+ "div",
2080
+ {
2081
+ style: {
2082
+ display: "flex",
2083
+ flexWrap: "wrap",
2084
+ gap: "8px",
2085
+ marginBottom: "8px"
2086
+ },
2087
+ children: screenshots.map((src, i) => /* @__PURE__ */ jsxs2(
2088
+ "div",
2089
+ {
2090
+ style: {
2091
+ position: "relative",
2092
+ width: "56px",
2093
+ height: "56px"
2094
+ },
2095
+ children: [
2096
+ /* @__PURE__ */ jsx2(
2097
+ "img",
2098
+ {
2099
+ src,
2100
+ alt: `Screenshot ${i + 1}`,
2101
+ onClick: () => setPreviewIndex(i),
2102
+ style: {
2103
+ width: "100%",
2104
+ height: "100%",
2105
+ borderRadius: "6px",
2106
+ border: `1px solid ${t.border}`,
2107
+ objectFit: "cover",
2108
+ objectPosition: "top",
2109
+ cursor: "zoom-in",
2110
+ display: "block"
2111
+ }
2112
+ }
2070
2113
  ),
2071
- "aria-label": `Remove screenshot ${i + 1}`,
2072
- style: {
2073
- position: "absolute",
2074
- top: "-6px",
2075
- right: "-6px",
2076
- width: "17px",
2077
- height: "17px",
2078
- borderRadius: "50%",
2079
- border: "none",
2080
- background: "#ef4444",
2081
- color: "#fff",
2082
- fontSize: "11px",
2083
- lineHeight: 1,
2084
- padding: 0,
2085
- cursor: "pointer",
2086
- display: "flex",
2087
- alignItems: "center",
2088
- justifyContent: "center"
2089
- },
2090
- children: /* @__PURE__ */ jsx2(
2091
- "svg",
2114
+ /* @__PURE__ */ jsx2(
2115
+ "button",
2092
2116
  {
2093
- width: "8",
2094
- height: "8",
2095
- viewBox: "0 0 10 10",
2096
- fill: "none",
2117
+ type: "button",
2118
+ onClick: () => setScreenshots(
2119
+ (prev) => prev.filter((_, idx) => idx !== i)
2120
+ ),
2121
+ "aria-label": `Remove screenshot ${i + 1}`,
2122
+ style: {
2123
+ position: "absolute",
2124
+ top: "-6px",
2125
+ right: "-6px",
2126
+ width: "17px",
2127
+ height: "17px",
2128
+ borderRadius: "50%",
2129
+ border: "none",
2130
+ background: "#ef4444",
2131
+ color: "#fff",
2132
+ fontSize: "11px",
2133
+ lineHeight: 1,
2134
+ padding: 0,
2135
+ cursor: "pointer",
2136
+ display: "flex",
2137
+ alignItems: "center",
2138
+ justifyContent: "center"
2139
+ },
2097
2140
  children: /* @__PURE__ */ jsx2(
2098
- "path",
2141
+ "svg",
2099
2142
  {
2100
- d: "M1 1L9 9M9 1L1 9",
2101
- stroke: "currentColor",
2102
- strokeWidth: "1.5",
2103
- strokeLinecap: "round"
2143
+ width: "8",
2144
+ height: "8",
2145
+ viewBox: "0 0 10 10",
2146
+ fill: "none",
2147
+ children: /* @__PURE__ */ jsx2(
2148
+ "path",
2149
+ {
2150
+ d: "M1 1L9 9M9 1L1 9",
2151
+ stroke: "currentColor",
2152
+ strokeWidth: "1.5",
2153
+ strokeLinecap: "round"
2154
+ }
2155
+ )
2104
2156
  }
2105
2157
  )
2106
2158
  }
2107
- )
2108
- }
2109
- ),
2110
- /* @__PURE__ */ jsx2(
2111
- "button",
2112
- {
2113
- type: "button",
2114
- onClick: () => setAnnotatingIndex(i),
2115
- "aria-label": `Annotate screenshot ${i + 1}`,
2116
- title: "Annotate",
2117
- style: {
2118
- position: "absolute",
2119
- top: "50%",
2120
- left: "50%",
2121
- transform: "translate(-50%, -50%)",
2122
- width: "24px",
2123
- height: "24px",
2124
- borderRadius: "50%",
2125
- border: "none",
2126
- background: t.accent,
2127
- color: t.accentText,
2128
- padding: 0,
2129
- cursor: "pointer",
2130
- display: "flex",
2131
- alignItems: "center",
2132
- justifyContent: "center",
2133
- boxShadow: "0 2px 8px rgba(0,0,0,0.45)"
2134
- },
2135
- children: /* @__PURE__ */ jsx2(
2136
- "svg",
2159
+ ),
2160
+ /* @__PURE__ */ jsx2(
2161
+ "button",
2137
2162
  {
2138
- width: "12",
2139
- height: "12",
2140
- viewBox: "0 0 24 24",
2141
- fill: "none",
2163
+ type: "button",
2164
+ onClick: () => setAnnotatingIndex(i),
2165
+ "aria-label": `Annotate screenshot ${i + 1}`,
2166
+ title: "Annotate",
2167
+ style: {
2168
+ position: "absolute",
2169
+ top: "50%",
2170
+ left: "50%",
2171
+ transform: "translate(-50%, -50%)",
2172
+ width: "24px",
2173
+ height: "24px",
2174
+ borderRadius: "50%",
2175
+ border: "none",
2176
+ background: t.accent,
2177
+ color: t.accentText,
2178
+ padding: 0,
2179
+ cursor: "pointer",
2180
+ display: "flex",
2181
+ alignItems: "center",
2182
+ justifyContent: "center",
2183
+ boxShadow: "0 2px 8px rgba(0,0,0,0.45)"
2184
+ },
2142
2185
  children: /* @__PURE__ */ jsx2(
2143
- "path",
2186
+ "svg",
2144
2187
  {
2145
- d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
2146
- stroke: "currentColor",
2147
- strokeWidth: "2.2",
2148
- strokeLinecap: "round",
2149
- strokeLinejoin: "round"
2188
+ width: "12",
2189
+ height: "12",
2190
+ viewBox: "0 0 24 24",
2191
+ fill: "none",
2192
+ children: /* @__PURE__ */ jsx2(
2193
+ "path",
2194
+ {
2195
+ d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
2196
+ stroke: "currentColor",
2197
+ strokeWidth: "2.2",
2198
+ strokeLinecap: "round",
2199
+ strokeLinejoin: "round"
2200
+ }
2201
+ )
2150
2202
  }
2151
2203
  )
2152
2204
  }
2153
2205
  )
2206
+ ]
2207
+ },
2208
+ i
2209
+ ))
2210
+ }
2211
+ ),
2212
+ /* @__PURE__ */ jsx2(
2213
+ "div",
2214
+ {
2215
+ onClick: () => {
2216
+ var _a;
2217
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
2218
+ },
2219
+ onDrop: (e) => {
2220
+ e.preventDefault();
2221
+ setScreenshotDragOver(false);
2222
+ const files = Array.from(
2223
+ e.dataTransfer.files
2224
+ ).filter((f) => f.type.startsWith("image/"));
2225
+ files.forEach((file) => {
2226
+ const reader = new FileReader();
2227
+ reader.onload = () => setScreenshots((prev) => [
2228
+ ...prev,
2229
+ reader.result
2230
+ ]);
2231
+ reader.readAsDataURL(file);
2232
+ });
2233
+ },
2234
+ onDragOver: (e) => {
2235
+ e.preventDefault();
2236
+ setScreenshotDragOver(true);
2237
+ },
2238
+ onDragLeave: () => setScreenshotDragOver(false),
2239
+ style: {
2240
+ border: `1.5px dashed ${screenshotDragOver ? t.accent : t.inputBorder}`,
2241
+ borderRadius: "8px",
2242
+ padding: screenshots.length > 0 ? "8px 12px" : "18px 12px",
2243
+ textAlign: "center",
2244
+ cursor: "pointer",
2245
+ background: screenshotDragOver ? isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.04)" : "transparent",
2246
+ transition: "border-color 0.15s ease, background 0.15s ease"
2247
+ },
2248
+ children: screenshots.length > 0 ? /* @__PURE__ */ jsx2(
2249
+ "p",
2250
+ {
2251
+ style: {
2252
+ margin: 0,
2253
+ fontSize: "11px",
2254
+ fontWeight: 500,
2255
+ color: t.textMuted
2256
+ },
2257
+ children: screenshotDragOver ? "Drop to attach" : "+ Add more \xB7 Drag & drop \xB7 Paste"
2258
+ }
2259
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
2260
+ /* @__PURE__ */ jsxs2(
2261
+ "svg",
2262
+ {
2263
+ width: "22",
2264
+ height: "22",
2265
+ viewBox: "0 0 24 24",
2266
+ fill: "none",
2267
+ style: {
2268
+ margin: "0 auto 6px",
2269
+ display: "block",
2270
+ opacity: 0.45
2271
+ },
2272
+ children: [
2273
+ /* @__PURE__ */ jsx2(
2274
+ "rect",
2275
+ {
2276
+ x: "3",
2277
+ y: "3",
2278
+ width: "18",
2279
+ height: "18",
2280
+ rx: "2",
2281
+ stroke: t.textMuted,
2282
+ strokeWidth: "1.5"
2283
+ }
2284
+ ),
2285
+ /* @__PURE__ */ jsx2(
2286
+ "circle",
2287
+ {
2288
+ cx: "8.5",
2289
+ cy: "8.5",
2290
+ r: "1.5",
2291
+ stroke: t.textMuted,
2292
+ strokeWidth: "1.5"
2293
+ }
2294
+ ),
2295
+ /* @__PURE__ */ jsx2(
2296
+ "path",
2297
+ {
2298
+ d: "M21 15l-5-5L5 21",
2299
+ stroke: t.textMuted,
2300
+ strokeWidth: "1.5",
2301
+ strokeLinecap: "round",
2302
+ strokeLinejoin: "round"
2303
+ }
2304
+ )
2305
+ ]
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsx2(
2309
+ "p",
2310
+ {
2311
+ style: {
2312
+ margin: 0,
2313
+ fontSize: "12px",
2314
+ fontWeight: 600,
2315
+ color: t.text
2316
+ },
2317
+ children: screenshotDragOver ? "Drop to attach" : "Add screenshots"
2318
+ }
2319
+ ),
2320
+ /* @__PURE__ */ jsx2(
2321
+ "p",
2322
+ {
2323
+ style: {
2324
+ margin: "3px 0 0",
2325
+ fontSize: "11px",
2326
+ color: t.textMuted
2327
+ },
2328
+ children: "Drag & drop \xB7 Paste \u2318V / Ctrl+V \xB7 Click to browse"
2154
2329
  }
2155
2330
  )
2156
- ]
2157
- },
2158
- i
2159
- ))
2160
- }
2161
- ),
2162
- /* @__PURE__ */ jsx2(
2163
- "div",
2164
- {
2165
- onClick: () => {
2166
- var _a;
2167
- return (_a = fileInputRef.current) == null ? void 0 : _a.click();
2168
- },
2169
- onDrop: (e) => {
2170
- e.preventDefault();
2171
- setScreenshotDragOver(false);
2172
- const files = Array.from(
2173
- e.dataTransfer.files
2174
- ).filter((f) => f.type.startsWith("image/"));
2175
- files.forEach((file) => {
2176
- const reader = new FileReader();
2177
- reader.onload = () => setScreenshots((prev) => [
2178
- ...prev,
2179
- reader.result
2180
- ]);
2181
- reader.readAsDataURL(file);
2182
- });
2183
- },
2184
- onDragOver: (e) => {
2185
- e.preventDefault();
2186
- setScreenshotDragOver(true);
2187
- },
2188
- onDragLeave: () => setScreenshotDragOver(false),
2189
- style: {
2190
- border: `1.5px dashed ${screenshotDragOver ? t.accent : t.inputBorder}`,
2191
- borderRadius: "8px",
2192
- padding: screenshots.length > 0 ? "8px 12px" : "18px 12px",
2193
- textAlign: "center",
2194
- cursor: "pointer",
2195
- background: screenshotDragOver ? isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.04)" : "transparent",
2196
- transition: "border-color 0.15s ease, background 0.15s ease"
2197
- },
2198
- children: screenshots.length > 0 ? /* @__PURE__ */ jsx2(
2199
- "p",
2331
+ ] })
2332
+ }
2333
+ )
2334
+ ] }),
2335
+ showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2336
+ /* @__PURE__ */ jsx2(
2337
+ "span",
2200
2338
  {
2201
2339
  style: {
2202
- margin: 0,
2203
- fontSize: "11px",
2204
- fontWeight: 500,
2205
- color: t.textMuted
2340
+ fontSize: "12px",
2341
+ color: t.textMuted,
2342
+ marginBottom: "6px",
2343
+ display: "block"
2206
2344
  },
2207
- children: screenshotDragOver ? "Drop to attach" : "+ Add more \xB7 Drag & drop \xB7 Paste"
2345
+ children: "Severity"
2208
2346
  }
2209
- ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
2210
- /* @__PURE__ */ jsxs2(
2211
- "svg",
2212
- {
2213
- width: "22",
2214
- height: "22",
2215
- viewBox: "0 0 24 24",
2216
- fill: "none",
2217
- style: {
2218
- margin: "0 auto 6px",
2219
- display: "block",
2220
- opacity: 0.45
2221
- },
2222
- children: [
2223
- /* @__PURE__ */ jsx2(
2224
- "rect",
2225
- {
2226
- x: "3",
2227
- y: "3",
2228
- width: "18",
2229
- height: "18",
2230
- rx: "2",
2231
- stroke: t.textMuted,
2232
- strokeWidth: "1.5"
2233
- }
2234
- ),
2235
- /* @__PURE__ */ jsx2(
2236
- "circle",
2237
- {
2238
- cx: "8.5",
2239
- cy: "8.5",
2240
- r: "1.5",
2241
- stroke: t.textMuted,
2242
- strokeWidth: "1.5"
2243
- }
2244
- ),
2245
- /* @__PURE__ */ jsx2(
2246
- "path",
2247
- {
2248
- d: "M21 15l-5-5L5 21",
2249
- stroke: t.textMuted,
2250
- strokeWidth: "1.5",
2251
- strokeLinecap: "round",
2252
- strokeLinejoin: "round"
2253
- }
2254
- )
2255
- ]
2256
- }
2257
- ),
2258
- /* @__PURE__ */ jsx2(
2259
- "p",
2260
- {
2261
- style: {
2262
- margin: 0,
2263
- fontSize: "12px",
2264
- fontWeight: 600,
2265
- color: t.text
2266
- },
2267
- children: screenshotDragOver ? "Drop to attach" : "Add screenshots"
2268
- }
2269
- ),
2270
- /* @__PURE__ */ jsx2(
2271
- "p",
2272
- {
2273
- style: {
2274
- margin: "3px 0 0",
2275
- fontSize: "11px",
2276
- color: t.textMuted
2277
- },
2278
- children: "Drag & drop \xB7 Paste \u2318V / Ctrl+V \xB7 Click to browse"
2279
- }
2280
- )
2281
- ] })
2282
- }
2283
- )
2284
- ] }),
2285
- showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2286
- /* @__PURE__ */ jsx2(
2287
- "span",
2288
- {
2289
- style: {
2290
- fontSize: "12px",
2291
- color: t.textMuted,
2292
- marginBottom: "6px",
2293
- display: "block"
2294
- },
2295
- children: "Severity"
2296
- }
2297
- ),
2298
- /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ jsx2(
2299
- "button",
2300
- {
2301
- type: "button",
2302
- onClick: () => setSeverity(s),
2303
- style: {
2304
- flex: 1,
2305
- padding: "6px 0",
2306
- borderRadius: "6px",
2307
- border: `1px solid ${severity === s ? t.accent : t.inputBorder}`,
2308
- background: severity === s ? t.accent : "transparent",
2309
- color: severity === s ? t.accentText : t.text,
2310
- fontSize: "12px",
2311
- fontWeight: 600,
2312
- cursor: "pointer",
2313
- fontFamily: "inherit",
2314
- textTransform: "capitalize",
2315
- transition: "all 0.15s ease"
2316
- },
2317
- children: s
2318
- },
2319
- s
2320
- )) })
2321
- ] }),
2322
- validationError && /* @__PURE__ */ jsx2(
2323
- "p",
2324
- {
2325
- style: {
2326
- color: "#ef4444",
2327
- fontSize: "12px",
2328
- marginTop: "6px"
2329
- },
2330
- children: validationError
2331
- }
2332
- ),
2333
- /* @__PURE__ */ jsx2(
2334
- "button",
2335
- {
2336
- type: "button",
2337
- onClick: handleSubmit,
2338
- disabled: !description.trim() || isSubmitting,
2339
- style: {
2340
- marginTop: "12px",
2341
- width: "100%",
2342
- padding: "10px",
2343
- borderRadius: "8px",
2344
- border: "none",
2345
- backgroundColor: !description.trim() || isSubmitting ? t.bgSecondary : t.accent,
2346
- color: !description.trim() || isSubmitting ? t.textMuted : t.accentText,
2347
- fontSize: "14px",
2348
- fontWeight: 600,
2349
- cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
2350
- fontFamily: "inherit",
2351
- transition: "background-color 0.15s ease"
2352
- },
2353
- children: isSubmitting ? "Sending..." : "Send Report"
2354
- }
2355
- )
2356
- ] })
2357
- ] }) }),
2347
+ ),
2348
+ /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ jsx2(
2349
+ "button",
2350
+ {
2351
+ type: "button",
2352
+ onClick: () => setSeverity(s),
2353
+ style: {
2354
+ flex: 1,
2355
+ padding: "6px 0",
2356
+ borderRadius: "6px",
2357
+ border: `1px solid ${severity === s ? t.accent : t.inputBorder}`,
2358
+ background: severity === s ? t.accent : "transparent",
2359
+ color: severity === s ? t.accentText : t.text,
2360
+ fontSize: "12px",
2361
+ fontWeight: 600,
2362
+ cursor: "pointer",
2363
+ fontFamily: "inherit",
2364
+ textTransform: "capitalize",
2365
+ transition: "all 0.15s ease"
2366
+ },
2367
+ children: s
2368
+ },
2369
+ s
2370
+ )) })
2371
+ ] }),
2372
+ validationError && /* @__PURE__ */ jsx2(
2373
+ "p",
2374
+ {
2375
+ style: {
2376
+ color: "#ef4444",
2377
+ fontSize: "12px",
2378
+ marginTop: "6px"
2379
+ },
2380
+ children: validationError
2381
+ }
2382
+ ),
2383
+ /* @__PURE__ */ jsx2(
2384
+ "button",
2385
+ {
2386
+ type: "button",
2387
+ onClick: handleSubmit,
2388
+ disabled: !description.trim() || isSubmitting,
2389
+ style: {
2390
+ marginTop: "12px",
2391
+ width: "100%",
2392
+ padding: "10px",
2393
+ borderRadius: "8px",
2394
+ border: "none",
2395
+ backgroundColor: !description.trim() || isSubmitting ? t.bgSecondary : t.accent,
2396
+ color: !description.trim() || isSubmitting ? t.textMuted : t.accentText,
2397
+ fontSize: "14px",
2398
+ fontWeight: 600,
2399
+ cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
2400
+ fontFamily: "inherit",
2401
+ transition: "background-color 0.15s ease"
2402
+ },
2403
+ children: isSubmitting ? "Sending..." : "Send Report"
2404
+ }
2405
+ )
2406
+ ] })
2407
+ ] })
2408
+ }
2409
+ ),
2358
2410
  /* @__PURE__ */ jsx2(
2359
2411
  "div",
2360
2412
  {
@@ -2942,7 +2994,7 @@ function GlitchgrabProviderInner({
2942
2994
  try {
2943
2995
  if (typeof window === "undefined") return;
2944
2996
  const handleKeyDown = (e) => {
2945
- if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "g") {
2997
+ if (matchesShortcut(e)) {
2946
2998
  e.preventDefault();
2947
2999
  openReportDialog();
2948
3000
  }
@@ -2952,6 +3004,10 @@ function GlitchgrabProviderInner({
2952
3004
  } catch (e) {
2953
3005
  }
2954
3006
  }, [openReportDialog]);
3007
+ const [shortcutLabel, setShortcutLabel] = useState3(GLITCHGRAB_SHORTCUT);
3008
+ useEffect3(() => {
3009
+ setShortcutLabel(getShortcutLabel());
3010
+ }, []);
2955
3011
  return /* @__PURE__ */ jsxs3(
2956
3012
  GlitchgrabContext.Provider,
2957
3013
  {
@@ -2962,7 +3018,8 @@ function GlitchgrabProviderInner({
2962
3018
  report,
2963
3019
  addBreadcrumb: addBreadcrumb2,
2964
3020
  openReportDialog,
2965
- enhanceText: enhance
3021
+ enhanceText: enhance,
3022
+ shortcutLabel
2966
3023
  },
2967
3024
  children: [
2968
3025
  /* @__PURE__ */ jsx3(
@@ -3193,6 +3250,8 @@ function useGlitchgrabActions({
3193
3250
  };
3194
3251
  }
3195
3252
  export {
3253
+ GLITCHGRAB_SHORTCUT,
3254
+ GLITCHGRAB_SHORTCUT_MAC,
3196
3255
  GlitchgrabErrorBoundary,
3197
3256
  GlitchgrabProvider,
3198
3257
  ReportButton,
@@ -3205,7 +3264,9 @@ export {
3205
3264
  enhanceText,
3206
3265
  fetchGlitchgrabReports,
3207
3266
  getBreadcrumbs,
3267
+ getShortcutLabel,
3208
3268
  initBreadcrumbs,
3269
+ matchesShortcut,
3209
3270
  sanitizeUrl,
3210
3271
  sendReport,
3211
3272
  shouldSkipDuplicate,