Merge pull request #845 from getmaxun/capflow-revamp
fix: confine capture list highlighting within window
This commit is contained in:
@@ -1423,7 +1423,8 @@ export const BrowserWindow = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const iframeRect = iframeElement.getBoundingClientRect();
|
const iframeRect = iframeElement.getBoundingClientRect();
|
||||||
const IFRAME_BODY_PADDING = 16;
|
const IFRAME_X_PADDING = 16;
|
||||||
|
const IFRAME_Y_PADDING = 136;
|
||||||
|
|
||||||
let mappedSimilarElements;
|
let mappedSimilarElements;
|
||||||
if (data.similarElements) {
|
if (data.similarElements) {
|
||||||
@@ -1432,8 +1433,8 @@ export const BrowserWindow = () => {
|
|||||||
rects: data.similarElements.rects.map(
|
rects: data.similarElements.rects.map(
|
||||||
(rect) =>
|
(rect) =>
|
||||||
new DOMRect(
|
new DOMRect(
|
||||||
rect.x + iframeRect.left - IFRAME_BODY_PADDING,
|
rect.x + iframeRect.left - IFRAME_X_PADDING,
|
||||||
rect.y + iframeRect.top - IFRAME_BODY_PADDING,
|
rect.y + iframeRect.top - IFRAME_Y_PADDING,
|
||||||
rect.width,
|
rect.width,
|
||||||
rect.height
|
rect.height
|
||||||
)
|
)
|
||||||
@@ -1448,8 +1449,8 @@ export const BrowserWindow = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const absoluteRect = new DOMRect(
|
const absoluteRect = new DOMRect(
|
||||||
data.rect.x + iframeRect.left - IFRAME_BODY_PADDING,
|
data.rect.x + iframeRect.left - IFRAME_X_PADDING,
|
||||||
data.rect.y + iframeRect.top - IFRAME_BODY_PADDING,
|
data.rect.y + iframeRect.top - IFRAME_Y_PADDING,
|
||||||
data.rect.width,
|
data.rect.width,
|
||||||
data.rect.height
|
data.rect.height
|
||||||
);
|
);
|
||||||
@@ -1469,8 +1470,8 @@ export const BrowserWindow = () => {
|
|||||||
return {
|
return {
|
||||||
element,
|
element,
|
||||||
rect: new DOMRect(
|
rect: new DOMRect(
|
||||||
elementRect.x + iframeRect.left - IFRAME_BODY_PADDING,
|
elementRect.x + iframeRect.left - IFRAME_X_PADDING,
|
||||||
elementRect.y + iframeRect.top - IFRAME_BODY_PADDING,
|
elementRect.y + iframeRect.top - IFRAME_Y_PADDING,
|
||||||
elementRect.width,
|
elementRect.width,
|
||||||
elementRect.height
|
elementRect.height
|
||||||
),
|
),
|
||||||
@@ -2187,7 +2188,15 @@ export const BrowserWindow = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Main content area */}
|
{/* Main content area */}
|
||||||
<div style={{ height: dimensions.height, overflow: "hidden" }}>
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
width: "100%",
|
||||||
|
height: dimensions.height,
|
||||||
|
overflow: "hidden",
|
||||||
|
borderRadius: "0px 0px 5px 5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* Add CSS for the spinner animation */}
|
{/* Add CSS for the spinner animation */}
|
||||||
<style>{`
|
<style>{`
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
@@ -2196,7 +2205,7 @@ export const BrowserWindow = () => {
|
|||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
|
|
||||||
{(getText === true || getList === true) &&
|
{(getText || getList) &&
|
||||||
!showAttributeModal &&
|
!showAttributeModal &&
|
||||||
highlighterData?.rect != null && (
|
highlighterData?.rect != null && (
|
||||||
<>
|
<>
|
||||||
@@ -2211,7 +2220,16 @@ export const BrowserWindow = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isDOMMode && highlighterData && (
|
{isDOMMode && highlighterData && (
|
||||||
<>
|
<div
|
||||||
|
id="dom-highlight-overlay"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
inset: 0, // top:0; right:0; bottom:0; left:0
|
||||||
|
overflow: "hidden", // clip everything within iframe area
|
||||||
|
pointerEvents: "none",
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* Individual element highlight (for non-group or hovered element) */}
|
{/* Individual element highlight (for non-group or hovered element) */}
|
||||||
{((getText && !listSelector) ||
|
{((getText && !listSelector) ||
|
||||||
(getList && paginationMode && paginationType !== "" &&
|
(getList && paginationMode && paginationType !== "" &&
|
||||||
@@ -2219,49 +2237,33 @@ export const BrowserWindow = () => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: Math.max(0, highlighterData.rect.x),
|
left: highlighterData.rect.x,
|
||||||
top: Math.max(0, highlighterData.rect.y),
|
top: highlighterData.rect.y,
|
||||||
width: Math.min(
|
width: highlighterData.rect.width,
|
||||||
highlighterData.rect.width,
|
height: highlighterData.rect.height,
|
||||||
dimensions.width
|
|
||||||
),
|
|
||||||
height: Math.min(
|
|
||||||
highlighterData.rect.height,
|
|
||||||
dimensions.height
|
|
||||||
),
|
|
||||||
background: "rgba(255, 0, 195, 0.15)",
|
background: "rgba(255, 0, 195, 0.15)",
|
||||||
border: "2px solid #ff00c3",
|
border: "2px solid #ff00c3",
|
||||||
borderRadius: "3px",
|
borderRadius: "3px",
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
zIndex: 1000,
|
|
||||||
boxShadow: "0 0 0 1px rgba(255, 255, 255, 0.8)",
|
boxShadow: "0 0 0 1px rgba(255, 255, 255, 0.8)",
|
||||||
transition: "all 0.1s ease-out",
|
transition: "all 0.1s ease-out",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Group elements highlighting with real-time coordinates */}
|
{/* Grouped list element highlights */}
|
||||||
{getList &&
|
{getList &&
|
||||||
!listSelector &&
|
!listSelector &&
|
||||||
currentGroupInfo?.isGroupElement &&
|
currentGroupInfo?.isGroupElement &&
|
||||||
highlighterData.groupElements &&
|
highlighterData.groupElements?.map((groupElement, index) => (
|
||||||
highlighterData.groupElements.map(
|
|
||||||
(groupElement, index) => (
|
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
{/* Highlight box */}
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: Math.max(0, groupElement.rect.x),
|
left: groupElement.rect.x,
|
||||||
top: Math.max(0, groupElement.rect.y),
|
top: groupElement.rect.y,
|
||||||
width: Math.min(
|
width: groupElement.rect.width,
|
||||||
groupElement.rect.width,
|
height: groupElement.rect.height,
|
||||||
dimensions.width
|
|
||||||
),
|
|
||||||
height: Math.min(
|
|
||||||
groupElement.rect.height,
|
|
||||||
dimensions.height
|
|
||||||
),
|
|
||||||
background: "rgba(255, 0, 195, 0.15)",
|
background: "rgba(255, 0, 195, 0.15)",
|
||||||
border: "2px dashed #ff00c3",
|
border: "2px dashed #ff00c3",
|
||||||
borderRadius: "3px",
|
borderRadius: "3px",
|
||||||
@@ -2275,8 +2277,8 @@ export const BrowserWindow = () => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: Math.max(0, groupElement.rect.x),
|
left: groupElement.rect.x,
|
||||||
top: Math.max(0, groupElement.rect.y - 20),
|
top: groupElement.rect.y - 20,
|
||||||
background: "#ff00c3",
|
background: "#ff00c3",
|
||||||
color: "white",
|
color: "white",
|
||||||
padding: "2px 6px",
|
padding: "2px 6px",
|
||||||
@@ -2298,21 +2300,15 @@ export const BrowserWindow = () => {
|
|||||||
listSelector &&
|
listSelector &&
|
||||||
!paginationMode &&
|
!paginationMode &&
|
||||||
!limitMode &&
|
!limitMode &&
|
||||||
highlighterData?.similarElements &&
|
highlighterData.similarElements?.rects?.map((rect, index) => (
|
||||||
highlighterData.similarElements.rects.map(
|
|
||||||
(rect, index) => (
|
|
||||||
<React.Fragment key={`item-${index}`}>
|
<React.Fragment key={`item-${index}`}>
|
||||||
{/* Highlight box for similar element */}
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: Math.max(0, rect.x),
|
left: rect.x,
|
||||||
top: Math.max(0, rect.y),
|
top: rect.y,
|
||||||
width: Math.min(rect.width, dimensions.width),
|
width: rect.width,
|
||||||
height: Math.min(
|
height: rect.height,
|
||||||
rect.height,
|
|
||||||
dimensions.height
|
|
||||||
),
|
|
||||||
background: "rgba(255, 0, 195, 0.15)",
|
background: "rgba(255, 0, 195, 0.15)",
|
||||||
border: "2px dashed #ff00c3",
|
border: "2px dashed #ff00c3",
|
||||||
borderRadius: "3px",
|
borderRadius: "3px",
|
||||||
@@ -2327,8 +2323,8 @@ export const BrowserWindow = () => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: Math.max(0, rect.x),
|
left: rect.x,
|
||||||
top: Math.max(0, rect.y - 20),
|
top: rect.y - 20,
|
||||||
background: "#ff00c3",
|
background: "#ff00c3",
|
||||||
color: "white",
|
color: "white",
|
||||||
padding: "2px 6px",
|
padding: "2px 6px",
|
||||||
@@ -2343,17 +2339,24 @@ export const BrowserWindow = () => {
|
|||||||
Item {index + 1}
|
Item {index + 1}
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
))}
|
||||||
)}
|
</div>
|
||||||
</>
|
)}
|
||||||
)}
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
{/* --- Main DOM Renderer Section --- */}
|
||||||
|
<div
|
||||||
|
id="iframe-wrapper"
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
overflow: "hidden", // key: confine everything below
|
||||||
|
borderRadius: "0px 0px 5px 5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
{isDOMMode ? (
|
{isDOMMode ? (
|
||||||
<div
|
<>
|
||||||
style={{ position: "relative", width: "100%", height: "100%" }}
|
|
||||||
>
|
|
||||||
{currentSnapshot ? (
|
{currentSnapshot ? (
|
||||||
<DOMBrowserRenderer
|
<DOMBrowserRenderer
|
||||||
width={dimensions.width}
|
width={dimensions.width}
|
||||||
@@ -2366,10 +2369,8 @@ export const BrowserWindow = () => {
|
|||||||
paginationMode={paginationMode}
|
paginationMode={paginationMode}
|
||||||
paginationType={paginationType}
|
paginationType={paginationType}
|
||||||
limitMode={limitMode}
|
limitMode={limitMode}
|
||||||
onHighlight={(data) => {
|
|
||||||
domHighlighterHandler(data);
|
|
||||||
}}
|
|
||||||
isCachingChildSelectors={isCachingChildSelectors}
|
isCachingChildSelectors={isCachingChildSelectors}
|
||||||
|
onHighlight={domHighlighterHandler}
|
||||||
onElementSelect={handleDOMElementSelection}
|
onElementSelect={handleDOMElementSelection}
|
||||||
onShowDatePicker={handleShowDatePicker}
|
onShowDatePicker={handleShowDatePicker}
|
||||||
onShowDropdown={handleShowDropdown}
|
onShowDropdown={handleShowDropdown}
|
||||||
@@ -2377,181 +2378,120 @@ export const BrowserWindow = () => {
|
|||||||
onShowDateTimePicker={handleShowDateTimePicker}
|
onShowDateTimePicker={handleShowDateTimePicker}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<DOMLoadingIndicator />
|
||||||
style={{
|
|
||||||
width: dimensions.width,
|
|
||||||
height: dimensions.height,
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
background: "#f5f5f5",
|
|
||||||
borderRadius: "5px",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: "60px",
|
|
||||||
height: "60px",
|
|
||||||
borderTop: "4px solid transparent",
|
|
||||||
borderRadius: "50%",
|
|
||||||
animation: "spin 1s linear infinite",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "18px",
|
|
||||||
color: "#ff00c3",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Loading website...
|
|
||||||
</div>
|
|
||||||
<style>{`
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Loading overlay positioned specifically over DOM content */}
|
{/* --- Loading overlay --- */}
|
||||||
{isCachingChildSelectors && (
|
{isCachingChildSelectors && (
|
||||||
<>
|
<>
|
||||||
{/* Background overlay */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
background: "rgba(255, 255, 255, 0.8)",
|
|
||||||
zIndex: 9999,
|
|
||||||
pointerEvents: "none",
|
|
||||||
borderRadius: "0px 0px 5px 5px",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Use processing coordinates captured before listSelector was set */}
|
|
||||||
{processingGroupCoordinates.map((groupElement, index) => (
|
|
||||||
<React.Fragment key={`group-highlight-${index}`}>
|
|
||||||
{/* Original highlight box */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
left: groupElement.rect.x,
|
|
||||||
top: groupElement.rect.y,
|
|
||||||
width: groupElement.rect.width,
|
|
||||||
height: groupElement.rect.height,
|
|
||||||
background: "rgba(255, 0, 195, 0.15)",
|
|
||||||
border: "2px dashed #ff00c3",
|
|
||||||
borderRadius: "3px",
|
|
||||||
pointerEvents: "none",
|
|
||||||
zIndex: 10000,
|
|
||||||
boxShadow: "0 0 0 1px rgba(255, 255, 255, 0.8)",
|
|
||||||
transition: "all 0.1s ease-out",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Label */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
left: groupElement.rect.x,
|
|
||||||
top: groupElement.rect.y - 20,
|
|
||||||
background: "#ff00c3",
|
|
||||||
color: "white",
|
|
||||||
padding: "2px 6px",
|
|
||||||
fontSize: "10px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
borderRadius: "2px",
|
|
||||||
pointerEvents: "none",
|
|
||||||
zIndex: 10001,
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
List item {index + 1}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scanning animation */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
left: groupElement.rect.x,
|
|
||||||
top: groupElement.rect.y,
|
|
||||||
width: groupElement.rect.width,
|
|
||||||
height: groupElement.rect.height,
|
|
||||||
overflow: "hidden",
|
|
||||||
zIndex: 10002,
|
|
||||||
pointerEvents: "none",
|
|
||||||
borderRadius: "3px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
left: 0,
|
|
||||||
width: "100%",
|
|
||||||
height: "8px",
|
|
||||||
background:
|
|
||||||
"linear-gradient(90deg, transparent 0%, rgba(255, 0, 195, 0.6) 50%, transparent 100%)",
|
|
||||||
animation: `scanDown-${index} 2s ease-in-out infinite`,
|
|
||||||
willChange: "transform",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>{`
|
|
||||||
@keyframes scanDown-${index} {
|
|
||||||
0% {
|
|
||||||
transform: translateY(-8px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(${groupElement.rect.height}px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{/* Fallback loader */}
|
|
||||||
{processingGroupCoordinates.length === 0 && (
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
inset: 0,
|
||||||
left: 0,
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
background: "rgba(255, 255, 255, 0.8)",
|
background: "rgba(255, 255, 255, 0.8)",
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
borderRadius: "0px 0px 5px 5px",
|
borderRadius: "0px 0px 5px 5px",
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
|
{processingGroupCoordinates.map((groupElement, index) => (
|
||||||
|
<React.Fragment key={`group-highlight-${index}`}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: groupElement.rect.x,
|
||||||
|
top: groupElement.rect.y,
|
||||||
|
width: groupElement.rect.width,
|
||||||
|
height: groupElement.rect.height,
|
||||||
|
background: "rgba(255, 0, 195, 0.15)",
|
||||||
|
border: "2px dashed #ff00c3",
|
||||||
|
borderRadius: "3px",
|
||||||
|
pointerEvents: "none",
|
||||||
|
zIndex: 10000,
|
||||||
|
boxShadow: "0 0 0 1px rgba(255, 255, 255, 0.8)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: groupElement.rect.x,
|
||||||
|
top: groupElement.rect.y - 20,
|
||||||
|
background: "#ff00c3",
|
||||||
|
color: "white",
|
||||||
|
padding: "2px 6px",
|
||||||
|
fontSize: "10px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
borderRadius: "2px",
|
||||||
|
pointerEvents: "none",
|
||||||
|
zIndex: 10001,
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
List item {index + 1}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: groupElement.rect.x,
|
||||||
|
top: groupElement.rect.y,
|
||||||
|
width: groupElement.rect.width,
|
||||||
|
height: groupElement.rect.height,
|
||||||
|
overflow: "hidden",
|
||||||
|
zIndex: 10002,
|
||||||
|
pointerEvents: "none",
|
||||||
|
borderRadius: "3px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "8px",
|
||||||
|
background:
|
||||||
|
"linear-gradient(90deg, transparent 0%, rgba(255, 0, 195, 0.6) 50%, transparent 100%)",
|
||||||
|
animation: `scanDown-${index} 2s ease-in-out infinite`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<style>{`
|
||||||
|
@keyframes scanDown-${index} {
|
||||||
|
0% { transform: translateY(-8px); }
|
||||||
|
100% { transform: translateY(${groupElement.rect.height}px); }
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{processingGroupCoordinates.length === 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: "40px",
|
position: "absolute",
|
||||||
height: "40px",
|
inset: 0,
|
||||||
border: "4px solid #f3f3f3",
|
background: "rgba(255, 255, 255, 0.8)",
|
||||||
borderTop: "4px solid #ff00c3",
|
display: "flex",
|
||||||
borderRadius: "50%",
|
alignItems: "center",
|
||||||
animation: "spin 1s linear infinite",
|
justifyContent: "center",
|
||||||
|
zIndex: 9999,
|
||||||
|
pointerEvents: "none",
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
</div>
|
<div
|
||||||
)}
|
style={{
|
||||||
</>
|
width: "40px",
|
||||||
)}
|
height: "40px",
|
||||||
</div>
|
border: "4px solid #f3f3f3",
|
||||||
|
borderTop: "4px solid #ff00c3",
|
||||||
|
borderRadius: "50%",
|
||||||
|
animation: "spin 1s linear infinite",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
/* Screenshot mode canvas */
|
|
||||||
<Canvas
|
<Canvas
|
||||||
onCreateRef={setCanvasReference}
|
onCreateRef={setCanvasReference}
|
||||||
width={dimensions.width}
|
width={dimensions.width}
|
||||||
@@ -2560,9 +2500,98 @@ export const BrowserWindow = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DOMLoadingIndicator: React.FC = () => {
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
const [pendingRequests, setPendingRequests] = useState(0);
|
||||||
|
const [hasStartedLoading, setHasStartedLoading] = useState(false);
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { state } = useContext(AuthContext);
|
||||||
|
const { user } = state;
|
||||||
|
const { browserWidth, browserHeight } = useBrowserDimensionsStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!socket) return;
|
||||||
|
|
||||||
|
const handleLoadingProgress = (data: {
|
||||||
|
progress: number;
|
||||||
|
pendingRequests: number;
|
||||||
|
userId: string;
|
||||||
|
}) => {
|
||||||
|
if (!data.userId || data.userId === user?.id) {
|
||||||
|
// Once loading has started, never reset progress to 0
|
||||||
|
if (!hasStartedLoading && data.progress > 0) {
|
||||||
|
setHasStartedLoading(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update progress if we haven't started or if new progress is higher
|
||||||
|
if (!hasStartedLoading || data.progress >= progress) {
|
||||||
|
setProgress(data.progress);
|
||||||
|
setPendingRequests(data.pendingRequests);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("domLoadingProgress", handleLoadingProgress);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("domLoadingProgress", handleLoadingProgress);
|
||||||
|
};
|
||||||
|
}, [socket, user?.id, hasStartedLoading, progress]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: browserWidth,
|
||||||
|
height: browserHeight,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
background: "#f5f5f5",
|
||||||
|
borderRadius: "5px",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Loading text with percentage */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "18px",
|
||||||
|
fontWeight: "500",
|
||||||
|
color: "#333",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Loading {progress}%
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Progress bar */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "240px",
|
||||||
|
height: "6px",
|
||||||
|
background: "#e0e0e0",
|
||||||
|
borderRadius: "3px",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: `${progress}%`,
|
||||||
|
height: "100%",
|
||||||
|
background: "linear-gradient(90deg, #ff00c3, #ff66d9)",
|
||||||
|
borderRadius: "3px",
|
||||||
|
transition: "width 0.3s ease-out",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const drawImage = (image: string, canvas: HTMLCanvasElement): void => {
|
const drawImage = (image: string, canvas: HTMLCanvasElement): void => {
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user