Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ Handles file system operations and provides a secure bridge between the frontend
---

Our Code of Conduct: [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)

Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.

2 changes: 1 addition & 1 deletion frontend/src/components/Media/ImageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ export function ImageCard({
</div>
</div>
);
}
}
45 changes: 37 additions & 8 deletions frontend/src/components/Navigation/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';

import { Input } from '@/components/ui/input';
import { ThemeSelector } from '@/components/ThemeToggle';
import { Search } from 'lucide-react';
Expand Down Expand Up @@ -63,7 +70,19 @@ export function Navbar() {

{/* FaceSearch Dialog */}

<FaceSearchDialog />
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div>
<FaceSearchDialog />
</div>
</TooltipTrigger>
<TooltipContent side="bottom">
<span>Face Scanner</span>
</TooltipContent>
</Tooltip>
</TooltipProvider>


<button
className="text-muted-foreground hover:bg-accent dark:hover:bg-accent/50 hover:text-foreground mx-1 cursor-pointer rounded-sm p-2"
Expand All @@ -82,13 +101,23 @@ export function Navbar() {
<span className="hidden text-sm sm:inline-block">
Welcome <span className="text-muted-foreground">{userName}</span>
</span>
<a href="/settings" className="p-2">
<img
src={userAvatar || '/photo1.png'}
className="hover:ring-primary/50 h-8 w-8 cursor-pointer rounded-full transition-all hover:ring-2"
alt="User avatar"
/>
</a>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<a href="/settings" className="p-2">
<img
src={userAvatar || '/photo1.png'}
className="hover:ring-primary/50 h-8 w-8 cursor-pointer rounded-full transition-all hover:ring-2"
alt="User avatar"
/>
</a>
</TooltipTrigger>
<TooltipContent side="bottom">
<span>Profile</span>
</TooltipContent>
</Tooltip>
</TooltipProvider>

</div>
</div>
</div>
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/components/OnboardingSteps/FolderSetupStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export function FolderSetupStep({

// Local state for folders
const [folder, setFolder] = useState<string>('');
const [error, setError] = useState<string>('');


useEffect(() => {
if (localStorage.getItem('folderChosen') === 'true') {
Expand All @@ -44,19 +46,30 @@ export function FolderSetupStep({
const selectedFolder = await pickSingleFolder();
if (selectedFolder) {
setFolder(selectedFolder);
setError('');
}
};


const handleRemoveFolder = () => {
setFolder('');
setError('Please select at least one folder to continue.');
};


const handleNext = () => {
if (!folder) {
setError('Please select at least one folder to continue.');
return;
}

setError('');
localStorage.setItem('folderChosen', 'true');
addFolderMutate(folder);
dispatch(markCompleted(stepIndex));
};


const handleBack = () => {
dispatch(previousStep());
};
Expand Down Expand Up @@ -132,6 +145,12 @@ export function FolderSetupStep({
</div>
</div>
)}
{error && (
<p className="text-destructive text-sm font-medium">
{error}
</p>
)}

</CardContent>

<CardFooter className="flex justify-between p-3">
Expand All @@ -144,10 +163,12 @@ export function FolderSetupStep({
</Button>
<Button
onClick={handleNext}
disabled={!folder}
className="cursor-pointer px-4 py-1 text-sm"
>
Next
</Button>

</CardFooter>
</Card>

Expand Down
95 changes: 86 additions & 9 deletions landing-page/src/components/ui/Features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,112 @@ const features: Feature[] = [
];

// FeatureCard component
<<<<<<< HEAD
import { useRef, useState, useEffect } from "react";
import { motion } from "framer-motion";
Comment on lines +57 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove duplicate import and unused import.

Line 57 duplicates the motion import from line 2, causing a redeclaration error. Additionally, useEffect is imported on line 56 but never used.

Apply this diff to fix the imports:

-import { useRef, useState, useEffect } from "react";
-import { motion } from "framer-motion";
+import { useRef, useState } from "react";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useRef, useState, useEffect } from "react";
import { motion } from "framer-motion";
import { useRef, useState } from "react";
🧰 Tools
🪛 Biome (2.1.2)

[error] 57-57: Shouldn't redeclare 'motion'. Consider to delete it or rename it.

'motion' is defined here:

(lint/suspicious/noRedeclare)

🤖 Prompt for AI Agents
In landing-page/src/components/ui/Features.tsx around lines 56 to 57, the file
has a duplicate import of `motion` and an unused `useEffect` import; remove
`useEffect` from the React named imports and delete the duplicated `motion`
import so you only import { useRef, useState } from "react" and a single import
{ motion } from "framer-motion".


// Assuming Feature type is defined elsewhere or imported
// interface Feature { ... }

=======
import { useRef, useState } from "react";
import { motion } from "framer-motion";

>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
Comment on lines +56 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Unresolved Git merge conflict markers.

The file contains unresolved merge conflict markers (<<<<<<< HEAD, =======, >>>>>>>) which cause parse errors and prevent the code from compiling. This must be resolved before the PR can be merged.

After resolving the conflict, ensure you keep only one set of imports:

-<<<<<<< HEAD
-import { useRef, useState, useEffect } from "react";
-import { motion } from "framer-motion";
-
-// Assuming Feature type is defined elsewhere or imported
-// interface Feature { ... }
-
-=======
 import { useRef, useState } from "react";
-import { motion } from "framer-motion";
-
->>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)

Note: Remove the duplicate motion import since it's already imported on line 2.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<<<<<<< HEAD
import { useRef, useState, useEffect } from "react";
import { motion } from "framer-motion";
// Assuming Feature type is defined elsewhere or imported
// interface Feature { ... }
=======
import { useRef, useState } from "react";
import { motion } from "framer-motion";
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
import { useRef, useState } from "react";
🧰 Tools
🪛 Biome (2.1.2)

[error] 62-63: Expected a statement but instead found '======='.

Expected a statement here.

(parse)


[error] 66-67: Expected a statement but instead found '>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)'.

Expected a statement here.

(parse)


[error] 67-67: numbers cannot be followed by identifiers directly after

an identifier cannot appear here

(parse)


[error] 58-58: Shouldn't redeclare 'motion'. Consider to delete it or rename it.

'motion' is defined here:

(lint/suspicious/noRedeclare)


[error] 64-64: Shouldn't redeclare 'useRef'. Consider to delete it or rename it.

'useRef' is defined here:

(lint/suspicious/noRedeclare)


[error] 64-64: Shouldn't redeclare 'useState'. Consider to delete it or rename it.

'useState' is defined here:

(lint/suspicious/noRedeclare)


[error] 65-65: Shouldn't redeclare 'motion'. Consider to delete it or rename it.

'motion' is defined here:

(lint/suspicious/noRedeclare)

🤖 Prompt for AI Agents
In landing-page/src/components/ui/Features.tsx around lines 56 to 67 there are
unresolved Git conflict markers (<<<<<<<, =======, >>>>>>>) that break parsing;
remove the conflict markers and consolidate the duplicate imports into a single
import block (keep useRef, useState, useEffect from "react" and a single import
of motion from "framer-motion"), ensuring no duplicate motion import remains and
only one import section is present.

const FeatureCard = ({ feature }: { feature: Feature }) => {
// Define size classes with a default value for undefined sizes
const sizeClasses = {
large: "md:col-span-2",
medium: "md:col-span-2",
small: "md:col-span-1",
};

// Use the feature's size or default to "small" if undefined
const sizeClass = sizeClasses[feature.size || "small"];

const hoverTimer = useRef<number | null>(null);
const [isHovered, setIsHovered] = useState(false);

<<<<<<< HEAD
// Clean Up: Detect touch capability safely for SSR/Hybrid devices
// Ideally, rely on the delay logic, but this prevents touch-emulation triggers
const isTouchDevice = () => {
if (typeof window === "undefined") return false;
return window.matchMedia("(hover: none)").matches;
};

const handleMouseEnter = () => {
if (isTouchDevice()) return;

// Logic: Only trigger state after 1 second of "intent"
hoverTimer.current = window.setTimeout(() => {
setIsHovered(true);
}, 1000);
=======
const isTouchDevice =
typeof window !== "undefined" &&
("ontouchstart" in window || navigator.maxTouchPoints > 0);

const handleMouseEnter = () => {
if (isTouchDevice) return;

hoverTimer.current = window.setTimeout(() => {
setIsHovered(true);
}, 1000); // 1s intentional hover
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
Comment on lines +80 to +106
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Unresolved merge conflict in hover logic.

Choose one implementation of isTouchDevice. The HEAD version uses a function with matchMedia("(hover: none)"), which is more reliable for detecting hover capability. The other version uses a constant check for ontouchstart/maxTouchPoints.

Recommended resolution using the more robust approach:

-<<<<<<< HEAD
-  // Clean Up: Detect touch capability safely for SSR/Hybrid devices
-  // Ideally, rely on the delay logic, but this prevents touch-emulation triggers
-  const isTouchDevice = () => {
-    if (typeof window === "undefined") return false;
-    return window.matchMedia("(hover: none)").matches;
-  };
-
-  const handleMouseEnter = () => {
-    if (isTouchDevice()) return;
-
-    // Logic: Only trigger state after 1 second of "intent"
-    hoverTimer.current = window.setTimeout(() => {
-      setIsHovered(true);
-    }, 1000); 
-=======
   const isTouchDevice =
     typeof window !== "undefined" &&
     ("ontouchstart" in window || navigator.maxTouchPoints > 0);

   const handleMouseEnter = () => {
     if (isTouchDevice) return;

     hoverTimer.current = window.setTimeout(() => {
       setIsHovered(true);
     }, 1000); // 1s intentional hover
->>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<<<<<<< HEAD
// Clean Up: Detect touch capability safely for SSR/Hybrid devices
// Ideally, rely on the delay logic, but this prevents touch-emulation triggers
const isTouchDevice = () => {
if (typeof window === "undefined") return false;
return window.matchMedia("(hover: none)").matches;
};
const handleMouseEnter = () => {
if (isTouchDevice()) return;
// Logic: Only trigger state after 1 second of "intent"
hoverTimer.current = window.setTimeout(() => {
setIsHovered(true);
}, 1000);
=======
const isTouchDevice =
typeof window !== "undefined" &&
("ontouchstart" in window || navigator.maxTouchPoints > 0);
const handleMouseEnter = () => {
if (isTouchDevice) return;
hoverTimer.current = window.setTimeout(() => {
setIsHovered(true);
}, 1000); // 1s intentional hover
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
// Clean Up: Detect touch capability safely for SSR/Hybrid devices
// Ideally, rely on the delay logic, but this prevents touch-emulation triggers
const isTouchDevice = () => {
if (typeof window === "undefined") return false;
return window.matchMedia("(hover: none)").matches;
};
const handleMouseEnter = () => {
if (isTouchDevice()) return;
// Logic: Only trigger state after 1 second of "intent"
hoverTimer.current = window.setTimeout(() => {
setIsHovered(true);
}, 1000);
};
🧰 Tools
🪛 Biome (2.1.2)

[error] 94-95: Expected a statement but instead found '======='.

Expected a statement here.

(parse)


[error] 105-106: Expected a statement but instead found '>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)'.

Expected a statement here.

(parse)


[error] 106-106: numbers cannot be followed by identifiers directly after

an identifier cannot appear here

(parse)


[error] 89-89: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)

🤖 Prompt for AI Agents
In landing-page/src/components/ui/Features.tsx around lines 80 to 106, there is
an unresolved merge conflict in the touch-detection/hover logic; keep the
matchMedia("(hover: none)") approach as it’s more reliable, remove the conflict
markers, and convert isTouchDevice into a safe SSR-aware function (if typeof
window === "undefined" return false; otherwise return window.matchMedia("(hover:
none)").matches). Ensure handleMouseEnter calls that function (if
(isTouchDevice()) return;) and preserve the 1s hoverTimer logic and cleanup
behavior.

};

const handleMouseLeave = () => {
if (hoverTimer.current) {
clearTimeout(hoverTimer.current);
hoverTimer.current = null;
}
setIsHovered(false);
};
Comment on lines 77 to 115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add cleanup on unmount to prevent memory leak.

The hover delay implementation is correct and achieves the PR objective of preventing accidental expansion. The timer cleanup in handleMouseLeave works well for normal interactions.

However, if the component unmounts while hoverTimer is pending, the timeout will still fire and attempt to update state on an unmounted component. Add a cleanup effect:

  const hoverTimer = useRef<number | null>(null);
  const [isHovered, setIsHovered] = useState(false);

+ useEffect(() => {
+   // Cleanup timer on unmount
+   return () => {
+     if (hoverTimer.current) {
+       clearTimeout(hoverTimer.current);
+     }
+   };
+ }, []);
+
  // Clean Up: Detect touch capability safely for SSR/Hybrid devices
  // Ideally, rely on the delay logic, but this prevents touch-emulation triggers
  const isTouchDevice = () => {

You'll need to add useEffect to the React imports on line 56.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In landing-page/src/components/ui/Features.tsx around lines 71 to 96, the hover
timeout may fire after the component unmounts and call setIsHovered on an
unmounted component; add a useEffect cleanup that clears hoverTimer.current on
unmount to prevent the memory leak and stale state update, and also add
useEffect to the React import list on line 56 so the hook is available.


return (
<motion.div
className={`group ${sizeClass} h-full`}
whileHover={{ scale: 1.02 }}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
<<<<<<< HEAD
// Scale is controlled by state, ensuring it syncs with the delay
=======
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
animate={isHovered ? { scale: 1.02 } : { scale: 1 }}
transition={{ duration: 0.3 }}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div
<<<<<<< HEAD
// CHANGED: Removed 'hover:border-...' and 'hover:shadow-...'
// Moved styling to the conditional string below to prevent instant flashing.
className={`relative h-full rounded-2xl bg-white dark:bg-[#161717]
border-2 p-6 transition-all duration-300 cursor-pointer
${
isHovered
? "border-blue-600 shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:shadow-[0_0_22px_rgba(30,64,179,1)]"
: "border-transparent"
}`}
=======
className="relative h-full rounded-2xl bg-white dark:bg-[#161717]
border-2 border-transparent p-6 transition-all duration-300
hover:border-blue-600 dark:hover:border-blue-600
hover:shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:hover:shadow-[0_0_22px_rgba(30,64,179,1)]"
hover:shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:hover:shadow-[0_0_22px_rgba(30,64,179,1)]
cursor-pointer"
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
Comment on lines +122 to +148
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Unresolved merge conflict in JSX.

The JSX section also has unresolved conflicts. The HEAD version controls styling via state (preferred for the delayed hover feature), while the other uses CSS hover pseudo-classes.

For the delayed hover to work correctly, use the state-controlled approach:

-<<<<<<< HEAD
-      // Scale is controlled by state, ensuring it syncs with the delay
-=======
->>>>>>> 2a16307 (...)
       animate={isHovered ? { scale: 1.02 } : { scale: 1 }}
       transition={{ duration: 0.3 }}
       ...
     >
       <div
-<<<<<<< HEAD
-        // CHANGED: Removed 'hover:border-...' and 'hover:shadow-...'
-        // Moved styling to the conditional string below to prevent instant flashing.
         className={`relative h-full rounded-2xl bg-white dark:bg-[#161717] 
         border-2 p-6 transition-all duration-300 cursor-pointer
         ${
           isHovered
             ? "border-blue-600 shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:shadow-[0_0_22px_rgba(30,64,179,1)]"
             : "border-transparent"
         }`}
-=======
-        className="relative h-full rounded-2xl ... hover:border-blue-600 ..."
->>>>>>> 2a16307 (...)
       >

The state-controlled version is required; using CSS hover: classes would bypass the intentional delay.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<<<<<<< HEAD
// Scale is controlled by state, ensuring it syncs with the delay
=======
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
animate={isHovered ? { scale: 1.02 } : { scale: 1 }}
transition={{ duration: 0.3 }}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div
<<<<<<< HEAD
// CHANGED: Removed 'hover:border-...' and 'hover:shadow-...'
// Moved styling to the conditional string below to prevent instant flashing.
className={`relative h-full rounded-2xl bg-white dark:bg-[#161717]
border-2 p-6 transition-all duration-300 cursor-pointer
${
isHovered
? "border-blue-600 shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:shadow-[0_0_22px_rgba(30,64,179,1)]"
: "border-transparent"
}`}
=======
className="relative h-full rounded-2xl bg-white dark:bg-[#161717]
border-2 border-transparent p-6 transition-all duration-300
hover:border-blue-600 dark:hover:border-blue-600
hover:shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:hover:shadow-[0_0_22px_rgba(30,64,179,1)]"
hover:shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:hover:shadow-[0_0_22px_rgba(30,64,179,1)]
cursor-pointer"
>>>>>>> 2a16307 (Gallery feature cards expand only after an intentional hover on desktop to prevent accidental interactions. Hover effects are disabled on touch devices.)
animate={isHovered ? { scale: 1.02 } : { scale: 1 }}
transition={{ duration: 0.3 }}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div
className={`relative h-full rounded-2xl bg-white dark:bg-[#161717]
border-2 p-6 transition-all duration-300 cursor-pointer
${
isHovered
? "border-blue-600 shadow-[0_0_15px_rgba(30,64,175,0.9)] dark:shadow-[0_0_22px_rgba(30,64,179,1)]"
: "border-transparent"
}`}
>
🧰 Tools
🪛 Biome (2.1.2)

[error] 122-122: expected > but instead found <

Remove <

(parse)


[error] 123-124: Expected a JSX attribute but instead found '======='.

Expected a JSX attribute here.

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 125-125: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 130-130: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 132-132: Expected a type parameter but instead found '<<<<<<'.

Expected a type parameter here.

(parse)


[error] 132-132: expected , but instead found HEAD

Remove HEAD

(parse)


[error] 135-135: expected , but instead found className

Remove className

(parse)


[error] 135-135: expected , but instead found =

Remove =

(parse)


[error] 135-135: expected , but instead found relative

Remove relative

(parse)


[error] 135-135: expected , but instead found h

Remove h

(parse)


[error] 135-135: expected , but instead found -

Remove -

(parse)


[error] 135-135: expected , but instead found full

Remove full

(parse)


[error] 135-135: expected , but instead found rounded

Remove rounded

(parse)


[error] 135-135: expected , but instead found -

Remove -

(parse)


[error] 135-135: numbers cannot be followed by identifiers directly after

an identifier cannot appear here

(parse)


[error] 135-135: expected , but instead found bg

Remove bg

(parse)


[error] 135-135: expected , but instead found -

Remove -

(parse)


[error] 135-135: expected , but instead found white

Remove white

(parse)


[error] 135-135: expected , but instead found dark

Remove dark

(parse)


[error] 135-135: expected , but instead found :

Remove :

(parse)


[error] 135-135: expected , but instead found bg

Remove bg

(parse)


[error] 135-135: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found border

Remove border

(parse)


[error] 136-136: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found p

Remove p

(parse)


[error] 136-136: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found transition

Remove transition

(parse)


[error] 136-136: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found all

Remove all

(parse)


[error] 136-136: expected , but instead found duration

Remove duration

(parse)


[error] 136-136: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found cursor

Remove cursor

(parse)


[error] 136-136: expected , but instead found -

Remove -

(parse)


[error] 136-136: expected , but instead found pointer

Remove pointer

(parse)


[error] 137-137: expected , but instead found $

Remove $

(parse)


[error] 137-137: expected , but instead found {

Remove {

(parse)


[error] 139-139: ';' expected'

An explicit or implicit semicolon is expected here...

(parse)


[error] 141-141: expected , but instead found ```

Remove `

(parse)

🤖 Prompt for AI Agents
In landing-page/src/components/ui/Features.tsx around lines 122 to 148, there's
an unresolved merge conflict with both the state-controlled hover version (HEAD)
and the CSS hover pseudo-class version present; keep the state-controlled
approach required for the delayed hover feature, remove the conflict markers
(<<<<<<<, =======, >>>>>>>) and delete the alternate branch that uses hover:
classes, ensure the component uses the isHovered-driven animate/transition and
onMouseEnter/onMouseLeave handlers, and preserve the conditional className that
toggles border and shadow based on isHovered (remove any hover:... and
dark:hover:... utilities so the visual changes are only driven by state).

>
<div className="mb-4 text-gray-800 dark:text-gray-200">{feature.icon}</div>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-gray-100">{feature.title}</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">{feature.description}</p>
<p className="text-sm text-gray-500 dark:text-gray-400">{feature.details}</p>
<div className="mb-4 text-gray-800 dark:text-gray-200">
{feature.icon}
</div>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-gray-100">
{feature.title}
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
{feature.description}
</p>
<p className="text-sm text-gray-500 dark:text-gray-400">
{feature.details}
</p>
</div>
</motion.div>
);
Expand Down