هذا الالتزام موجود في:
Your Name
2025-10-10 15:53:32 +00:00
الأصل 9230fd8e4e 7810e18241
التزام b9c53be445
7 ملفات معدلة مع 309 إضافات و99 حذوفات

عرض الملف

@@ -9,34 +9,52 @@
padding-left: 1rem;
padding-right: 1rem;
box-sizing: border-box;
}
}
@media (max-width: 1299px) {
@media (max-width: 1299px) {
.container {
max-width: 100%;
}
}
}
@media (min-width: 1300px) {
@media (min-width: 1300px) {
.container {
max-width: 1300px;
}
}
}
@media (min-width: 1600px) {
@media (min-width: 1500px) {
.container {
max-width: 1500px;
}
}
@media (min-width: 1600px) {
.container {
max-width: 1600px;
}
}
}
.recharts-surface {
.recharts-surface {
cursor: pointer !important;
outline: none !important;
border: none !important;
box-shadow: none !important;
focus:outline-none !important;
focus:ring-0 !important;
focus:border-none !important;
focus: outline-none !important;
focus: ring-0 !important;
focus: border-none !important;
}
@media (min-width: 1024px) and (max-width: 1250px) {
.pr-m-5 {
padding-right: 5px;
}
}
@media (min-width: 1024px) and (max-width: 1296px) {
.w-m-40 {
width: 40% !important;
}
}

عرض الملف

@@ -95,14 +95,14 @@ const CampaignTracker = ({ handleMenuClick }: { handleMenuClick: () => void }) =
</div>
{/* Progress Sections */}
<div className="space-y-6">
<div className="space-y-8">
{progressSections.map((section, index) => {
const progressPercentage = (section.current / section.total) * 100
return (
<div key={index} className="space-y-1">
{/* Section Title and Progress */}
<div className="flex items-center justify-between">
<div className="flex items-center justify-between mb-2">
<h3 className="text-sm font-semibold text-gray-900">
{section.title}: {section.current}/{section.total}
</h3>

عرض الملف

@@ -9,13 +9,16 @@ import {
Info,
ArrowUp,
Link,
ChevronDown
ChevronDown,
MapPin,
Sparkles
} from "lucide-react";
import MetricCard from "./shared/MetricCard";
import UrlDropdown from "./shared/UrlDropdown";
import HeaderPage from "./shared/HeaderPage";
import Google from "../assets/icons/google-original-logo.svg";
import Gemini from "../assets/icons/gemini.svg";
import Gemini2 from "../assets/icons/gemini2.svg";
import Perplexity from "../assets/icons/perplexity-dark-logo.svg";
import Vector from "../assets/icons/Vector.png";
import Vector2 from "../assets/icons/Vector2.png";
@@ -236,6 +239,103 @@ const CARDS = [
}
];
const competitors = [
{
domain: "Cherrybekaertla.com",
googleRank: 1,
mapPins: 7,
hasAi: true,
hasCircle: true,
hasDiamond: true,
hasTree: true,
hasLLM: true,
tags: [
{
content: [
{ icon: "Google", value: "1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "7", }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
]
},
{
domain: "Gerbercompany.com",
googleRank: 1,
mapPins: 7,
hasAi: true,
hasCircle: true,
hasDiamond: true,
hasTree: true,
hasLLM: true,
tags: [
{
content: [
{ icon: "Google", value: "1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "7", }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
]
},
{
domain: "Mysite.com",
googleRank: 1,
mapPins: 7,
hasAi: true,
hasCircle: true,
hasDiamond: true,
hasTree: true,
hasLLM: true,
tags: [
{
content: [
{ icon: "Google", value: "1" }
],
color: "#4285F4"
},
{
content: [
{ icon: "Map", value: "7", }
],
color: "#4285F4"
},
{
content: [
{ icon: "Ai" },
{ icon: "Perplexity" },
{ icon: "GPT" }
]
}
]
},
]
const pillClass = (val: string) =>
val === 'Done' ? 'bg-green-100 text-green-700 font-bold'
: val === 'In Progress' ? 'bg-blue-100 text-blue-700 font-bold'
@@ -247,6 +347,7 @@ export default function DashboardGrid() {
const [activeCard, setActiveCard] = useState<string | null>(null);
const [hoverState, setHoverState] = useState<HoverState>({ cardId: null, ringIndex: null });
const [isHovered, setIsHovered] = useState(false);
const [showKeywordAnalysis, setShowKeywordAnalysis] = useState<string | null>(null);
const handleCardClick = (campaignName: string, paused: boolean) => {
if (paused) return;
@@ -275,6 +376,14 @@ export default function DashboardGrid() {
setHoverState({ cardId, ringIndex });
};
const handleResumeClick = (campaignName: string) => {
setShowKeywordAnalysis(campaignName);
};
const handleCloseKeywordAnalysis = () => {
setShowKeywordAnalysis(null);
};
const TagComponent = ({ content, color = "#4285F4", faded = false }: Tag & { faded?: boolean }) => {
const getIconContent = (item: TagContent) => {
switch (item.icon) {
@@ -282,7 +391,7 @@ export default function DashboardGrid() {
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.value && <span className="text-[#17171B] font-semibold 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}
@@ -293,7 +402,7 @@ export default function DashboardGrid() {
case "Map":
return (
<>
<img src={Map} alt="Map" className="w-5 h-5" />
<img src={Map} alt="Map" className="w-5 h-6" />
{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`}>
@@ -303,11 +412,41 @@ export default function DashboardGrid() {
</>
);
case "Ai":
return <img src={Gemini} alt="AI" className="w-5 h-5" />;
return (
<>
<img src={Gemini2} alt="AI" 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 "GPT":
return <img src={GPT} alt="GPT" className="w-5 h-5" />;
return (
<>
<img src={GPT} alt="GPT" 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 "Perplexity":
return <img src={Perplexity} alt="Perplexity" className="w-5 h-5" />;
return (
<>
<img src={Perplexity} alt="Perplexity" 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>
)}
</>
)
default:
return item.text || null;
}
@@ -401,14 +540,60 @@ export default function DashboardGrid() {
<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'
<div className={`absolute w-full h-full [backface-visibility:hidden] bg-white rounded-2xl border transition-all duration-300 ease-in-out cursor-pointer ${card.faded ? "opacity- 60" : ""}
${selectedCampaigns.includes(card.title) ? 'shadow-md scale-[1.02]' : 'hover:scale-135 hover:shadow-md'
}`}
style={{
transform: selectedCampaigns.includes(card.title)
? 'translateY(-5px) scale(1.02)'
: 'translateY(0px) scale(1)'
}}>
{
card.paused && showKeywordAnalysis === card.title
?
<div className="bg-[#f6f8fe] rounded-xl shadow-sm border border-gray-200 p-6 px-20 h-full">
{/* New Keyword Badge */}
<div className="flex justify-center mb-4">
<div className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium text-[#197232]" style={{ background: "linear-gradient(90deg, #d6fbe2 30%, #edf9d5 100%)" }}>
<Sparkles className="w-4 h-4" />
NEW High-Value Keyword Found
</div>
</div>
{/* Keyword Title */}
<h2 className="text-2xl font-bold text-gray-900 text-center mb-6">Tax Prep Attorney Los Angeles</h2>
{/* Competitors List */}
<div className="space-y-4 mb-6">
{competitors.map((competitor, index) => (
<div key={index} className="space-y-2">
<div className="text-md text-gray-600 font-bold">{competitor.domain}</div>
<div className="flex items-center gap-3 flex-wrap">
{competitor.tags.map((tag, i) => (
<TagComponent
key={i}
{...tag}
faded={card.faded}
/>
))}
</div>
</div>
))}
</div>
{/* Bottom CTA */}
<div className="text-center">
<p className="text-md text-gray-500 ">Your competitors own this keyword.</p>
<p className="text-md font-semibold text-[#2B2D3B] mb-3">Add it to capture visibility and sales.</p>
<button className="inline-flex items-center gap-2 px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition-colors">
<span className="text-lg">+</span>
Add Keyword
</button>
</div>
</div>
:
<div className="p-5 flex flex-col items-center h-full">
{card.badge && (
<div className="absolute top-0 right-0 overflow-hidden w-32 h-32 pointer-events-none">
@@ -447,13 +632,27 @@ export default function DashboardGrid() {
{card.actionLink}
</div>
)}
{card.paused && (
<div className="mt-1 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>
<button
onClick={(e) => {
e.stopPropagation();
handleResumeClick(card.title);
}}
className="text-blue-600 text-sm hover:underline transition-all duration-300 hover:text-blue-800"
>
Resume
</button>
</div>
)}
)
}
</div>
}
</div>
{/* Back of card */}
@@ -536,6 +735,7 @@ export default function DashboardGrid() {
</div>
))}
</div>
</>
);
}

عرض الملف

@@ -64,6 +64,7 @@ export default function MultiRingCircularProgress({ card, hoveredIndex, onHover,
onMouseEnter={() => onHover(index)}
onMouseLeave={() => onHover(null)}
fill={getHoverColor(ring, index)}
className="focus:outline-none focus:ring-0 focus:border-none"
// pointerEvents={'none'}
>
<Cell

عرض الملف

@@ -28,13 +28,14 @@ const BacklinkTypeDropdown = ({ options, title, subTitle }: { options: Record<st
return (
<div className='relative' ref={dropdownRef}>
<button
className='border rounded-lg px-3 py-1 bg-white text-gray-500 font-medium flex items-center text-md'
className={`border rounded-lg px-3 py-1 bg-white text-gray-500 font-medium flex items-center text-md ${dropdownOpen ? "border-2 border-solid border-blue-500" : ""}`}
onClick={() => setDropdownOpen(v => !v)}
>
{title} <ChevronDown className='ml-2' />
{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-[150px]'>
<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

عرض الملف

@@ -35,7 +35,7 @@ function ProgressMetrics() {
<div className="w-[100%]">
<div className="flex items-center justify-between">
<div className="text-lg 3xl:text-4xl font-bold text-gray-900 mb-1">60%</div>
<div className="text-lg 3xl:text-3xl font-bold text-gray-900 mb-1">120/250 <span className="text-gray-500">links</span></div>
<div className="text-md 3xl:text-3xl font-bold text-gray-900 mb-1">120/250 <span className="text-gray-500">links</span></div>
</div>
<div className="text-xs 2xl:text-sm text-gray-500 mb-2">until content publishing + LLM seeding unlocked</div>
{/* Progress bar */}
@@ -49,7 +49,7 @@ function ProgressMetrics() {
</div>
<div className="flex items-center md:w-1/3 w-full md:border-r-2 border-0 border-solid border-gray-300 2xl:gap-12 lg:gap-6 gap-3">
<div className="flex items-center md:w-1/3 w-full md:border-r-2 border-0 border-solid border-gray-300 2xl:gap-12 lg:gap-3 gap-3 pr-m-5 w-m-40">
{/* 75% Keyword Visibility */}
<div className="w-[30%]">
<div className="text-xl 2xl:text-3xl font-bold text-gray-900 mb-1">75%</div>
@@ -57,16 +57,12 @@ function ProgressMetrics() {
</div>
<div className="flex items-center gap-3 w-[100%]">
<div className="flex items-center gap-3 flex-wrap">
<div className="flex items-center gap-3 ">
<MetricCard
img={Google} tooltipText="Google" valueChange="+1" size="sm" disabled />
<MetricCard
img={Map} tooltipText="Map" valueChange="+1" size="sm" disabled value="Map" />
{/* <MetricCard
img={Gemini} tooltipText="ChatGPT" valueChange="+1" size="sm" extraStyle="border-2 border-solid border-gray-300 rounded-lg " /> */}
<MetricCard
img={ChatGPT} tooltipText="ChatGPT" valueChange="+1" size="sm" />

عرض الملف

@@ -1,17 +1,11 @@
import React, { useState } from 'react';
import Vector from "../assets/icons/Vector.png"
import Vector2 from "../assets/icons/Vector2.png"
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 Amazing from "../assets/icons/amazon.svg"
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.svg"
import No from "../assets/icons/NA.svg"
import Share2 from "../assets/icons/Share2.png"
@@ -108,7 +102,7 @@ function Portfolio() {
<BacklinkTypeDropdown options={{ DA: true, DR: true, Traffic: true }} title="Traffic" subTitle="Show rings:" />
<button className='bg-[#fff] text-gray-500 border px-3 sm:px-4 py-1 rounded-lg text-sm sm:text-md font-bold transition-colors flex items-center gap-2'>
<button className='bg-[#fff] text-gray-500 border px-3 sm:px-4 py-2 rounded-lg text-sm sm:text-md font-bold transition-colors flex items-center gap-2'>
<img src={Share2} alt="" className='w-4 h-4' />
<span>Export</span>
</button>