diff --git a/frontend/src/components/format/FormatCard.jsx b/frontend/src/components/format/FormatCard.jsx
index 506cb43..a0860a3 100644
--- a/frontend/src/components/format/FormatCard.jsx
+++ b/frontend/src/components/format/FormatCard.jsx
@@ -1,4 +1,4 @@
-import React, {useState} from 'react';
+import React, {useState, useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
import {Copy, Check, FlaskConical, FileText, ListFilter} from 'lucide-react';
import Tooltip from '@ui/Tooltip';
@@ -14,6 +14,8 @@ function FormatCard({
willBeSelected,
onSelect
}) {
+ const [isVisible, setIsVisible] = useState(false);
+ const cardRef = useRef(null);
const [showDescription, setShowDescription] = useState(() => {
const saved = localStorage.getItem(`format-view-${format.file_name}`);
return saved !== null ? JSON.parse(saved) : true;
@@ -64,8 +66,27 @@ function FormatCard({
}
};
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ setIsVisible(entry.isIntersecting);
+ },
+ {
+ threshold: 0,
+ rootMargin: '100px' // Keep cards rendered 100px outside viewport
+ }
+ );
+
+ if (cardRef.current) {
+ observer.observe(cardRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
return (
-
+ {isVisible ? (
+
{/* Header Section */}
@@ -237,6 +259,15 @@ function FormatCard({
)}
+ ) : (
+
+ )}
);
}
diff --git a/frontend/src/components/regex/RegexCard.jsx b/frontend/src/components/regex/RegexCard.jsx
index 1fde0ac..5f5e434 100644
--- a/frontend/src/components/regex/RegexCard.jsx
+++ b/frontend/src/components/regex/RegexCard.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState, useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
import {Copy, Check, FlaskConical} from 'lucide-react';
import Tooltip from '@ui/Tooltip';
@@ -15,6 +15,9 @@ const RegexCard = ({
willBeSelected,
onSelect
}) => {
+ const [isVisible, setIsVisible] = useState(false);
+ const cardRef = useRef(null);
+
const totalTests = pattern.tests?.length || 0;
const passedTests = pattern.tests?.filter(t => t.passes)?.length || 0;
const passRate =
@@ -46,8 +49,27 @@ const RegexCard = ({
return 'text-red-400';
};
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ setIsVisible(entry.isIntersecting);
+ },
+ {
+ threshold: 0,
+ rootMargin: '100px' // Keep cards rendered 100px outside viewport
+ }
+ );
+
+ if (cardRef.current) {
+ observer.observe(cardRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
return (
-
+ {isVisible ? (
+
{/* Header Section */}
@@ -183,6 +206,15 @@ const RegexCard = ({
)}
+ ) : (
+
+ )}
);
};