@taterboom/shiteki 0.1.0 → 0.1.2

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
@@ -1,5 +1,5 @@
1
1
  // src/components/ShitekiWidget.tsx
2
- import { useCallback as useCallback9, useEffect as useEffect7, useState as useState11 } from "react";
2
+ import { useCallback as useCallback9, useEffect as useEffect8, useState as useState12 } from "react";
3
3
  import ReactDOM from "react-dom";
4
4
  import { AnimatePresence as AnimatePresence3 } from "motion/react";
5
5
 
@@ -44,6 +44,13 @@ function useAnnotations() {
44
44
  });
45
45
  return annotation;
46
46
  }, []);
47
+ const update = useCallback((id, comment) => {
48
+ setAnnotations((prev) => {
49
+ const next = prev.map((a) => a.id === id ? { ...a, comment } : a);
50
+ writeStored(next, nextIdRef.current);
51
+ return next;
52
+ });
53
+ }, []);
47
54
  const remove = useCallback((id) => {
48
55
  setAnnotations((prev) => {
49
56
  const next = prev.filter((a) => a.id !== id);
@@ -56,7 +63,7 @@ function useAnnotations() {
56
63
  nextIdRef.current = 1;
57
64
  removeStored();
58
65
  }, []);
59
- return { annotations, add, remove, clear };
66
+ return { annotations, add, update, remove, clear };
60
67
  }
61
68
 
62
69
  // src/hooks/useConfig.ts
@@ -78,7 +85,8 @@ function merge(defaults, stored) {
78
85
  githubToken: stored.githubToken || defaults.githubToken,
79
86
  owner: stored.owner || defaults.owner,
80
87
  repo: stored.repo || defaults.repo,
81
- labels: stored.labels ?? defaults.labels
88
+ labels: stored.labels ?? defaults.labels,
89
+ clearAfterCopy: stored.clearAfterCopy ?? defaults.clearAfterCopy
82
90
  };
83
91
  }
84
92
  function useConfig(defaults) {
@@ -340,7 +348,7 @@ function useKeyboardShortcuts(opts) {
340
348
  if (key === "c" && opts.annotationCount > 0) {
341
349
  e.preventDefault();
342
350
  opts.onCopy();
343
- } else if (key === "s" && opts.annotationCount > 0) {
351
+ } else if (key === "s" && opts.annotationCount > 0 && opts.canSend) {
344
352
  e.preventDefault();
345
353
  opts.onSend();
346
354
  } else if (key === "d" && opts.annotationCount > 0) {
@@ -360,6 +368,7 @@ function useKeyboardShortcuts(opts) {
360
368
  opts.open,
361
369
  opts.mode,
362
370
  opts.annotationCount,
371
+ opts.canSend,
363
372
  opts.settingsOpen,
364
373
  opts.sendDialogOpen,
365
374
  opts.onCopy,
@@ -406,13 +415,13 @@ function generatePrompt(annotations) {
406
415
  `**Annotations:** ${annotations.length}`,
407
416
  `**Captured:** ${now}`
408
417
  ];
409
- for (const ann of annotations) {
418
+ annotations.forEach((ann, i) => {
410
419
  const { elementInfo: el } = ann;
411
420
  lines.push(
412
421
  "",
413
422
  "---",
414
423
  "",
415
- `## Annotation #${ann.id}`,
424
+ `## Annotation #${i + 1}`,
416
425
  "",
417
426
  "**What should change:**",
418
427
  `> ${ann.comment}`,
@@ -426,7 +435,7 @@ function generatePrompt(annotations) {
426
435
  if (attrEntries.length > 0) {
427
436
  lines.push(`- Attributes: ${attrEntries.map(([k, v]) => `\`${k}="${v}"\``).join(", ")}`);
428
437
  }
429
- }
438
+ });
430
439
  lines.push("");
431
440
  return lines.join("\n");
432
441
  }
@@ -444,6 +453,7 @@ function Toolbar({
444
453
  annotationCount,
445
454
  copied,
446
455
  sending,
456
+ canSend,
447
457
  settingsOpen,
448
458
  onOpen,
449
459
  onCopy,
@@ -514,25 +524,25 @@ function Toolbar({
514
524
  transition: spring,
515
525
  style: { overflow: "hidden", display: "flex", alignItems: "center", gap: 4 },
516
526
  children: [
517
- annotationCount > 0 && /* @__PURE__ */ jsx("div", { className: "shiteki-toolbar-sep" }),
518
- annotationCount > 0 && /* @__PURE__ */ jsx("button", { className: "shiteki-toolbar-btn", onClick: onCopy, title: "Copy to clipboard", children: copied ? /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
527
+ /* @__PURE__ */ jsx("div", { className: "shiteki-toolbar-sep" }),
528
+ /* @__PURE__ */ jsx("button", { className: "shiteki-toolbar-btn", onClick: onCopy, disabled: annotationCount === 0, title: "Copy to clipboard", children: copied ? /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
519
529
  /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
520
530
  /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
521
531
  ] }) }),
522
- annotationCount > 0 && /* @__PURE__ */ jsx(
532
+ /* @__PURE__ */ jsx(
523
533
  "button",
524
534
  {
525
535
  className: "shiteki-toolbar-btn",
526
- onClick: onSend,
527
- disabled: sending,
528
- title: "Send as GitHub Issue",
536
+ onClick: canSend ? onSend : onSettings,
537
+ disabled: sending || annotationCount === 0,
538
+ title: canSend ? "Send as GitHub Issue" : "Configure settings to enable send",
529
539
  children: /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
530
540
  /* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
531
541
  /* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
532
542
  ] })
533
543
  }
534
544
  ),
535
- annotationCount > 0 && /* @__PURE__ */ jsx("button", { className: "shiteki-toolbar-btn", onClick: onClear, title: "Clear all annotations", children: /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
545
+ /* @__PURE__ */ jsx("button", { className: "shiteki-toolbar-btn", onClick: onClear, disabled: annotationCount === 0, title: "Clear all annotations", children: /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
536
546
  /* @__PURE__ */ jsx("polyline", { points: "3 6 5 6 21 6" }),
537
547
  /* @__PURE__ */ jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
538
548
  ] }) }),
@@ -566,20 +576,35 @@ function Toolbar({
566
576
  exit: { opacity: 0, y: 4 },
567
577
  transition: { duration: 0.15 },
568
578
  children: [
569
- /* @__PURE__ */ jsxs("span", { children: [
570
- /* @__PURE__ */ jsx("kbd", { children: "X" }),
571
- " Toggle",
572
- /* @__PURE__ */ jsx("kbd", { children: "C" }),
573
- " Copy",
574
- /* @__PURE__ */ jsx("kbd", { children: "S" }),
575
- " Send",
576
- /* @__PURE__ */ jsx("kbd", { children: "DD" }),
577
- " Clear"
578
- ] }),
579
579
  /* @__PURE__ */ jsx("button", { className: "shiteki-shortcut-hint-close", onClick: onDismissHint, "aria-label": "Dismiss", children: /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
580
580
  /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
581
581
  /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
582
- ] }) })
582
+ ] }) }),
583
+ /* @__PURE__ */ jsxs("div", { className: "shiteki-shortcut-hint-list", children: [
584
+ /* @__PURE__ */ jsxs("span", { children: [
585
+ /* @__PURE__ */ jsx("kbd", { children: "X" }),
586
+ " Toggle"
587
+ ] }),
588
+ /* @__PURE__ */ jsxs("span", { children: [
589
+ /* @__PURE__ */ jsx("kbd", { children: "C" }),
590
+ " Copy"
591
+ ] }),
592
+ /* @__PURE__ */ jsxs("span", { children: [
593
+ /* @__PURE__ */ jsx("kbd", { children: "S" }),
594
+ " Send"
595
+ ] }),
596
+ /* @__PURE__ */ jsxs("span", { children: [
597
+ /* @__PURE__ */ jsx("kbd", { children: "DD" }),
598
+ " Clear"
599
+ ] }),
600
+ /* @__PURE__ */ jsxs("span", { children: [
601
+ /* @__PURE__ */ jsxs("kbd", { children: [
602
+ navigator.userAgent.includes("Mac") ? "\u2318" : "Ctrl",
603
+ "+Click"
604
+ ] }),
605
+ " Remove"
606
+ ] })
607
+ ] })
583
608
  ]
584
609
  },
585
610
  "hint"
@@ -699,23 +724,123 @@ function AnnotationPopover({ elementInfo, onAdd, onCancel }) {
699
724
  );
700
725
  }
701
726
 
727
+ // src/components/AnnotationDetailPopover.tsx
728
+ import { useEffect as useEffect4, useRef as useRef6, useState as useState8 } from "react";
729
+ import { motion as motion3 } from "motion/react";
730
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
731
+ function AnnotationDetailPopover({ annotation, index, onUpdate, onRemove, onClose }) {
732
+ const [comment, setComment] = useState8(annotation.comment);
733
+ const textareaRef = useRef6(null);
734
+ const [dragOffset, setDragOffset] = useState8({ x: 0, y: 0 });
735
+ const dragRef = useRef6(null);
736
+ useEffect4(() => {
737
+ textareaRef.current?.focus();
738
+ }, []);
739
+ const { rect } = annotation.elementInfo;
740
+ const spaceBelow = window.innerHeight - (rect.top + rect.height);
741
+ const above = spaceBelow < 250;
742
+ const top = above ? rect.top - 180 : rect.top + rect.height + 8;
743
+ let left = rect.left + rect.width / 2 - 160;
744
+ left = Math.max(12, Math.min(left, window.innerWidth - 332));
745
+ const yOffset = above ? -8 : 8;
746
+ const handlePointerDown = (e) => {
747
+ dragRef.current = { startX: e.clientX, startY: e.clientY, origX: dragOffset.x, origY: dragOffset.y };
748
+ e.target.setPointerCapture(e.pointerId);
749
+ };
750
+ const handlePointerMove = (e) => {
751
+ if (!dragRef.current) return;
752
+ setDragOffset({
753
+ x: dragRef.current.origX + e.clientX - dragRef.current.startX,
754
+ y: dragRef.current.origY + e.clientY - dragRef.current.startY
755
+ });
756
+ };
757
+ const handlePointerUp = () => {
758
+ dragRef.current = null;
759
+ };
760
+ const handleSubmit = (e) => {
761
+ e.preventDefault();
762
+ if (!comment.trim()) return;
763
+ onUpdate(comment.trim());
764
+ };
765
+ return /* @__PURE__ */ jsxs3(
766
+ motion3.div,
767
+ {
768
+ className: "shiteki-popover",
769
+ style: { top: top + dragOffset.y, left: left + dragOffset.x, transformOrigin: above ? "bottom center" : "top center" },
770
+ initial: { opacity: 0, scale: 0.95, y: yOffset },
771
+ animate: { opacity: 1, scale: 1, y: 0 },
772
+ exit: { opacity: 0, scale: 0.95, y: yOffset },
773
+ transition: spring,
774
+ children: [
775
+ /* @__PURE__ */ jsxs3(
776
+ "div",
777
+ {
778
+ className: "shiteki-popover-info",
779
+ style: { cursor: "grab" },
780
+ onPointerDown: handlePointerDown,
781
+ onPointerMove: handlePointerMove,
782
+ onPointerUp: handlePointerUp,
783
+ children: [
784
+ /* @__PURE__ */ jsxs3("span", { className: "shiteki-popover-tag", children: [
785
+ "#",
786
+ index,
787
+ " <",
788
+ annotation.elementInfo.tagName,
789
+ ">"
790
+ ] }),
791
+ annotation.elementInfo.textContent && /* @__PURE__ */ jsxs3("span", { className: "shiteki-popover-text", children: [
792
+ '"',
793
+ annotation.elementInfo.textContent,
794
+ '"'
795
+ ] })
796
+ ]
797
+ }
798
+ ),
799
+ /* @__PURE__ */ jsxs3("form", { className: "shiteki-popover-form", onSubmit: handleSubmit, children: [
800
+ /* @__PURE__ */ jsx4(
801
+ "textarea",
802
+ {
803
+ ref: textareaRef,
804
+ className: "shiteki-popover-textarea",
805
+ placeholder: "What should change?",
806
+ value: comment,
807
+ onChange: (e) => setComment(e.target.value),
808
+ rows: 3
809
+ }
810
+ ),
811
+ /* @__PURE__ */ jsxs3("div", { className: "shiteki-popover-actions", children: [
812
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "shiteki-btn shiteki-btn--danger shiteki-btn--icon", onClick: onRemove, title: "Remove annotation", children: /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
813
+ /* @__PURE__ */ jsx4("polyline", { points: "3 6 5 6 21 6" }),
814
+ /* @__PURE__ */ jsx4("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
815
+ ] }) }),
816
+ /* @__PURE__ */ jsx4("div", { style: { flex: 1 } }),
817
+ /* @__PURE__ */ jsx4("button", { type: "button", className: "shiteki-btn shiteki-btn--ghost", onClick: onClose, children: "Cancel" }),
818
+ /* @__PURE__ */ jsx4("button", { type: "submit", className: "shiteki-btn shiteki-btn--primary", disabled: !comment.trim(), children: "Save" })
819
+ ] })
820
+ ] })
821
+ ]
822
+ }
823
+ );
824
+ }
825
+
702
826
  // src/components/AnnotationMarkers.tsx
703
827
  import { AnimatePresence as AnimatePresence2 } from "motion/react";
704
828
 
705
829
  // src/hooks/useMarkerPositions.ts
706
- import { useEffect as useEffect4, useState as useState8 } from "react";
830
+ import { useEffect as useEffect5, useState as useState9 } from "react";
707
831
  function useMarkerPositions(annotations) {
708
- const [positions, setPositions] = useState8([]);
709
- useEffect4(() => {
832
+ const [positions, setPositions] = useState9([]);
833
+ useEffect5(() => {
710
834
  function update() {
711
- const newPositions = annotations.map((ann) => {
835
+ const newPositions = annotations.map((ann, i) => {
836
+ const index = i + 1;
712
837
  const el = document.querySelector(ann.elementInfo.selector);
713
838
  if (el) {
714
839
  const rect = el.getBoundingClientRect();
715
- return { id: ann.id, top: rect.top, left: rect.left + rect.width };
840
+ return { id: ann.id, index, top: rect.top, left: rect.left + rect.width };
716
841
  }
717
842
  const r = ann.elementInfo.rect;
718
- return { id: ann.id, top: r.top, left: r.left + r.width };
843
+ return { id: ann.id, index, top: r.top, left: r.left + r.width };
719
844
  });
720
845
  setPositions(newPositions);
721
846
  }
@@ -731,56 +856,57 @@ function useMarkerPositions(annotations) {
731
856
  }
732
857
 
733
858
  // src/components/AnnotationMarker.tsx
734
- import { motion as motion3 } from "motion/react";
735
- import { jsx as jsx4 } from "react/jsx-runtime";
736
- function AnnotationMarker({ id, top, left, onRemove }) {
737
- return /* @__PURE__ */ jsx4(
738
- motion3.div,
859
+ import { motion as motion4 } from "motion/react";
860
+ import { jsx as jsx5 } from "react/jsx-runtime";
861
+ function AnnotationMarker({ id, index, top, left, onClick }) {
862
+ return /* @__PURE__ */ jsx5(
863
+ motion4.div,
739
864
  {
740
865
  className: "shiteki-marker",
741
866
  style: { top: top - 10, left: left - 10 },
742
- title: `Annotation #${id} (click to remove)`,
743
- onClick: () => onRemove(id),
867
+ title: `#${index} \u2014 click to view, ${navigator.userAgent.includes("Mac") ? "\u2318" : "Ctrl"}+click to remove`,
868
+ onClick: (e) => onClick(id, e),
744
869
  initial: { opacity: 0, scale: 0 },
745
870
  animate: { opacity: 1, scale: 1 },
746
871
  exit: { opacity: 0, scale: 0 },
747
872
  transition: spring,
748
873
  whileHover: { scale: 1.25 },
749
- children: id
874
+ children: index
750
875
  }
751
876
  );
752
877
  }
753
878
 
754
879
  // src/components/AnnotationMarkers.tsx
755
- import { jsx as jsx5 } from "react/jsx-runtime";
756
- function AnnotationMarkers({ annotations, onRemove }) {
880
+ import { jsx as jsx6 } from "react/jsx-runtime";
881
+ function AnnotationMarkers({ annotations, onClick }) {
757
882
  const positions = useMarkerPositions(annotations);
758
- return /* @__PURE__ */ jsx5(AnimatePresence2, { children: positions.map((pos) => /* @__PURE__ */ jsx5(
883
+ return /* @__PURE__ */ jsx6(AnimatePresence2, { children: positions.map((pos) => /* @__PURE__ */ jsx6(
759
884
  AnnotationMarker,
760
885
  {
761
886
  id: pos.id,
887
+ index: pos.index,
762
888
  top: pos.top,
763
889
  left: pos.left,
764
- onRemove
890
+ onClick
765
891
  },
766
892
  pos.id
767
893
  )) });
768
894
  }
769
895
 
770
896
  // src/components/StatusMessage.tsx
771
- import { useEffect as useEffect5 } from "react";
772
- import { motion as motion4 } from "motion/react";
773
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
897
+ import { useEffect as useEffect6 } from "react";
898
+ import { motion as motion5 } from "motion/react";
899
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
774
900
  function StatusMessage({ state, onDismiss }) {
775
- useEffect5(() => {
901
+ useEffect6(() => {
776
902
  if (state.status === "success" || state.status === "error") {
777
903
  const timer = setTimeout(onDismiss, 4e3);
778
904
  return () => clearTimeout(timer);
779
905
  }
780
906
  }, [state.status, onDismiss]);
781
907
  if (state.status === "success") {
782
- return /* @__PURE__ */ jsxs3(
783
- motion4.div,
908
+ return /* @__PURE__ */ jsxs4(
909
+ motion5.div,
784
910
  {
785
911
  className: "shiteki-status shiteki-status--success",
786
912
  initial: { opacity: 0, y: 12, scale: 0.95 },
@@ -790,7 +916,7 @@ function StatusMessage({ state, onDismiss }) {
790
916
  children: [
791
917
  "Issue created!",
792
918
  " ",
793
- /* @__PURE__ */ jsxs3("a", { href: state.result.issueUrl, target: "_blank", rel: "noopener noreferrer", children: [
919
+ /* @__PURE__ */ jsxs4("a", { href: state.result.issueUrl, target: "_blank", rel: "noopener noreferrer", children: [
794
920
  "#",
795
921
  state.result.issueNumber
796
922
  ] })
@@ -799,8 +925,8 @@ function StatusMessage({ state, onDismiss }) {
799
925
  );
800
926
  }
801
927
  if (state.status === "error") {
802
- return /* @__PURE__ */ jsx6(
803
- motion4.div,
928
+ return /* @__PURE__ */ jsx7(
929
+ motion5.div,
804
930
  {
805
931
  className: "shiteki-status shiteki-status--error",
806
932
  initial: { opacity: 0, y: 12, scale: 0.95 },
@@ -812,8 +938,8 @@ function StatusMessage({ state, onDismiss }) {
812
938
  );
813
939
  }
814
940
  if (state.status === "loading") {
815
- return /* @__PURE__ */ jsx6(
816
- motion4.div,
941
+ return /* @__PURE__ */ jsx7(
942
+ motion5.div,
817
943
  {
818
944
  className: "shiteki-status",
819
945
  initial: { opacity: 0, y: 12, scale: 0.95 },
@@ -828,16 +954,45 @@ function StatusMessage({ state, onDismiss }) {
828
954
  }
829
955
 
830
956
  // src/components/SettingsPanel.tsx
831
- import { useCallback as useCallback7, useState as useState9 } from "react";
832
- import { motion as motion5 } from "motion/react";
833
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
957
+ import { useCallback as useCallback7, useState as useState10 } from "react";
958
+ import { motion as motion6 } from "motion/react";
959
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
960
+ function HelpLink({ href }) {
961
+ return /* @__PURE__ */ jsx8(
962
+ "a",
963
+ {
964
+ className: "shiteki-settings-help",
965
+ href,
966
+ target: "_blank",
967
+ rel: "noopener noreferrer",
968
+ onClick: (e) => e.stopPropagation(),
969
+ children: /* @__PURE__ */ jsxs5("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
970
+ /* @__PURE__ */ jsx8("circle", { cx: "8", cy: "8", r: "7", stroke: "currentColor", strokeWidth: "1.5" }),
971
+ /* @__PURE__ */ jsx8(
972
+ "text",
973
+ {
974
+ x: "8",
975
+ y: "11.5",
976
+ textAnchor: "middle",
977
+ fill: "currentColor",
978
+ fontSize: "10",
979
+ fontWeight: "600",
980
+ fontFamily: "inherit",
981
+ children: "?"
982
+ }
983
+ )
984
+ ] })
985
+ }
986
+ );
987
+ }
834
988
  function SettingsPanel({ config, onSave, onCancel }) {
835
- const [mode, setMode] = useState9(config.mode);
836
- const [endpoint, setEndpoint] = useState9(config.endpoint);
837
- const [githubToken, setGithubToken] = useState9(config.githubToken);
838
- const [owner, setOwner] = useState9(config.owner);
839
- const [repo, setRepo] = useState9(config.repo);
840
- const [labels, setLabels] = useState9((config.labels ?? []).join(", "));
989
+ const [mode, setMode] = useState10(config.mode);
990
+ const [endpoint, setEndpoint] = useState10(config.endpoint);
991
+ const [githubToken, setGithubToken] = useState10(config.githubToken);
992
+ const [owner, setOwner] = useState10(config.owner);
993
+ const [repo, setRepo] = useState10(config.repo);
994
+ const [labels, setLabels] = useState10((config.labels ?? []).join(", "));
995
+ const [clearAfterCopy, setClearAfterCopy] = useState10(config.clearAfterCopy ?? false);
841
996
  const handleSave = useCallback7(() => {
842
997
  onSave({
843
998
  mode,
@@ -845,11 +1000,12 @@ function SettingsPanel({ config, onSave, onCancel }) {
845
1000
  githubToken: githubToken.trim(),
846
1001
  owner: owner.trim(),
847
1002
  repo: repo.trim(),
848
- labels: labels.split(",").map((l) => l.trim()).filter(Boolean)
1003
+ labels: labels.split(",").map((l) => l.trim()).filter(Boolean),
1004
+ clearAfterCopy
849
1005
  });
850
- }, [mode, endpoint, githubToken, owner, repo, labels, onSave]);
851
- return /* @__PURE__ */ jsxs4(
852
- motion5.div,
1006
+ }, [mode, endpoint, githubToken, owner, repo, labels, clearAfterCopy, onSave]);
1007
+ return /* @__PURE__ */ jsxs5(
1008
+ motion6.div,
853
1009
  {
854
1010
  className: "shiteki-settings",
855
1011
  initial: { opacity: 0, y: 12 },
@@ -857,13 +1013,13 @@ function SettingsPanel({ config, onSave, onCancel }) {
857
1013
  exit: { opacity: 0, y: 12 },
858
1014
  transition: spring,
859
1015
  children: [
860
- /* @__PURE__ */ jsx7("div", { className: "shiteki-settings-header", children: "Settings" }),
861
- /* @__PURE__ */ jsxs4("div", { className: "shiteki-settings-body", children: [
862
- /* @__PURE__ */ jsxs4("div", { className: "shiteki-settings-field", children: [
863
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "Submit mode" }),
864
- /* @__PURE__ */ jsxs4("div", { className: "shiteki-radio-group", children: [
865
- /* @__PURE__ */ jsxs4("label", { className: "shiteki-radio", children: [
866
- /* @__PURE__ */ jsx7(
1016
+ /* @__PURE__ */ jsx8("div", { className: "shiteki-settings-header", children: "Settings" }),
1017
+ /* @__PURE__ */ jsxs5("div", { className: "shiteki-settings-body", children: [
1018
+ /* @__PURE__ */ jsxs5("div", { className: "shiteki-settings-field", children: [
1019
+ /* @__PURE__ */ jsx8("span", { className: "shiteki-settings-label", children: "Submit mode" }),
1020
+ /* @__PURE__ */ jsxs5("div", { className: "shiteki-radio-group", children: [
1021
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-radio", children: [
1022
+ /* @__PURE__ */ jsx8(
867
1023
  "input",
868
1024
  {
869
1025
  type: "radio",
@@ -872,10 +1028,10 @@ function SettingsPanel({ config, onSave, onCancel }) {
872
1028
  onChange: () => setMode("endpoint")
873
1029
  }
874
1030
  ),
875
- /* @__PURE__ */ jsx7("span", { children: "Endpoint" })
1031
+ /* @__PURE__ */ jsx8("span", { children: "Endpoint" })
876
1032
  ] }),
877
- /* @__PURE__ */ jsxs4("label", { className: "shiteki-radio", children: [
878
- /* @__PURE__ */ jsx7(
1033
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-radio", children: [
1034
+ /* @__PURE__ */ jsx8(
879
1035
  "input",
880
1036
  {
881
1037
  type: "radio",
@@ -884,13 +1040,16 @@ function SettingsPanel({ config, onSave, onCancel }) {
884
1040
  onChange: () => setMode("direct")
885
1041
  }
886
1042
  ),
887
- /* @__PURE__ */ jsx7("span", { children: "Direct" })
1043
+ /* @__PURE__ */ jsx8("span", { children: "Direct" })
888
1044
  ] })
889
1045
  ] })
890
1046
  ] }),
891
- mode === "endpoint" ? /* @__PURE__ */ jsxs4("label", { className: "shiteki-settings-field", children: [
892
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "Endpoint" }),
893
- /* @__PURE__ */ jsx7(
1047
+ mode === "endpoint" ? /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field", children: [
1048
+ /* @__PURE__ */ jsxs5("span", { className: "shiteki-settings-label", children: [
1049
+ "Endpoint",
1050
+ /* @__PURE__ */ jsx8(HelpLink, { href: "https://github.com/taterboom/shiteki/tree/main/apps/api" })
1051
+ ] }),
1052
+ /* @__PURE__ */ jsx8(
894
1053
  "input",
895
1054
  {
896
1055
  className: "shiteki-settings-input",
@@ -900,9 +1059,12 @@ function SettingsPanel({ config, onSave, onCancel }) {
900
1059
  placeholder: "https://..."
901
1060
  }
902
1061
  )
903
- ] }) : /* @__PURE__ */ jsxs4("label", { className: "shiteki-settings-field", children: [
904
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "GitHub Token" }),
905
- /* @__PURE__ */ jsx7(
1062
+ ] }) : /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field", children: [
1063
+ /* @__PURE__ */ jsxs5("span", { className: "shiteki-settings-label", children: [
1064
+ "GitHub Token",
1065
+ /* @__PURE__ */ jsx8(HelpLink, { href: "https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" })
1066
+ ] }),
1067
+ /* @__PURE__ */ jsx8(
906
1068
  "input",
907
1069
  {
908
1070
  className: "shiteki-settings-input",
@@ -913,9 +1075,9 @@ function SettingsPanel({ config, onSave, onCancel }) {
913
1075
  }
914
1076
  )
915
1077
  ] }),
916
- /* @__PURE__ */ jsxs4("label", { className: "shiteki-settings-field", children: [
917
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "Owner" }),
918
- /* @__PURE__ */ jsx7(
1078
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field", children: [
1079
+ /* @__PURE__ */ jsx8("span", { className: "shiteki-settings-label", children: "Owner" }),
1080
+ /* @__PURE__ */ jsx8(
919
1081
  "input",
920
1082
  {
921
1083
  className: "shiteki-settings-input",
@@ -926,9 +1088,9 @@ function SettingsPanel({ config, onSave, onCancel }) {
926
1088
  }
927
1089
  )
928
1090
  ] }),
929
- /* @__PURE__ */ jsxs4("label", { className: "shiteki-settings-field", children: [
930
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "Repo" }),
931
- /* @__PURE__ */ jsx7(
1091
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field", children: [
1092
+ /* @__PURE__ */ jsx8("span", { className: "shiteki-settings-label", children: "Repo" }),
1093
+ /* @__PURE__ */ jsx8(
932
1094
  "input",
933
1095
  {
934
1096
  className: "shiteki-settings-input",
@@ -939,9 +1101,12 @@ function SettingsPanel({ config, onSave, onCancel }) {
939
1101
  }
940
1102
  )
941
1103
  ] }),
942
- /* @__PURE__ */ jsxs4("label", { className: "shiteki-settings-field", children: [
943
- /* @__PURE__ */ jsx7("span", { className: "shiteki-settings-label", children: "Labels" }),
944
- /* @__PURE__ */ jsx7(
1104
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field", children: [
1105
+ /* @__PURE__ */ jsxs5("span", { className: "shiteki-settings-label", children: [
1106
+ "Labels",
1107
+ /* @__PURE__ */ jsx8(HelpLink, { href: "https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/managing-labels" })
1108
+ ] }),
1109
+ /* @__PURE__ */ jsx8(
945
1110
  "input",
946
1111
  {
947
1112
  className: "shiteki-settings-input",
@@ -951,11 +1116,23 @@ function SettingsPanel({ config, onSave, onCancel }) {
951
1116
  placeholder: "bug, feedback"
952
1117
  }
953
1118
  )
1119
+ ] }),
1120
+ /* @__PURE__ */ jsxs5("label", { className: "shiteki-settings-field shiteki-settings-field--row", children: [
1121
+ /* @__PURE__ */ jsx8("span", { className: "shiteki-settings-label", children: "Clear after copy" }),
1122
+ /* @__PURE__ */ jsx8(
1123
+ "input",
1124
+ {
1125
+ type: "checkbox",
1126
+ className: "shiteki-settings-checkbox",
1127
+ checked: clearAfterCopy,
1128
+ onChange: (e) => setClearAfterCopy(e.target.checked)
1129
+ }
1130
+ )
954
1131
  ] })
955
1132
  ] }),
956
- /* @__PURE__ */ jsxs4("div", { className: "shiteki-settings-actions", children: [
957
- /* @__PURE__ */ jsx7("button", { className: "shiteki-btn shiteki-btn--ghost", onClick: onCancel, children: "Cancel" }),
958
- /* @__PURE__ */ jsx7("button", { className: "shiteki-btn shiteki-btn--primary", onClick: handleSave, children: "Save" })
1133
+ /* @__PURE__ */ jsxs5("div", { className: "shiteki-settings-actions", children: [
1134
+ /* @__PURE__ */ jsx8("button", { className: "shiteki-btn shiteki-btn--ghost", onClick: onCancel, children: "Cancel" }),
1135
+ /* @__PURE__ */ jsx8("button", { className: "shiteki-btn shiteki-btn--primary", onClick: handleSave, children: "Save" })
959
1136
  ] })
960
1137
  ]
961
1138
  }
@@ -963,13 +1140,13 @@ function SettingsPanel({ config, onSave, onCancel }) {
963
1140
  }
964
1141
 
965
1142
  // src/components/SendDialog.tsx
966
- import { useCallback as useCallback8, useEffect as useEffect6, useRef as useRef6, useState as useState10 } from "react";
967
- import { motion as motion6 } from "motion/react";
968
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1143
+ import { useCallback as useCallback8, useEffect as useEffect7, useRef as useRef7, useState as useState11 } from "react";
1144
+ import { motion as motion7 } from "motion/react";
1145
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
969
1146
  function SendDialog({ defaultTitle, sending, onConfirm, onCancel }) {
970
- const [title, setTitle] = useState10(defaultTitle);
971
- const inputRef = useRef6(null);
972
- useEffect6(() => {
1147
+ const [title, setTitle] = useState11(defaultTitle);
1148
+ const inputRef = useRef7(null);
1149
+ useEffect7(() => {
973
1150
  inputRef.current?.focus();
974
1151
  inputRef.current?.select();
975
1152
  }, []);
@@ -981,8 +1158,8 @@ function SendDialog({ defaultTitle, sending, onConfirm, onCancel }) {
981
1158
  },
982
1159
  [title, sending, onConfirm]
983
1160
  );
984
- return /* @__PURE__ */ jsxs5(
985
- motion6.div,
1161
+ return /* @__PURE__ */ jsxs6(
1162
+ motion7.div,
986
1163
  {
987
1164
  className: "shiteki-popover",
988
1165
  style: {
@@ -996,9 +1173,9 @@ function SendDialog({ defaultTitle, sending, onConfirm, onCancel }) {
996
1173
  exit: { opacity: 0, y: 12 },
997
1174
  transition: spring,
998
1175
  children: [
999
- /* @__PURE__ */ jsx8("div", { className: "shiteki-popover-info", children: /* @__PURE__ */ jsx8("span", { className: "shiteki-popover-tag", children: "Create Issue" }) }),
1000
- /* @__PURE__ */ jsxs5("form", { className: "shiteki-popover-form", onSubmit: handleSubmit, children: [
1001
- /* @__PURE__ */ jsx8(
1176
+ /* @__PURE__ */ jsx9("div", { className: "shiteki-popover-info", children: /* @__PURE__ */ jsx9("span", { className: "shiteki-popover-tag", children: "Create Issue" }) }),
1177
+ /* @__PURE__ */ jsxs6("form", { className: "shiteki-popover-form", onSubmit: handleSubmit, children: [
1178
+ /* @__PURE__ */ jsx9(
1002
1179
  "input",
1003
1180
  {
1004
1181
  ref: inputRef,
@@ -1009,8 +1186,8 @@ function SendDialog({ defaultTitle, sending, onConfirm, onCancel }) {
1009
1186
  placeholder: "Issue title"
1010
1187
  }
1011
1188
  ),
1012
- /* @__PURE__ */ jsxs5("div", { className: "shiteki-popover-actions", children: [
1013
- /* @__PURE__ */ jsx8(
1189
+ /* @__PURE__ */ jsxs6("div", { className: "shiteki-popover-actions", children: [
1190
+ /* @__PURE__ */ jsx9(
1014
1191
  "button",
1015
1192
  {
1016
1193
  type: "button",
@@ -1020,7 +1197,7 @@ function SendDialog({ defaultTitle, sending, onConfirm, onCancel }) {
1020
1197
  children: "Cancel"
1021
1198
  }
1022
1199
  ),
1023
- /* @__PURE__ */ jsx8(
1200
+ /* @__PURE__ */ jsx9(
1024
1201
  "button",
1025
1202
  {
1026
1203
  type: "submit",
@@ -1059,22 +1236,23 @@ function styleInject(css, { insertAt } = {}) {
1059
1236
  }
1060
1237
 
1061
1238
  // src/styles/widget.css
1062
- styleInject('.shiteki-root {\n --shiteki-primary: #2563eb;\n --shiteki-primary-hover: #1d4ed8;\n --shiteki-bg: #ffffff;\n --shiteki-border: #e5e7eb;\n --shiteki-text: #111827;\n --shiteki-text-secondary: #6b7280;\n --shiteki-radius: 12px;\n --shiteki-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n font-family:\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: var(--shiteki-text);\n box-sizing: border-box;\n}\n.shiteki-toolbar {\n position: fixed;\n bottom: 20px;\n right: 20px;\n display: flex;\n align-items: center;\n border-radius: 9999px;\n z-index: 99999;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n box-shadow: var(--shiteki-shadow);\n}\n.shiteki-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--shiteki-text);\n cursor: pointer;\n transition: background 0.15s, color 0.15s;\n}\n.shiteki-toolbar-btn:hover {\n background: #f3f4f6;\n}\n.shiteki-toolbar-btn:active {\n transform: scale(0.9);\n}\n.shiteki-toolbar-btn--active {\n background: var(--shiteki-primary);\n color: #fff;\n}\n.shiteki-toolbar-btn--active:hover {\n background: var(--shiteki-primary-hover);\n}\n.shiteki-toolbar-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.shiteki-toolbar-picker {\n position: relative;\n}\n.shiteki-toolbar-badge {\n position: absolute;\n top: -4px;\n right: -6px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 8px;\n background: #ef4444;\n color: #fff;\n font-size: 10px;\n font-weight: 700;\n line-height: 1;\n pointer-events: none;\n box-sizing: border-box;\n}\n.shiteki-toolbar-sep {\n width: 1px;\n height: 24px;\n background: var(--shiteki-border);\n margin: 0 4px;\n}\n.shiteki-highlight {\n position: fixed;\n pointer-events: none;\n border: 1.5px solid var(--shiteki-primary, #2563eb);\n background: rgba(37, 99, 235, 0.08);\n z-index: 99997;\n transition: all 0.05s ease-out;\n box-sizing: border-box;\n}\n.shiteki-marker {\n position: fixed;\n width: 22px;\n height: 22px;\n border-radius: 50%;\n background: var(--shiteki-primary, #2563eb);\n color: #fff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 99998;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);\n user-select: none;\n}\n.shiteki-popover {\n position: fixed;\n width: 320px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: var(--shiteki-radius);\n box-shadow: var(--shiteki-shadow);\n z-index: 99999;\n overflow: hidden;\n}\n.shiteki-popover-info {\n padding: 10px 14px;\n background: #f9fafb;\n border-bottom: 1px solid var(--shiteki-border);\n display: flex;\n align-items: baseline;\n gap: 8px;\n overflow: hidden;\n}\n.shiteki-popover-tag {\n font-family:\n ui-monospace,\n SFMono-Regular,\n "SF Mono",\n Menlo,\n monospace;\n font-size: 12px;\n font-weight: 600;\n color: var(--shiteki-primary);\n white-space: nowrap;\n}\n.shiteki-popover-text {\n font-size: 12px;\n color: var(--shiteki-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.shiteki-popover-form {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.shiteki-popover-textarea {\n width: 100%;\n padding: 8px 10px;\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n color: var(--shiteki-text);\n background: transparent;\n outline: none;\n resize: vertical;\n min-height: 60px;\n box-sizing: border-box;\n transition: border-color 0.15s;\n}\n.shiteki-popover-textarea:focus {\n border-color: var(--shiteki-primary);\n}\n.shiteki-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.shiteki-btn {\n padding: 6px 14px;\n border: none;\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n}\n.shiteki-btn:active {\n transform: scale(0.95);\n}\n.shiteki-btn--primary {\n background: var(--shiteki-primary);\n color: #fff;\n}\n.shiteki-btn--primary:hover:not(:disabled) {\n background: var(--shiteki-primary-hover);\n}\n.shiteki-btn--primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.shiteki-btn--ghost {\n background: transparent;\n color: var(--shiteki-text-secondary);\n}\n.shiteki-btn--ghost:hover {\n background: #f3f4f6;\n}\n.shiteki-status {\n position: fixed;\n bottom: 76px;\n right: 20px;\n padding: 8px 18px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n box-shadow: var(--shiteki-shadow);\n font-size: 13px;\n white-space: nowrap;\n z-index: 99998;\n}\n.shiteki-status--success {\n color: #059669;\n}\n.shiteki-status--error {\n color: #dc2626;\n}\n.shiteki-status a {\n color: inherit;\n text-decoration: underline;\n}\n.shiteki-settings {\n position: fixed;\n bottom: 76px;\n right: 20px;\n width: 280px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: var(--shiteki-radius);\n box-shadow: var(--shiteki-shadow);\n z-index: 99999;\n overflow: hidden;\n}\n.shiteki-settings-header {\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 600;\n border-bottom: 1px solid var(--shiteki-border);\n background: #f9fafb;\n}\n.shiteki-settings-body {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.shiteki-settings-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.shiteki-settings-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--shiteki-text-secondary);\n}\n.shiteki-settings-input {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n color: var(--shiteki-text);\n background: transparent;\n outline: none;\n box-sizing: border-box;\n transition: border-color 0.15s;\n}\n.shiteki-settings-input:focus {\n border-color: var(--shiteki-primary);\n}\n.shiteki-radio-group {\n display: flex;\n gap: 12px;\n}\n.shiteki-radio {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n cursor: pointer;\n}\n.shiteki-radio input[type=radio] {\n margin: 0;\n accent-color: var(--shiteki-primary);\n cursor: pointer;\n}\n.shiteki-settings-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 0 14px 12px;\n}\n.shiteki-shortcut-hint {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 10px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n box-shadow: var(--shiteki-shadow);\n font-size: 12px;\n color: var(--shiteki-text-secondary);\n white-space: nowrap;\n}\n.shiteki-shortcut-hint kbd {\n display: inline-block;\n padding: 1px 5px;\n margin-right: 2px;\n background: #f3f4f6;\n border: 1px solid var(--shiteki-border);\n border-radius: 4px;\n font-family: inherit;\n font-size: 11px;\n font-weight: 600;\n color: var(--shiteki-text);\n line-height: 1.4;\n min-width: 19.5px;\n text-align: center;\n}\n.shiteki-shortcut-hint span {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.shiteki-shortcut-hint-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--shiteki-text-secondary);\n cursor: pointer;\n padding: 0;\n}\n.shiteki-shortcut-hint-close:hover {\n background: #f3f4f6;\n}\n');
1239
+ styleInject('.shiteki-root {\n --shiteki-primary: #2563eb;\n --shiteki-primary-hover: #1d4ed8;\n --shiteki-bg: #ffffff;\n --shiteki-border: #e5e7eb;\n --shiteki-text: #111827;\n --shiteki-text-secondary: #6b7280;\n --shiteki-radius: 12px;\n --shiteki-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n font-family:\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n Roboto,\n sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: var(--shiteki-text);\n box-sizing: border-box;\n}\n.shiteki-toolbar {\n position: fixed;\n bottom: 20px;\n right: 20px;\n display: flex;\n align-items: center;\n gap: 2px;\n border-radius: 9999px;\n z-index: 99999;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n box-shadow: var(--shiteki-shadow);\n}\n.shiteki-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--shiteki-text);\n cursor: pointer;\n transition: background 0.15s, color 0.15s;\n}\n.shiteki-toolbar-btn:hover {\n background: #f3f4f6;\n}\n.shiteki-toolbar-btn:active {\n transform: scale(0.9);\n}\n.shiteki-toolbar-btn--active {\n background: var(--shiteki-primary);\n color: #fff;\n}\n.shiteki-toolbar-btn--active:hover {\n background: var(--shiteki-primary-hover);\n}\n.shiteki-toolbar-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.shiteki-toolbar-picker {\n position: relative;\n}\n.shiteki-toolbar-badge {\n position: absolute;\n top: -4px;\n right: -6px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 8px;\n background: #ef4444;\n color: #fff;\n font-size: 10px;\n font-weight: 700;\n line-height: 1;\n pointer-events: none;\n box-sizing: border-box;\n}\n.shiteki-toolbar-sep {\n width: 1px;\n height: 24px;\n background: var(--shiteki-border);\n margin: 0 4px;\n}\n.shiteki-highlight {\n position: fixed;\n pointer-events: none;\n border: 1.5px solid var(--shiteki-primary, #2563eb);\n background: rgba(37, 99, 235, 0.08);\n z-index: 99997;\n transition: all 0.05s ease-out;\n box-sizing: border-box;\n}\n.shiteki-marker {\n position: fixed;\n width: 22px;\n height: 22px;\n border-radius: 50%;\n background: var(--shiteki-primary, #2563eb);\n color: #fff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: 99998;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);\n user-select: none;\n}\n.shiteki-popover {\n position: fixed;\n width: 320px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: var(--shiteki-radius);\n box-shadow: var(--shiteki-shadow);\n z-index: 99999;\n overflow: hidden;\n}\n.shiteki-popover-info {\n padding: 10px 14px;\n background: #f9fafb;\n border-bottom: 1px solid var(--shiteki-border);\n display: flex;\n align-items: baseline;\n gap: 8px;\n overflow: hidden;\n}\n.shiteki-popover-tag {\n font-family:\n ui-monospace,\n SFMono-Regular,\n "SF Mono",\n Menlo,\n monospace;\n font-size: 12px;\n font-weight: 600;\n color: var(--shiteki-primary);\n white-space: nowrap;\n}\n.shiteki-popover-text {\n font-size: 12px;\n color: var(--shiteki-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.shiteki-popover-form {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.shiteki-popover-textarea {\n width: 100%;\n padding: 8px 10px;\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n color: var(--shiteki-text);\n background: transparent;\n outline: none;\n resize: vertical;\n min-height: 60px;\n box-sizing: border-box;\n transition: border-color 0.15s;\n}\n.shiteki-popover-textarea:focus {\n border-color: var(--shiteki-primary);\n}\n.shiteki-popover-comment {\n font-size: 13px;\n color: var(--shiteki-text);\n white-space: pre-wrap;\n word-break: break-word;\n}\n.shiteki-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.shiteki-btn {\n padding: 6px 14px;\n border: none;\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s;\n}\n.shiteki-btn:active {\n transform: scale(0.95);\n}\n.shiteki-btn--primary {\n background: var(--shiteki-primary);\n color: #fff;\n}\n.shiteki-btn--primary:hover:not(:disabled) {\n background: var(--shiteki-primary-hover);\n}\n.shiteki-btn--primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.shiteki-btn--ghost {\n background: transparent;\n color: var(--shiteki-text-secondary);\n}\n.shiteki-btn--ghost:hover {\n background: #f3f4f6;\n}\n.shiteki-btn--danger {\n background: #fee2e2;\n color: #dc2626;\n}\n.shiteki-btn--danger:hover {\n background: #fecaca;\n}\n.shiteki-btn--icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n padding: 0;\n}\n.shiteki-status {\n position: fixed;\n bottom: 76px;\n right: 20px;\n padding: 8px 18px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n box-shadow: var(--shiteki-shadow);\n font-size: 13px;\n white-space: nowrap;\n z-index: 99998;\n}\n.shiteki-status--success {\n color: #059669;\n}\n.shiteki-status--error {\n color: #dc2626;\n}\n.shiteki-status a {\n color: inherit;\n text-decoration: underline;\n}\n.shiteki-settings {\n position: fixed;\n bottom: 76px;\n right: 20px;\n width: 280px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: var(--shiteki-radius);\n box-shadow: var(--shiteki-shadow);\n z-index: 99999;\n overflow: hidden;\n}\n.shiteki-settings-header {\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 600;\n border-bottom: 1px solid var(--shiteki-border);\n background: #f9fafb;\n}\n.shiteki-settings-body {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.shiteki-settings-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.shiteki-settings-field--row {\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n}\n.shiteki-settings-checkbox {\n margin: 0;\n accent-color: var(--shiteki-primary);\n cursor: pointer;\n}\n.shiteki-settings-label {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n font-weight: 500;\n color: var(--shiteki-text-secondary);\n}\n.shiteki-settings-help {\n display: inline-flex;\n align-items: center;\n color: var(--shiteki-text-secondary);\n opacity: 0.5;\n transition: opacity 0.15s;\n}\n.shiteki-settings-help:hover {\n opacity: 1;\n}\n.shiteki-settings-input {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n font: inherit;\n font-size: 13px;\n color: var(--shiteki-text);\n background: transparent;\n outline: none;\n box-sizing: border-box;\n transition: border-color 0.15s;\n}\n.shiteki-settings-input:focus {\n border-color: var(--shiteki-primary);\n}\n.shiteki-radio-group {\n display: flex;\n gap: 12px;\n}\n.shiteki-radio {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n cursor: pointer;\n}\n.shiteki-radio input[type=radio] {\n margin: 0;\n accent-color: var(--shiteki-primary);\n cursor: pointer;\n}\n.shiteki-settings-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 0 14px 12px;\n}\n.shiteki-shortcut-hint {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 0;\n display: flex;\n flex-direction: column;\n gap: 0;\n padding: 8px 12px;\n background: var(--shiteki-bg);\n border: 1px solid var(--shiteki-border);\n border-radius: 8px;\n box-shadow: var(--shiteki-shadow);\n font-size: 12px;\n color: var(--shiteki-text-secondary);\n white-space: nowrap;\n}\n.shiteki-shortcut-hint-close {\n position: absolute;\n top: 6px;\n right: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: var(--shiteki-text-secondary);\n cursor: pointer;\n padding: 0;\n}\n.shiteki-shortcut-hint-close:hover {\n background: #f3f4f6;\n}\n.shiteki-shortcut-hint-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.shiteki-shortcut-hint-list span {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.shiteki-shortcut-hint kbd {\n display: inline-block;\n padding: 1px 5px;\n background: #f3f4f6;\n border: 1px solid var(--shiteki-border);\n border-radius: 4px;\n font-family: inherit;\n font-size: 11px;\n font-weight: 600;\n color: var(--shiteki-text);\n line-height: 1.4;\n min-width: 20px;\n text-align: center;\n}\n.shiteki-shortcut-hint-close:hover {\n background: #f3f4f6;\n}\n');
1063
1240
 
1064
1241
  // src/components/ShitekiWidget.tsx
1065
- import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1242
+ import { Fragment, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1066
1243
  function ShitekiWidget(props) {
1067
1244
  const { config, updateConfig } = useConfig(props);
1068
- const [open, setOpen] = useState11(false);
1069
- const [mode, setMode] = useState11("idle");
1070
- const [settingsOpen, setSettingsOpen] = useState11(false);
1071
- const [sendDialogOpen, setSendDialogOpen] = useState11(false);
1072
- const [selectedElement, setSelectedElement] = useState11(null);
1073
- const { annotations, add, remove, clear } = useAnnotations();
1245
+ const [open, setOpen] = useState12(false);
1246
+ const [mode, setMode] = useState12("idle");
1247
+ const [settingsOpen, setSettingsOpen] = useState12(false);
1248
+ const [sendDialogOpen, setSendDialogOpen] = useState12(false);
1249
+ const [selectedElement, setSelectedElement] = useState12(null);
1250
+ const [viewingAnnotation, setViewingAnnotation] = useState12(null);
1251
+ const { annotations, add, update, remove, clear } = useAnnotations();
1074
1252
  const { state: submitState, submit, reset: resetSubmit } = useSubmit(config);
1075
1253
  const { copied, copy } = useClipboard();
1076
1254
  const { showHint, dismissHint } = useShortcutHint();
1077
- useEffect7(() => {
1255
+ useEffect8(() => {
1078
1256
  if (submitState.status === "success") {
1079
1257
  clear();
1080
1258
  }
@@ -1117,10 +1295,43 @@ function ShitekiWidget(props) {
1117
1295
  setSelectedElement(null);
1118
1296
  setMode("picking");
1119
1297
  }, []);
1298
+ const handleMarkerClick = useCallback9(
1299
+ (id, e) => {
1300
+ if (e.metaKey || e.ctrlKey) {
1301
+ remove(id);
1302
+ } else {
1303
+ const ann = annotations.find((a) => a.id === id);
1304
+ if (ann) setViewingAnnotation(ann);
1305
+ }
1306
+ },
1307
+ [annotations, remove]
1308
+ );
1309
+ const handleCloseViewing = useCallback9(() => {
1310
+ setViewingAnnotation(null);
1311
+ }, []);
1312
+ const handleUpdateViewing = useCallback9(
1313
+ (comment) => {
1314
+ if (viewingAnnotation) {
1315
+ update(viewingAnnotation.id, comment);
1316
+ setViewingAnnotation(null);
1317
+ }
1318
+ },
1319
+ [viewingAnnotation, update]
1320
+ );
1321
+ const handleRemoveViewing = useCallback9(() => {
1322
+ if (viewingAnnotation) {
1323
+ remove(viewingAnnotation.id);
1324
+ setViewingAnnotation(null);
1325
+ }
1326
+ }, [viewingAnnotation, remove]);
1120
1327
  const handleCopy = useCallback9(() => {
1121
1328
  const prompt = generatePrompt(annotations);
1122
1329
  copy(prompt);
1123
- }, [annotations, copy]);
1330
+ if (config.clearAfterCopy) {
1331
+ clear();
1332
+ setSelectedElement(null);
1333
+ }
1334
+ }, [annotations, copy, config.clearAfterCopy, clear]);
1124
1335
  const handleSend = useCallback9(() => {
1125
1336
  setSendDialogOpen(true);
1126
1337
  }, []);
@@ -1138,11 +1349,13 @@ function ShitekiWidget(props) {
1138
1349
  const handleClear = useCallback9(() => {
1139
1350
  clear();
1140
1351
  setSelectedElement(null);
1352
+ setViewingAnnotation(null);
1141
1353
  }, [clear]);
1142
1354
  const handleClose = useCallback9(() => {
1143
1355
  setOpen(false);
1144
1356
  setMode("idle");
1145
1357
  setSelectedElement(null);
1358
+ setViewingAnnotation(null);
1146
1359
  setSettingsOpen(false);
1147
1360
  }, []);
1148
1361
  const handleToggleSettings = useCallback9(() => {
@@ -1158,10 +1371,12 @@ function ShitekiWidget(props) {
1158
1371
  const handleSettingsCancel = useCallback9(() => {
1159
1372
  setSettingsOpen(false);
1160
1373
  }, []);
1374
+ const canSend = config.owner.trim() !== "" && config.repo.trim() !== "" && (config.mode === "endpoint" ? config.endpoint.trim() !== "" : config.githubToken.trim() !== "");
1161
1375
  useKeyboardShortcuts({
1162
1376
  open,
1163
1377
  mode,
1164
1378
  annotationCount: annotations.length,
1379
+ canSend,
1165
1380
  settingsOpen,
1166
1381
  sendDialogOpen,
1167
1382
  onCopy: handleCopy,
@@ -1174,14 +1389,15 @@ function ShitekiWidget(props) {
1174
1389
  onCloseSendDialog: handleSendCancel
1175
1390
  });
1176
1391
  return ReactDOM.createPortal(
1177
- /* @__PURE__ */ jsxs6("div", { className: "shiteki-root", children: [
1178
- /* @__PURE__ */ jsx9(
1392
+ /* @__PURE__ */ jsxs7("div", { className: "shiteki-root", children: [
1393
+ /* @__PURE__ */ jsx10(
1179
1394
  Toolbar,
1180
1395
  {
1181
1396
  open,
1182
1397
  annotationCount: annotations.length,
1183
1398
  copied,
1184
1399
  sending: submitState.status === "loading",
1400
+ canSend,
1185
1401
  settingsOpen,
1186
1402
  onOpen: handleOpen,
1187
1403
  onCopy: handleCopy,
@@ -1193,9 +1409,9 @@ function ShitekiWidget(props) {
1193
1409
  onDismissHint: dismissHint
1194
1410
  }
1195
1411
  ),
1196
- open && /* @__PURE__ */ jsxs6(Fragment, { children: [
1197
- /* @__PURE__ */ jsx9(ElementHighlight, { rect: hoveredRect }),
1198
- /* @__PURE__ */ jsx9(AnimatePresence3, { children: mode === "annotating" && selectedElement && /* @__PURE__ */ jsx9(
1412
+ open && /* @__PURE__ */ jsxs7(Fragment, { children: [
1413
+ /* @__PURE__ */ jsx10(ElementHighlight, { rect: hoveredRect }),
1414
+ /* @__PURE__ */ jsx10(AnimatePresence3, { children: mode === "annotating" && selectedElement && /* @__PURE__ */ jsx10(
1199
1415
  AnnotationPopover,
1200
1416
  {
1201
1417
  elementInfo: selectedElement,
@@ -1204,9 +1420,20 @@ function ShitekiWidget(props) {
1204
1420
  },
1205
1421
  "popover"
1206
1422
  ) }),
1207
- /* @__PURE__ */ jsx9(AnnotationMarkers, { annotations, onRemove: remove }),
1208
- /* @__PURE__ */ jsxs6(AnimatePresence3, { children: [
1209
- settingsOpen && /* @__PURE__ */ jsx9(
1423
+ /* @__PURE__ */ jsx10(AnnotationMarkers, { annotations, onClick: handleMarkerClick }),
1424
+ /* @__PURE__ */ jsx10(AnimatePresence3, { children: viewingAnnotation && /* @__PURE__ */ jsx10(
1425
+ AnnotationDetailPopover,
1426
+ {
1427
+ annotation: viewingAnnotation,
1428
+ index: annotations.findIndex((a) => a.id === viewingAnnotation.id) + 1,
1429
+ onUpdate: handleUpdateViewing,
1430
+ onRemove: handleRemoveViewing,
1431
+ onClose: handleCloseViewing
1432
+ },
1433
+ "detail"
1434
+ ) }),
1435
+ /* @__PURE__ */ jsxs7(AnimatePresence3, { children: [
1436
+ settingsOpen && /* @__PURE__ */ jsx10(
1210
1437
  SettingsPanel,
1211
1438
  {
1212
1439
  config,
@@ -1215,7 +1442,7 @@ function ShitekiWidget(props) {
1215
1442
  },
1216
1443
  "settings"
1217
1444
  ),
1218
- sendDialogOpen && /* @__PURE__ */ jsx9(
1445
+ sendDialogOpen && /* @__PURE__ */ jsx10(
1219
1446
  SendDialog,
1220
1447
  {
1221
1448
  defaultTitle: `Visual Annotations (${annotations.length}) \u2014 ${document.title || location.href}`,
@@ -1226,7 +1453,7 @@ function ShitekiWidget(props) {
1226
1453
  "send-dialog"
1227
1454
  )
1228
1455
  ] }),
1229
- /* @__PURE__ */ jsx9(AnimatePresence3, { children: submitState.status !== "idle" && /* @__PURE__ */ jsx9(StatusMessage, { state: submitState, onDismiss: resetSubmit }, "status") })
1456
+ /* @__PURE__ */ jsx10(AnimatePresence3, { children: submitState.status !== "idle" && /* @__PURE__ */ jsx10(StatusMessage, { state: submitState, onDismiss: resetSubmit }, "status") })
1230
1457
  ] })
1231
1458
  ] }),
1232
1459
  document.body