diff --git a/packages/react-grab/src/components/comments-dropdown.tsx b/packages/react-grab/src/components/comments-dropdown.tsx index 319167ffc..ccd072fa7 100644 --- a/packages/react-grab/src/components/comments-dropdown.tsx +++ b/packages/react-grab/src/components/comments-dropdown.tsx @@ -40,6 +40,21 @@ const getCommentItemDisplayName = (item: CommentItem): string => { return item.componentName ?? item.tagName; }; +const getCommentItemUrlLabel = (item: CommentItem): string | undefined => { + if (!item.url) return undefined; + try { + const parsed = new URL(item.url); + const currentHost = typeof window !== "undefined" ? window.location.host : ""; + const pathAndQuery = `${parsed.pathname}${parsed.search}`; + if (parsed.host && parsed.host !== currentHost) { + return `${parsed.host}${pathAndQuery}`; + } + return pathAndQuery || "/"; + } catch { + return item.url; + } +}; + export const CommentsDropdown: Component = (props) => { let containerRef: HTMLDivElement | undefined; const { @@ -284,6 +299,16 @@ export const CommentsDropdown: Component = (props) => { {item.commentText} + + {(urlLabel) => ( + + {urlLabel()} + + )} + {formatRelativeTime(item.timestamp)} diff --git a/packages/react-grab/src/constants.ts b/packages/react-grab/src/constants.ts index 29d6dca49..47b74ffae 100644 --- a/packages/react-grab/src/constants.ts +++ b/packages/react-grab/src/constants.ts @@ -126,7 +126,6 @@ export const ZOOM_DETECTION_THRESHOLD = 0.01; export const MOUNT_ROOT_RECHECK_DELAY_MS = 1000; -export const MAX_COMMENT_ITEMS = 20; export const MAX_SESSION_STORAGE_SIZE_BYTES = 2 * 1024 * 1024; // Must match the CSS exit transition on dropdown components or the DOM // unmounts mid-animation. diff --git a/packages/react-grab/src/core/index.tsx b/packages/react-grab/src/core/index.tsx index 8dba00964..73c9f3ef0 100644 --- a/packages/react-grab/src/core/index.tsx +++ b/packages/react-grab/src/core/index.tsx @@ -784,6 +784,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { previewBounds: copiedElements.map((copiedElement) => createElementBounds(copiedElement)), elementSelectors, commentText: extraPrompt, + url: typeof window !== "undefined" ? window.location.href : undefined, timestamp: Date.now(), }); setCommentItems(updatedCommentItems); @@ -3341,8 +3342,11 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { } }; + const decorateContentWithUrl = (content: string, url: string | undefined): string => + url ? `${content}\n at ${url}` : content; + const copyCommentItemContent = (item: CommentItem) => { - copyContent(item.content, { + copyContent(decorateContentWithUrl(item.content, item.url), { tagName: item.tagName, componentName: item.componentName ?? item.elementName, commentText: item.commentText, @@ -3386,7 +3390,9 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { if (currentCommentItems.length === 0) return; const combinedContent = joinSnippets( - currentCommentItems.map((commentItem) => commentItem.content), + currentCommentItems.map((commentItem) => + decorateContentWithUrl(commentItem.content, commentItem.url), + ), ); const firstItem = currentCommentItems[0]; @@ -3395,7 +3401,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { entries: currentCommentItems.map((commentItem) => ({ tagName: commentItem.tagName, componentName: commentItem.componentName ?? commentItem.elementName, - content: commentItem.content, + content: decorateContentWithUrl(commentItem.content, commentItem.url), commentText: commentItem.commentText, })), }); diff --git a/packages/react-grab/src/types.ts b/packages/react-grab/src/types.ts index 31910ad6f..ef6ee517c 100644 --- a/packages/react-grab/src/types.ts +++ b/packages/react-grab/src/types.ts @@ -344,6 +344,7 @@ export interface CommentItem { previewBounds?: OverlayBounds[]; elementSelectors?: string[]; commentText?: string; + url?: string; timestamp: number; } diff --git a/packages/react-grab/src/utils/comment-storage.ts b/packages/react-grab/src/utils/comment-storage.ts index b87998676..a2d182899 100644 --- a/packages/react-grab/src/utils/comment-storage.ts +++ b/packages/react-grab/src/utils/comment-storage.ts @@ -1,4 +1,4 @@ -import { MAX_COMMENT_ITEMS, MAX_SESSION_STORAGE_SIZE_BYTES } from "../constants.js"; +import { MAX_SESSION_STORAGE_SIZE_BYTES } from "../constants.js"; import type { CommentItem } from "../types.js"; import { generateId } from "./generate-id.js"; import { logRecoverableError } from "./log-recoverable-error.js"; @@ -76,9 +76,7 @@ if (typeof window !== "undefined") { export const loadComments = (): CommentItem[] => commentItems; export const addCommentItem = (item: Omit): CommentItem[] => - persistCommentItems( - [{ ...item, id: generateId("comment") }, ...commentItems].slice(0, MAX_COMMENT_ITEMS), - ); + persistCommentItems([{ ...item, id: generateId("comment") }, ...commentItems]); export const removeCommentItem = (itemId: string): void => { persistCommentItems(commentItems.filter((innerItem) => innerItem.id !== itemId));