@sirendesign/markup 1.0.9 → 1.0.12

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.js CHANGED
@@ -850,6 +850,7 @@ const initialState = {
850
850
  config: defaultConfig,
851
851
  currentUser: null,
852
852
  isAuthenticated: false,
853
+ viewportMode: null,
853
854
  };
854
855
  const useMarkupStore = create()(persist((set, get) => ({
855
856
  ...initialState,
@@ -857,6 +858,7 @@ const useMarkupStore = create()(persist((set, get) => ({
857
858
  setIsCapturing: (isCapturing) => set({ isCapturing }),
858
859
  setIsAnnotating: (isAnnotating) => set({ isAnnotating }),
859
860
  setCurrentScreenshot: (screenshot) => set({ currentScreenshot: screenshot }),
861
+ setAnnotations: (annotations) => set({ annotations }),
860
862
  addAnnotation: (annotation) => set((state) => ({
861
863
  annotations: [...state.annotations, annotation],
862
864
  })),
@@ -895,6 +897,7 @@ const useMarkupStore = create()(persist((set, get) => ({
895
897
  console.log('Store: Setting authenticated:', isAuthenticated);
896
898
  set({ isAuthenticated });
897
899
  },
900
+ setViewportMode: (mode) => set({ viewportMode: mode }),
898
901
  addComment: (feedbackId, comment) => set((state) => ({
899
902
  feedbackItems: state.feedbackItems.map((f) => f.id === feedbackId
900
903
  ? { ...f, comments: [...f.comments, comment], updatedAt: new Date().toISOString() }
@@ -8740,7 +8743,65 @@ var parseBackgroundColor = function (context, element, backgroundColorOverride)
8740
8743
  : defaultBackgroundColor;
8741
8744
  };
8742
8745
 
8743
- async function captureScreenshot() {
8746
+ const identifyComponent = (element) => {
8747
+ var _a, _b;
8748
+ if (!element)
8749
+ return undefined;
8750
+ let current = element;
8751
+ const depth = 5; // Search up 5 levels
8752
+ for (let i = 0; i < depth; i++) {
8753
+ if (!current)
8754
+ break;
8755
+ // 1. Check for data-component attribute (common pattern)
8756
+ if (current.getAttribute('data-component')) {
8757
+ return current.getAttribute('data-component') || undefined;
8758
+ }
8759
+ // 2. Check for data-testid
8760
+ if (current.getAttribute('data-testid')) {
8761
+ return current.getAttribute('data-testid') || undefined;
8762
+ }
8763
+ // 3. React DevTools internals (brittle, but sometimes works)
8764
+ // @ts-ignore
8765
+ const key = Object.keys(current).find(k => k.startsWith('__reactFiber$'));
8766
+ if (key) {
8767
+ // @ts-ignore
8768
+ const fiber = current[key];
8769
+ if ((_a = fiber === null || fiber === void 0 ? void 0 : fiber.type) === null || _a === void 0 ? void 0 : _a.displayName) {
8770
+ return fiber.type.displayName;
8771
+ }
8772
+ if ((_b = fiber === null || fiber === void 0 ? void 0 : fiber.type) === null || _b === void 0 ? void 0 : _b.name) {
8773
+ return fiber.type.name;
8774
+ }
8775
+ }
8776
+ // 4. ID or specific classes
8777
+ if (current.id)
8778
+ return `#${current.id}`;
8779
+ if (current.parentElement) {
8780
+ current = current.parentElement;
8781
+ }
8782
+ else {
8783
+ break;
8784
+ }
8785
+ }
8786
+ return undefined;
8787
+ };
8788
+ const getElementInfo = (element) => {
8789
+ if (!element)
8790
+ return undefined;
8791
+ const tagName = element.tagName.toLowerCase();
8792
+ const classes = element.className && typeof element.className === 'string'
8793
+ ? element.className.split(' ').filter(c => c.trim()).slice(0, 3).join(' ')
8794
+ : '';
8795
+ let info = `<${tagName}`;
8796
+ if (element.id)
8797
+ info += ` id="${element.id}"`;
8798
+ if (classes)
8799
+ info += ` class="${classes}"`;
8800
+ info += '>';
8801
+ return info;
8802
+ };
8803
+
8804
+ async function captureScreenshot(clickElement) {
8744
8805
  try {
8745
8806
  // Hide the markup widget before capturing
8746
8807
  const widget = document.querySelector('[data-markup-widget]');
@@ -8753,6 +8814,12 @@ async function captureScreenshot() {
8753
8814
  scale: window.devicePixelRatio,
8754
8815
  logging: false,
8755
8816
  backgroundColor: null,
8817
+ width: window.innerWidth,
8818
+ height: window.innerHeight,
8819
+ x: window.scrollX,
8820
+ y: window.scrollY,
8821
+ windowWidth: window.innerWidth,
8822
+ windowHeight: window.innerHeight,
8756
8823
  ignoreElements: (element) => {
8757
8824
  return element.hasAttribute('data-markup-widget');
8758
8825
  },
@@ -8768,7 +8835,20 @@ async function captureScreenshot() {
8768
8835
  throw error;
8769
8836
  }
8770
8837
  }
8771
- function getPageMetadata() {
8838
+ const detectDeviceType = () => {
8839
+ const width = window.innerWidth;
8840
+ const userAgent = navigator.userAgent.toLowerCase();
8841
+ // Check user agent for mobile/tablet indicators
8842
+ const isMobileUA = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);
8843
+ const isTabletUA = /tablet|ipad|playbook|silk|kindle/i.test(userAgent);
8844
+ // Prioritize user agent, then fall back to screen width
8845
+ if (isMobileUA && width < 768)
8846
+ return 'mobile';
8847
+ if (isTabletUA || (width >= 768 && width < 1024))
8848
+ return 'tablet';
8849
+ return 'desktop';
8850
+ };
8851
+ function getPageMetadata(clickElement) {
8772
8852
  return {
8773
8853
  url: window.location.href,
8774
8854
  title: document.title,
@@ -8777,6 +8857,9 @@ function getPageMetadata() {
8777
8857
  devicePixelRatio: window.devicePixelRatio,
8778
8858
  userAgent: navigator.userAgent,
8779
8859
  timestamp: new Date().toISOString(),
8860
+ deviceType: detectDeviceType(),
8861
+ componentName: clickElement ? identifyComponent(clickElement) : undefined,
8862
+ elementInfo: clickElement ? getElementInfo(clickElement) : undefined,
8780
8863
  };
8781
8864
  }
8782
8865
  function getElementSelector(element) {
@@ -11446,6 +11529,7 @@ const UndoIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { classNam
11446
11529
  const CheckIcon = ({ className, ...props }) => (jsxRuntime.jsx("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
11447
11530
  const TrashIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntime.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" })] }));
11448
11531
  const EditIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }), jsxRuntime.jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })] }));
11532
+ const CopyIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }));
11449
11533
  const InboxIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12" }), jsxRuntime.jsx("path", { d: "M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" })] }));
11450
11534
  const SendIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), jsxRuntime.jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }));
11451
11535
  const PlusIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
@@ -11458,6 +11542,9 @@ const UserIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { classNam
11458
11542
  const ZoomInIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }), jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }), jsxRuntime.jsx("line", { x1: "11", y1: "8", x2: "11", y2: "14" }), jsxRuntime.jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })] }));
11459
11543
  const CalendarIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
11460
11544
  const ChevronRightIcon = ({ className, ...props }) => (jsxRuntime.jsx("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }));
11545
+ const DesktopIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "8", y1: "21", x2: "16", y2: "21" }), jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12", y2: "21" })] }));
11546
+ const TabletIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12.01", y2: "18" })] }));
11547
+ const MobileIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "7", y: "2", width: "10", height: "20", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12.01", y2: "18" })] }));
11461
11548
 
11462
11549
  const tools = [
11463
11550
  { id: 'pen', icon: PencilIcon, label: 'Draw' },
@@ -11774,22 +11861,43 @@ const AnnotationOverlay = ({ screenshot, onComplete, onCancel, }) => {
11774
11861
  : 'Click and drag to annotate • Use tools above to switch modes' })] }), document.body);
11775
11862
  };
11776
11863
 
11777
- const FeedbackForm = ({ onSubmit, onCancel, }) => {
11864
+ const FeedbackForm = ({ onSubmit, onCancel, initialData, getSessionEvents, lastClickedElement, lastClickedText, }) => {
11778
11865
  var _a, _b;
11779
- const { config, currentScreenshot, setCurrentScreenshot, annotations, clearAnnotations, setIsCapturing, isCapturing, currentUser, } = useMarkupStore();
11780
- const [title, setTitle] = require$$0.useState("");
11781
- const [description, setDescription] = require$$0.useState("");
11782
- const [priority, setPriority] = require$$0.useState("medium");
11783
- const [feedbackType, setFeedbackType] = require$$0.useState("general");
11784
- const [currentCopy, setCurrentCopy] = require$$0.useState("");
11785
- const [newCopy, setNewCopy] = require$$0.useState("");
11786
- const [selectedTags, setSelectedTags] = require$$0.useState([]);
11866
+ const { config, currentScreenshot, setCurrentScreenshot, annotations, setAnnotations, clearAnnotations, setIsCapturing, isCapturing, currentUser, } = useMarkupStore();
11867
+ const [title, setTitle] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.title) || "");
11868
+ const [description, setDescription] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.description) || "");
11869
+ const [priority, setPriority] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.priority) || "medium");
11870
+ const [feedbackType, setFeedbackType] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.type) || "general");
11871
+ const [currentCopy, setCurrentCopy] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.currentCopy) || "");
11872
+ const [newCopy, setNewCopy] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.newCopy) || "");
11873
+ const [designMockup, setDesignMockup] = require$$0.useState(initialData === null || initialData === void 0 ? void 0 : initialData.designMockup);
11874
+ const [selectedTags, setSelectedTags] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.tags) || []);
11787
11875
  const [isAnnotating, setIsAnnotating] = require$$0.useState(false);
11788
11876
  const [isSubmitting, setIsSubmitting] = require$$0.useState(false);
11789
- const [annotatedScreenshot, setAnnotatedScreenshot] = require$$0.useState(null);
11790
- // Auto-capture selected text when component mounts
11877
+ const [annotatedScreenshot, setAnnotatedScreenshot] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.screenshot) || null);
11878
+ // Screen recording states
11879
+ const [isRecording, setIsRecording] = require$$0.useState(false);
11880
+ const [recordedVideo, setRecordedVideo] = require$$0.useState(initialData === null || initialData === void 0 ? void 0 : initialData.screenRecording);
11881
+ const [mediaRecorder, setMediaRecorder] = require$$0.useState(null);
11882
+ const [recordingStream, setRecordingStream] = require$$0.useState(null);
11883
+ // Load initial annotations into store if editing
11884
+ require$$0.useEffect(() => {
11885
+ if (initialData === null || initialData === void 0 ? void 0 : initialData.annotations) {
11886
+ setAnnotations(initialData.annotations);
11887
+ }
11888
+ }, [initialData, setAnnotations]);
11889
+ // Auto-capture selected text when component mounts (only if creating new)
11791
11890
  require$$0.useEffect(() => {
11792
11891
  var _a;
11892
+ if (initialData)
11893
+ return;
11894
+ // First check if user clicked on text element
11895
+ if (lastClickedText && lastClickedText.length > 0) {
11896
+ setCurrentCopy(lastClickedText);
11897
+ setFeedbackType("copy-amendment");
11898
+ return;
11899
+ }
11900
+ // Fallback to selected text
11793
11901
  const selectedText = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString().trim();
11794
11902
  if (selectedText &&
11795
11903
  selectedText.length > 0 &&
@@ -11797,7 +11905,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11797
11905
  setCurrentCopy(selectedText);
11798
11906
  setFeedbackType("copy-amendment");
11799
11907
  }
11800
- }, []);
11908
+ }, [initialData, lastClickedText]);
11801
11909
  const handleCaptureScreenshot = async () => {
11802
11910
  try {
11803
11911
  setIsCapturing(true);
@@ -11812,6 +11920,57 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11812
11920
  setIsCapturing(false);
11813
11921
  }
11814
11922
  };
11923
+ const handleStartRecording = async () => {
11924
+ try {
11925
+ const stream = await navigator.mediaDevices.getDisplayMedia({
11926
+ video: { mediaSource: 'screen' },
11927
+ audio: false,
11928
+ });
11929
+ setRecordingStream(stream);
11930
+ const recorder = new MediaRecorder(stream, {
11931
+ mimeType: 'video/webm;codecs=vp8',
11932
+ });
11933
+ const chunks = [];
11934
+ recorder.ondataavailable = (e) => {
11935
+ if (e.data.size > 0) {
11936
+ chunks.push(e.data);
11937
+ }
11938
+ };
11939
+ recorder.onstop = () => {
11940
+ const blob = new Blob(chunks, { type: 'video/webm' });
11941
+ // Convert blob to base64 data URL for storage
11942
+ const reader = new FileReader();
11943
+ reader.onloadend = () => {
11944
+ const base64data = reader.result;
11945
+ setRecordedVideo(base64data);
11946
+ };
11947
+ reader.readAsDataURL(blob);
11948
+ // Stop all tracks
11949
+ stream.getTracks().forEach(track => track.stop());
11950
+ setRecordingStream(null);
11951
+ };
11952
+ recorder.start();
11953
+ setMediaRecorder(recorder);
11954
+ setIsRecording(true);
11955
+ }
11956
+ catch (error) {
11957
+ console.error('Failed to start recording:', error);
11958
+ alert('Screen recording is not supported or permission was denied.');
11959
+ }
11960
+ };
11961
+ const handleStopRecording = () => {
11962
+ if (mediaRecorder && mediaRecorder.state !== 'inactive') {
11963
+ mediaRecorder.stop();
11964
+ setIsRecording(false);
11965
+ }
11966
+ };
11967
+ const handleDeleteRecording = () => {
11968
+ setRecordedVideo(undefined);
11969
+ if (recordingStream) {
11970
+ recordingStream.getTracks().forEach(track => track.stop());
11971
+ setRecordingStream(null);
11972
+ }
11973
+ };
11815
11974
  const handleAnnotationComplete = (newAnnotations, screenshot) => {
11816
11975
  setAnnotatedScreenshot(screenshot);
11817
11976
  setIsAnnotating(false);
@@ -11834,6 +11993,23 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11834
11993
  const toggleTag = (tag) => {
11835
11994
  setSelectedTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]);
11836
11995
  };
11996
+ const priorityColors = {
11997
+ low: "bg-brand-green/30 text-gray-700",
11998
+ medium: "bg-brand-blue/50 text-gray-800",
11999
+ high: "bg-brand-pink/30 text-gray-800",
12000
+ critical: "bg-brand-pink text-gray-800",
12001
+ };
12002
+ const handleMockupUpload = (e) => {
12003
+ var _a;
12004
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
12005
+ if (file) {
12006
+ const reader = new FileReader();
12007
+ reader.onloadend = () => {
12008
+ setDesignMockup(reader.result);
12009
+ };
12010
+ reader.readAsDataURL(file);
12011
+ }
12012
+ };
11837
12013
  const handleSubmit = async (e) => {
11838
12014
  var _a, _b, _c, _d;
11839
12015
  e.preventDefault();
@@ -11843,7 +12019,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11843
12019
  return;
11844
12020
  setIsSubmitting(true);
11845
12021
  const feedback = {
11846
- id: generateId(),
12022
+ id: (initialData === null || initialData === void 0 ? void 0 : initialData.id) || generateId(),
11847
12023
  type: feedbackType,
11848
12024
  title: title.trim() || (feedbackType === "copy-amendment" ? "Copy Amendment" : ""),
11849
12025
  description: description.trim(),
@@ -11853,19 +12029,22 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11853
12029
  newCopy: feedbackType === "copy-amendment" ? newCopy.trim() : undefined,
11854
12030
  screenshot: annotatedScreenshot || currentScreenshot || undefined,
11855
12031
  annotations: annotations,
11856
- status: "open",
12032
+ status: (initialData === null || initialData === void 0 ? void 0 : initialData.status) || "open",
11857
12033
  priority,
11858
- pageMetadata: getPageMetadata(),
11859
- createdAt: new Date().toISOString(),
12034
+ pageMetadata: (initialData === null || initialData === void 0 ? void 0 : initialData.pageMetadata) || getPageMetadata(lastClickedElement || undefined),
12035
+ createdAt: (initialData === null || initialData === void 0 ? void 0 : initialData.createdAt) || new Date().toISOString(),
11860
12036
  updatedAt: new Date().toISOString(),
11861
- createdBy: currentUser || {
12037
+ createdBy: (initialData === null || initialData === void 0 ? void 0 : initialData.createdBy) || currentUser || {
11862
12038
  id: ((_a = config.user) === null || _a === void 0 ? void 0 : _a.id) || "anonymous",
11863
12039
  name: ((_b = config.user) === null || _b === void 0 ? void 0 : _b.name) || "Anonymous",
11864
12040
  email: ((_c = config.user) === null || _c === void 0 ? void 0 : _c.email) || "",
11865
12041
  role: ((_d = config.user) === null || _d === void 0 ? void 0 : _d.role) || "default",
11866
12042
  },
11867
- comments: [],
12043
+ comments: (initialData === null || initialData === void 0 ? void 0 : initialData.comments) || [],
11868
12044
  tags: selectedTags,
12045
+ sessionEvents: getSessionEvents ? getSessionEvents() : undefined,
12046
+ designMockup,
12047
+ screenRecording: recordedVideo,
11869
12048
  };
11870
12049
  try {
11871
12050
  if (config.onSubmit) {
@@ -11895,7 +12074,9 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11895
12074
  { id: "copy-amendment", label: "Copy Change" },
11896
12075
  ].map((type) => (jsxRuntime.jsx("div", { onClick: () => setFeedbackType(type.id), className: cn("flex-1 py-2 px-3 rounded-xl text-xs font-medium cursor-pointer transition-all text-center", feedbackType === type.id
11897
12076
  ? "bg-[#C2D1D9] text-black shadow-md shadow-[#C2D1D9]/30"
11898
- : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: type.label }, type.id))) })] }), feedbackType === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Current Copy" }), jsxRuntime.jsx("textarea", { placeholder: "Select text on page or paste current copy here...", value: currentCopy, onChange: (e) => setCurrentCopy(e.target.value), className: "w-full px-4 py-3 bg-red-50 border border-red-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-red-500 focus:shadow-lg focus:shadow-red-500/10 transition-all" })] }), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "New Copy *" }), jsxRuntime.jsx("textarea", { placeholder: "Enter the replacement text...", value: newCopy, onChange: (e) => setNewCopy(e.target.value), required: feedbackType === "copy-amendment", className: "w-full px-4 py-3 bg-green-50 border border-green-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-green-500 focus:shadow-lg focus:shadow-green-500/10 transition-all" })] })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Title *" }), jsxRuntime.jsx("input", { type: "text", placeholder: "Brief description of the issue", value: title, onChange: (e) => setTitle(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Description" }), jsxRuntime.jsx("textarea", { placeholder: "Provide more details about the issue...", value: description, onChange: (e) => setDescription(e.target.value), className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm min-h-[100px] resize-y focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), annotatedScreenshot || currentScreenshot ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md mb-5 group", children: [jsxRuntime.jsx("img", { src: annotatedScreenshot || currentScreenshot || "", alt: "Screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" }), jsxRuntime.jsxs("div", { className: "absolute top-3 right-3 flex gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleEditScreenshot, className: "bg-white text-gray-700 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-gray-100 shadow-lg transition-all", children: [jsxRuntime.jsx(EditIcon, { className: "w-3.5 h-3.5" }), " Edit"] }), jsxRuntime.jsxs("button", { type: "button", onClick: handleRemoveScreenshot, className: "bg-white text-red-600 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-red-50 shadow-lg transition-all", children: [jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }), " Remove"] })] })] })) : (jsxRuntime.jsx("div", { onClick: handleCaptureScreenshot, className: "w-full p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium mb-5 hover:border-indigo-400 hover:text-indigo-600 hover:bg-indigo-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCapturing ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" }), "Capturing..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CameraIcon, { className: "w-5 h-5" }), " Capture Screenshot"] })) })), config.availableTags && config.availableTags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: config.availableTags.map((tag) => (jsxRuntime.jsx("div", { onClick: () => toggleTag(tag), className: cn("px-3 py-1.5 rounded-full text-xs font-medium cursor-pointer transition-all", selectedTags.includes(tag)
12077
+ : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: type.label }, type.id))) })] }), feedbackType === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Current Copy" }), jsxRuntime.jsx("textarea", { placeholder: "Select text on page or paste current copy here...", value: currentCopy, onChange: (e) => setCurrentCopy(e.target.value), className: "w-full px-4 py-3 bg-red-50 border border-red-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-red-500 focus:shadow-lg focus:shadow-red-500/10 transition-all" })] }), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "New Copy *" }), jsxRuntime.jsx("textarea", { placeholder: "Enter the replacement text...", value: newCopy, onChange: (e) => setNewCopy(e.target.value), required: feedbackType === "copy-amendment", className: "w-full px-4 py-3 bg-green-50 border border-green-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-green-500 focus:shadow-lg focus:shadow-green-500/10 transition-all" })] })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Title *" }), jsxRuntime.jsx("input", { type: "text", placeholder: "Brief description of the issue", value: title, onChange: (e) => setTitle(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Description" }), jsxRuntime.jsx("textarea", { placeholder: "Provide more details about the issue...", value: description, onChange: (e) => setDescription(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all min-h-[100px] resize-y" })] })), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Priority" }), jsxRuntime.jsx("div", { className: "flex gap-2", children: Object.keys(priorityColors).map((p) => (jsxRuntime.jsx("div", { onClick: () => setPriority(p), className: cn("flex-1 py-2 px-2 rounded-xl text-xs font-medium cursor-pointer transition-all text-center capitalize border border-transparent", priority === p
12078
+ ? cn(priorityColors[p], "border-transparent shadow-sm")
12079
+ : "bg-gray-100 text-gray-600 hover:bg-gray-200"), children: p }, p))) })] }), annotatedScreenshot || currentScreenshot ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md mb-5 group", children: [jsxRuntime.jsx("img", { src: annotatedScreenshot || currentScreenshot || "", alt: "Screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" }), jsxRuntime.jsxs("div", { className: "absolute top-3 right-3 flex gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleEditScreenshot, className: "bg-white text-gray-700 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-gray-100 shadow-lg transition-all", children: [jsxRuntime.jsx(EditIcon, { className: "w-3.5 h-3.5" }), " Edit"] }), jsxRuntime.jsxs("button", { type: "button", onClick: handleRemoveScreenshot, className: "bg-white text-red-600 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-red-50 shadow-lg transition-all", children: [jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }), " Remove"] })] })] })) : (jsxRuntime.jsxs("div", { className: "flex gap-3 mb-5", children: [jsxRuntime.jsx("div", { onClick: handleCaptureScreenshot, className: "flex-1 p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium hover:border-indigo-400 hover:text-indigo-600 hover:bg-indigo-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCapturing ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" }), "Capturing..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CameraIcon, { className: "w-5 h-5" }), " Screenshot"] })) }), jsxRuntime.jsx("div", { onClick: isRecording ? handleStopRecording : handleStartRecording, className: "flex-1 p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium hover:border-red-400 hover:text-red-600 hover:bg-red-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isRecording ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-2.5 h-2.5 bg-red-600 rounded-sm animate-pulse" }), "Stop Recording"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeWidth: "2" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "4", fill: "currentColor" })] }), "Record Screen"] })) })] })), recordedVideo && (jsxRuntime.jsxs("div", { className: "mb-5 relative rounded-xl overflow-hidden shadow-md border border-gray-200", children: [jsxRuntime.jsx("video", { src: recordedVideo, controls: true, className: "w-full h-auto" }), jsxRuntime.jsx("button", { type: "button", onClick: handleDeleteRecording, className: "absolute top-2 right-2 bg-white text-red-500 p-1.5 rounded-lg shadow hover:bg-gray-100 cursor-pointer border-none", children: jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }) })] })), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Design Mockup" }), designMockup ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md group border border-gray-200", children: [jsxRuntime.jsx("img", { src: designMockup, className: "w-full h-32 object-cover", alt: "Mockup" }), jsxRuntime.jsx("button", { type: "button", onClick: () => setDesignMockup(undefined), className: "absolute top-2 right-2 bg-white text-red-500 p-1.5 rounded-lg shadow hover:bg-gray-100 cursor-pointer border-none", children: jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }) })] })) : (jsxRuntime.jsxs("div", { className: "border-2 border-dashed border-gray-200 rounded-xl p-4 bg-gray-50 flex items-center justify-center relative hover:bg-white hover:border-[#C2D1D9] transition-all", children: [jsxRuntime.jsx("input", { type: "file", accept: "image/*", onChange: handleMockupUpload, className: "absolute inset-0 opacity-0 cursor-pointer w-full h-full" }), jsxRuntime.jsxs("span", { className: "text-sm text-gray-500 flex items-center gap-2 font-medium", children: [jsxRuntime.jsx(PlusIcon, { className: "w-4 h-4" }), " Upload Mockup"] })] }))] }), config.availableTags && config.availableTags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: config.availableTags.map((tag) => (jsxRuntime.jsx("div", { onClick: () => toggleTag(tag), className: cn("px-3 py-1.5 rounded-full text-xs font-medium cursor-pointer transition-all", selectedTags.includes(tag)
11899
12080
  ? "bg-[#C2D1D9] text-white shadow-md shadow-[#C2D1D9]/30"
11900
12081
  : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: tag }, tag))) })] })), jsxRuntime.jsxs("div", { className: "flex gap-3 mt-6 pt-6 border-t border-gray-100", children: [jsxRuntime.jsx("div", { onClick: onCancel, className: "flex-1 py-3 px-5 rounded-xl text-sm font-semibold cursor-pointer transition-all bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-md text-center", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.cancelButton) || "Cancel" }), jsxRuntime.jsx("div", { onClick: (e) => {
11901
12082
  const isValid = feedbackType === "copy-amendment" ? newCopy.trim() : title.trim();
@@ -11914,7 +12095,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11914
12095
  backgroundColor: (feedbackType === "copy-amendment" ? !newCopy.trim() : !title.trim()) || isSubmitting
11915
12096
  ? "#9ca3af"
11916
12097
  : "green-500",
11917
- }, children: isSubmitting ? (jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin mx-auto block" })) : (((_b = config.labels) === null || _b === void 0 ? void 0 : _b.submitButton) || "Submit Feedback") })] })] }));
12098
+ }, children: isSubmitting ? (jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin mx-auto block" })) : (((_b = config.labels) === null || _b === void 0 ? void 0 : _b.submitButton) || (initialData ? "Update Feedback" : "Submit Feedback")) })] })] }));
11918
12099
  };
11919
12100
 
11920
12101
  const statusOptions$1 = [
@@ -11925,16 +12106,16 @@ const statusOptions$1 = [
11925
12106
  { value: "closed", label: "Closed" },
11926
12107
  ];
11927
12108
  const priorityColors$1 = {
11928
- low: "bg-gray-100 text-gray-700",
11929
- medium: "bg-yellow-100 text-yellow-800",
11930
- high: "bg-orange-100 text-orange-800",
11931
- critical: "bg-red-100 text-red-800",
12109
+ low: "bg-brand-green/30 text-gray-700",
12110
+ medium: "bg-brand-blue/50 text-gray-800",
12111
+ high: "bg-brand-pink/30 text-gray-800",
12112
+ critical: "bg-brand-pink text-gray-800",
11932
12113
  };
11933
12114
  const statusColors = {
11934
- open: "bg-blue-100 text-blue-800",
11935
- "in-progress": "bg-purple-100 text-purple-800",
11936
- resolved: "bg-green-100 text-green-800",
11937
- closed: "bg-gray-100 text-gray-600",
12115
+ open: "bg-brand-blue/50 text-gray-800",
12116
+ "in-progress": "bg-yellow-100 text-gray-800",
12117
+ resolved: "bg-brand-green/50 text-gray-900",
12118
+ closed: "bg-brand-pink/30 text-gray-800",
11938
12119
  };
11939
12120
  const FeedbackList = ({ feedbackItems, onSelectFeedback, }) => {
11940
12121
  const { config } = useMarkupStore();
@@ -11972,7 +12153,10 @@ const FeedbackList = ({ feedbackItems, onSelectFeedback, }) => {
11972
12153
  }, [feedbackItems, statusFilter, sortBy]);
11973
12154
  return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [jsxRuntime.jsxs("div", { className: "flex gap-2 pb-4 mb-4", children: [jsxRuntime.jsxs("div", { className: "relative flex-1", children: [jsxRuntime.jsx(FilterIcon, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" }), jsxRuntime.jsx("select", { value: statusFilter, onChange: (e) => setStatusFilter(e.target.value), className: "w-full pl-9 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-xs font-medium appearance-none focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", children: statusOptions$1.map((option) => (jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))) })] }), jsxRuntime.jsxs("div", { className: "relative flex-1", children: [jsxRuntime.jsx(CalendarIcon, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" }), jsxRuntime.jsxs("select", { value: sortBy, onChange: (e) => setSortBy(e.target.value), className: "w-full pl-9 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-xs font-medium appearance-none focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", children: [jsxRuntime.jsx("option", { value: "newest", children: "Newest First" }), jsxRuntime.jsx("option", { value: "oldest", children: "Oldest First" }), jsxRuntime.jsx("option", { value: "priority", children: "Priority" })] })] })] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto -mx-1 px-1", children: filteredAndSortedItems.length === 0 ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-10 text-gray-400", children: [jsxRuntime.jsx(InboxIcon, { className: "w-12 h-12 mb-3 opacity-50" }), jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500", children: "No feedback items" }), jsxRuntime.jsx("p", { className: "text-xs text-gray-400 mt-1", children: statusFilter !== "all"
11974
12155
  ? "Try changing the filter"
11975
- : "Be the first to add feedback!" })] })) : (jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: filteredAndSortedItems.map((item) => (jsxRuntime.jsxs("div", { onClick: () => onSelectFeedback(item), className: "w-full p-4 bg-white rounded-xl border border-gray-200 cursor-pointer text-left transition-all hover:shadow-lg hover:shadow-gray-200 hover:border-gray-300", children: [jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-gray-900 m-0 flex-1 line-clamp-2", children: item.title }), jsxRuntime.jsx(ChevronRightIcon, { className: "w-4 h-4 text-gray-400 flex-shrink-0 mt-0.5" })] }), item.description && (jsxRuntime.jsx("p", { className: "text-xs text-gray-600 m-0 mb-3 line-clamp-2", children: item.description })), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", statusColors[item.status]), children: item.status.replace("-", " ") }), jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", priorityColors$1[item.priority]), children: item.priority }), item.createdBy && (jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-600 font-medium", children: ["by ", item.createdBy.name] })), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 ml-auto font-medium", children: formatDate(item.createdAt) })] }), item.tags && item.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 mt-3", children: [item.tags.slice(0, 3).map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-md text-[10px] font-medium", children: tag }, tag))), item.tags.length > 3 && (jsxRuntime.jsxs("span", { className: "px-2 py-1 text-gray-500 text-[10px] font-medium", children: ["+", item.tags.length - 3, " more"] }))] }))] }, item.id))) })) }), feedbackItems.length > 0 && (jsxRuntime.jsxs("div", { className: "pt-3 mt-3 border-t border-gray-200 text-xs text-gray-400 text-center", children: ["Showing ", filteredAndSortedItems.length, " of", " ", feedbackItems.length, " items"] }))] }));
12156
+ : "Be the first to add feedback!" })] })) : (jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: filteredAndSortedItems.map((item) => {
12157
+ var _a;
12158
+ return (jsxRuntime.jsxs("div", { onClick: () => onSelectFeedback(item), className: "w-full p-4 bg-white rounded-xl border border-gray-200 cursor-pointer text-left transition-all hover:shadow-lg hover:shadow-gray-200 hover:border-gray-300", children: [jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-1", children: [jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-gray-900 m-0 flex-1 line-clamp-2", children: item.title }), ((_a = item.pageMetadata) === null || _a === void 0 ? void 0 : _a.deviceType) && (jsxRuntime.jsxs("div", { className: "flex-shrink-0", children: [item.pageMetadata.deviceType === 'desktop' && (jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4 text-gray-400", title: "Desktop" })), item.pageMetadata.deviceType === 'tablet' && (jsxRuntime.jsx(TabletIcon, { className: "w-4 h-4 text-gray-400", title: "Tablet" })), item.pageMetadata.deviceType === 'mobile' && (jsxRuntime.jsx(MobileIcon, { className: "w-4 h-4 text-gray-400", title: "Mobile" }))] }))] }), jsxRuntime.jsx(ChevronRightIcon, { className: "w-4 h-4 text-gray-400 flex-shrink-0 mt-0.5" })] }), item.description && (jsxRuntime.jsx("p", { className: "text-xs text-gray-600 m-0 mb-3 line-clamp-2", children: item.description })), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", statusColors[item.status]), children: item.status.replace("-", " ") }), jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", priorityColors$1[item.priority]), children: item.priority }), item.createdBy && (jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-600 font-medium", children: ["by ", item.createdBy.name] })), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 ml-auto font-medium", children: formatDate(item.createdAt) })] }), item.tags && item.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 mt-3", children: [item.tags.slice(0, 3).map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-md text-[10px] font-medium", children: tag }, tag))), item.tags.length > 3 && (jsxRuntime.jsxs("span", { className: "px-2 py-1 text-gray-500 text-[10px] font-medium", children: ["+", item.tags.length - 3, " more"] }))] }))] }, item.id));
12159
+ }) })) }), feedbackItems.length > 0 && (jsxRuntime.jsxs("div", { className: "pt-3 mt-3 border-t border-gray-200 text-xs text-gray-400 text-center", children: ["Showing ", filteredAndSortedItems.length, " of", " ", feedbackItems.length, " items"] }))] }));
11976
12160
  };
11977
12161
 
11978
12162
  const getDefaultsFromPostinstall = () => (undefined);
@@ -37115,6 +37299,7 @@ const subscribeFeedback = (projectId, callback) => {
37115
37299
  return onSnapshot(q, (snapshot) => {
37116
37300
  console.log('Firestore snapshot received:', snapshot.size, 'documents');
37117
37301
  const feedbackItems = snapshot.docs.map((doc) => {
37302
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
37118
37303
  const data = doc.data();
37119
37304
  return {
37120
37305
  id: doc.id,
@@ -37136,16 +37321,21 @@ const subscribeFeedback = (projectId, callback) => {
37136
37321
  devicePixelRatio: 1,
37137
37322
  userAgent: '',
37138
37323
  timestamp: new Date().toISOString(),
37324
+ deviceType: 'desktop',
37139
37325
  },
37140
- createdAt: data.createdAt.toDate().toISOString(),
37141
- updatedAt: data.createdAt.toDate().toISOString(),
37326
+ createdAt: ((_c = (_b = (_a = data.createdAt) === null || _a === void 0 ? void 0 : _a.toDate) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.toISOString()) || new Date().toISOString(),
37327
+ updatedAt: ((_f = (_e = (_d = data.updatedAt) === null || _d === void 0 ? void 0 : _d.toDate) === null || _e === void 0 ? void 0 : _e.call(_d)) === null || _f === void 0 ? void 0 : _f.toISOString()) || ((_j = (_h = (_g = data.createdAt) === null || _g === void 0 ? void 0 : _g.toDate) === null || _h === void 0 ? void 0 : _h.call(_g)) === null || _j === void 0 ? void 0 : _j.toISOString()) || new Date().toISOString(),
37142
37328
  createdBy: data.createdBy || {
37143
37329
  id: data.userId,
37144
37330
  name: 'User',
37145
37331
  email: '',
37146
- role: 'client',
37332
+ role: 'default',
37147
37333
  },
37148
37334
  tags: data.tags || [],
37335
+ sessionEvents: data.sessionEvents,
37336
+ componentName: data.componentName,
37337
+ designMockup: data.designMockup,
37338
+ screenRecording: data.screenRecording,
37149
37339
  };
37150
37340
  });
37151
37341
  callback(feedbackItems);
@@ -37205,30 +37395,114 @@ const canDeleteFeedback = (currentUser, feedbackCreatorId) => {
37205
37395
  }
37206
37396
  return false;
37207
37397
  };
37398
+ /**
37399
+ * Check if a user can edit/amend feedback
37400
+ * Only the creator, developers, or admins can edit
37401
+ */
37402
+ const canEditFeedback = (currentUser, feedbackCreatorId) => {
37403
+ // Creator can edit their own feedback
37404
+ if (currentUser.id === feedbackCreatorId) {
37405
+ return true;
37406
+ }
37407
+ // Admins and developers can edit any feedback
37408
+ if (currentUser.role === 'admin' || currentUser.role === 'developer') {
37409
+ return true;
37410
+ }
37411
+ return false;
37412
+ };
37208
37413
 
37209
37414
  const statusOptions = [
37210
- { value: "open", label: "Open", color: "bg-blue-500" },
37211
- { value: "in-progress", label: "In Progress", color: "bg-purple-500" },
37212
- { value: "resolved", label: "Resolved", color: "bg-green-500" },
37213
- { value: "closed", label: "Closed", color: "bg-gray-500" },
37415
+ { value: "open", label: "Open", color: "bg-brand-blue text-gray-900" },
37416
+ {
37417
+ value: "in-progress",
37418
+ label: "In Progress",
37419
+ color: "bg-yellow-100 text-gray-900",
37420
+ },
37421
+ {
37422
+ value: "resolved",
37423
+ label: "Resolved",
37424
+ color: "bg-brand-green text-white",
37425
+ },
37426
+ {
37427
+ value: "closed",
37428
+ label: "Closed",
37429
+ color: "bg-brand-pink text-gray-900",
37430
+ },
37214
37431
  ];
37215
37432
  const priorityColors = {
37216
- low: "bg-gray-100 text-gray-700",
37217
- medium: "bg-yellow-100 text-yellow-800",
37218
- high: "bg-orange-100 text-orange-800",
37219
- critical: "bg-red-100 text-red-800",
37433
+ low: "bg-brand-green/30 text-gray-700",
37434
+ medium: "bg-brand-blue/50 text-gray-800",
37435
+ high: "bg-brand-pink/30 text-gray-800",
37436
+ critical: "bg-brand-pink text-gray-800",
37220
37437
  };
37221
37438
  const FeedbackDetail = ({ feedback: initialFeedback, onBack, onDelete, onUpdate, }) => {
37222
- var _a, _b;
37439
+ var _a, _b, _c;
37223
37440
  const { config, updateFeedback: updateFeedback$1, currentUser } = useMarkupStore();
37224
37441
  const [feedback, setFeedback] = require$$0.useState(initialFeedback);
37225
37442
  const [newComment, setNewComment] = require$$0.useState("");
37226
37443
  const [isAddingComment, setIsAddingComment] = require$$0.useState(false);
37227
37444
  const [showFullScreenshot, setShowFullScreenshot] = require$$0.useState(false);
37228
37445
  const [copied, setCopied] = require$$0.useState(false);
37446
+ const [isEditing, setIsEditing] = require$$0.useState(false);
37447
+ // Feature 2 & 5 states
37448
+ const [showReplay, setShowReplay] = require$$0.useState(false);
37449
+ const [showOverlay, setShowOverlay] = require$$0.useState(false);
37450
+ const [overlayOpacity, setOverlayOpacity] = require$$0.useState(50);
37451
+ // Parse session actions
37452
+ const sessionActions = require$$0.useMemo(() => {
37453
+ if (!feedback.sessionEvents)
37454
+ return null;
37455
+ try {
37456
+ return JSON.parse(feedback.sessionEvents);
37457
+ }
37458
+ catch (e) {
37459
+ console.error("Failed to parse session events", e);
37460
+ return null;
37461
+ }
37462
+ }, [feedback.sessionEvents]);
37463
+ // Format timestamp
37464
+ const formatTimestamp = (timestamp) => {
37465
+ const date = new Date(timestamp);
37466
+ return date.toLocaleTimeString('en-US', {
37467
+ hour: '2-digit',
37468
+ minute: '2-digit',
37469
+ second: '2-digit',
37470
+ hour12: false
37471
+ });
37472
+ };
37473
+ // Get relative time
37474
+ const getRelativeTime = (timestamp, baseTimestamp) => {
37475
+ const diff = Math.floor((timestamp - baseTimestamp) / 1000);
37476
+ if (diff === 0)
37477
+ return 'start';
37478
+ return `+${diff}s`;
37479
+ };
37229
37480
  const isReadOnly = ((_a = config.user) === null || _a === void 0 ? void 0 : _a.role) === "default" || config.allowStatusChange === false;
37230
- // Check if current user can delete this feedback
37231
- const canDelete = currentUser ? canDeleteFeedback(currentUser, feedback.createdBy.id) : false;
37481
+ // Check if current user can delete/edit this feedback
37482
+ const canDelete = currentUser
37483
+ ? canDeleteFeedback(currentUser, feedback.createdBy.id)
37484
+ : false;
37485
+ const canEdit = currentUser
37486
+ ? canEditFeedback(currentUser, feedback.createdBy.id)
37487
+ : false;
37488
+ const handleEditSubmit = async (updatedFeedback) => {
37489
+ setFeedback(updatedFeedback);
37490
+ updateFeedback$1(updatedFeedback);
37491
+ // Update in Firebase if initialized
37492
+ try {
37493
+ await updateFeedback(feedback.id, updatedFeedback);
37494
+ }
37495
+ catch (error) {
37496
+ console.warn("Failed to update feedback in Firebase:", error);
37497
+ }
37498
+ if (onUpdate) {
37499
+ onUpdate(updatedFeedback);
37500
+ }
37501
+ setIsEditing(false);
37502
+ };
37503
+ if (isEditing) {
37504
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [jsxRuntime.jsx("div", { className: "flex items-center justify-between p-5 pb-3 mb-3 border-b border-gray-200", children: jsxRuntime.jsxs("div", { onClick: () => setIsEditing(false), className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Cancel Editing"] }) }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto px-5", children: jsxRuntime.jsx(FeedbackForm, { initialData: feedback, onSubmit: handleEditSubmit, onCancel: () => setIsEditing(false) }) })] }));
37505
+ }
37232
37506
  const handleCopy = async () => {
37233
37507
  const feedbackText = `
37234
37508
  📝 ${feedback.title}
@@ -37272,7 +37546,7 @@ ${feedback.comments && feedback.comments.length > 0
37272
37546
  await updateFeedback(feedback.id, { status: newStatus });
37273
37547
  }
37274
37548
  catch (error) {
37275
- console.warn('Failed to update status in Firebase:', error);
37549
+ console.warn("Failed to update status in Firebase:", error);
37276
37550
  }
37277
37551
  if (config.onStatusChange) {
37278
37552
  await config.onStatusChange(feedback.id, newStatus);
@@ -37308,11 +37582,11 @@ ${feedback.comments && feedback.comments.length > 0
37308
37582
  // Update in Firebase if initialized
37309
37583
  try {
37310
37584
  await updateFeedback(feedback.id, {
37311
- comments: updatedFeedback.comments
37585
+ comments: updatedFeedback.comments,
37312
37586
  });
37313
37587
  }
37314
37588
  catch (error) {
37315
- console.warn('Failed to add comment in Firebase:', error);
37589
+ console.warn("Failed to add comment in Firebase:", error);
37316
37590
  }
37317
37591
  if (config.onCommentAdd) {
37318
37592
  await config.onCommentAdd(feedback.id, comment);
@@ -37331,7 +37605,7 @@ ${feedback.comments && feedback.comments.length > 0
37331
37605
  await deleteFeedback(feedback.id);
37332
37606
  }
37333
37607
  catch (error) {
37334
- console.warn('Failed to delete from Firebase:', error);
37608
+ console.warn("Failed to delete from Firebase:", error);
37335
37609
  }
37336
37610
  if (config.onDelete) {
37337
37611
  await config.onDelete(feedback.id);
@@ -37340,22 +37614,28 @@ ${feedback.comments && feedback.comments.length > 0
37340
37614
  onDelete(feedback.id);
37341
37615
  }
37342
37616
  };
37343
- return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full px-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between pb-3 mb-3 border-b border-gray-200", children: [jsxRuntime.jsxs("div", { onClick: onBack, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Back"] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("div", { onClick: handleCopy, className: "flex items-center gap-1.5 text-sm text-indigo-600 bg-transparent border-none cursor-pointer hover:text-indigo-700 transition-colors", children: copied ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4" }), "Copied!"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }), "Copy"] })) }), canDelete && onDelete && (jsxRuntime.jsxs("div", { onClick: handleDelete, className: "flex items-center gap-1.5 text-sm text-red-600 bg-transparent border-none cursor-pointer hover:text-red-700 transition-colors", children: [jsxRuntime.jsx(TrashIcon, { className: "w-4 h-4" }), "Delete"] }))] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto pr-1", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h3", { className: "text-base font-semibold text-gray-900 m-0 mb-2", children: feedback.title }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [feedback.type && (jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", feedback.type === "copy-amendment"
37344
- ? "bg-purple-100 text-purple-800"
37617
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full px-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between pb-3 mb-3 border-b border-gray-200", children: [jsxRuntime.jsxs("div", { onClick: onBack, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Back"] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("div", { onClick: handleCopy, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: copied ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4" }), "Copied!"] })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(CopyIcon, { className: "w-4 h-4" }) })) }), canEdit && (jsxRuntime.jsx("div", { onClick: () => setIsEditing(true), className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: jsxRuntime.jsx(EditIcon, { className: "w-4 h-4" }) })), canDelete && onDelete && (jsxRuntime.jsx("div", { onClick: handleDelete, className: "flex items-center gap-1.5 text-sm text-red-600 bg-transparent border-none cursor-pointer hover:text-red-700 transition-colors", children: jsxRuntime.jsx(TrashIcon, { className: "w-4 h-4" }) }))] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto pr-1", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("div", { className: "flex items-start gap-2 mb-2", children: [jsxRuntime.jsx("h3", { className: "text-base font-semibold text-gray-900 m-0 flex-1", children: feedback.title }), ((_b = feedback.pageMetadata) === null || _b === void 0 ? void 0 : _b.deviceType) && (jsxRuntime.jsxs("div", { className: "flex-shrink-0 mt-0.5", children: [feedback.pageMetadata.deviceType === 'desktop' && (jsxRuntime.jsx(DesktopIcon, { className: "w-5 h-5 text-gray-500", title: "Desktop" })), feedback.pageMetadata.deviceType === 'tablet' && (jsxRuntime.jsx(TabletIcon, { className: "w-5 h-5 text-gray-500", title: "Tablet" })), feedback.pageMetadata.deviceType === 'mobile' && (jsxRuntime.jsx(MobileIcon, { className: "w-5 h-5 text-gray-500", title: "Mobile" }))] }))] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [feedback.type && (jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", feedback.type === "copy-amendment"
37618
+ ? "bg-brand-blue/50 text-gray-800"
37345
37619
  : feedback.type === "bug"
37346
- ? "bg-red-100 text-red-800"
37620
+ ? "bg-brand-pink/30 text-gray-800"
37347
37621
  : feedback.type === "feature"
37348
- ? "bg-blue-100 text-blue-800"
37622
+ ? "bg-brand-green/30 text-gray-800"
37349
37623
  : "bg-gray-100 text-gray-700"), children: feedback.type === "copy-amendment"
37350
37624
  ? "Copy"
37351
37625
  : "General" })), jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", priorityColors[feedback.priority]), children: feedback.priority }), jsxRuntime.jsx("span", { className: "text-xs text-gray-400", children: formatDate(feedback.createdAt) })] })] }), !isReadOnly && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Status" }), jsxRuntime.jsx("div", { className: "flex gap-1.5", children: statusOptions.map((option) => (jsxRuntime.jsx("div", { onClick: () => handleStatusChange(option.value), className: cn("flex-1 py-1.5 px-2 rounded-lg text-[10px] font-medium border cursor-pointer transition-all text-center", feedback.status === option.value
37352
- ? "bg-[#C2D1D9] text-white border-[#C2D1D9]"
37353
- : "bg-white text-gray-600 border-gray-200 hover:border-indigo-300"), children: option.label }, option.value))) })] })), feedback.screenshot && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screenshot" }), jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md cursor-pointer group", onClick: () => setShowFullScreenshot(true), children: [jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all flex items-center justify-center", children: jsxRuntime.jsx("div", { className: "bg-white rounded-full p-3 shadow-xl transform scale-90 group-hover:scale-100 transition-transform", children: jsxRuntime.jsx(ZoomInIcon, { className: "w-6 h-6 text-gray-700" }) }) })] })] })), feedback.description && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Description" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600 m-0 whitespace-pre-wrap", children: feedback.description })] })), feedback.tags && feedback.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: feedback.tags.map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-full text-xs", children: tag }, tag))) })] })), feedback.pageMetadata && (jsxRuntime.jsxs("div", { className: "mb-4 p-2.5 bg-gray-50 rounded-lg", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Page Info" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 space-y-1", children: [jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "URL:" }), " ", feedback.pageMetadata.url] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Screen:" }), " ", feedback.pageMetadata.screenWidth, "x", feedback.pageMetadata.screenHeight] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "User Agent:" }), " ", feedback.pageMetadata.userAgent] })] })] })), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: ["Comments (", ((_b = feedback.comments) === null || _b === void 0 ? void 0 : _b.length) || 0, ")"] }), feedback.comments && feedback.comments.length > 0 && (jsxRuntime.jsx("div", { className: "space-y-3 mb-4", children: feedback.comments.map((comment) => (jsxRuntime.jsxs("div", { className: "p-3 bg-white border border-gray-200 rounded-xl shadow-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gradient-to-br from-[#C2D1D9] to-purple-500 flex items-center justify-center shadow-md", children: jsxRuntime.jsx(UserIcon, { className: "w-4 h-4 text-white" }) }), jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-900", children: comment.createdBy.name }), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 font-medium", children: formatDate(comment.createdAt) })] }), jsxRuntime.jsx("p", { className: "text-sm text-gray-700 m-0 ml-10 whitespace-pre-wrap", children: comment.content || comment.text })] }, comment.id))) })), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx("input", { type: "text", value: newComment, onChange: (e) => setNewComment(e.target.value), placeholder: "Add a comment...", className: "flex-1 px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", onKeyDown: (e) => {
37626
+ ? cn(option.color, "border-transparent")
37627
+ : "bg-white text-gray-600 border-gray-200 hover:border-brand-blue"), children: option.label }, option.value))) })] })), feedback.screenshot && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screenshot" }), jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md cursor-pointer group", onClick: () => setShowFullScreenshot(true), children: [jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all flex items-center justify-center", children: jsxRuntime.jsx("div", { className: "bg-white rounded-full p-3 shadow-xl transform scale-90 group-hover:scale-100 transition-transform", children: jsxRuntime.jsx(ZoomInIcon, { className: "w-6 h-6 text-gray-700" }) }) })] })] })), feedback.screenRecording && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screen Recording" }), jsxRuntime.jsx("div", { className: "relative rounded-xl overflow-hidden shadow-md border border-gray-200", children: jsxRuntime.jsx("video", { src: feedback.screenRecording, controls: true, className: "w-full h-auto bg-black" }) })] })), (feedback.designMockup || feedback.sessionEvents) && (jsxRuntime.jsxs("div", { className: "flex gap-2 mb-5", children: [feedback.sessionEvents && (jsxRuntime.jsx("button", { onClick: () => setShowReplay(true), className: "flex-1 bg-gray-100 text-gray-700 py-2.5 rounded-xl text-xs font-semibold hover:bg-gray-200 transition-colors flex items-center justify-center gap-2 border border-gray-200 cursor-pointer", children: "Play Session" })), feedback.designMockup && (jsxRuntime.jsx("button", { onClick: () => setShowOverlay(true), className: "flex-1 bg-gray-100 text-gray-700 py-2.5 rounded-xl text-xs font-semibold hover:bg-gray-200 transition-colors flex items-center justify-center gap-2 border border-gray-200 cursor-pointer", children: "Overlay Mockup" }))] })), feedback.type === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [feedback.currentCopy && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Current Copy" }), jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3", children: jsxRuntime.jsx("p", { className: "text-sm text-gray-800 m-0 whitespace-pre-wrap", children: feedback.currentCopy }) })] })), feedback.newCopy && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "New Copy" }), jsxRuntime.jsx("div", { className: "bg-green-50 border border-green-200 rounded-lg p-3", children: jsxRuntime.jsx("p", { className: "text-sm text-gray-800 m-0 whitespace-pre-wrap", children: feedback.newCopy }) })] }))] })), feedback.description && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Description" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600 m-0 whitespace-pre-wrap", children: feedback.description })] })), feedback.tags && feedback.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: feedback.tags.map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-full text-xs", children: tag }, tag))) })] })), feedback.pageMetadata && (jsxRuntime.jsxs("div", { className: "mb-4 p-2.5 bg-gray-50 rounded-lg", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Page Info" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 space-y-1", children: [jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "URL:" }), " ", feedback.pageMetadata.url] }), feedback.pageMetadata.componentName && (jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Component:" }), " ", jsxRuntime.jsx("code", { className: "bg-gray-200 px-1.5 py-0.5 rounded text-xs font-mono text-gray-800", children: feedback.pageMetadata.componentName })] })), feedback.pageMetadata.elementInfo && (jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Element:" }), " ", jsxRuntime.jsx("code", { className: "bg-blue-50 px-1.5 py-0.5 rounded text-xs font-mono text-blue-800", children: feedback.pageMetadata.elementInfo })] })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Screen:" }), " ", feedback.pageMetadata.screenWidth, "x", feedback.pageMetadata.screenHeight] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "User Agent:" }), " ", feedback.pageMetadata.userAgent] })] })] })), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: ["Comments (", ((_c = feedback.comments) === null || _c === void 0 ? void 0 : _c.length) || 0, ")"] }), feedback.comments && feedback.comments.length > 0 && (jsxRuntime.jsx("div", { className: "space-y-3 mb-4", children: feedback.comments.map((comment) => (jsxRuntime.jsxs("div", { className: "p-3 bg-white border border-gray-200 rounded-xl shadow-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gradient-to-br from-[#C2D1D9] to-purple-500 flex items-center justify-center shadow-md", children: jsxRuntime.jsx(UserIcon, { className: "w-4 h-4 text-white" }) }), jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-900", children: comment.createdBy.name }), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 font-medium", children: formatDate(comment.createdAt) })] }), jsxRuntime.jsx("p", { className: "text-sm text-gray-700 m-0 ml-10 whitespace-pre-wrap", children: comment.content || comment.text })] }, comment.id))) })), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx("input", { type: "text", value: newComment, onChange: (e) => setNewComment(e.target.value), placeholder: "Add a comment...", className: "flex-1 px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", onKeyDown: (e) => {
37354
37628
  if (e.key === "Enter" && !e.shiftKey) {
37355
37629
  e.preventDefault();
37356
37630
  handleAddComment();
37357
37631
  }
37358
- } }), jsxRuntime.jsx("button", { onClick: handleAddComment, disabled: !newComment.trim() || isAddingComment, className: "p-2.5 rounded-xl border-none text-white cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed hover:shadow-lg transition-all", style: { backgroundColor: "var(--markup-primary)" }, children: jsxRuntime.jsx(SendIcon, { className: "w-5 h-5" }) })] })] })] }), showFullScreenshot && feedback.screenshot && (jsxRuntime.jsxs("div", { className: "fixed inset-0 bg-black z-[1000001] flex items-center justify-center", onClick: () => setShowFullScreenshot(false), children: [jsxRuntime.jsx("button", { onClick: () => setShowFullScreenshot(false), className: "absolute top-4 right-4 p-3 bg-white/10 rounded-full border-none cursor-pointer hover:bg-white/20 transition-colors z-10", children: jsxRuntime.jsx(CloseIcon, { className: "w-8 h-8 text-white" }) }), jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full h-full object-contain", onClick: (e) => e.stopPropagation() })] }))] }));
37632
+ } }), jsxRuntime.jsx("button", { onClick: handleAddComment, disabled: !newComment.trim() || isAddingComment, className: "p-2.5 rounded-xl border-none text-white cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed hover:shadow-lg transition-all", style: { backgroundColor: "var(--markup-primary)" }, children: jsxRuntime.jsx(SendIcon, { className: "w-5 h-5" }) })] })] })] }), showFullScreenshot &&
37633
+ feedback.screenshot &&
37634
+ reactDom.createPortal(jsxRuntime.jsxs("div", { className: "fixed inset-0 bg-black/90 backdrop-blur-sm z-[2147483647] flex items-center justify-center p-10 animate-in fade-in duration-200", onClick: () => setShowFullScreenshot(false), children: [jsxRuntime.jsx("button", { onClick: () => setShowFullScreenshot(false), className: "absolute top-6 right-6 p-2 bg-white/10 rounded-full border-none cursor-pointer hover:bg-white/20 transition-colors z-10", children: jsxRuntime.jsx(CloseIcon, { className: "w-8 h-8 text-white" }) }), jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "max-w-full max-h-full object-contain rounded-lg shadow-2xl", onClick: (e) => e.stopPropagation() })] }), document.body), showReplay && sessionActions && sessionActions.length > 0 && reactDom.createPortal(jsxRuntime.jsx("div", { className: "fixed inset-0 z-[10000] bg-black/80 backdrop-blur-sm flex items-center justify-center p-5 animate-in fade-in duration-200", onClick: () => setShowReplay(false), children: jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl overflow-hidden shadow-2xl max-w-[900px] w-full flex flex-col max-h-[90vh]", onClick: (e) => e.stopPropagation(), children: [jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-100 flex items-center justify-between bg-gray-50", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900", children: "Session Activity Timeline" }), jsxRuntime.jsx("p", { className: "text-xs text-gray-600 mt-1", children: "User actions recorded during feedback creation" })] }), jsxRuntime.jsx("button", { onClick: () => setShowReplay(false), className: "p-2 hover:bg-gray-200 rounded-full transition-colors cursor-pointer text-gray-500 hover:text-gray-900 border-none bg-transparent", children: jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }) })] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: jsxRuntime.jsx("div", { className: "space-y-2", children: sessionActions.map((action, idx) => {
37635
+ var _a;
37636
+ const baseTime = ((_a = sessionActions[0]) === null || _a === void 0 ? void 0 : _a.timestamp) || action.timestamp;
37637
+ return (jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors", children: [jsxRuntime.jsxs("div", { className: "flex-shrink-0 w-20 text-xs font-mono text-gray-600", children: [jsxRuntime.jsx("div", { children: formatTimestamp(action.timestamp) }), jsxRuntime.jsx("div", { className: "text-gray-400", children: getRelativeTime(action.timestamp, baseTime) })] }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [action.type === 'click' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-blue-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Clicked" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700 font-mono bg-white px-2 py-1 rounded border border-gray-200", children: ["<", action.data.elementTag || 'unknown', action.data.elementId && ` id="${action.data.elementId}"`, action.data.elementClass && ` class="${action.data.elementClass}"`, ">"] }), action.data.elementText && (jsxRuntime.jsxs("div", { className: "mt-1 text-sm text-gray-600", children: ["Text: ", jsxRuntime.jsxs("span", { className: "italic", children: ["\"", action.data.elementText.substring(0, 100), action.data.elementText.length > 100 ? '...' : '', "\""] })] }))] })), action.type === 'navigation' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-purple-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Navigated" })] }), jsxRuntime.jsx("div", { className: "text-sm text-gray-700 break-all", children: action.data.url })] })), action.type === 'scroll' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-green-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Scrolled" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: ["Position: ", action.data.scrollY, "px"] })] })), action.type === 'input' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-orange-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Input" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: [action.data.inputType, " field"] })] }))] })] }, idx));
37638
+ }) }) })] }) }), document.body), showOverlay && feedback.designMockup && reactDom.createPortal(jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[10000] pointer-events-none", children: [jsxRuntime.jsx("img", { src: feedback.designMockup, style: { opacity: overlayOpacity / 100 }, className: "w-full h-full object-contain object-top", alt: "Design Mockup Overlay" }), jsxRuntime.jsxs("div", { className: "fixed bottom-10 left-1/2 -translate-x-1/2 bg-white/90 backdrop-blur border border-gray-200 shadow-xl rounded-full p-2 px-6 flex items-center gap-4 pointer-events-auto", children: [jsxRuntime.jsx("span", { className: "text-xs font-bold text-gray-500 uppercase whitespace-nowrap", children: "Overlay Opacity" }), jsxRuntime.jsx("input", { type: "range", min: "0", max: "100", value: overlayOpacity, onChange: (e) => setOverlayOpacity(Number(e.target.value)), className: "w-32 accent-brand-blue" }), jsxRuntime.jsx("button", { onClick: () => setShowOverlay(false), className: "ml-2 hover:bg-gray-200 p-1.5 rounded-full border-none bg-transparent", children: jsxRuntime.jsx(CloseIcon, { className: "w-4 h-4 text-gray-500" }) })] })] }), document.body)] }));
37359
37639
  };
37360
37640
 
37361
37641
  const signUp = async (email, password) => {
@@ -37407,18 +37687,82 @@ const AuthForm = ({ onSuccess }) => {
37407
37687
  };
37408
37688
  return (jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center h-full p-5", children: jsxRuntime.jsxs("div", { className: "w-full max-w-md", children: [jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl shadow-2xl p-8", children: [jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2 text-center", children: mode === "login" ? "Sign In" : "Create Account" }), jsxRuntime.jsx("p", { className: "text-gray-600 text-sm text-center mb-6", children: mode === "login"
37409
37689
  ? "Sign in to submit and manage feedback"
37410
- : "Create an account to get started" }), jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-2", children: "Email Address" }), jsxRuntime.jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "you@example.com" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "password", className: "block text-sm font-medium text-gray-700 mb-2", children: "Password" }), jsxRuntime.jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "Minimum 6 characters" })] }), error && (jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg text-sm", children: error })), jsxRuntime.jsx("div", { onClick: handleSubmit, className: "w-full bg-[#c2d1d9] text-white py-2.5 px-4 rounded-lg font-medium hover:bg-[#c2d1d9]/80 focus:ring-4 focus:ring-blue transition-all cursor-pointer text-center", children: loading
37690
+ : "Create an account to get started" }), jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-2", children: "Email Address" }), jsxRuntime.jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "you@example.com" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "password", className: "block text-sm font-medium text-gray-700 mb-2", children: "Password" }), jsxRuntime.jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "Minimum 6 characters" })] }), error && (jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg text-sm", children: error })), jsxRuntime.jsx("div", { onClick: handleSubmit, className: "w-full bg-[#c2d1d9] text-black py-2.5 px-4 rounded-lg font-medium hover:bg-[#c2d1d9]/80 focus:ring-4 focus:ring-blue transition-all cursor-pointer text-center", children: loading
37411
37691
  ? "Please wait..."
37412
37692
  : mode === "login"
37413
37693
  ? "Sign In"
37414
37694
  : "Create Account" })] }), jsxRuntime.jsx("div", { className: "mt-6 text-center", children: jsxRuntime.jsx("div", { onClick: () => {
37415
37695
  setMode(mode === "login" ? "signup" : "login");
37416
37696
  setError(null);
37417
- }, className: "bg-gray-500 text-white w-full font-medium cursor-pointer", children: mode === "login"
37697
+ }, className: "bg-pink text-black w-full font-medium cursor-pointer hover:underline", children: mode === "login"
37418
37698
  ? "Don't have an account? Sign up"
37419
37699
  : "Already have an account? Sign in" }) })] }), jsxRuntime.jsx("p", { className: "text-center text-xs text-gray-500 mt-6", children: "Your feedback will be associated with your account" })] }) }));
37420
37700
  };
37421
37701
 
37702
+ const VIEWPORT_PRESETS = [
37703
+ { name: "iPhone SE", width: 375, height: 667, deviceType: "mobile" },
37704
+ { name: "iPhone 12 Pro", width: 390, height: 844, deviceType: "mobile" },
37705
+ { name: "iPhone 14 Pro Max", width: 430, height: 932, deviceType: "mobile" },
37706
+ { name: "iPad Mini", width: 768, height: 1024, deviceType: "tablet" },
37707
+ { name: "iPad Pro", width: 1024, height: 1366, deviceType: "tablet" },
37708
+ { name: "Desktop", width: 1920, height: 1080, deviceType: "desktop" },
37709
+ ];
37710
+ const ViewportControls = () => {
37711
+ const { viewportMode, setViewportMode, isOpen: isWidgetOpen } = useMarkupStore();
37712
+ const [isExpanded, setIsExpanded] = require$$0.useState(false);
37713
+ const dropdownRef = require$$0.useRef(null);
37714
+ const handlePresetClick = (preset) => {
37715
+ setViewportMode({ width: preset.width, height: preset.height });
37716
+ setIsExpanded(false);
37717
+ };
37718
+ const handleReset = () => {
37719
+ setViewportMode(null);
37720
+ setIsExpanded(false);
37721
+ };
37722
+ const isActivePreset = (preset) => {
37723
+ return (viewportMode === null || viewportMode === void 0 ? void 0 : viewportMode.width) === preset.width && (viewportMode === null || viewportMode === void 0 ? void 0 : viewportMode.height) === preset.height;
37724
+ };
37725
+ // Close dropdown on outside click
37726
+ require$$0.useEffect(() => {
37727
+ if (!isExpanded)
37728
+ return;
37729
+ const handleClickOutside = (event) => {
37730
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
37731
+ setIsExpanded(false);
37732
+ }
37733
+ };
37734
+ document.addEventListener('mousedown', handleClickOutside);
37735
+ return () => document.removeEventListener('mousedown', handleClickOutside);
37736
+ }, [isExpanded]);
37737
+ // Handle ESC key to close dropdown or reset viewport
37738
+ require$$0.useEffect(() => {
37739
+ const handleKeyDown = (event) => {
37740
+ if (event.key === 'Escape') {
37741
+ if (isExpanded) {
37742
+ setIsExpanded(false);
37743
+ event.preventDefault();
37744
+ }
37745
+ else if (viewportMode) {
37746
+ handleReset();
37747
+ event.preventDefault();
37748
+ }
37749
+ }
37750
+ };
37751
+ document.addEventListener('keydown', handleKeyDown);
37752
+ return () => document.removeEventListener('keydown', handleKeyDown);
37753
+ }, [isExpanded, viewportMode]);
37754
+ // Don't show controls when widget is not open
37755
+ if (!isWidgetOpen)
37756
+ return null;
37757
+ return (jsxRuntime.jsxs("div", { ref: dropdownRef, className: "fixed top-4 left-1/2 -translate-x-1/2 z-[999998] flex items-center gap-2", children: [!viewportMode ? (jsxRuntime.jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "bg-white border-2 border-gray-300 rounded-xl px-4 py-2 shadow-lg hover:shadow-xl transition-all flex items-center gap-2 text-sm font-medium text-gray-700 hover:text-gray-900 hover:border-gray-400", children: [jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4" }), "Responsive Mode"] })) : (jsxRuntime.jsxs("div", { className: "bg-white border-2 border-gray-300 rounded-xl px-4 py-2 shadow-lg flex items-center gap-3", children: [jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-700", children: [viewportMode.width, " \u00D7 ", viewportMode.height] }), jsxRuntime.jsx("button", { onClick: () => setIsExpanded(!isExpanded), className: "text-gray-600 hover:text-gray-900 transition-colors", children: jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4" }) }), jsxRuntime.jsx("button", { onClick: handleReset, className: "px-2 py-1 text-xs font-medium text-red-600 hover:text-white hover:bg-red-600 border border-red-600 rounded transition-colors", children: "Reset" })] })), isExpanded && (jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-2xl p-3 min-w-[240px]", children: jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mb-2", children: "Mobile" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "mobile").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37758
+ ? "bg-blue-50 border border-blue-200"
37759
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(MobileIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name))), jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mt-4 mb-2", children: "Tablet" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "tablet").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37760
+ ? "bg-blue-50 border border-blue-200"
37761
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(TabletIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name))), jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mt-4 mb-2", children: "Desktop" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "desktop").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37762
+ ? "bg-blue-50 border border-blue-200"
37763
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(DesktopIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name)))] }) }))] }));
37764
+ };
37765
+
37422
37766
  const useFirebaseSync = () => {
37423
37767
  const config = useMarkupStore((state) => state.config);
37424
37768
  const setCurrentUser = useMarkupStore((state) => state.setCurrentUser);
@@ -37513,6 +37857,109 @@ const useFirebaseSync = () => {
37513
37857
  }, [config.projectId, setFeedbackItems, isAuthenticated]);
37514
37858
  };
37515
37859
 
37860
+ const useSessionRecording = () => {
37861
+ const actionsRef = require$$0.useRef([]);
37862
+ const maxActions = 50; // Keep last 50 actions
37863
+ require$$0.useEffect(() => {
37864
+ if (typeof window === 'undefined')
37865
+ return;
37866
+ const recordAction = (action) => {
37867
+ if (actionsRef.current.length >= maxActions) {
37868
+ actionsRef.current.shift();
37869
+ }
37870
+ actionsRef.current.push(action);
37871
+ };
37872
+ // Record clicks
37873
+ const handleClick = (e) => {
37874
+ var _a;
37875
+ const target = e.target;
37876
+ if (target.closest('[data-markup-widget]'))
37877
+ return;
37878
+ recordAction({
37879
+ type: 'click',
37880
+ timestamp: Date.now(),
37881
+ data: {
37882
+ elementTag: target.tagName.toLowerCase(),
37883
+ elementText: ((_a = target.textContent) === null || _a === void 0 ? void 0 : _a.slice(0, 50).trim()) || undefined,
37884
+ elementId: target.id || undefined,
37885
+ elementClass: target.className && typeof target.className === 'string'
37886
+ ? target.className.split(' ').slice(0, 3).join(' ')
37887
+ : undefined,
37888
+ }
37889
+ });
37890
+ };
37891
+ // Record navigation
37892
+ const handleNavigation = () => {
37893
+ recordAction({
37894
+ type: 'navigation',
37895
+ timestamp: Date.now(),
37896
+ data: {
37897
+ url: window.location.href
37898
+ }
37899
+ });
37900
+ };
37901
+ // Record scroll (throttled)
37902
+ let scrollTimeout;
37903
+ const handleScroll = () => {
37904
+ clearTimeout(scrollTimeout);
37905
+ scrollTimeout = setTimeout(() => {
37906
+ recordAction({
37907
+ type: 'scroll',
37908
+ timestamp: Date.now(),
37909
+ data: {
37910
+ scrollY: window.scrollY
37911
+ }
37912
+ });
37913
+ }, 500);
37914
+ };
37915
+ // Record input events
37916
+ const handleInput = (e) => {
37917
+ const target = e.target;
37918
+ if (target.closest('[data-markup-widget]'))
37919
+ return;
37920
+ recordAction({
37921
+ type: 'input',
37922
+ timestamp: Date.now(),
37923
+ data: {
37924
+ elementTag: target.tagName.toLowerCase(),
37925
+ elementId: target.id || undefined,
37926
+ inputType: target.type || undefined,
37927
+ }
37928
+ });
37929
+ };
37930
+ // Record initial page load
37931
+ recordAction({
37932
+ type: 'navigation',
37933
+ timestamp: Date.now(),
37934
+ data: { url: window.location.href }
37935
+ });
37936
+ document.addEventListener('click', handleClick, true);
37937
+ window.addEventListener('popstate', handleNavigation);
37938
+ window.addEventListener('scroll', handleScroll, { passive: true });
37939
+ document.addEventListener('input', handleInput, true);
37940
+ return () => {
37941
+ document.removeEventListener('click', handleClick, true);
37942
+ window.removeEventListener('popstate', handleNavigation);
37943
+ window.removeEventListener('scroll', handleScroll);
37944
+ document.removeEventListener('input', handleInput, true);
37945
+ clearTimeout(scrollTimeout);
37946
+ };
37947
+ }, []);
37948
+ const getSessionEvents = require$$0.useCallback(() => {
37949
+ if (actionsRef.current.length === 0) {
37950
+ return undefined;
37951
+ }
37952
+ return JSON.stringify(actionsRef.current);
37953
+ }, []);
37954
+ const clearSession = require$$0.useCallback(() => {
37955
+ actionsRef.current = [];
37956
+ }, []);
37957
+ return {
37958
+ getSessionEvents,
37959
+ clearSession
37960
+ };
37961
+ };
37962
+
37516
37963
  const MarkupWidget = ({ config: userConfig, }) => {
37517
37964
  var _a;
37518
37965
  // Initialize Firebase synchronously on first render only
@@ -37527,9 +37974,76 @@ const MarkupWidget = ({ config: userConfig, }) => {
37527
37974
  console.error('Failed to initialize Firebase:', error);
37528
37975
  }
37529
37976
  }
37530
- const { isOpen, setIsOpen, activeTab, setActiveTab, selectedFeedback, setSelectedFeedback, feedbackItems, addFeedbackItem, config, setConfig, reset, isAuthenticated, currentUser, } = useMarkupStore();
37977
+ const { isOpen, setIsOpen, activeTab, setActiveTab, selectedFeedback, setSelectedFeedback, feedbackItems, addFeedbackItem, removeFeedbackItem, updateFeedback, config, setConfig, reset, isAuthenticated, currentUser, viewportMode, setViewportMode, } = useMarkupStore();
37531
37978
  // Initialize Firebase sync
37532
37979
  useFirebaseSync();
37980
+ // Initialize Session Recording (Feature 2)
37981
+ const { getSessionEvents } = useSessionRecording();
37982
+ // Track last clicked element for component detection (Feature 4)
37983
+ const lastClickedElementRef = require$$0.useRef(null);
37984
+ const [lastClickedText, setLastClickedText] = require$$0.useState('');
37985
+ require$$0.useEffect(() => {
37986
+ const handleClick = (e) => {
37987
+ var _a;
37988
+ // Store the clicked element (but ignore clicks on the widget itself)
37989
+ const target = e.target;
37990
+ if (!target.closest('[data-markup-widget]')) {
37991
+ lastClickedElementRef.current = target;
37992
+ // If user clicked on text content, capture it for copy amendment
37993
+ // Get the immediate text content (not children)
37994
+ let textContent = '';
37995
+ if (target.childNodes.length > 0) {
37996
+ // Try to get direct text nodes only
37997
+ for (const node of Array.from(target.childNodes)) {
37998
+ if (node.nodeType === Node.TEXT_NODE) {
37999
+ textContent += node.textContent || '';
38000
+ }
38001
+ }
38002
+ textContent = textContent.trim();
38003
+ }
38004
+ // If no direct text, fall back to full textContent
38005
+ if (!textContent) {
38006
+ textContent = ((_a = target.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
38007
+ }
38008
+ if (textContent && textContent.length > 0 && textContent.length < 500) {
38009
+ setLastClickedText(textContent);
38010
+ }
38011
+ else {
38012
+ setLastClickedText('');
38013
+ }
38014
+ }
38015
+ };
38016
+ document.addEventListener('click', handleClick, true);
38017
+ return () => document.removeEventListener('click', handleClick, true);
38018
+ }, []);
38019
+ // Apply viewport mode styling to document (like browser dev tools)
38020
+ require$$0.useEffect(() => {
38021
+ if (viewportMode) {
38022
+ const root = document.documentElement;
38023
+ const body = document.body;
38024
+ // Apply dark background to body
38025
+ body.style.background = 'rgba(0, 0, 0, 0.5)';
38026
+ body.style.overflow = 'visible';
38027
+ // Apply viewport constraints with smooth transition
38028
+ root.style.transition = 'max-width 0.3s ease-in-out, margin 0.3s ease-in-out, background 0.2s ease-in-out';
38029
+ root.style.maxWidth = `${viewportMode.width}px`;
38030
+ root.style.margin = '0 auto';
38031
+ root.style.border = '2px solid #999';
38032
+ root.style.background = '#ffffff'; // Ensure content area has white background
38033
+ root.style.boxShadow = '0 0 50px rgba(0, 0, 0, 0.3)';
38034
+ return () => {
38035
+ // Reset to full width
38036
+ root.style.transition = '';
38037
+ root.style.maxWidth = '';
38038
+ root.style.margin = '';
38039
+ root.style.border = '';
38040
+ root.style.background = '';
38041
+ root.style.boxShadow = '';
38042
+ body.style.overflow = '';
38043
+ body.style.background = '';
38044
+ };
38045
+ }
38046
+ }, [viewportMode]);
37533
38047
  require$$0.useEffect(() => {
37534
38048
  if (userConfig) {
37535
38049
  setConfig(userConfig);
@@ -37601,7 +38115,8 @@ const MarkupWidget = ({ config: userConfig, }) => {
37601
38115
  }, [setSelectedFeedback]);
37602
38116
  const handleBackFromDetail = require$$0.useCallback(() => {
37603
38117
  setSelectedFeedback(null);
37604
- }, [setSelectedFeedback]);
38118
+ setViewportMode(null);
38119
+ }, [setSelectedFeedback, setViewportMode]);
37605
38120
  const handleLogout = require$$0.useCallback(async () => {
37606
38121
  try {
37607
38122
  await logOut();
@@ -37614,6 +38129,15 @@ const MarkupWidget = ({ config: userConfig, }) => {
37614
38129
  const handleAuthSuccess = require$$0.useCallback(() => {
37615
38130
  setActiveTab("create");
37616
38131
  }, [setActiveTab]);
38132
+ const handleDeleteFeedback = require$$0.useCallback((id) => {
38133
+ removeFeedbackItem(id);
38134
+ setSelectedFeedback(null);
38135
+ }, [removeFeedbackItem, setSelectedFeedback]);
38136
+ const handleUpdateFeedback = require$$0.useCallback((updatedFeedback) => {
38137
+ updateFeedback(updatedFeedback);
38138
+ // Also update selected feedback if it's the same one (it should be)
38139
+ setSelectedFeedback(updatedFeedback);
38140
+ }, [updateFeedback, setSelectedFeedback]);
37617
38141
  const openFeedbackCount = feedbackItems.filter((f) => f.status === "open").length;
37618
38142
  ({
37619
38143
  ["--markup-primary"]: config.primaryColor || "#6366f1",
@@ -37621,15 +38145,15 @@ const MarkupWidget = ({ config: userConfig, }) => {
37621
38145
  ? adjustColor(config.primaryColor, -20)
37622
38146
  : "#4f46e5",
37623
38147
  });
37624
- return (jsxRuntime.jsxs("div", { className: cn("markup-widget fixed z-[999999] right-0 top-1/2 flex items-center transition-transform duration-300 ease-in-out", isOpen ? "" : "hover:translate-x-[-8px]"), style: {
37625
- transform: isOpen
37626
- ? "translateY(-50%) translateX(0)"
37627
- : "translateY(-50%) translateX(calc(100% - 40px))",
37628
- }, "data-markup-widget": true, children: [jsxRuntime.jsxs("div", { onClick: handleToggle, className: "relative bg-white h-fit flex items-center gap-2 px-2 pr-5 text-black border-none rounded-l-2xl cursor-pointer text-sm font-semibold transition-all py-5 shadow-lg", children: [isOpen && jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }), jsxRuntime.jsx("span", { className: "text-black", style: { writingMode: "sideways-lr" }, children: "Siren" }), openFeedbackCount > 0 && (jsxRuntime.jsx("span", { className: "absolute -top-3 -left-1 min-w-[24px] h-[24px] px-1 bg-[#E6B6CF] text-black rounded-full text-xs font-semibold flex items-center justify-center", children: openFeedbackCount }))] }), jsxRuntime.jsxs("div", { className: "bg-white w-[500px] h-[750px] rounded-l-xl shadow-2xl overflow-hidden flex flex-col text-black", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 text-black", style: { backgroundColor: "var(--markup-primary)" }, children: [jsxRuntime.jsx("h2", { className: "text-base font-semibold m-0", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.feedbackTitle) || "Feedback" }), isAuthenticated && currentUser && (jsxRuntime.jsx("div", { onClick: handleLogout, className: "text-xs p-2 border-black border text-black rounded-xl ", children: jsxRuntime.jsx("h2", { children: "Sign Out" }) }))] }), !isAuthenticated ? (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntime.jsx(AuthForm, { onSuccess: handleAuthSuccess }) })) : selectedFeedback ? (jsxRuntime.jsx(FeedbackDetail, { feedback: selectedFeedback, onBack: handleBackFromDetail })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex border-b border-gray-200 px-5", children: [jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "create"
37629
- ? "bg-gray-200"
37630
- : "border-white"), onClick: () => setActiveTab("create"), children: [jsxRuntime.jsx(PlusIcon, { className: "w-3.5 h-3.5" }), "New"] }), jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "list"
37631
- ? "bg-gray-200"
37632
- : "border-white"), onClick: () => setActiveTab("list"), children: ["View All (", feedbackItems.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-5", children: [activeTab === "create" && (jsxRuntime.jsx(FeedbackForm, { onSubmit: handleSubmitFeedback, onCancel: handleCancel })), activeTab === "list" && (jsxRuntime.jsx(FeedbackList, { feedbackItems: feedbackItems, onSelectFeedback: handleSelectFeedback }))] })] }))] })] }));
38148
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ViewportControls, {}), jsxRuntime.jsxs("div", { className: cn("markup-widget fixed z-[999999] right-0 top-1/2 flex items-center transition-transform duration-300 ease-in-out", isOpen ? "" : "hover:translate-x-[-8px]"), style: {
38149
+ transform: isOpen
38150
+ ? "translateY(-50%) translateX(0)"
38151
+ : "translateY(-50%) translateX(calc(100% - 40px))",
38152
+ }, "data-markup-widget": true, children: [jsxRuntime.jsxs("div", { onClick: handleToggle, className: "relative bg-white h-fit flex items-center gap-2 px-2 pr-5 text-black border-none rounded-l-2xl cursor-pointer text-sm font-semibold transition-all py-5 shadow-lg", children: [isOpen && jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }), jsxRuntime.jsx("span", { className: "text-black", style: { writingMode: "sideways-lr" }, children: "Siren" }), openFeedbackCount > 0 && (jsxRuntime.jsx("span", { className: "absolute -top-3 -left-1 min-w-[24px] h-[24px] px-1 bg-[#E6B6CF] text-black rounded-full text-xs font-semibold flex items-center justify-center", children: openFeedbackCount }))] }), jsxRuntime.jsxs("div", { className: "bg-white w-[500px] h-[750px] rounded-l-xl shadow-2xl overflow-hidden flex flex-col text-black", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 text-black", style: { backgroundColor: "var(--markup-primary)" }, children: [jsxRuntime.jsx("h2", { className: "text-base font-semibold m-0", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.feedbackTitle) || "Feedback" }), isAuthenticated && currentUser && (jsxRuntime.jsx("div", { onClick: handleLogout, className: "text-xs py-2 px-4 bg-gray-50 border border-gray-200 text-black rounded-xl hover:bg-gray-200 cursor-pointer transition-all flex items-center gap-2", children: jsxRuntime.jsx("h2", { children: "Sign Out" }) }))] }), !isAuthenticated ? (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntime.jsx(AuthForm, { onSuccess: handleAuthSuccess }) })) : selectedFeedback ? (jsxRuntime.jsx(FeedbackDetail, { feedback: selectedFeedback, onBack: handleBackFromDetail, onDelete: handleDeleteFeedback, onUpdate: handleUpdateFeedback })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex border-b border-gray-200 px-5", children: [jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "create"
38153
+ ? "bg-gray-200"
38154
+ : "border-white"), onClick: () => setActiveTab("create"), children: [jsxRuntime.jsx(PlusIcon, { className: "w-3.5 h-3.5" }), "New"] }), jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "list"
38155
+ ? "bg-gray-200"
38156
+ : "border-white"), onClick: () => setActiveTab("list"), children: ["View All (", feedbackItems.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-5", children: [activeTab === "create" && (jsxRuntime.jsx(FeedbackForm, { onSubmit: handleSubmitFeedback, onCancel: handleCancel, getSessionEvents: getSessionEvents, lastClickedElement: lastClickedElementRef.current, lastClickedText: lastClickedText })), activeTab === "list" && (jsxRuntime.jsx(FeedbackList, { feedbackItems: feedbackItems, onSelectFeedback: handleSelectFeedback }))] })] }))] })] })] }));
37633
38157
  };
37634
38158
  function adjustColor(color, amount) {
37635
38159
  const clamp = (val) => Math.min(255, Math.max(0, val));