Updated the design step 1 is finsih now I'll check it with mohammed

هذا الالتزام موجود في:
2025-10-03 10:34:58 +03:00
الأصل c8743c2f5a
التزام 4a9915a6b7
38 ملفات معدلة مع 3369 إضافات و1898 حذوفات

عرض الملف

@@ -7,6 +7,8 @@ import Portfolio from './pages/Portfolio';
import Settings from './pages/Settings';
import Strategy from './pages/Strategy';
import Login from './pages/login';
import ProtectedRoute from './components/ProtectedRoute';
function App() {
return (
@@ -15,10 +17,12 @@ function App() {
<div className="min-h-screen bg-white">
<Header />
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/portfolio" element={<Portfolio />} />
<Route path="/strategy" element={<Strategy />} />
<Route path="/settings" element={<Settings />} />
<Route path="/login" element={<Login />} />
<Route path="/" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
<Route path="/portfolio" element={<ProtectedRoute><Portfolio /></ProtectedRoute>} />
<Route path="/strategy" element={<ProtectedRoute><Strategy /></ProtectedRoute>} />
<Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
</Routes>
<Footer />
</div>

ثنائية
src/assets/icons/Google.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 598 B

ثنائية
src/assets/icons/InProgress.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 574 B

ثنائية
src/assets/icons/Share2.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 543 B

ثنائية
src/assets/icons/amazon.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 658 B

ثنائية
src/assets/icons/gemini-border.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 943 B

ثنائية
src/assets/icons/gemini.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 553 B

ثنائية
src/assets/icons/gemini1.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 652 B

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 458 B

ثنائية
src/assets/icons/iconheader/active.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 1.1 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 1.1 KiB

ثنائية
src/assets/icons/iconheader/total.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 1.3 KiB

ثنائية
src/assets/icons/map.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 604 B

ثنائية
src/assets/icons/no.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 636 B

عرض الملف

@@ -1,6 +1,6 @@
const CampaignTracker = () => {
const CampaignTracker = ({ handleMenuClick }: { handleMenuClick: () => void }) => {
const progressSections = [
{
title: "Social",
@@ -80,16 +80,16 @@ const CampaignTracker = () => {
{/* Status Cards */}
<div className="grid grid-cols-3 gap-4 mb-8">
<div className="bg-gray-50 rounded-lg p-1 border">
<div className="text-sm text-gray-600 mb-1">Indexed:</div>
<div className="px-2 rounded-lg p-1 border">
<div className=" text-gray-700 mb-1 ">Indexed:</div>
<div className="text-sm font-bold text-gray-900">77%</div>
</div>
<div className="bg-gray-50 rounded-lg p-1 border">
<div className="text-sm text-gray-600 mb-1">Interlinked:</div>
<div className="px-2 rounded-lg p-1 border">
<div className="text- text-gray-700 mb-1 ">Interlinked:</div>
<div className="text-sm font-bold text-gray-900">5%</div>
</div>
<div className="bg-gray-50 rounded-lg p-1 border">
<div className="text-sm text-gray-600 mb-1">Publishing:</div>
<div className="px-2 rounded-lg p-1 border">
<div className="text- text-gray-700 mb-1 ">Publishing:</div>
<div className="text-sm font-bold text-gray-900">Locked</div>
</div>
</div>
@@ -120,7 +120,7 @@ const CampaignTracker = () => {
</div>
{/* Progress Bar */}
<div className={`w-full h-3 ${section.bgColor} rounded-full overflow-hidden`}>
<div className={`w-full h-3 ${section.bgColor} rounded-full overflow-hidden cursor-pointer`} onClick={handleMenuClick} >
<div
className={`h-full ${section.color} rounded-full transition-all duration-500 ease-out`}
style={{ width: `${progressPercentage}%` }}

عرض الملف

@@ -1,6 +1,6 @@
// DashboardGrid.tsx
import { useState } from "react";
import React, { useState } from "react";
import MultiRingCircularProgress from "./MultiRingCircularProgress";
import CampaignTracker from "./CampaignTracker";
import {
@@ -14,79 +14,188 @@ import {
import MetricCard from "./shared/MetricCard";
import UrlDropdown from "./shared/UrlDropdown";
import HeaderPage from "./shared/HeaderPage";
import Google from "../assets/icons/Google.png";
import Gemini from "../assets/icons/gemini.png";
import Perplexity from "../assets/icons/preplextiy.png";
import Vector from "../assets/icons/Vector.png";
import Vector2 from "../assets/icons/Vector2.png";
import GPT from "../assets/icons/gpt.png";
import Map from "../assets/icons/map.png";
import TotalBacklinks from "../assets/icons/iconheader/total.png";
import ActiveKeywords from "../assets/icons/iconheader/active.png";
import PortfolioPerformance from "../assets/icons/iconheader/portfolio.png";
import InfoBadge from "../assets/icons/iconheader/Info-badge.png";
import Amazon from "../assets/icons/amazon.png";
interface TagContent {
icon: string;
text?: string;
value?: string;
extra?: string;
}
interface Tag {
content: TagContent[];
color?: string;
}
interface HoverState {
cardId: string | null;
ringIndex: number | null;
}
const CARDS = [
{
title: "Richard Bower CPA",
title: "CPA Hollywood",
percent: 99,
rings: [
{ color: "#4285F4", value: 99 }, // blue
{ color: "#34A853", value: 80 }, // green
{ color: "#FBBC05", value: 60 }, // yellow
{ color: "#EA4335", value: 40 } // red
{ color: "#4c60e5", value: 99 }, // blue
{ color: "#4285f4", value: 50 }, // blue
{ color: "#34a853", value: 80 }, // green
{ color: "#fbbc05", value: 90 }, // yellow
{ color: "#ea4335", value: 40 } // red
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "Ai" },
{ text: "LLM" },
{
content: [
{ icon: "Google", value: "14", extra: "+1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "7", extra: "+2" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
]
},
{
title: "CPA Los Angeles",
percent: 24,
rings: [
{ color: "#4285F4", value: 24 },
{ color: "#34A853", value: 18 },
{ color: "#FBBC05", value: 14 },
{ color: "#EA4335", value: 8 }
{ color: "#4c60e5", value: 25 }, // blue
{ color: "#4285f4", value: 21 }, // blue
{ color: "#34a853", value: 40 }, // green
{ color: "#fbbc05", value: 30 }, // yellow
{ color: "#ea4335", value: 20 } // red
],
tags: [
{ text: "G 14", extra: "-2", color: "#4285F4" }
{
content: [
{ icon: "Google", value: "14", extra: "-2" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "GPT" }
]
}
]
},
{
title: "CPA Los Angeles4",
percent: 45,
rings: [
{ color: "#4285F4", value: 45 },
{ color: "#34A853", value: 42 },
{ color: "#FBBC05", value: 32 },
{ color: "#EA4335", value: 24 }
{ color: "#4c60e5", value: 45 }, // blue
{ color: "#4285f4", value: 42 }, // blue
{ color: "#34a853", value: 32 }, // green
{ color: "#fbbc05", value: 28 }, // yellow
{ color: "#ea4335", value: 24 } // red
],
tags: [
{ text: "G 14", extra: "-2", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
{
content: [
{ icon: "Google", value: "14", extra: "-2" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "5", extra: "+1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" }
]
}
]
},
{
title: "Best CPA Los Angeles5",
percent: 89,
rings: [
{ color: "#4285F4", value: 89 },
{ color: "#34A853", value: 80 },
{ color: "#FBBC05", value: 72 },
{ color: "#EA4335", value: 57 }
{ color: "#4c60e5", value: 89 }, // blue
{ color: "#4285f4", value: 80 }, // blue
{ color: "#34a853", value: 72 }, // green
{ color: "#fbbc05", value: 65 }, // yellow
{ color: "#ea4335", value: 57 } // red
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
{
content: [
{ icon: "Google", value: "14", extra: "+1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "9", extra: "+3" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "GPT" },
{ icon: "Perplexity" }
]
}
]
},
{
title: "CPA Hollywood",
percent: 100,
title: "CPA Hollywood 2",
percent: 98,
rings: [
{ color: "#4285F4", value: 100 },
{ color: "#34A853", value: 100 },
{ color: "#FBBC05", value: 100 },
{ color: "#EA4335", value: 100 }
{ color: "#4c60e5", value: 98 }, // blue
{ color: "#4285f4", value: 98 }, // blue
{ color: "#34a853", value: 98 }, // green
{ color: "#fbbc05", value: 98 }, // yellow
{ color: "#ea4335", value: 100 } // red
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
{
content: [
{ icon: "Google", value: "14", extra: "+1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "7", extra: "+2" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
],
badge: "Content Unlocked",
actionLink: "View Published Content "
@@ -95,15 +204,32 @@ const CARDS = [
title: "Best CPA Los Angeles21",
percent: 89,
rings: [
{ color: "#cccccc", value: 89 },
{ color: "#cccccc", value: 80 },
{ color: "#cccccc", value: 72 },
{ color: "#cccccc", value: 57 }
{ color: "#cccccc", value: 89 }, // gray
{ color: "#cccccc", value: 80 }, // gray
{ color: "#cccccc", value: 72 }, // gray
{ color: "#cccccc", value: 65 }, // gray
{ color: "#cccccc", value: 57 } // gray
],
tags: [
{ text: "G 14", extra: "+1", color: "#cccccc" },
{ text: "+7", color: "#cccccc" },
{ text: "Ai", color: "#cccccc" }
{
content: [
{ icon: "Google", value: "14", extra: "+1" }
],
color: "#cccccc"
},
{
content: [
{ icon: "Map", value: "7", extra: "+2" }
],
color: "#cccccc"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
],
faded: true,
paused: true
@@ -116,33 +242,140 @@ const pillClass = (val: string) =>
: 'bg-gray-100 text-gray-700 font-bold';
export default function DashboardGrid() {
const [selectedCampaigns, setSelectedCampaigns] = useState<string[]>([])
const [tableView, setTableView] = useState<string | null>(null)
const [activeCard, setActiveCard] = useState<string | null>(null)
const [selectedCampaigns, setSelectedCampaigns] = useState<string[]>([]);
const [tableView, setTableView] = useState<string | null>(null);
const [activeCard, setActiveCard] = useState<string | null>(null);
const [hoverState, setHoverState] = useState<HoverState>({ cardId: null, ringIndex: null });
const [isHovered, setIsHovered] = useState(false);
const handleCardClick = (campaignName: string, paused: boolean) => {
if (paused) return;
setSelectedCampaigns([campaignName]);
setActiveCard(campaignName);
if (activeCard) {
if (!selectedCampaigns.includes(campaignName)) {
setSelectedCampaigns(prev => [...prev, campaignName])
}
setActiveCard(campaignName)
}
};
const handleBackClick = () => {
const handleBackClick = (e: React.MouseEvent) => {
e.stopPropagation(); // Prevent event bubbling to card click
if (tableView) {
setTableView(null)
setTableView(null);
} else if (activeCard) {
// Remove only the active card from selected campaigns
setSelectedCampaigns(prev => prev.filter(card => card !== activeCard))
setActiveCard(null)
setSelectedCampaigns(prev => prev.filter(card => card !== activeCard));
setActiveCard(null);
}
}
};
const handleMenuClick = (campaignName: string) => {
setTableView(campaignName)
}
setTableView(campaignName);
};
const handleRingHover = (cardId: string, ringIndex: number | null) => {
setHoverState({ cardId, ringIndex });
};
const TagComponent = ({ content, color = "#4285F4", faded = false }: Tag & { faded?: boolean }) => {
const getIconContent = (item: TagContent) => {
switch (item.icon) {
case "Google":
return (
<>
<img src={Google} alt="Google" className="w-5 h-5" />
{item.value && <span className="text-black font-bold text-md">{item.value}</span>}
{item.extra && (
<span className={`ml-1 text-md ${item.extra.startsWith('+') ? 'text-green-600' : 'text-red-600'} font-bold`}>
{item.extra}
</span>
)}
</>
);
case "Map":
return (
<>
<img src={Map} alt="Map" className="w-5 h-5" />
{item.value && <span className="text-black font-bold text-md">{item.value}</span>}
{item.extra && (
<span className={`ml-1 text-md ${item.extra.startsWith('+') ? 'text-green-600' : 'text-red-600'} font-bold`}>
{item.extra}
</span>
)}
</>
);
case "Ai":
return <img src={Gemini} alt="AI" className="w-5 h-5" />;
case "GPT":
return <img src={GPT} alt="GPT" className="w-5 h-5" />;
case "Perplexity":
return <img src={Perplexity} alt="Perplexity" className="w-5 h-5" />;
default:
return item.text || null;
}
};
return (
<span
className={`rounded-full border-2 border-gray-200 bg-white px-3 py-1 flex items-center gap-2 text-sm font-medium transition-all duration-300 hover:scale-105
${faded ? "text-gray-200 border-gray-100" : "text-gray-400 border-gray-100 hover:border-blue-100"
}`}
style={color ? { color } : {}} // borderColor: color
>
{content.map((item, index) => (
<div key={index} className="flex items-center gap-1 py-1">
{getIconContent(item)}
</div>
))}
</span>
);
};
const CardHeader = ({ title, value, valueChange, icon, tooltipText }: { title: string, value: string, valueChange?: string, icon: string, tooltipText?: string }) => {
return (
<div className="flex items-center gap-2 border-r-2 border-gray-200 pr-4 last:border-r-0 w-[32%]"
onMouseEnter={() => {
if (tooltipText) {
setIsHovered(true)
}
}}
onMouseLeave={() => {
if (tooltipText) {
setIsHovered(false)
}
}}>
<img src={icon} alt="Active Keywords" className="w-14 h-14" />
<div className="flex flex-col px-4">
<div className="flex items-center gap-2">
<span className="text-2xl text-gray-500 font-bold">{value}</span>
{tooltipText && <div className="relative">
{/* <Info size={16} className="text-gray-800 cursor-pointer" /> */}
<img src={InfoBadge} alt="Info" className="w-4 h-4 text-gray-800 cursor-pointer" />
{isHovered && (
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-2 px-4 py-2 w-72 bg-gray-800 text-white text-sm rounded-lg shadow-lg z-50 transition-opacity duration-300 pointer-events-none opacity-100">
{/* Tooltip triangle */}
<div className="absolute bottom-full left-1/2 -translate-x-1/2 w-0 h-0 border-8 border-transparent border-b-gray-800"></div>
{tooltipText}
</div>
)}
</div>}
</div>
<div className="text-lg text-gray-500 ">{title}</div>
<div className="text-lg text-gray-500 flex items-center gap-2">
<span className="text-lg text-gray-500 font-bold">{valueChange}</span>
</div>
</div>
</div>
)
}
return (
<>
@@ -150,28 +383,11 @@ export default function DashboardGrid() {
{/* Main content area with new metric cards */}
<main className="pb-4 px-2 border-collapse border-2 mb-6 rounded-lg">
<div className="flex flex-wrap gap-4 lg:flex-row flex-col">
<MetricCard
icon={FileText}
value="5"
label="Active Keywords"
// tooltipText="Total Keywords"
valueChange="10"
/>
<MetricCard
icon={Link}
value="112"
label="Total Backlinks"
// tooltipText="Total Backlinks"
valueChange="10"
/>
<MetricCard
icon={TrendingUp}
value="34%"
valueChange="+6%"
label="Portfolio Performance"
tooltipText="The % of keywords with top rankings, including page 1, map pack, and Ai."
/>
<div className="flex flex-wrap gap-4 lg:flex-row flex-col justify-between items-center py-4 px-4">
<CardHeader title="Active Keywords" value="5" icon={ActiveKeywords} />
<CardHeader title="Total Backlinks" value="112/1012" icon={TotalBacklinks} />
<CardHeader title="Portfolio Performance" value="34%" icon={PortfolioPerformance} tooltipText="Portfolio Performance is the percentage of keywords that are performing well." />
</div>
</main>
@@ -179,141 +395,138 @@ export default function DashboardGrid() {
{CARDS.map((card, idx) => (
<div
key={idx}
className={`bg-white rounded-2xl shadow-lg border transition-all duration-700 ease-in-out transform
hover:shadow-2xl hover:scale-105 cursor-pointer
${card.faded ? "opacity-60" : ""}
${activeCard === card.title ? "cursor-default" : "cursor-pointer"}
${selectedCampaigns.includes(card.title)
? 'shadow-2xl scale-[1.02] '
: 'hover:scale-105 hover:shadow-xl'
}`}
onClick={() => handleCardClick(card.title, card.paused)}
style={{
transform: selectedCampaigns.includes(card.title)
? 'translateY(-5px) scale(1.02)'
: 'translateY(0px) scale(1)'
}}
className="[perspective:1000px] h-[560px]"
onClick={() => handleCardClick(card.title, card.paused || false)}
>
{selectedCampaigns.includes(card.title) && activeCard === card.title ? (
<div className="py-3 flex flex-col">
{/* Header */}
<div className="flex items-center justify-between border-b border-gray-200 pb-2">
<div className="flex items-center gap-4">
<button
onClick={handleBackClick}
<div className={`relative w-full h-full transition-transform duration-700 ease-in-out [transform-style:preserve-3d] ${selectedCampaigns.includes(card.title) ? '[transform:rotateY(180deg)]' : ''
}`}>
{/* Front of card */}
<div className={`absolute w-full h-full [backface-visibility:hidden] bg-white rounded-2xl shadow-lg border transition-all duration-300 ease-in-out cursor-pointer ${card.faded ? "opacity-60" : ""}
${selectedCampaigns.includes(card.title) ? 'shadow-2xl scale-[1.02]' : 'hover:scale-105 hover:shadow-xl'
}`}
style={{
transform: selectedCampaigns.includes(card.title)
? 'translateY(-5px) scale(1.02)'
: 'translateY(0px) scale(1)'
}}>
<div className="p-5 flex flex-col items-center h-full">
{card.badge && (
<div className="absolute top-4 right-4 bg-green-500 text-white px-3 py-1 rounded-full text-xs font-bold transform rotate-12 shadow-lg">
{card.badge}
</div>
)}
<MultiRingCircularProgress
card={card}
hoveredIndex={hoverState.cardId === card.title ? hoverState.ringIndex : null}
onHover={(index) => handleRingHover(card.title, index)}
cardId={card.title}
/>
<div className={`mt-1 font-bold text-lg text-center ${card.faded ? "text-gray-400" : "text-gray-900"}`}>
{card.title}
</div>
{/* Tags */}
<div className="mt-3 flex flex-row gap-2 flex-wrap justify-center">
{card.tags.map((tag, i) => (
<TagComponent
key={i}
{...tag}
faded={card.faded}
/>
))}
</div>
{card.actionLink && (
<div className="mt-3 text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800">
{card.actionLink}
</div>
)}
{card.paused && (
<div className="mt-3 text-center">
<div className="text-gray-400 text-sm">Campaign paused</div>
<button className="text-blue-600 text-sm hover:underline transition-all duration-300 hover:text-blue-800">Resume</button>
</div>
)}
</div>
</div>
{/* Back of card */}
<div className="absolute w-full h-full [backface-visibility:hidden] [transform:rotateY(180deg)] bg-white rounded-2xl shadow-lg border transition-all duration-300 ease-in-out"
style={{
transform: selectedCampaigns.includes(card.title)
? 'translateY(-5px) scale(1.02) rotateY(180deg)'
: 'translateY(0px) scale(1) rotateY(180deg)'
}}>
<div className="py-3 flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between border-b border-gray-200 pb-2 px-3">
<div className="flex items-center gap-4">
<button
onClick={handleBackClick}
className="px-2 py-1 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110 border-2 border-gray-200"
>
<ArrowLeft className="w-5 h-5 text-gray-600" />
</button>
<h1 className="text-xl font-bold text-gray-900">{card.title}</h1>
</div>
{/* <button
onClick={() => handleMenuClick(card.title)}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
title="View table"
>
<ArrowLeft className="w-5 h-5 text-gray-600" />
</button>
<h1 className="text-xl font-bold text-gray-900">{card.title}</h1>
<Menu className="w-5 h-5 text-gray-600" />
</button> */}
</div>
<button
onClick={() => handleMenuClick(card.title)}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
title="View table"
{/* Content with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-0 translate-y-4 pointer-events-none'
: 'opacity-100 translate-y-0'
}`}
style={{ display: tableView !== card.title ? 'block' : 'none' }}>
<CampaignTracker handleMenuClick={() => handleMenuClick(card.title)} />
</div>
{/* Table View with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-100 translate-y-0'
: 'opacity-0 translate-y-4 pointer-events-none'
}`}
style={{ display: tableView === card.title ? 'block' : 'none' }}
>
<Menu className="w-5 h-5 text-gray-600" />
</button>
</div>
{/* Content with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-0 translate-y-4 pointer-events-none'
: 'opacity-100 translate-y-0'
}`}
style={{ display: tableView !== card.title ? 'block' : 'none' }}>
<CampaignTracker />
</div>
{/* Table View with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-100 translate-y-0'
: 'opacity-0 translate-y-4 pointer-events-none'
}`}
style={{ display: tableView === card.title ? 'block' : 'none' }}
>
<div className="custom-scrollbar-table">
<table className="w-full rounded-lg ">
<tbody>
{[
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅿️', title: 'Pinterest DR 97 DA 95 Traffic 3,989,220' },
{ icon: '📄', title: 'Questions to ask your CPA Substack DR 97 DA 95' }
].map((row, rIdx) => (
<tr key={rIdx} className='border-b last:border-0 hover:bg-[#f1f7fe] transition-colors'>
<td className='py-3 pl-2 text-center w-10'>{row.icon}</td>
<td className='py-3 px-1 min-w-[300px] text-[#4285F4] hover:text-[#1e40af] cursor-pointer font-medium' title={row.title}>
<div className='truncate max-w-[300px] text-sm underline'>{row.title}</div>
</td>
</tr>
))}
</tbody>
</table>
<div className="custom-scrollbar-table">
<table className="w-full rounded-lg ">
<tbody>
{[
{ icon: Amazon, title: 'Questions to ask your CPA httpAmazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: Amazon, title: 'Questions to ask your CPA httpAmazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: Amazon, title: 'Questions to ask your CPA httpAmazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon' },
{ icon: Amazon, title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: Amazon, title: 'Pinterest DR 97 DA 95 Traffic 3,989,220' },
{ icon: Amazon, title: 'Questions to ask your CPA Substack DR 97 DA 95' }
].map((row, rIdx) => (
<tr key={rIdx} className='border-b last:border-0 hover:bg-[#f1f7fe] transition-colors px-2 flex items-center'>
<td className='py-3 pl-2 text-center '>
<img src={row.icon} alt='' className="w-8 h-8 rounded-lg" />
</td>
<td className='py-3 px-1 min-w-[300px] text-[#4285F4] hover:text-[#1e40af] cursor-pointer font-medium' title={row.title}>
<div className='truncate max-w-[340px] text-sm underline'>{row.title}</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800 text-center pt-3" style={{ boxShadow: '#dadada 0px -6px 10px' }}>View All</div>
</div>
<div className="text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800 text-center pt-3" style={{ boxShadow: '#dadada 0px -6px 10px' }}>View All</div>
</div>
</div>
) : (
// Card preview state
<div className="p-5 flex flex-col items-center">
{card.badge && (
<div className="absolute top-4 right-4 bg-green-500 text-white px-3 py-1 rounded-full text-xs font-bold transform rotate-12 shadow-lg">
{card.badge}
</div>
)}
<MultiRingCircularProgress card={card} />
<div className={`mt-4 font-bold text-lg text-center ${card.faded ? "text-gray-400" : "text-gray-900"}`}>
{card.title}
</div>
<div className="mt-3 flex flex-row gap-2 flex-wrap justify-center">
{card.tags.map((tag, i) => (
<span
key={i}
className={`rounded-full border-2 bg-white px-3 py-1 flex items-center text-sm font-medium transition-all duration-300 hover:scale-105 ${card.faded
? "text-gray-400 border-gray-300"
: "text-gray-700 border-gray-200 hover:border-blue-300"
}`}
style={tag.color ? { color: tag.color, borderColor: tag.color } : {}}
>
{tag.text}
{tag.extra && (
<span className={`ml-1 text-xs ${card.faded ? "text-gray-400" : "text-green-600 font-bold"
}`}>
{tag.extra}
</span>
)}
</span>
))}
</div>
{card.actionLink && (
<div className="mt-3 text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800">
{card.actionLink}
</div>
)}
{card.paused && (
<div className="mt-3 text-center">
<div className="text-gray-400 text-sm">Campaign paused</div>
<button className="text-blue-600 text-sm hover:underline transition-all duration-300 hover:text-blue-800">Resume</button>
</div>
)}
</div>
)}
</div>
</div>
))}
</div>
</>
);

عرض الملف

@@ -324,18 +324,18 @@ const IntegratedStrategy = () => {
<div className="mb-4">
<div className={`${category.color} px-3 py-2 border-l-4 border-blue-500`}>
<div className="flex items-center gap-2">
<div className="w-3 h-3 bg-blue-500 rounded-full"></div>
<span className="font-medium text-gray-700">{category.name}</span>
<span className="text-gray-600 text-sm">{category.count}</span>
<div className="w-2 h-5 bg-blue-500 rounded"></div>
<span className="font-medium text-lg text-[#2B2D3B]">{category.name}</span>
<span className="text-[#2B2D3B] text-lg font-bold bg-white py-[1px] px-[10px] rounded-full">{category.count}</span>
</div>
</div>
<div className="bg-white border border-t-0 rounded-b-md">
{category.items.map((item) => (
<div key={item.id} className="px-3 py-2 border-b border-gray-100 last:border-b-0">
<div className="flex items-center gap-2">
<span className="text-lg mt-0.5">{item.icon}</span>
<span className="text-xl mt-0.5">{item.icon}</span>
<span
className={`text-sm text-blue-600 hover:text-blue-800 ${item.isLink ? "underline cursor-pointer" : "text-gray-700"}`}
className={`text-md font-semibold text-blue-600 hover:text-blue-800 ${item.isLink ? "underline cursor-pointer" : "text-gray-700"}`}
>
{item.title}
</span>
@@ -351,11 +351,11 @@ const IntegratedStrategy = () => {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{columns.map((column, index) => (
<div key={index} className="bg-white rounded-lg shadow-sm border">
<div className="border-b border-gray-200 p-4">
<div className="border-b border-gray-200 bg-[#f6f6fa] p-4 shadow-lg ">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<h2 className="text-lg font-semibold text-gray-900">{column.title}</h2>
<span className="bg-gray-100 text-gray-600 px-2 py-1 rounded-full text-sm font-medium">
<h2 className="text-lg font-bold text-[#2B2D3B]">{column.title}</h2>
<span className="text-[#2B2D3B] bg-[#e9eaf1] px-2 py-1 rounded-full text-md font-semibold">
{column.count}
</span>
</div>

عرض الملف

@@ -13,20 +13,33 @@ interface Card {
interface MultiRingCircularProgressProps {
card: Card;
hoveredIndex: number | null;
onHover: (index: number | null) => void;
cardId: string;
}
export default function MultiRingCircularProgress({ card }: MultiRingCircularProgressProps) {
export default function MultiRingCircularProgress({ card, hoveredIndex, onHover, cardId }: MultiRingCircularProgressProps) {
const { percent, rings } = card;
// Create ring data with proper outer and inner radius calculations
const ringData = rings.map((ring, index) => ({
...ring,
outerRadius: 120 - (index * 18), // Decrease by 18px for each ring
innerRadius: 105 - (index * 18), // Decrease by 18px for each ring
outerRadius: 125 - (index * 20), // Decrease by 20px for each ring
innerRadius: 110 - (index * 20), // Decrease by 20px for each ring
}));
// When a ring is hovered, other rings become gray
const getHoverColor = (ring: Ring, index: number) => {
if (hoveredIndex === null) return ring.color;
if (hoveredIndex === index) return ring.color;
return "#d3d3d3"; // gray for non-hovered rings
};
return (
<div className="flex items-center justify-center pointer-events-none hover:scale-115 transition-all duration-300">
<div
className="flex items-center justify-center hover:scale-115 transition-all duration-300 cursor-pointer"
onMouseLeave={() => onHover(null)}
>
<PieChart width={400} height={400}>
{ringData.map((ring, index) => (
<Pie
@@ -41,9 +54,15 @@ export default function MultiRingCircularProgress({ card }: MultiRingCircularPro
innerRadius={ring.innerRadius}
outerRadius={ring.outerRadius}
paddingAngle={0}
isAnimationActive={false}
isAnimationActive={true}
scale={1.5}
onMouseEnter={() => onHover(index)}
onMouseLeave={() => onHover(null)}
fill={getHoverColor(ring, index)}
>
<Cell fill={ring.color} />
<Cell
fill={getHoverColor(ring, index)}
/>
<Cell fill="#f2f3f5" />
</Pie>
))}

عرض الملف

@@ -1,37 +1,51 @@
import React, { useState } from 'react'
import { ChevronDown } from 'lucide-react';
import React, { useState, useEffect, useRef } from 'react'
const BacklinkTypeDropdown = () => {
const BacklinkTypeDropdown = ({ options, title, subTitle }: { options: Record<string, boolean>, title: string, subTitle?: string }) => {
const [dropdownOpen, setDropdownOpen] = useState(false);
const [checkedRings, setCheckedRings] = useState<Record<string, boolean>>({
Social: true, Citation: true, 'Web 2.0': true, Multimedia: false, Crowd: false
});
const [checkedRings, setCheckedRings] = useState<Record<string, boolean>>(options);
const dropdownRef = useRef<HTMLDivElement>(null);
const toggleRing = (ring: string) => setCheckedRings(r => ({ ...r, [ring]: !r[ring] }));
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setDropdownOpen(false);
}
};
if (dropdownOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownOpen]);
return (
<div className='relative'>
<div className='relative' ref={dropdownRef}>
<button
className='border rounded-lg px-3 py-1 bg-white text-gray-700 font-medium flex items-center text-xs'
className='border rounded-lg px-3 py-1 bg-white text-gray-500 font-medium flex items-center text-md'
onClick={() => setDropdownOpen(v => !v)}
>
Backlink Type <svg className='ml-2 w-4 h-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'>
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M19 9l-7 7-7-7' />
</svg>
{title} <ChevronDown className='ml-2' />
</button>
{dropdownOpen && (
<div className='absolute z-10 bg-white shadow-lg border rounded-lg top-[110%] right-0 px-4 py-3 min-w-[190px]'>
<div className='font-semibold text-xs text-gray-700 mb-2'>Show rings:</div>
<div className='absolute z-10 bg-white shadow-lg border rounded-lg top-[110%] right-0 px-4 py-3 min-w-[150px]'>
<div className='font-semibold text-md text-gray-700 mb-2'>{subTitle}:</div>
{Object.keys(checkedRings).map((ring, idx) => (
<label
key={idx}
className='flex items-center gap-2 py-1 text-[14px] cursor-pointer select-none'
className='flex items-center gap-2 py-1 text-[16px] cursor-pointer select-none'
style={{ fontWeight: 500 }}
>
<input
type='checkbox'
checked={checkedRings[ring]}
className='form-checkbox accent-blue-600 w-4 h-4'
className='form-checkbox accent-blue-600 w-4 h-4 rounded-full'
onChange={() => toggleRing(ring)}
/>
{ring}

عرض الملف

@@ -0,0 +1,20 @@
import { Navigate } from 'react-router-dom';
interface ProtectedRouteProps {
children: JSX.Element;
}
const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
// Check if user is logged in (from localStorage or context)
const user = localStorage.getItem('sp_user');
if (!user) {
// If not logged in, redirect to login page
return <Navigate to="/login" replace />;
}
// Else render the protected component
return children;
};
export default ProtectedRoute;

عرض الملف

@@ -1,25 +1,48 @@
import Preplextiy from "../../assets/icons/Preplextiy.png"
import ChatGPT from "../../assets/icons/gpt.png"
import MetricCard from "../shared/MetricCard"
import Progress from "../../assets/icons/InProgress.png"
import No from "../../assets/icons/no.png"
import { CircleCheck } from 'lucide-react'
import { Stepper } from "../shared/Stepper"
import Preplextiy from "../../assets/icons/preplextiy.png"
import ChatGPT from "../../assets/icons/gpt.png"
import Gemini from "../../assets/icons/gemini.png"
import Gemini1 from "../../assets/icons/gemini1.png"
import Gemini2 from "../../assets/icons/gemini-border.png"
import Google from "../../assets/icons/Google.png"
function ProgressMetrics() {
return (
<div className="bg-white rounded-lg border border-gray-200 p-3 mb-6">
<h3 className="text-lg font-bold text-gray-600 mb-2">CPA Los Angeles</h3>
<div className="flex items-center justify-between border-2 border-solid border-gray-100 rounded-lg p-4">
<div className="flex items-center justify-between pb-3 px-2">
<h3 className="text-lg font-bold text-gray-600">CPA Los Angeles</h3>
{/* Example 2: With Completed Status */}
<div>
<Stepper
steps={[
{ number: 1, label: "Building Backlinks", status: "completed" },
{ number: 2, label: "Indexing", status: "active" },
{ number: 3, label: "LLM Seeding", status: "inactive" },
]}
/>
</div>
</div>
<div className="flex items-center justify-between border-2 border-solid border-gray-100 rounded-lg p-4 gap-8">
{/* Left section with progress indicators */}
<div className="flex items-center w-1/4 ">
<div className="flex items-center w-1/3 border-r-2 border-solid border-gray-300 pr-10">
{/* 60% Progress */}
<div className="w-[100%]">
<div className="flex items-center justify-between">
<div className="text-4xl font-bold text-gray-900 mb-1">60%</div>
<div className="text-md font-bold text-gray-900 mb-1">120/250 <span className="text-gray-500">links</span></div>
<div className="text-3xl font-bold text-gray-900 mb-1">120/250 <span className="text-gray-500">links</span></div>
</div>
<div className="text-sm text-gray-500 mb-2">until content publishing + LLM seeding unlocked</div>
{/* Progress bar */}
<div className="w-70 h-2 bg-gray-200 rounded-full overflow-hidden">
<div className="w-70 h-3 bg-gray-200 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-blue-500 via-green-500 via-yellow-500 to-orange-500 rounded-full"
style={{ width: "60%" }}
@@ -29,7 +52,7 @@ function ProgressMetrics() {
</div>
<div className="flex items-center w-1/3 2xl:gap-32 gap-3">
<div className="flex items-center w-1/3 border-r-2 border-solid border-gray-300 2xl:gap-32 gap-3">
{/* 75% Keyword Visibility */}
<div className="w-[30%]">
<div className="text-4xl font-bold text-gray-900 mb-1">75%</div>
@@ -37,15 +60,21 @@ function ProgressMetrics() {
</div>
<div className="flex items-center gap-3 w-[100%]">
<div className="flex items-center gap-8">
<div className="flex items-center gap-3">
<MetricCard
img={ChatGPT}
value="10" label="ChatGPT" tooltipText="ChatGPT is a chatbot that can answer questions and help with tasks." valueChange="+1" size="sm" />
{/* <img src={ChatGPT} alt="ChatGPT" className="w-8 h-8" /> */}
img={ChatGPT} tooltipText="ChatGPT" valueChange="+1" size="sm" />
<MetricCard
img={Preplextiy}
value="10" label="Preplextiy" tooltipText="Preplextiy is a chatbot that can answer questions and help with tasks." valueChange="+1" size="sm" />
tooltipText="Preplextiy" valueChange="+1" size="sm" />
<MetricCard
img={ChatGPT} tooltipText="ChatGPT" valueChange="+1" size="sm" />
<MetricCard
img={Gemini} tooltipText="Gemini" valueChange="+1" size="sm" extraStyle="border-2 border-solid border-gray-300 rounded-lg " />
</div>
</div>
</div>
@@ -69,17 +98,17 @@ function ProgressMetrics() {
</svg>
</div>
<div className="text-right">
<div className="flex items-center justify-end gap-1 mb-1">
<span className="text-gray-400">G</span>
<div className="flex items-center justify-start gap-1 mb-1">
<img src={Google} className="w-5 h-5 mr-2" alt="" />
<span className="text-lg font-bold text-gray-900">7</span>
<span className="text-lg text-green-600 font-medium">+10</span>
</div>
<div className="flex items-center justify-end gap-1 mb-1">
<span className="text-orange-500">📍</span>
<div className="flex items-center justify-start gap-1 mb-1">
<img src={Google} className="w-5 h-5 mr-2" alt="" />
<span className="text-lg font-bold text-gray-900">5</span>
<span className="text-lg text-green-600 font-medium">+3</span>
</div>
<div className="text-xs text-gray-500">Current Rank</div>
<div className="text-md text-gray-500">Current Rank</div>
</div>
</div>
</div>

عرض الملف

@@ -21,7 +21,7 @@ const RoadmapSidebar = ({
]
return (
<div className="w-80 h-[100%] bg-white border-2 border-gray-200 rounded-lg">
<div className="lg:w-80 w-[96%] mb-3 lg:mb-0 h-[100%] bg-white border-2 border-gray-200 rounded-lg">
{mode ?
null
:

عرض الملف

@@ -0,0 +1,307 @@
"use client"
import type React from "react"
import { useState } from "react"
import { ArrowLeft, Menu } from "lucide-react"
import CampaignTracker from "./CampaignTracker";
// Your existing components - make sure these are imported
// import MultiRingCircularProgress from './multi-ring-circular-progress';
// import CampaignTracker from './campaign-tracker';
const CARDS = [
{
title: "Richard Bower CPA",
percent: 99,
rings: [
{ color: "#4285F4", value: 99 }, // blue
{ color: "#34A853", value: 80 }, // green
{ color: "#FBBC05", value: 60 }, // yellow
{ color: "#EA4335", value: 40 } // red
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "Ai" },
{ text: "LLM" },
]
},
{
title: "CPA Los Angeles",
percent: 24,
rings: [
{ color: "#4285F4", value: 24 },
{ color: "#34A853", value: 18 },
{ color: "#FBBC05", value: 14 },
{ color: "#EA4335", value: 8 }
],
tags: [
{ text: "G 14", extra: "-2", color: "#4285F4" }
]
},
{
title: "CPA Los Angeles4",
percent: 45,
rings: [
{ color: "#4285F4", value: 45 },
{ color: "#34A853", value: 42 },
{ color: "#FBBC05", value: 32 },
{ color: "#EA4335", value: 24 }
],
tags: [
{ text: "G 14", extra: "-2", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
]
},
{
title: "Best CPA Los Angeles5",
percent: 89,
rings: [
{ color: "#4285F4", value: 89 },
{ color: "#34A853", value: 80 },
{ color: "#FBBC05", value: 72 },
{ color: "#EA4335", value: 57 }
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
]
},
{
title: "CPA Hollywood",
percent: 100,
rings: [
{ color: "#4285F4", value: 100 },
{ color: "#34A853", value: 100 },
{ color: "#FBBC05", value: 100 },
{ color: "#EA4335", value: 100 }
],
tags: [
{ text: "G 14", extra: "+1", color: "#4285F4" },
{ text: "+7" },
{ text: "Ai" }
],
badge: "Content Unlocked",
actionLink: "View Published Content "
},
{
title: "Best CPA Los Angeles21",
percent: 89,
rings: [
{ color: "#cccccc", value: 89 },
{ color: "#cccccc", value: 80 },
{ color: "#cccccc", value: 72 },
{ color: "#cccccc", value: 57 }
],
tags: [
{ text: "G 14", extra: "+1", color: "#cccccc" },
{ text: "+7", color: "#cccccc" },
{ text: "Ai", color: "#cccccc" }
],
faded: true,
paused: true
}
];
export default function FlipCardComplete() {
const [selectedCampaigns, setSelectedCampaigns] = useState<string[]>([])
const [activeCard, setActiveCard] = useState<string | null>(null)
const [tableView, setTableView] = useState<string | null>(null)
const [flippedCards, setFlippedCards] = useState<string[]>([])
const handleCardClick = (title: string, paused: boolean) => {
if (paused) return
if (!flippedCards.includes(title)) {
setFlippedCards([...flippedCards, title])
setSelectedCampaigns([...selectedCampaigns, title])
setActiveCard(title)
}
}
const handleBackClick = (e: React.MouseEvent, title: string) => {
e.stopPropagation()
setFlippedCards(flippedCards.filter((t) => t !== title))
setSelectedCampaigns(selectedCampaigns.filter((t) => t !== title))
setActiveCard(null)
setTableView(null)
}
const handleMenuClick = (title: string) => {
setTableView(tableView === title ? null : title)
}
console.log(CARDS)
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
{CARDS.map((card, idx) => (
<div key={idx} className="relative h-[500px]" style={{ perspective: "1000px" }}>
<div
className={`relative w-full h-full transition-transform duration-700 ease-in-out`}
style={{
transformStyle: "preserve-3d",
transform: flippedCards.includes(card.title) ? "rotateY(180deg)" : "rotateY(0deg)",
}}
>
{/* FRONT FACE - Your original card preview */}
<div
className={`absolute w-full h-full bg-white rounded-2xl shadow-lg border transition-all duration-300 hover:shadow-2xl hover:scale-105 cursor-pointer
${card.faded ? "opacity-60" : ""}
${card.paused ? "cursor-not-allowed" : "cursor-pointer"}`}
style={{
backfaceVisibility: "hidden",
WebkitBackfaceVisibility: "hidden",
}}
onClick={() => handleCardClick(card.title, card.paused)}
>
<div className="p-5 flex flex-col items-center h-full justify-center">
{card.badge && (
<div className="absolute top-4 right-4 bg-green-500 text-white px-3 py-1 rounded-full text-xs font-bold transform rotate-12 shadow-lg">
{card.badge}
</div>
)}
<div className="w-32 h-32 rounded-full bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center text-white font-bold text-2xl">
{card.title.charAt(0)}
</div>
<div className={`mt-4 font-bold text-lg text-center ${card.faded ? "text-gray-400" : "text-gray-900"}`}>
{card.title}
</div>
<div className="mt-3 flex flex-row gap-2 flex-wrap justify-center">
{card.tags.map((tag, i) => (
<span
key={i}
className={`rounded-full border-2 bg-white px-3 py-1 flex items-center text-sm font-medium transition-all duration-300 hover:scale-105 ${
card.faded
? "text-gray-400 border-gray-300"
: "text-gray-700 border-gray-200 hover:border-blue-300"
}`}
style={tag.color ? { color: tag.color, borderColor: tag.color } : {}}
>
{tag.text}
{tag.extra && (
<span className={`ml-1 text-xs ${card.faded ? "text-gray-400" : "text-green-600 font-bold"}`}>
{tag.extra}
</span>
)}
</span>
))}
</div>
{card.actionLink && (
<div className="mt-3 text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800">
{card.actionLink}
</div>
)}
{card.paused && (
<div className="mt-3 text-center">
<div className="text-gray-400 text-sm">Campaign paused</div>
<button className="text-blue-600 text-sm hover:underline transition-all duration-300 hover:text-blue-800">
Resume
</button>
</div>
)}
</div>
</div>
{/* BACK FACE - Your original expanded card view */}
<div
className="absolute w-full h-full bg-white rounded-2xl shadow-2xl border"
style={{
backfaceVisibility: "hidden",
WebkitBackfaceVisibility: "hidden",
transform: "rotateY(180deg)",
}}
>
<div className="py-3 flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between border-b border-gray-200 pb-2 px-4">
<div className="flex items-center gap-4">
<button
onClick={(e) => handleBackClick(e, card.title)}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
>
<ArrowLeft className="w-5 h-5 text-gray-600" />
</button>
<h1 className="text-xl font-bold text-gray-900">{card.title}</h1>
</div>
<button
onClick={() => handleMenuClick(card.title)}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
title="View table"
>
<Menu className="w-5 h-5 text-gray-600" />
</button>
</div>
{/* Content with smooth transitions */}
<div
className={`transition-all duration-700 ease-in-out px-4 ${
tableView === card.title
? "opacity-0 translate-y-4 pointer-events-none"
: "opacity-100 translate-y-0"
}`}
style={{ display: tableView !== card.title ? "block" : "none" }}
>
<div className="py-4">
<CampaignTracker />
</div>
</div>
{/* Table View with smooth transitions */}
<div
className={`transition-all duration-700 ease-in-out flex-1 overflow-hidden ${
tableView === card.title
? "opacity-100 translate-y-0"
: "opacity-0 translate-y-4 pointer-events-none"
}`}
style={{ display: tableView === card.title ? "block" : "none" }}
>
<div className="overflow-y-auto h-full custom-scrollbar-table">
<table className="w-full rounded-lg">
<tbody>
{[
{ icon: "🅰️", title: "Questions to ask your CPA httpAmazon" },
{ icon: "🅰️", title: "Questions to ask your CPA Published on Amazon" },
{ icon: "🎵", title: "Questions to ask your CPA Published on Amazon AWS" },
{ icon: "🅰️", title: "Questions to ask your CPA httpAmazon" },
{ icon: "🅰️", title: "Questions to ask your CPA Published on Amazon" },
{ icon: "🎵", title: "Questions to ask your CPA Published on Amazon AWS" },
{ icon: "🅰️", title: "Questions to ask your CPA httpAmazon" },
{ icon: "🅰️", title: "Questions to ask your CPA Published on Amazon" },
{ icon: "🎵", title: "Questions to ask your CPA Published on Amazon AWS" },
{ icon: "🅿️", title: "Pinterest DR 97 DA 95 Traffic 3,989,220" },
{ icon: "📄", title: "Questions to ask your CPA Substack DR 97 DA 95" },
].map((row, rIdx) => (
<tr key={rIdx} className="border-b last:border-0 hover:bg-[#f1f7fe] transition-colors">
<td className="py-3 pl-2 text-center w-10">{row.icon}</td>
<td
className="py-3 px-1 min-w-[300px] text-[#4285F4] hover:text-[#1e40af] cursor-pointer font-medium"
title={row.title}
>
<div className="truncate max-w-[300px] text-sm underline">{row.title}</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div
className="text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800 text-center pt-3"
style={{ boxShadow: "#dadada 0px -6px 10px" }}
>
View All
</div>
</div>
</div>
</div>
</div>
</div>
))}
</div>
)
}

عرض الملف

@@ -2,8 +2,8 @@ import React from 'react'
const ContainerPage = ({ children }: { children: React.ReactNode }) => {
return (
<div className='min-h-screen container pt-6 pb-20'>
{children}
<div className='min-h-screen container pt-6 pb-20'>
{children}
</div>
)
}

عرض الملف

@@ -3,9 +3,9 @@ import { Link } from "react-router-dom"
const Footer = () => {
return (
<footer className="bg-gray-100 py-6">
<div className="max-w-7xl mx-auto px-6">
<div className="container px-6">
{/* Navigation Links */}
<nav className="flex flex-wrap items-center justify-center space-x-8 mb-4">
<nav className="flex flex-wrap items-center space-x-8 mb-4">
<Link to="#" className="text-gray-600 hover:text-gray-800 font-medium m-0">Home</Link>
<Link to="#" className="text-gray-600 hover:text-gray-800 font-medium m-0">About</Link>
<Link to="#" className="text-gray-600 hover:text-gray-800 font-medium m-0">Journal</Link>
@@ -15,7 +15,7 @@ const Footer = () => {
</nav>
{/* Copyright and Legal */}
<div className="flex items-center justify-center text-sm text-gray-600 lg:flex-row flex-col">
<div className="flex items-center text-sm text-gray-600 lg:flex-row flex-col">
<span>©One Keyword LLC. Premiere Position LLC.</span>
<span className="mx-2">|</span>
<span>30745 Pacific Coast Hwy Ste 21 Malibu, CA 90265</span>

عرض الملف

@@ -1,8 +1,9 @@
import { ArrowUp, Info } from "lucide-react";
import { useState } from "react";
// Reusable Metric Card Component
const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChange, size }: { icon: any, img: any, value: any, label: any, tooltipText: any, valueChange: any, size: any }) => {
const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChange, size, extraStyle }: { icon?: any, img?: any, value?: any, label?: any, tooltipText?: any, valueChange?: any, size?: any, extraStyle?: any }) => {
const [isHovered, setIsHovered] = useState(false);
if (Img) {
@@ -10,14 +11,16 @@ const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChan
<div className="relative cursor-pointer"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<img src={Img} alt="Img" className="w-12 h-12" />
<div className=" ">
<div className={`${extraStyle}`}>
<img src={Img} alt="Img" className="w-10 h-10" />
</div>
<div className="">
{tooltipText && (
<div className="relative">
{isHovered && (
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-2 px-4 py-2 w-72 bg-gray-800 text-white text-sm rounded-lg shadow-lg z-50 transition-opacity duration-300 pointer-events-none opacity-100">
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-2 px-4 py-2 min-w-28 text-center bg-gray-800 text-white text-lg rounded-lg shadow-lg z-50 transition-opacity duration-300 pointer-events-none opacity-100 ">
{/* Tooltip triangle */}
<div className="absolute bottom-full left-1/2 -translate-x-1/2 w-0 h-0 border-8 border-transparent border-b-gray-800"></div>
<div className="absolute bottom-full left-1/2 -translate-x-1/2 w-0 h-0 border-8 border-transparent border-b-gray-800 "></div>
{tooltipText}
</div>
)}
@@ -28,6 +31,7 @@ const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChan
</div>
)
}
return (
<div
className="flex-1 min-w-[50px] bg-white rounded-xl shadow-sm p-2 flex items-center space-x-2 relative"
@@ -40,11 +44,11 @@ const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChan
</div>
)}
<div className="flex-1">
<div className={`${size === 'sm' ? 'text-sm border-2 border-gray-200 px-1 rounded-lg' : 'text-xl'} font-bold text-gray-800 flex items-center space-x-2`}>
<span>{value}</span>
<span className="text-sm text-gray-400">{!tooltipText && label}</span>
<span className="text-gray-600 bg-gray-200 px-1 py-1 rounded-md">{value}</span>
{valueChange && (
<div className="flex items-center text-sm font-semibold text-green-500">
{Icon && (
@@ -55,7 +59,7 @@ const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChan
)}
<div className="flex items-center space-x-1 mt-1 text-gray-500">
<span className="text-sm">{label}</span>
<span className="text-sm">{tooltipText && label}</span>
{tooltipText && (
<div className="relative">
<Info size={16} className="text-gray-400 cursor-pointer" />

عرض الملف

@@ -0,0 +1,59 @@
import { Check } from "lucide-react"
interface Step {
number: number
label: string
status: "active" | "inactive" | "completed"
}
interface StepperProps {
steps: Step[]
}
export function Stepper({ steps }: StepperProps) {
return (
<div className="inline-flex items-center gap-3 rounded-full px-4 py-2">
{steps.map((step, index) => (
<div key={step.number} className="flex items-center gap-3 ">
{/* Step Badge and Label */}
<div className="flex items-center gap-2 bg-[#E6ECFB] rounded-full px-3 py-2">
{/* Numbered Badge */}
<div
className={`flex items-center justify-center w-6 h-6 rounded-full text-md font-semibold ${
step.status === "completed" || step.status === "active" ? "bg-[#4C60E5] text-white" : "bg-gray-300 text-gray-600"
}`}
>
{step.number}
</div>
{/* Step Label */}
<span
className={`text-sm font-medium whitespace-nowrap ${
step.status === "active" || step.status === "completed" ? "text-gray-900" : "text-gray-500"
}`}
>
{step.label}
</span>
</div>
{/* Separator - Three Dots or Checkmark */}
{index < steps.length - 1 && (
<div className="flex items-center gap-1">
<div className={`w-1 h-1 rounded-full ${step.status === "completed" ? "bg-[#4C60E5]" : "bg-gray-400"}`} />
<div className={`w-1 h-1 rounded-full ${step.status === "completed" ? "bg-[#4C60E5]" : "bg-gray-400"}`} />
<div className={`w-1 h-1 rounded-full ${step.status === "completed" ? "bg-[#4C60E5]" : "bg-gray-400"}`} />
</div>
)}
{/* Checkmark Icon for Last Step */}
{index === steps.length - 1 && (
<div className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-300">
<Check className="w-4 h-4 text-white" />
</div>
)}
</div>
))}
</div>
)
}

عرض الملف

@@ -24,7 +24,7 @@ export default function UrlDropdown() {
<div className="relative text-sm max-w-[400px] min-w-[220px]">
{/* Input box */}
<div
className="flex justify-between items-center border border-gray-300 bg-white px-2 py-1 rounded-xl cursor-pointer"
className="flex justify-between items-center border border-gray-300 bg-white px-2 py-1 rounded-xl cursor-pointer focus:border-2 focus:border-blue-500"
onClick={toggleDropdown}
>
<span className="truncate text-gray-800">{selected}</span>
@@ -35,7 +35,7 @@ export default function UrlDropdown() {
{/* Dropdown list */}
{isOpen && (
<div className="absolute mt-1 w-full bg-white border border-gray-200 rounded shadow max-h-60 overflow-y-auto z-10">
<div className="absolute mt-1 w-full bg-white border border-gray-200 rounded shadow max-h-60 overflow-y-auto z-10 ">
{urlOptions.map((url, index) => (
<div
key={index}

136
src/components/test Normal file
عرض الملف

@@ -0,0 +1,136 @@
{CARDS.map((card, idx) => (
<div
key={idx}
className={`bg-white rounded-2xl shadow-lg border transition-all duration-700 ease-in-out transform
hover:shadow-2xl hover:scale-105 cursor-pointer
${card.faded ? "opacity-60" : ""}
${activeCard === card.title ? "cursor-default" : "cursor-pointer"}
${selectedCampaigns.includes(card.title)
? 'shadow-2xl scale-[1.02] '
: 'hover:scale-105 hover:shadow-xl'
} `}
onClick={() => handleCardClick(card.title, card.paused)}
style={{
transform: selectedCampaigns.includes(card.title)
? 'translateY(-5px) scale(1.02)'
: 'translateY(0px) scale(1)'
}}
>
{selectedCampaigns.includes(card.title) && activeCard === card.title ? (
<div className="py-3 flex flex-col ">
{/* Header */}
<div className="flex items-center justify-between border-b border-gray-200 pb-2">
<div className="flex items-center gap-4">
<button
onClick={handleBackClick}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
>
<ArrowLeft className="w-5 h-5 text-gray-600" />
</button>
<h1 className="text-xl font-bold text-gray-900">{card.title}</h1>
</div>
<button
onClick={() => handleMenuClick(card.title)}
className="p-2 hover:bg-gray-100 rounded-lg transition-all duration-300 hover:scale-110"
title="View table"
>
<Menu className="w-5 h-5 text-gray-600" />
</button>
</div>
{/* Content with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-0 translate-y-4 pointer-events-none'
: 'opacity-100 translate-y-0'
}`}
style={{ display: tableView !== card.title ? 'block' : 'none' }}>
<CampaignTracker />
</div>
{/* Table View with smooth transitions */}
<div className={`transition-all duration-700 ease-in-out ${tableView === card.title
? 'opacity-100 translate-y-0'
: 'opacity-0 translate-y-4 pointer-events-none'
}`}
style={{ display: tableView === card.title ? 'block' : 'none' }}
>
<div className="custom-scrollbar-table">
<table className="w-full rounded-lg ">
<tbody>
{[
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS' },
{ icon: '🅿️', title: 'Pinterest DR 97 DA 95 Traffic 3,989,220' },
{ icon: '📄', title: 'Questions to ask your CPA Substack DR 97 DA 95' }
].map((row, rIdx) => (
<tr key={rIdx} className='border-b last:border-0 hover:bg-[#f1f7fe] transition-colors'>
<td className='py-3 pl-2 text-center w-10'>{row.icon}</td>
<td className='py-3 px-1 min-w-[300px] text-[#4285F4] hover:text-[#1e40af] cursor-pointer font-medium' title={row.title}>
<div className='truncate max-w-[300px] text-sm underline'>{row.title}</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800 text-center pt-3" style={{ boxShadow: '#dadada 0px -6px 10px' }}>View All</div>
</div>
</div>
) : (
// Card preview state
<div className="p-5 flex flex-col items-center">
{card.badge && (
<div className="absolute top-4 right-4 bg-green-500 text-white px-3 py-1 rounded-full text-xs font-bold transform rotate-12 shadow-lg">
{card.badge}
</div>
)}
<MultiRingCircularProgress card={card} />
<div className={`mt-4 font-bold text-lg text-center ${card.faded ? "text-gray-400" : "text-gray-900"}`}>
{card.title}
</div>
<div className="mt-3 flex flex-row gap-2 flex-wrap justify-center">
{card.tags.map((tag, i) => (
<span
key={i}
className={`rounded-full border-2 bg-white px-3 py-1 flex items-center text-sm font-medium transition-all duration-300 hover:scale-105 ${card.faded
? "text-gray-400 border-gray-300"
: "text-gray-700 border-gray-200 hover:border-blue-300"
}`}
style={tag.color ? { color: tag.color, borderColor: tag.color } : {}}
>
{tag.text}
{tag.extra && (
<span className={`ml-1 text-xs ${card.faded ? "text-gray-400" : "text-green-600 font-bold"
}`}>
{tag.extra}
</span>
)}
</span>
))}
</div>
{card.actionLink && (
<div className="mt-3 text-blue-600 text-sm cursor-pointer hover:underline transition-all duration-300 hover:text-blue-800">
{card.actionLink}
</div>
)}
{card.paused && (
<div className="mt-3 text-center">
<div className="text-gray-400 text-sm">Campaign paused</div>
<button className="text-blue-600 text-sm hover:underline transition-all duration-300 hover:text-blue-800">Resume</button>
</div>
)}
</div>
)}
</div>
))}

عرض الملف

@@ -6,49 +6,62 @@ import BacklinkTypeDropdown from '../components/Portfolio/BacklinkTypeDropdown';
import RoadmapSidebar from '../components/Strategy/RoadmapSidebar';
import HeaderPage from '../components/shared/HeaderPage';
import ContainerPage from '../components/shared/ContainerPage';
import Amazing from "../assets/icons/amazon.png"
import { CircleCheck } from 'lucide-react';
// import Pinterest from "../assets/icons/pinterest.png"
// import AppleMusic from "../assets/icons/apple-music.png"
// import Substack from "../assets/icons/substack.png"
// import Pin from "../assets/icons/pin.png"
import Progress from "../assets/icons/InProgress.png"
import No from "../assets/icons/no.png"
import Share2 from "../assets/icons/Share2.png"
import MetricCard from '../components/shared/MetricCard';
const done = <div className='flex items-center gap-2 w-[100px]'> <CircleCheck className='w-6 h-6 text-[#fff] bg-green-500 rounded-full' /> <span className='text-green-500 font-bold text-md'>Done</span></div>
// Sidebar data
const sidebarLinks = [
'CPA Los Angeles',
'Richard Bower CPA',
'CPA Los Angeles',
'CPA Hollywood',
'Best CPA Los Angeles',
'CPA Los Angeles',
];
const progress = <div className='flex items-center gap-2 w-[100px]'>
<img src={Progress} alt="" className='w-6 h-6' />
<span className='text-blue-500 font-bold text-md'>In Progress</span></div>
// Category table data
const nA = <div className='flex items-center gap-2'>
<img src={No} alt="" className='w-6 h-6' />
<span className='text-gray-500 font-bold text-md'>N/A</span></div>
const categories = [
{
name: 'Social',
color: 'border-l-4 border-[#4285F4] bg-[#001EE21C]',
rows: [
{ icon: '🅰️', title: 'Questions to ask your CPA httpAmazon', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '🎵', title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'In Progress', interlinked: 'N/A', date: '9/16/25' },
{ icon: '🅿️', title: 'Pinterest DR 97 DA 95 Traffic 3,989,220', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '📄', title: 'Questions to ask your CPA Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'In Progress', interlinked: 'In Progress', date: '9/16/25' }
{
icon: Amazing, title: 'Questions to ask your CPA httpAmazon', DR: 90, DA: 97, traffic: '3,902,293',
indexed: done,
interlinked: done, date: '9/16/25'
},
{ icon: Amazing, title: 'Questions to ask your CPA Published on Amazon', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: progress, interlinked: nA, date: '9/16/25' },
{ icon: Amazing, title: 'Pinterest DR 97 DA 95 Traffic 3,989,220', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Questions to ask your CPA Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: progress, interlinked: progress, date: '9/16/25' }
]
},
{
name: 'Citation',
color: 'border-l-4 border-[#0ea5e9] bg-[#3C87FF2B]',
rows: [
{ icon: '📄', title: 'Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'N/A', date: '9/16/25' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '🅿️', title: 'Paypal DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' }
{ icon: Amazing, title: 'Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: nA, date: '9/16/25' },
{ icon: Amazing, title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Paypal DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: done, date: '9/16/25' }
]
},
{
name: 'Web 2.0',
color: 'border-l-4 border-[#22c55e] bg-[#f0fdf4]',
rows: [
{ icon: '🅿️', title: 'Paypal DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'In Progress', interlinked: 'Done', date: '9/16/25' },
{ icon: '🎵', title: 'Apple Music DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '📄', title: 'Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '🅰️', title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' },
{ icon: '🅿️', title: 'Pin DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: 'Done', interlinked: 'Done', date: '9/16/25' }
{ icon: Amazing, title: 'Paypal DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: progress, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Apple Music DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: nA, date: '9/16/25' },
{ icon: Amazing, title: 'Substack DR 97 DA 95', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Questions to ask your CPA Published on Amazon AWS', DR: 90, DA: 97, traffic: '3,902,293', indexed: progress, interlinked: done, date: '9/16/25' },
{ icon: Amazing, title: 'Pin DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: progress, date: '9/16/25' }
]
}
];
@@ -56,7 +69,7 @@ const categories = [
const pillClass = (val: string) =>
val === 'Done' ? 'bg-green-100 text-green-700 font-bold'
: val === 'In Progress' ? 'bg-blue-100 text-blue-700 whitespace-nowrap font-bold'
: 'bg-gray-100 text-gray-700 font-bold';
: 'bg-gray -100 text-gray-700 font-bold';
function Portfolio() {
const [selectedKeyword, setSelectedKeyword] = useState("CPA Los Angeles")
@@ -66,93 +79,65 @@ function Portfolio() {
<ContainerPage>
<HeaderPage title="Live Library" />
<div className='flex gap-8 mx-auto'>
{/* Sidebar */}
{/* <aside className='w-72 border rounded-2xl shadow-sm bg-white px-5 py-6 h-fit'>
<div className='font-extrabold text-xl mb-5 text-[#4285F4] flex items-center'>
<span className='w-3 h-3 rounded-full bg-[#4285F4] mr-2'></span>
Live Library
</div>
<ul className='space-y-2'>
{sidebarLinks.map((link, idx) => (
<li key={idx} className={`px-3 py-2 text-md flex items-center gap-2 rounded-xl cursor-pointer hover:bg-[#e3edfc] transition-colors ${idx === 0 ? 'bg-[#e3edfc] text-[#4285F4] font-bold' : 'text-gray-700'}`}>
{
idx === 0
?
<img src={Vector} alt={link} className="w-4 h-4" />
:
<img src={Vector2} alt={link} className="w-4 h-4" />
}
{link}
</li>
))}
</ul>
</aside> */}
<RoadmapSidebar mode={"portfolio"} selectedKeyword={selectedKeyword} onKeywordSelect={setSelectedKeyword} />
{/* Table Section */}
<section className='flex-1 bg-white border rounded-2xl shadow-sm px-6 py-4'>
{/* Title Bar */}
<div className='flex items-center justify-between mb-2'>
<div className='flex flex-col items-start gap-3'>
<div className='flex flex-col items-start gap-2'>
<span className='text-2xl font-extrabold text-[#4285F4]'>CPA Los Angeles</span>
<span className='bg-[#f1f5f9] text-gray-700 px-3 py-1 rounded-md text-xs border font-medium'>Links: <b>Indexed 32%</b> Interlinked <b>4%</b></span>
<span className='text-gray-500 rounded-md text-md font-medium'><span className='font-bold pr-3 text-black'>Links:</span>
<span className='flex items-center gap-2 text-gray-800'>Content Publishing:
<span className='bg-[#fee2e2] text-[#dc2626] px-2 py-0 rounded-md text-xs font-bold border'>Locked</span>
Indexed <b className='font-bold bg-[#e2eff7] text-[#004A74] px-2 py-1 rounded-md mx-1 mr-5'>32%</b>
Interlinked <b className='font-bold bg-[#e2eff7] text-[#004A74] px-2 py-1 rounded-md mx-1'>4%</b></span>
<span className='flex items-center gap-2 text-gray-800 text-md'>Content Publishing:
<span className='bg-[#f9eaef] text-[#8B0E3A] px-2 py-0 rounded-md font-bold border'>Locked</span>
</span>
</div>
<div className='flex items-center gap-3'>
<BacklinkTypeDropdown />
<select className='border px-3 py-1 rounded-lg text-xs bg-[#e3edfc] font-bold text-[#4285F4] hover:bg-[#4285F4] hover:text-white transition-colors'>
<option>DA</option>
<option>DR</option>
<option>Traffic</option>
</select>
<select className='border px-3 py-1 rounded-lg text-xs bg-[#e3edfc] font-bold text-[#4285F4] hover:bg-[#4285F4] hover:text-white transition-colors'>
<option>Traffic</option>
<option>DA</option>
<option>DR</option>
</select>
<button className='bg-[#e3edfc] text-[#4285F4] border px-4 py-1 rounded-lg text-xs font-bold hover:bg-[#4285F4] hover:text-white transition-colors'>Export</button>
<BacklinkTypeDropdown options={
{
Social: true, Citation: true, 'Web 2.0': true, Multimedia: false, Crowd: false
}} title="Backlink Type" subTitle="Show rings:" />
<BacklinkTypeDropdown options={{ DA: true, DR: true, Traffic: true }} title="DA" subTitle="Show rings:" />
<BacklinkTypeDropdown options={{ DA: true, DR: true, Traffic: true }} title="DA" subTitle="Show rings:" />
<BacklinkTypeDropdown options={{ DA: true, DR: true, Traffic: true }} title="Traffic" subTitle="Show rings:" />
<button className='bg-[#fff] text-gray-500 border px-4 py-1 rounded-lg text-md font-bold transition-colors flex items-center gap-2'>
<img src={Share2} alt="" />
<span>Export</span>
{/* <MetricCard label="Export" tooltipText="tooltipText" /> */}
</button>
</div>
</div>
{/* Global Filter/Sort Header Row */}
<div className='flex items-center justify-end gap-4 mb-2 px-4 py-3 '>
<div className='flex items-center gap-8 text-sm font-medium text-gray-600'>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
DR <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors '>
DR <SortIcon />
</span>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
DA <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
DA <SortIcon />
</span>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
Traffic <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
Traffic <SortIcon />
</span>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
Indexed <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
Indexed <SortIcon />
</span>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
Interlinked <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
Interlinked <SortIcon />
</span>
<span className='flex items-center cursor-pointer hover:text-[#4285F4] transition-colors'>
Date <svg className='ml-1 w-4 h-4' fill='currentColor' viewBox='0 0 20 20'>
<path fillRule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clipRule='evenodd' />
</svg>
Date <SortIcon />
</span>
</div>
</div>
@@ -163,10 +148,10 @@ function Portfolio() {
<div className={`px-4 py-3 rounded-lg font-bold text-sm ${cat.color} mb-3`}>
<div className='flex items-center gap-3'>
<div className='flex items-center gap-2'>
<span className='text-lg'>{cat.name === 'Social' ? '💬' : cat.name === 'Citation' ? '📊' : '🌐'}</span>
{/* <span className='text-lg'>{cat.name === 'Social' ? '💬' : cat.name === 'Citation' ? '📊' : '🌐'}</span> */}
<span>{cat.name}</span>
</div>
<span className='text-xs font-semibold text-gray-500 bg-white px-2 py-1 rounded-full'>{cat.rows.length}</span>
<span className='text-md font-bold bg-white p-1 px-2 rounded-full'>{cat.rows.length}</span>
</div>
</div>
<div className='bg-white rounded-xl border overflow-hidden shadow-sm'>
@@ -174,20 +159,27 @@ function Portfolio() {
<tbody>
{cat.rows.map((row, rIdx) => (
<tr key={rIdx} className='border-b last:border-0 hover:bg-[#f1f7fe] transition-colors'>
<td className='py-3 px-4 text-center w-12'>{row.icon}</td>
<td className='py-3 px-4 w-full text-[#4285F4] hover:text-[#1e40af] cursor-pointer font-medium' title={row.title}>
<div className='truncate max-w-[350px] whitespace-pre-wrap'>{row.title}</div>
<td className='w-12 px-4 py-3'>
<div className='flex items-center gap-2'>
<img src={row.icon} alt="" className='w-10 h-10 rounded-full' />
<span className='text-xs font-bold w-[40px]'> </span>
</div>
</td>
<td className='py-3 px-4 text-center w-16 font-semibold'>{row.DR}</td>
<td className='py-3 px-4 text-center w-16 font-semibold'>{row.DA}</td>
<td className='py-3 px-4 text-center w-24 font-semibold'>{row.traffic}</td>
<td className='py-3 px-4 text-center w-20'>
<span className={`px-2 py-1 rounded-full text-xs ${pillClass(row.indexed)}`}>{row.indexed}</span>
<td className='w-full text-[#4285F4] hover:text-[#1e40af] font-medium' title={row.title}>
<div className='truncate max-w-[400px] whitespace-pre-wrap underline py-1 cursor-pointer'>{row.title}</div>
</td>
<td className='py-3 px-4 text-center w-24'>
<span className={`px-2 py-1 rounded-full text-xs ${pillClass(row.interlinked)}`}>{row.interlinked}</span>
<td className='py-3 px-4 text-center w-20 font-semibold text-gray-700'>{row.DR}</td>
<td className='py-3 px-4 text-center w-20 font-semibold text-gray-700'>{row.DA}</td>
<td className='py-3 px-4 text-center w-24 font-semibold text-gray-700'>{row.traffic}</td>
<td className='py-3 px-4 text-center '>
<div className={`rounded-full text-xs ${pillClass(row.indexed.toString())}`}>{row.indexed}</div>
{/* whitespace-nowrap */}
</td>
<td className='py-3 px-4 text-center w-20 font-medium text-gray-600'>{row.date}</td>
<td className='py-3 px-2 text-center w-28'>
<span className={`rounded-full text-xs ${pillClass(row.interlinked.toString())}`}>{row.interlinked}</span>
</td>
<td className='py-3 px-4 text-center w-24 font-medium text-gray-700'>{row.date}</td>
</tr>
))}
</tbody>
@@ -202,3 +194,12 @@ function Portfolio() {
}
export default Portfolio;
const SortIcon = () => {
return (
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg" className='ml-2'>
<path d="M10.6944 9.46965C10.6944 9.58746 10.6464 9.70528 10.5744 9.79953L7.52593 13.004C7.38191 13.1689 7.11788 13.1925 6.94985 13.0511C6.92585 13.0276 6.92585 13.0276 6.90184 13.004L3.85342 9.77596C3.78141 9.70528 3.7334 9.58746 3.7334 9.46965C3.7334 9.23403 3.92543 9.02197 4.16546 8.99841H10.2623C10.5024 8.99841 10.6944 9.21047 10.6944 9.46965ZM10.6944 5.89049C10.6944 6.12611 10.5024 6.33817 10.2623 6.36173H4.16546C3.92543 6.36173 3.7334 6.14967 3.7334 5.89049C3.7334 5.77268 3.78141 5.65486 3.85342 5.56062L6.90184 2.35614C7.04587 2.1912 7.3099 2.16764 7.47793 2.30902C7.50193 2.33258 7.50193 2.33258 7.52593 2.35614L10.5744 5.58418C10.6464 5.65486 10.6944 5.77268 10.6944 5.89049Z" fill="#999BAD" />
</svg>
)
}

عرض الملف

@@ -20,7 +20,7 @@ function Strategy() {
return (
<ContainerPage>
<HeaderPage title="Strategy" />
<div className="flex bg-white h-[100%]">
<div className="flex lg:flex-row flex-col items-center lg:items-start bg-white h-[100%]">
{/* <RoadmapSidebar selectedKeyword={selectedKeyword} onKeywordSelect={setSelectedKeyword} /> */}
@@ -31,11 +31,8 @@ function Strategy() {
<div className="bg-white rounded-lg border border-gray-200 p-3 pb-10">
{
selectedKeyword === "CPA Los Angeles" ? <IntegratedStrategy /> : <ShowDetails />
{selectedKeyword === "CPA Los Angeles" ? <IntegratedStrategy /> : <ShowDetails />
}
{/* <IntegratedStrategy /> */}
{/* <ShowDetails /> */}
</div>
</div>

668
src/pages/login.tsx Normal file
عرض الملف

@@ -0,0 +1,668 @@
import { useState } from 'react';
// Removed: import { useRouter } from 'next/navigation'; // Next.js specific
// Removed: import { motion } from 'framer-motion'; // External library not available
export default function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// Replaced useRouter with a simple object for basic navigation
const router = {
push: (path: string) => {
window.location.href = path; // Simulating navigation for a generic React environment
},
};
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
// Removed unused state: const [isHovering, setIsHovering] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError('');
try {
const response = await fetch('https://solidpoint-auth.ghaymah.systems/signin/email-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
const data = await response.json();
if (response.ok) {
// استخراج البيانات المهمة من الاستجابة
const accessToken = data.session?.accessToken;
const refreshToken = data.session?.refreshToken;
const userId = data.session?.user?.id;
// تخزين بيانات المستخدم في localStorage
const userData = {
email,
accessToken,
userId,
isLoggedIn: true,
lastLogin: new Date().toISOString()
};
localStorage.setItem('sp_user', JSON.stringify(userData));
localStorage.setItem('user_id', userId); // تخزين user_id بشكل منفصل للمكونات التي تحتاجه
window.dispatchEvent(new Event('userChanged'));
// تخزين الـ tokens في HttpOnly cookies
try {
const tokenResponse = await fetch('/api/auth/store-tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
access_token: accessToken,
refresh_token: refreshToken,
expires_in: 3600 // مدة صلاحية الـ token بالثواني (ساعة واحدة)
})
});
if (!tokenResponse.ok) {
console.error('Failed to store token in HttpOnly cookie');
} else {
console.log('Token stored successfully in HttpOnly cookie');
}
} catch (error) {
console.error('Error storing token in HttpOnly cookie:', error);
}
// Show success animation before navigating
const successElement = document.createElement('div');
successElement.className = 'fixed inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm z-50';
successElement.innerHTML = `
<div class="text-center p-8 bg-white dark:bg-gray-800 rounded-lg shadow-lg">
<svg class="w-16 h-16 mx-auto text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<h2 class="mt-3 text-xl font-bold text-gray-900 dark:text-white">Welcome back!</h2>
<p class="mt-2 text-gray-600 dark:text-gray-300">You have successfully logged in.</p>
</div>
`;
document.body.appendChild(successElement);
// Add animation with CSS
const checkmark = successElement.querySelector('svg');
if (checkmark) {
checkmark.style.transform = 'scale(0)';
checkmark.style.transition = 'transform 0.5s ease-out';
setTimeout(() => {
checkmark.style.transform = 'scale(1)';
}, 100);
}
// Navigate after animation completes
setTimeout(() => {
// Remove the success element before navigating
document.body.removeChild(successElement);
router.push('/');
}, 1800);
} else {
setError(data?.message || 'Failed to login. Please check your credentials.');
}
} catch (err: any) {
setError('Failed to login. Please try again.');
} finally {
setIsLoading(false);
}
};
const handleSubmitSignUp = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError('');
try {
const response = await fetch('https://solidpoint-auth.ghaymah.systems/signup/email-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }), // Add more fields like name if needed
});
const data = await response.json();
console.log(data);
if (response.ok) {
const accessToken = data.session?.accessToken;
const refreshToken = data.session?.refreshToken;
const userId = data.session?.user?.id;
const userData = {
email,
accessToken,
userId,
isLoggedIn: true,
lastLogin: new Date().toISOString()
};
localStorage.setItem('sp_user', JSON.stringify(userData));
localStorage.setItem('user_id', userId);
window.dispatchEvent(new Event('userChanged'));
// Store tokens in HttpOnly cookies
try {
const tokenResponse = await fetch('/api/auth/store-tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
access_token: accessToken,
refresh_token: refreshToken,
expires_in: 3600
})
});
if (!tokenResponse.ok) {
console.error('Failed to store token in HttpOnly cookie');
} else {
console.log('Token stored successfully in HttpOnly cookie');
}
} catch (error) {
console.error('Error storing token in HttpOnly cookie:', error);
}
// Success animation
const successElement = document.createElement('div');
successElement.className = 'fixed inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm z-50';
successElement.innerHTML = `
<div class="text-center p-8 bg-white dark:bg-gray-800 rounded-lg shadow-lg">
<svg class="w-16 h-16 mx-auto text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<h2 class="mt-3 text-xl font-bold text-gray-900 dark:text-white">Account Created!</h2>
<p class="mt-2 text-gray-600 dark:text-gray-300">You have successfully signed up.</p>
</div>
`;
document.body.appendChild(successElement);
const checkmark = successElement.querySelector('svg');
if (checkmark) {
checkmark.style.transform = 'scale(0)';
checkmark.style.transition = 'transform 0.5s ease-out';
setTimeout(() => {
checkmark.style.transform = 'scale(1)';
}, 100);
}
setTimeout(() => {
document.body.removeChild(successElement);
router.push('/');
}, 1800);
} else {
setError(data?.message || 'Signup failed. Please check your info.');
}
} catch (err: any) {
setError('Signup failed. Please try again.');
} finally {
setIsLoading(false);
}
};
const [swapAuth, setSwapAuth] = useState(false);
const swapAuthFunction = () => {
setSwapAuth(!swapAuth);
setEmail('');
setPassword('');
setError('');
}
const handleSubmitForgotPassword = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError('');
// setMessage('');
try {
const res = await fetch('https://solidpoint-auth.ghaymah.systems/user/password/reset', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
if (res.ok) {
// setMessage('If the email exists, a reset link has been sent.');
console.log('If the email exists, a reset link has been sent.');
} else {
const data = await res.json();
setError(data.message || 'Failed to send reset email.');
}
} catch {
setError('Failed to send reset email. Try again later.');
} finally {
setIsLoading(false);
}
};
const [forgotPassword, setForgotPassword] = useState(false);
if (forgotPassword) {
return (
<div className="min-h-screen w-full bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 dark:from-gray-800 dark:via-indigo-900 dark:to-purple-900 font-inter relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 opacity-20 dark:opacity-10">
<div className="absolute top-10 left-10 w-72 h-72 bg-blue-400 dark:bg-blue-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
<div className="absolute top-0 right-10 w-72 h-72 bg-purple-400 dark:bg-purple-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-indigo-400 dark:bg-indigo-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-[40%_60%] min-h-screen gap-0 md:gap-4 relative z-10">
<div className="flex flex-col justify-center px-8 sm:px-12 py-12 bg-white/80 dark:bg-gray-800/90 backdrop-blur-md shadow-lg rounded-xl border border-white/20 dark:border-gray-700/30 transition-all duration-200">
{/* Logo */}
<div className="flex items-center justify-center mb-6">
<div className="relative flex items-center justify-center h-12 w-12">
<div className="absolute w-11 h-11 rounded-full border-[1.5px] border-blue-500/40"></div>
<div className="absolute w-10 h-10 rounded-full border-2 border-blue-600/70"></div>
<div className="absolute w-10 h-10 rounded-full bg-gradient-to-r from-blue-500/20 to-indigo-600/20 blur-md"></div>
<div className="absolute w-9 h-9 rounded-full bg-gradient-to-tr from-blue-500/30 to-indigo-600/5 blur-[6px]"></div>
<div className="absolute w-8 h-8 rounded-full border-[1px] border-blue-600/60 shadow-[0_0_12px_rgba(59,130,246,0.4)] shadow-[0_0_18px_rgba(79,70,229,0.5)]"></div>
</div>
<span className="ml-3 text-2xl font-bold bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent">SolidPoint</span>
</div>
<h1 className="text-3xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent text-center">
Welcome Back!
</h1>
<p className="text-sm mb-6 text-gray-600 dark:text-gray-300 text-center">
Please enter your credentials to access your account.
</p>
{error && (
<div
className="p-3 mb-4 text-red-700 bg-red-100 dark:bg-red-900/30 dark:text-red-300 rounded-lg border border-red-200 dark:border-red-800 flex items-center space-x-2 text-sm"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>{error}</span>
</div>
)}
<form onSubmit={handleSubmitForgotPassword} className="space-y-4 mt-4">
{/* <form onSubmit={swapAuth ? handleSubmitSignUp : forgotPassword ? handleSubmitForgotPassword : handleSubmit} className="space-y-4 mt-4"> */}
<div className="relative">
<label htmlFor="email" className="block text-sm font-medium mb-1">Email Address</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<input
id="email"
name="email"
type="email"
required
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
placeholder="your.email@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full py-3 px-4 bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-medium rounded-lg shadow-md transition-all duration-200 disabled:opacity-70 text-sm flex items-center justify-center space-x-2"
>
{isLoading ? (
<>
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>
{
swapAuth ?
"Signing up..."
:
"Logging in..."
}
</span>
</>
) : (
<>
<span>Get Password</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</>
)}
</button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm text-gray-500 dark:text-gray-400 rounded-md">
remember your password?
</span>
</div>
</div>
<div
className="w-full flex items-center justify-center py-2.5 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-800/70 backdrop-blur-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200"
onClick={() => setForgotPassword(false)}
>
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
Back to Login
</span>
</div>
</form>
</div>
<RightSide />
</div>
</div>
)
}
return (
// Replaced motion.div with standard div and adopted SignUp's overall layout
<div className="min-h-screen w-full bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 dark:from-gray-800 dark:via-indigo-900 dark:to-purple-900 font-inter relative overflow-hidden">
{/* Background decorative elements - optimized for performance */}
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 opacity-20 dark:opacity-10">
<div className="absolute top-10 left-10 w-72 h-72 bg-blue-400 dark:bg-blue-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
<div className="absolute top-0 right-10 w-72 h-72 bg-purple-400 dark:bg-purple-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-indigo-400 dark:bg-indigo-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
</div>
{/* Page split with 35%/65% ratio and responsiveness */}
<div className="grid grid-cols-1 lg:grid-cols-[40%_60%] min-h-screen gap-0 md:gap-4 relative z-10">
{/* Left side - Login Form (aligned with SignUp's form side) */}
<div className="flex flex-col justify-center px-8 sm:px-12 py-12 bg-white/80 dark:bg-gray-800/90 backdrop-blur-md shadow-lg rounded-xl border border-white/20 dark:border-gray-700/30 transition-all duration-200">
{/* Logo */}
<div className="flex items-center justify-center mb-6">
<div className="relative flex items-center justify-center h-12 w-12">
<div className="absolute w-11 h-11 rounded-full border-[1.5px] border-blue-500/40"></div>
<div className="absolute w-10 h-10 rounded-full border-2 border-blue-600/70"></div>
<div className="absolute w-10 h-10 rounded-full bg-gradient-to-r from-blue-500/20 to-indigo-600/20 blur-md"></div>
<div className="absolute w-9 h-9 rounded-full bg-gradient-to-tr from-blue-500/30 to-indigo-600/5 blur-[6px]"></div>
<div className="absolute w-8 h-8 rounded-full border-[1px] border-blue-600/60 shadow-[0_0_12px_rgba(59,130,246,0.4)] shadow-[0_0_18px_rgba(79,70,229,0.5)]"></div>
</div>
<span className="ml-3 text-2xl font-bold bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent">SolidPoint</span>
</div>
<h1 className="text-3xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent text-center">
Welcome Back!
</h1>
<p className="text-sm mb-6 text-gray-600 dark:text-gray-300 text-center">
Please enter your credentials to access your account.
</p>
{error && (
<div
className="p-3 mb-4 text-red-700 bg-red-100 dark:bg-red-900/30 dark:text-red-300 rounded-lg border border-red-200 dark:border-red-800 flex items-center space-x-2 text-sm"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>{error}</span>
</div>
)}
<form onSubmit={swapAuth ? handleSubmitSignUp : handleSubmit} className="space-y-4 mt-4">
<div className="relative">
<label htmlFor="email" className="block text-sm font-medium mb-1">Email Address</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<input
id="email"
name="email"
type="email"
required
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
placeholder="your.email@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
</div>
<div className="relative">
<label htmlFor="password" className="block text-sm font-medium mb-1">Password</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<input
id="password"
name="password"
type="password"
required
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="button"
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400"
onClick={() => {
const input = document.getElementById('password') as HTMLInputElement;
input.type = input.type === 'password' ? 'text' : 'password';
}}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
</button>
</div>
</div>
{
!forgotPassword && (
<div style={{ margin: '10px auto 5px', color: 'blue', cursor: 'pointer', width: '100%', textAlign: 'center' }} onClick={() => setForgotPassword(!forgotPassword)}>
Forgot password?
</div>
)
}
<button
type="submit"
disabled={isLoading}
className="w-full py-3 px-4 bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-medium rounded-lg shadow-md transition-all duration-200 disabled:opacity-70 text-sm flex items-center justify-center space-x-2"
>
{isLoading ? (
<>
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>
{
swapAuth ?
"Signing up..."
:
"Logging in..."
}
</span>
</>
) : (
<>
<span>{swapAuth ? "Sign Up" : "Login"}</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</>
)}
</button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm text-gray-500 dark:text-gray-400 rounded-md">
{
swapAuth ? "Already have an account" : "Don't have an account"
}
</span>
</div>
</div>
<button
type="button"
className="w-full flex items-center justify-center py-2.5 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-800/70 backdrop-blur-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200"
onClick={swapAuthFunction}
>
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
{
swapAuth ?
"Login"
:
"Create an account"
}
</span>
</button>
</form>
</div>
<RightSide />
</div>
</div>
);
}
const RightSide = () => {
return (
<div className="flex flex-col justify-center px-6 sm:px-12 py-8 text-gray-900 dark:text-white bg-white/10 dark:bg-gray-800/20 backdrop-blur-md rounded-xl border border-white/20 dark:border-gray-700/30 shadow-lg transition-all duration-200">
<h2 className="text-2xl font-bold mb-6 bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent text-center">Why Choose SolidPoint?</h2>
{/* Platform Purpose */}
<div className="mb-4 bg-white/20 dark:bg-white/5 p-4 rounded-xl border border-indigo-500/40 dark:border-indigo-500/20 shadow-md hover:shadow-md transition-all duration-200 hover:border-indigo-500/60 dark:hover:border-indigo-500/40 hover:bg-indigo-500/10">
<h3 className="text-lg font-bold mb-2 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent flex items-center">
<div className="shrink-0 bg-gradient-to-br from-blue-500 to-indigo-600 p-1.5 rounded-lg shadow-md mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
</div>
Platform Purpose
</h3>
<ul className="space-y-1 text-gray-800 dark:text-gray-300 ml-4 font-medium">
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
SolidPoint is an AI-powered content summarization platform
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
Helps users save time by extracting key insights from various content types
</li>
</ul>
</div>
{/* Key Features */}
<div className="mb-4 bg-white/20 dark:bg-white/5 p-4 rounded-xl border border-purple-500/40 dark:border-purple-500/20 shadow-md hover:shadow-md transition-all duration-200 hover:border-purple-500/60 dark:hover:border-purple-500/40 hover:bg-purple-500/10">
<h3 className="text-lg font-bold mb-2 bg-gradient-to-r from-purple-400 to-indigo-500 bg-clip-text text-transparent flex items-center">
<div className="shrink-0 bg-gradient-to-br from-purple-500 to-indigo-600 p-1.5 rounded-lg shadow-md mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg>
</div>
Key Features Highlighted
</h3>
<ul className="space-y-1 text-gray-800 dark:text-gray-300 ml-4">
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
<span className="font-medium text-blue-700 dark:text-blue-300">Security:</span>
<span className="ml-1 text-gray-800 dark:text-gray-300">Data protection and privacy</span>
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-purple-600 dark:text-purple-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
<span className="font-medium text-purple-700 dark:text-purple-300">Summarization:</span>
<span className="ml-1 text-gray-800 dark:text-gray-300">AI-powered content condensation</span>
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-pink-600 dark:text-pink-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
<span className="font-medium text-pink-700 dark:text-pink-300">Performance:</span>
<span className="ml-1 text-gray-800 dark:text-gray-300">Fast and reliable service</span>
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mr-2 text-green-600 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
<span className="font-medium text-green-700 dark:text-green-300">Pricing:</span>
<span className="ml-1 text-gray-800 dark:text-gray-300">Cost-effective plans for different needs</span>
</li>
</ul>
</div>
{/* Target Use Cases */}
<div className="bg-white/10 p-3 rounded-xl border border-teal-500/30 shadow-md hover:shadow-md transition-all duration-200 hover:border-teal-500/40 hover:bg-teal-500/10">
<h3 className="text-lg font-bold mb-1 bg-gradient-to-r from-teal-400 to-blue-500 bg-clip-text text-transparent flex items-center">
<div className="shrink-0 bg-gradient-to-br from-teal-500 to-blue-600 p-1 rounded-lg shadow-md mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
</div>
Target Use Cases
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-1 ml-1 transition-all duration-200">
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
<div className="shrink-0 bg-red-500/30 p-1.5 rounded-full mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-red-600 dark:text-red-500" viewBox="0 0 24 24" fill="currentColor">
<path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z" />
</svg>
</div>
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">YouTube video summarization</span>
</div>
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
<div className="shrink-0 bg-orange-500/30 p-1.5 rounded-full mr-2">
<img src="/reddit_logo.jpeg" className="h-4 w-4 rounded-full" alt="Reddit logo" />
</div>
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">Reddit post summarization</span>
</div>
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
<div className="shrink-0 bg-blue-500/30 p-1.5 rounded-full mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-blue-600 dark:text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
</svg>
</div>
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">arXiv paper summarization</span>
</div>
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
<div className="shrink-0 bg-green-500/30 p-1.5 rounded-full mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-green-600 dark:text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
</div>
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">Website content summarization</span>
</div>
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm md:col-span-2">
<div className="shrink-0 bg-purple-500/30 p-1.5 rounded-full mr-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-purple-600 dark:text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
</div>
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">PDF to flashcard conversion</span>
</div>
</div>
</div>
</div>
)
}