From af18c72116a04ffcdbdf747af8eb26ea62da693f Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:25:20 +0530 Subject: [PATCH 01/33] feat: add playwright default dimensions --- src/constants/const.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/constants/const.ts b/src/constants/const.ts index a1d7393d..103cb4db 100644 --- a/src/constants/const.ts +++ b/src/constants/const.ts @@ -1,6 +1,10 @@ export const VIEWPORT_W = 900; export const VIEWPORT_H = 400; +// Default Playwright viewport dimensions +export const BROWSER_DEFAULT_WIDTH = 1280; +export const BROWSER_DEFAULT_HEIGHT = 720; + export const ONE_PERCENT_OF_VIEWPORT_W = VIEWPORT_W / 100; export const ONE_PERCENT_OF_VIEWPORT_H = VIEWPORT_H / 100; From 7b715284bf37a4164db7d1393ebebe1a0df61732 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:35:35 +0530 Subject: [PATCH 02/33] feat: map coords for highlighter data --- src/components/browser/BrowserWindow.tsx | 124 ++++++++++++++++------- 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/src/components/browser/BrowserWindow.tsx b/src/components/browser/BrowserWindow.tsx index 8edae179..dbd43f61 100644 --- a/src/components/browser/BrowserWindow.tsx +++ b/src/components/browser/BrowserWindow.tsx @@ -9,6 +9,8 @@ import { useBrowserSteps, TextStep } from '../../context/browserSteps'; import { useGlobalInfoStore } from '../../context/globalInfo'; import { useTranslation } from 'react-i18next'; import { AuthContext } from '../../context/auth'; +import { coordinateMapper } from '../../helpers/coordinateMapper'; +import { VIEWPORT_H, VIEWPORT_W } from '../../constants/const'; interface ElementInfo { tagName: string; @@ -31,6 +33,12 @@ interface AttributeOption { interface ScreencastData { image: string; userId: string; + viewport?: ViewportInfo | null; +} + +interface ViewportInfo { + width: number; + height: number; } @@ -69,6 +77,7 @@ export const BrowserWindow = () => { const [attributeOptions, setAttributeOptions] = useState([]); const [selectedElement, setSelectedElement] = useState<{ selector: string, info: ElementInfo | null } | null>(null); const [currentListId, setCurrentListId] = useState(null); + const [viewportInfo, setViewportInfo] = useState({ width: VIEWPORT_W, height: VIEWPORT_H }); const [listSelector, setListSelector] = useState(null); const [fields, setFields] = useState>({}); @@ -82,6 +91,10 @@ export const BrowserWindow = () => { const { state } = useContext(AuthContext); const { user } = state; + useEffect(() => { + coordinateMapper.updateDimensions(VIEWPORT_W, VIEWPORT_H, viewportInfo.width, viewportInfo.height); + }, [viewportInfo]); + useEffect(() => { if (listSelector) { window.sessionStorage.setItem('recordingListSelector', listSelector); @@ -124,12 +137,33 @@ export const BrowserWindow = () => { } }, [getList, resetListState]); + useEffect(() => { + if (socket) { + socket.on('viewportInfo', (data: { width: number, height: number, userId: string }) => { + if (!data.userId || data.userId === user?.id) { + setViewportInfo({ + width: data.width, + height: data.height + }); + } + }); + + return () => { + socket.off('viewportInfo'); + }; + } + }, [socket, user?.id]); + const screencastHandler = useCallback((data: string | ScreencastData) => { if (typeof data === 'string') { setScreenShot(data); } else if (data && typeof data === 'object' && 'image' in data) { if (!data.userId || data.userId === user?.id) { setScreenShot(data.image); + + if (data.viewport) { + setViewportInfo(data.viewport); + } } } }, [screenShot, user?.id]); @@ -149,78 +183,85 @@ export const BrowserWindow = () => { }, [screenShot, canvasRef, socket, screencastHandler]); const highlighterHandler = useCallback((data: { rect: DOMRect, selector: string, elementInfo: ElementInfo | null, childSelectors?: string[] }) => { + // Map the incoming DOMRect from browser coordinates to canvas coordinates + const mappedRect = new DOMRect( + data.rect.x, + data.rect.y, + data.rect.width, + data.rect.height + ); + + const mappedData = { + ...data, + rect: mappedRect + }; + if (getList === true) { if (listSelector) { socket?.emit('listSelector', { selector: listSelector }); - const hasValidChildSelectors = Array.isArray(data.childSelectors) && data.childSelectors.length > 0; + const hasValidChildSelectors = Array.isArray(mappedData.childSelectors) && mappedData.childSelectors.length > 0; if (limitMode) { setHighlighterData(null); } else if (paginationMode) { // Only set highlighterData if type is not empty, 'none', 'scrollDown', or 'scrollUp' if (paginationType !== '' && !['none', 'scrollDown', 'scrollUp'].includes(paginationType)) { - setHighlighterData(data); + setHighlighterData(mappedData); } else { setHighlighterData(null); } - } else if (data.childSelectors && data.childSelectors.includes(data.selector)) { + } else if (mappedData.childSelectors && mappedData.childSelectors.includes(mappedData.selector)) { // Highlight only valid child elements within the listSelector - setHighlighterData(data); - } else if (data.elementInfo?.isIframeContent && data.childSelectors) { - // Handle pure iframe elements - similar to previous shadow DOM logic but using iframe syntax - // Check if the selector matches any iframe child selectors - const isIframeChild = data.childSelectors.some(childSelector => - data.selector.includes(':>>') && // Iframe uses :>> for traversal + setHighlighterData(mappedData); + } else if (mappedData.elementInfo?.isIframeContent && mappedData.childSelectors) { + // Handle iframe elements + const isIframeChild = mappedData.childSelectors.some(childSelector => + mappedData.selector.includes(':>>') && childSelector.split(':>>').some(part => - data.selector.includes(part.trim()) + mappedData.selector.includes(part.trim()) ) ); - setHighlighterData(isIframeChild ? data : null); - } else if (data.selector.includes(':>>') && hasValidChildSelectors) { + setHighlighterData(isIframeChild ? mappedData : null); + } else if (mappedData.selector.includes(':>>') && hasValidChildSelectors) { // Handle mixed DOM cases with iframes - // Split the selector into parts and check each against child selectors - const selectorParts = data.selector.split(':>>').map(part => part.trim()); + const selectorParts = mappedData.selector.split(':>>').map(part => part.trim()); const isValidMixedSelector = selectorParts.some(part => - // We know data.childSelectors is defined due to hasValidChildSelectors check - data.childSelectors!.some(childSelector => + mappedData.childSelectors!.some(childSelector => childSelector.includes(part) ) ); - setHighlighterData(isValidMixedSelector ? data : null); - } else if (data.elementInfo?.isShadowRoot && data.childSelectors) { - // New case: Handle pure Shadow DOM elements - // Check if the selector matches any shadow root child selectors - const isShadowChild = data.childSelectors.some(childSelector => - data.selector.includes('>>') && // Shadow DOM uses >> for piercing + setHighlighterData(isValidMixedSelector ? mappedData : null); + } else if (mappedData.elementInfo?.isShadowRoot && mappedData.childSelectors) { + // Handle Shadow DOM elements + const isShadowChild = mappedData.childSelectors.some(childSelector => + mappedData.selector.includes('>>') && childSelector.split('>>').some(part => - data.selector.includes(part.trim()) + mappedData.selector.includes(part.trim()) ) ); - setHighlighterData(isShadowChild ? data : null); - } else if (data.selector.includes('>>') && hasValidChildSelectors) { - // New case: Handle mixed DOM cases - // Split the selector into parts and check each against child selectors - const selectorParts = data.selector.split('>>').map(part => part.trim()); + setHighlighterData(isShadowChild ? mappedData : null); + } else if (mappedData.selector.includes('>>') && hasValidChildSelectors) { + // Handle mixed DOM cases + const selectorParts = mappedData.selector.split('>>').map(part => part.trim()); const isValidMixedSelector = selectorParts.some(part => - // Now we know data.childSelectors is defined - data.childSelectors!.some(childSelector => + mappedData.childSelectors!.some(childSelector => childSelector.includes(part) ) ); - setHighlighterData(isValidMixedSelector ? data : null); + setHighlighterData(isValidMixedSelector ? mappedData : null); } else { - // if !valid child in normal mode, clear the highlighter + // If not a valid child in normal mode, clear the highlighter setHighlighterData(null); } } else { // Set highlighterData for the initial listSelector selection - setHighlighterData(data); + setHighlighterData(mappedData); } } else { // For non-list steps - setHighlighterData(data); + setHighlighterData(mappedData); } - }, [highlighterData, getList, socket, listSelector, paginationMode, paginationType, captureStage]); + }, [getList, socket, listSelector, paginationMode, paginationType, limitMode]); useEffect(() => { @@ -260,11 +301,13 @@ export const BrowserWindow = () => { const clickY = e.clientY - canvasRect.top; const highlightRect = highlighterData.rect; + + const mappedRect = coordinateMapper.mapBrowserRectToCanvas(highlightRect); if ( - clickX >= highlightRect.left && - clickX <= highlightRect.right && - clickY >= highlightRect.top && - clickY <= highlightRect.bottom + clickX >= mappedRect.left && + clickX <= mappedRect.right && + clickY >= mappedRect.top && + clickY <= mappedRect.bottom ) { const options = getAttributeOptions(highlighterData.elementInfo?.tagName || '', highlighterData.elementInfo); @@ -498,6 +541,9 @@ export const BrowserWindow = () => { width={900} height={400} /> +
+ Browser viewport: {viewportInfo.width}x{viewportInfo.height} +
); From 592ab6bd3328022354fc9a8a4eb2c0af5efa02f5 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:39:09 +0530 Subject: [PATCH 03/33] feat: map coords for canvas --- src/components/recorder/canvas.tsx | 41 ++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/components/recorder/canvas.tsx b/src/components/recorder/canvas.tsx index 9640c061..68df5843 100644 --- a/src/components/recorder/canvas.tsx +++ b/src/components/recorder/canvas.tsx @@ -6,6 +6,8 @@ import DatePicker from '../pickers/DatePicker'; import Dropdown from '../pickers/Dropdown'; import TimePicker from '../pickers/TimePicker'; import DateTimeLocalPicker from '../pickers/DateTimeLocalPicker'; +import { VIEWPORT_H, VIEWPORT_W } from '../../constants/const'; +import { coordinateMapper } from '../../helpers/coordinateMapper'; interface CreateRefCallback { (ref: React.RefObject): void; @@ -76,10 +78,18 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { getListRef.current = getList; }, [getText, getList]); + useEffect(() => { + coordinateMapper.updateDimensions(VIEWPORT_W, VIEWPORT_H); + }, []); + useEffect(() => { if (socket) { socket.on('showDatePicker', (info: { coordinates: Coordinates, selector: string }) => { - setDatePickerInfo(info); + const canvasCoords = coordinateMapper.mapBrowserToCanvas(info.coordinates); + setDatePickerInfo({ + ...info, + coordinates: canvasCoords + }); }); socket.on('showDropdown', (info: { @@ -92,15 +102,27 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { selected: boolean; }>; }) => { - setDropdownInfo(info); + const canvasCoords = coordinateMapper.mapBrowserToCanvas(info.coordinates); + setDropdownInfo({ + ...info, + coordinates: canvasCoords + }); }); socket.on('showTimePicker', (info: { coordinates: Coordinates, selector: string }) => { - setTimePickerInfo(info); + const canvasCoords = coordinateMapper.mapBrowserToCanvas(info.coordinates); + setTimePickerInfo({ + ...info, + coordinates: canvasCoords + }); }); socket.on('showDateTimePicker', (info: { coordinates: Coordinates, selector: string }) => { - setDateTimeLocalInfo(info); + const canvasCoords = coordinateMapper.mapBrowserToCanvas(info.coordinates); + setDateTimeLocalInfo({ + ...info, + coordinates: canvasCoords + }); }); return () => { @@ -114,13 +136,14 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { const onMouseEvent = useCallback((event: MouseEvent) => { if (socket && canvasRef.current) { - // Get the canvas bounding rectangle const rect = canvasRef.current.getBoundingClientRect(); const clickCoordinates = { x: event.clientX - rect.left, // Use relative x coordinate y: event.clientY - rect.top, // Use relative y coordinate }; + const browserCoordinates = coordinateMapper.mapCanvasToBrowser(clickCoordinates); + switch (event.type) { case 'mousedown': if (getTextRef.current === true) { @@ -128,7 +151,7 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { } else if (getListRef.current === true) { console.log('Capturing List...'); } else { - socket.emit('input:mousedown', clickCoordinates); + socket.emit('input:mousedown', browserCoordinates); } notifyLastAction('click'); break; @@ -146,7 +169,7 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { x: clickCoordinates.x, y: clickCoordinates.y, }; - socket.emit('input:mousemove', clickCoordinates); + socket.emit('input:mousemove', browserCoordinates); notifyLastAction('move'); } break; @@ -173,9 +196,11 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { const onKeyboardEvent = useCallback((event: KeyboardEvent) => { if (socket) { + const browserCoordinates = coordinateMapper.mapCanvasToBrowser(lastMousePosition.current); + switch (event.type) { case 'keydown': - socket.emit('input:keydown', { key: event.key, coordinates: lastMousePosition.current }); + socket.emit('input:keydown', { key: event.key, coordinates: browserCoordinates }); notifyLastAction(`${event.key} pressed`); break; case 'keyup': From d043aba06e9a4995abc9a96fd7db481c1b3b76ef Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:40:28 +0530 Subject: [PATCH 04/33] feat: update viewport with dimensions --- .../classes/RemoteBrowser.ts | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/server/src/browser-management/classes/RemoteBrowser.ts b/server/src/browser-management/classes/RemoteBrowser.ts index 85d1928c..f5e5d940 100644 --- a/server/src/browser-management/classes/RemoteBrowser.ts +++ b/server/src/browser-management/classes/RemoteBrowser.ts @@ -269,7 +269,7 @@ export class RemoteBrowser { }; } const contextOptions: any = { - viewport: { height: 400, width: 900 }, + // viewport: { height: 400, width: 900 }, // recordVideo: { dir: 'videos/' } // Force reduced motion to prevent animation issues reducedMotion: 'reduce', @@ -322,6 +322,15 @@ export class RemoteBrowser { await this.setupPageEventListeners(this.currentPage); + const viewportSize = await this.currentPage.viewportSize(); + if (viewportSize) { + this.socket.emit('viewportInfo', { + width: viewportSize.width, + height: viewportSize.height, + userId: this.userId + }); + } + try { const blocker = await PlaywrightBlocker.fromLists(fetch, ['https://easylist.to/easylist/easylist.txt']); await blocker.enableBlockingInPage(this.currentPage); @@ -335,6 +344,19 @@ export class RemoteBrowser { } }; + public updateViewportInfo = async (): Promise => { + if (this.currentPage) { + const viewportSize = await this.currentPage.viewportSize(); + if (viewportSize) { + this.socket.emit('viewportInfo', { + width: viewportSize.width, + height: viewportSize.height, + userId: this.userId + }); + } + } + }; + /** * Registers all event listeners needed for the recording editor session. * Should be called only once after the full initialization of the remote browser. @@ -452,6 +474,8 @@ export class RemoteBrowser { // Set flag to indicate screencast is active this.isScreencastActive = true; + await this.updateViewportInfo(); + this.client.on('Page.screencastFrame', ({ data: base64, sessionId }) => { // Only process if screencast is still active for this user if (!this.isScreencastActive) { @@ -563,7 +587,7 @@ export class RemoteBrowser { const workflow = this.generator.AddGeneratedFlags(this.generator.getWorkflowFile()); await this.initializeNewPage(); if (this.currentPage) { - this.currentPage.setViewportSize({ height: 400, width: 900 }); + // this.currentPage.setViewportSize({ height: 400, width: 900 }); const params = this.generator.getParams(); if (params) { this.interpreterSettings.params = params.reduce((acc, param) => { @@ -721,7 +745,7 @@ export class RemoteBrowser { * @param payload the screenshot binary data * @returns void */ - private emitScreenshot = async (payload: Buffer): Promise => { + private emitScreenshot = async (payload: Buffer, viewportSize?: { width: number, height: number }): Promise => { if (this.isProcessingScreenshot) { if (this.screenshotQueue.length < SCREENCAST_CONFIG.maxQueueSize) { this.screenshotQueue.push(payload); @@ -736,11 +760,14 @@ export class RemoteBrowser { const base64Data = optimizedScreenshot.toString('base64'); const dataWithMimeType = `data:image/jpeg;base64,${base64Data}`; -// Emit with user context to ensure the frontend can identify which browser's screenshot this is -this.socket.emit('screencast', { - image: dataWithMimeType, - userId: this.userId -}); logger.debug('Screenshot emitted'); + // Emit with user context to ensure the frontend can identify which browser's screenshot this is + this.socket.emit('screencast', { + image: dataWithMimeType, + userId: this.userId, + viewport: viewportSize || await this.currentPage?.viewportSize() || null + }); + + logger.debug('Screenshot emitted'); } catch (error) { logger.error('Screenshot emission failed:', error); } finally { From e7b3b20526b99642d0402d614e272dbcfa8b8035 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:41:09 +0530 Subject: [PATCH 05/33] feat: map coords for highlighter component --- src/components/recorder/Highlighter.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/recorder/Highlighter.tsx b/src/components/recorder/Highlighter.tsx index 562fd81e..a63c3c23 100644 --- a/src/components/recorder/Highlighter.tsx +++ b/src/components/recorder/Highlighter.tsx @@ -1,5 +1,6 @@ import React from 'react'; import styled from "styled-components"; +import { coordinateMapper } from '../../helpers/coordinateMapper'; interface HighlighterProps { unmodifiedRect: DOMRect; @@ -13,13 +14,15 @@ export const Highlighter = ({ unmodifiedRect, displayedSelector = '', width, hei if (!unmodifiedRect) { return null; } else { + const mappedRect = coordinateMapper.mapBrowserRectToCanvas(unmodifiedRect); + const rect = { - top: unmodifiedRect.top + canvasRect.top + window.scrollY, - left: unmodifiedRect.left + canvasRect.left + window.scrollX, - right: unmodifiedRect.right + canvasRect.left, - bottom: unmodifiedRect.bottom + canvasRect.top, - width: unmodifiedRect.width, - height: unmodifiedRect.height, + top: mappedRect.top + canvasRect.top + window.scrollY, + left: mappedRect.left + canvasRect.left + window.scrollX, + right: mappedRect.right + canvasRect.left, + bottom: mappedRect.bottom + canvasRect.top, + width: mappedRect.width, + height: mappedRect.height, }; From 0d7becbf8e5d509b8d4b97539ed81b0f651f1b63 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 12:41:44 +0530 Subject: [PATCH 06/33] feat: add coord mapping class --- src/helpers/coordinateMapper.ts | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/helpers/coordinateMapper.ts diff --git a/src/helpers/coordinateMapper.ts b/src/helpers/coordinateMapper.ts new file mode 100644 index 00000000..0e124615 --- /dev/null +++ b/src/helpers/coordinateMapper.ts @@ -0,0 +1,73 @@ +import { BROWSER_DEFAULT_HEIGHT, BROWSER_DEFAULT_WIDTH, VIEWPORT_H, VIEWPORT_W } from "../constants/const"; + +export class CoordinateMapper { + private canvasWidth: number; + private canvasHeight: number; + private browserWidth: number; + private browserHeight: number; + + constructor( + canvasWidth: number = VIEWPORT_W, + canvasHeight: number = VIEWPORT_H, + browserWidth: number = BROWSER_DEFAULT_WIDTH, + browserHeight: number = BROWSER_DEFAULT_HEIGHT + ) { + this.canvasWidth = canvasWidth; + this.canvasHeight = canvasHeight; + this.browserWidth = browserWidth; + this.browserHeight = browserHeight; + } + + mapCanvasToBrowser(coord: { x: number, y: number }): { x: number, y: number } { + return { + x: (coord.x / this.canvasWidth) * this.browserWidth, + y: (coord.y / this.canvasHeight) * this.browserHeight + }; + } + + mapBrowserToCanvas(coord: { x: number, y: number }): { x: number, y: number } { + return { + x: (coord.x / this.browserWidth) * this.canvasWidth, + y: (coord.y / this.browserHeight) * this.canvasHeight + }; + } + + mapBrowserRectToCanvas(rect: DOMRect): DOMRect { + const topLeft = this.mapBrowserToCanvas({ x: rect.left, y: rect.top }); + const bottomRight = this.mapBrowserToCanvas({ x: rect.right, y: rect.bottom }); + + const width = bottomRight.x - topLeft.x; + const height = bottomRight.y - topLeft.y; + + return new DOMRect( + topLeft.x, + topLeft.y, + width, + height + ); + } + + mapCanvasRectToBrowser(rect: DOMRect): DOMRect { + const topLeft = this.mapCanvasToBrowser({ x: rect.left, y: rect.top }); + const bottomRight = this.mapCanvasToBrowser({ x: rect.right, y: rect.bottom }); + + const width = bottomRight.x - topLeft.x; + const height = bottomRight.y - topLeft.y; + + return new DOMRect( + topLeft.x, + topLeft.y, + width, + height + ); + } + + updateDimensions(canvasWidth?: number, canvasHeight?: number, browserWidth?: number, browserHeight?: number) { + if (canvasWidth) this.canvasWidth = canvasWidth; + if (canvasHeight) this.canvasHeight = canvasHeight; + if (browserWidth) this.browserWidth = browserWidth; + if (browserHeight) this.browserHeight = browserHeight; + } +} + +export const coordinateMapper = new CoordinateMapper(); \ No newline at end of file From 193e2a21af6431bdc04a3d8bd79fca6ac94591dc Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:38:46 +0530 Subject: [PATCH 07/33] feat: set dimensions for store --- src/context/browserDimensions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context/browserDimensions.tsx b/src/context/browserDimensions.tsx index bc0d97ae..c2c744e1 100644 --- a/src/context/browserDimensions.tsx +++ b/src/context/browserDimensions.tsx @@ -7,8 +7,8 @@ interface BrowserDimensions { }; class BrowserDimensionsStore implements Partial { - width: number = 900; - height: number = 400; + width: number = window.innerWidth * 0.75; + height: number = window.innerHeight * 0.64; }; const browserDimensionsStore = new BrowserDimensionsStore(); From c6bc6257f0c31857193a6a3b6e98a30f9f203729 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:39:59 +0530 Subject: [PATCH 08/33] feat: update dimensions canvas --- src/components/recorder/canvas.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/recorder/canvas.tsx b/src/components/recorder/canvas.tsx index 68df5843..12464d9a 100644 --- a/src/components/recorder/canvas.tsx +++ b/src/components/recorder/canvas.tsx @@ -6,7 +6,6 @@ import DatePicker from '../pickers/DatePicker'; import Dropdown from '../pickers/Dropdown'; import TimePicker from '../pickers/TimePicker'; import DateTimeLocalPicker from '../pickers/DateTimeLocalPicker'; -import { VIEWPORT_H, VIEWPORT_W } from '../../constants/const'; import { coordinateMapper } from '../../helpers/coordinateMapper'; interface CreateRefCallback { @@ -79,7 +78,7 @@ const Canvas = ({ width, height, onCreateRef }: CanvasProps) => { }, [getText, getList]); useEffect(() => { - coordinateMapper.updateDimensions(VIEWPORT_W, VIEWPORT_H); + coordinateMapper.updateDimensions(window.innerWidth * 0.75, window.innerHeight * 0.64); }, []); useEffect(() => { From 7ba6ddfe8bac8c8c78b9c3363528664164265d3e Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:40:43 +0530 Subject: [PATCH 09/33] feat: update initial coordinates for coord mapping --- src/helpers/coordinateMapper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/coordinateMapper.ts b/src/helpers/coordinateMapper.ts index 0e124615..dad27fd4 100644 --- a/src/helpers/coordinateMapper.ts +++ b/src/helpers/coordinateMapper.ts @@ -1,4 +1,4 @@ -import { BROWSER_DEFAULT_HEIGHT, BROWSER_DEFAULT_WIDTH, VIEWPORT_H, VIEWPORT_W } from "../constants/const"; +import { BROWSER_DEFAULT_HEIGHT, BROWSER_DEFAULT_WIDTH } from "../constants/const"; export class CoordinateMapper { private canvasWidth: number; @@ -7,8 +7,8 @@ export class CoordinateMapper { private browserHeight: number; constructor( - canvasWidth: number = VIEWPORT_W, - canvasHeight: number = VIEWPORT_H, + canvasWidth: number = window.innerWidth * 0.75, + canvasHeight: number = window.innerHeight * 0.64, browserWidth: number = BROWSER_DEFAULT_WIDTH, browserHeight: number = BROWSER_DEFAULT_HEIGHT ) { From d9f9147a50795f5855fc1cddda7b3c0a27226d81 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:42:08 +0530 Subject: [PATCH 10/33] feat: update dimensions for browser window --- src/components/browser/BrowserWindow.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/browser/BrowserWindow.tsx b/src/components/browser/BrowserWindow.tsx index dbd43f61..4076c680 100644 --- a/src/components/browser/BrowserWindow.tsx +++ b/src/components/browser/BrowserWindow.tsx @@ -77,7 +77,7 @@ export const BrowserWindow = () => { const [attributeOptions, setAttributeOptions] = useState([]); const [selectedElement, setSelectedElement] = useState<{ selector: string, info: ElementInfo | null } | null>(null); const [currentListId, setCurrentListId] = useState(null); - const [viewportInfo, setViewportInfo] = useState({ width: VIEWPORT_W, height: VIEWPORT_H }); + const [viewportInfo, setViewportInfo] = useState({ width: window.innerWidth * 0.75, height: window.innerHeight * 0.64 }); const [listSelector, setListSelector] = useState(null); const [fields, setFields] = useState>({}); @@ -92,7 +92,7 @@ export const BrowserWindow = () => { const { user } = state; useEffect(() => { - coordinateMapper.updateDimensions(VIEWPORT_W, VIEWPORT_H, viewportInfo.width, viewportInfo.height); + coordinateMapper.updateDimensions(window.innerWidth * 0.75, window.innerHeight * 0.64, viewportInfo.width, viewportInfo.height); }, [viewportInfo]); useEffect(() => { @@ -480,7 +480,7 @@ export const BrowserWindow = () => { }, [paginationMode, resetPaginationSelector]); return ( -
+
{ getText === true || getList === true ? ( { ) : null } -
+
{((getText === true || getList === true) && !showAttributeModal && highlighterData?.rect != null && highlighterData?.rect.top != null) && canvasRef?.current ? : null} -
- Browser viewport: {viewportInfo.width}x{viewportInfo.height} -
); @@ -558,7 +555,7 @@ const drawImage = (image: string, canvas: HTMLCanvasElement): void => { img.src = image; img.onload = () => { URL.revokeObjectURL(img.src); - ctx?.drawImage(img, 0, 0, 900, 400); + ctx?.drawImage(img, 0, 0, window.innerWidth * 0.75, window.innerHeight * 0.64); }; }; From 2705cfb11155bd0f8bcaf023daf771e0ed2b8644 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:42:46 +0530 Subject: [PATCH 11/33] feat: rm vierport const --- src/components/browser/BrowserWindow.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/browser/BrowserWindow.tsx b/src/components/browser/BrowserWindow.tsx index 4076c680..b8d55191 100644 --- a/src/components/browser/BrowserWindow.tsx +++ b/src/components/browser/BrowserWindow.tsx @@ -10,7 +10,6 @@ import { useGlobalInfoStore } from '../../context/globalInfo'; import { useTranslation } from 'react-i18next'; import { AuthContext } from '../../context/auth'; import { coordinateMapper } from '../../helpers/coordinateMapper'; -import { VIEWPORT_H, VIEWPORT_W } from '../../constants/const'; interface ElementInfo { tagName: string; From dd4032c51accce16e418f79e1266006186d4d0b5 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:43:35 +0530 Subject: [PATCH 12/33] feat: adapt to browser width --- src/components/browser/BrowserContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/browser/BrowserContent.tsx b/src/components/browser/BrowserContent.tsx index ec882965..3be4f194 100644 --- a/src/components/browser/BrowserContent.tsx +++ b/src/components/browser/BrowserContent.tsx @@ -146,7 +146,7 @@ export const BrowserContent = () => { /> From 035655b61cace0a30e4f17f88df6d45efe4c105e Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:45:07 +0530 Subject: [PATCH 13/33] feat: refactor index css to scale --- src/index.css | 135 ++++++++++++++++---------------------------------- 1 file changed, 42 insertions(+), 93 deletions(-) diff --git a/src/index.css b/src/index.css index e63d18f7..c5a70424 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,4 @@ +/* Base styles */ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', @@ -13,6 +14,13 @@ body { overflow-y: auto; } +html { + width: 100%; + height: 100%; + overflow-y: auto; +} + +/* Form element autofill styles */ input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, @@ -26,18 +34,12 @@ select:-webkit-autofill:focus { transition: background-color 5000s ease-in-out 0s !important; } -html { - width: 100%; - height: 100%; - overflow-y: auto; -} - a { color: #ff00c3; +} - &:hover { - color: #ff00c3; - } +a:hover { + color: #ff00c3; } code { @@ -46,6 +48,7 @@ code { color: #ff00c3; } +/* Browser-specific elements */ #browser-actions { right: 0; overflow-x: hidden; @@ -55,19 +58,21 @@ code { display: flex; justify-content: center; align-items: center; - overflow: hidden; position: relative; + box-sizing: border-box; + width: calc(100% - 4rem); + height: calc(100vh - 4rem); + margin: 2rem 2rem 2rem 2rem; + overflow: hidden; } #browser-content { height: 100%; width: 100%; display: flex; - flex-direction: column; + flex-direction: column; transform: scale(1); - /* Ensure no scaling */ transform-origin: top left; - /* Keep the position fixed */ } #browser-window { @@ -76,100 +81,44 @@ code { } .right-side-panel { - margin: 0; + margin-left: 1.5rem; transform: scale(1); transform-origin: top left; overflow: hidden; position: relative; } -@media (min-width: 1024px) and (max-width: 1211px) { +.MuiButton-root[sx*="position: 'absolute'"] { + bottom: 2rem !important; + margin-bottom: 0 !important; +} + +/* Consistent layout across all screen sizes */ +@media screen and (min-width: 1024px) { #browser-recorder { - box-sizing: border-box; - height: 100vh; - margin: 0; + width: calc(100% - 4rem); + height: calc(100vh - 4rem); + margin: 2rem 2rem 2rem 2rem; } } -/* For laptops (between 1024px and 1440px) */ -@media (min-width: 1211px) and (max-width: 1440px) { +/* Adjust for very small screens */ +@media screen and (max-width: 1023px) { #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 0.6rem); - margin: 0.3rem; + width: calc(100% - 2rem); + height: calc(100vh - 3rem); + margin: 1.5rem 1rem 1.5rem 1rem; + } + + .right-side-panel { + margin-left: 1rem; } } -/* For desktops (between 1441px and 1920px) */ -@media (min-width: 1441px) and (max-width: 1500px) { +/* Adjust for very large screens - prevent content from stretching too much */ +@media screen and (min-width: 2000px) { #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem; - } -} - -@media (min-width: 1501px) and (max-width: 1700px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 8rem; - } -} - -@media (min-width: 1701px) and (max-width: 1800px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 14rem; - } -} - -@media (min-width: 1801px) and (max-width: 1900px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 18.5rem; - } -} - -@media (min-width: 1900px) and (max-width: 1920px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 20rem; - } -} - -/* For very large desktops (greater than 1920px) */ -@media (min-width: 1921px) and (max-width: 2000px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 20rem; - } -} - -@media (min-width: 2001px) and (max-width: 2500px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 24rem; - } -} - -@media (min-width: 2501px) and (max-width: 2999px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 40rem; - } -} - -@media (min-width: 3000px) { - #browser-recorder { - box-sizing: border-box; - height: calc(100vh - 2rem); - margin: 1rem 55rem; + width: 1800px; + margin: 2rem auto 2rem auto; } } \ No newline at end of file From 9517dbd99ae0b48de1fc0d393fe9e9aa3f4d9650 Mon Sep 17 00:00:00 2001 From: Rohit Date: Fri, 14 Mar 2025 23:46:50 +0530 Subject: [PATCH 14/33] feat: refactor height width of output preview --- src/components/run/InterpretationLog.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index 925a95ba..70dc430b 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -130,6 +130,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se return ( +