Merge branch 'main' of https://app.gitpasha.com/mohammedsaid18/dashboard
هذا الالتزام موجود في:
@@ -79,7 +79,7 @@ const CampaignTracker = ({ handleMenuClick }: { handleMenuClick: () => void }) =
|
|||||||
|
|
||||||
|
|
||||||
{/* Status Cards */}
|
{/* Status Cards */}
|
||||||
<div className="grid grid-cols-3 gap-4 mb-8">
|
<div className="grid grid-cols-3 gap-4 mb-4">
|
||||||
<div className="px-2 rounded-lg p-1 border">
|
<div className="px-2 rounded-lg p-1 border">
|
||||||
<div className=" text-gray-700 mb-1 ">Indexed:</div>
|
<div className=" text-gray-700 mb-1 ">Indexed:</div>
|
||||||
<div className="text-sm font-bold text-gray-900">77%</div>
|
<div className="text-sm font-bold text-gray-900">77%</div>
|
||||||
@@ -95,14 +95,14 @@ const CampaignTracker = ({ handleMenuClick }: { handleMenuClick: () => void }) =
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Progress Sections */}
|
{/* Progress Sections */}
|
||||||
<div className="space-y-8">
|
<div className="space-y-7">
|
||||||
{progressSections.map((section, index) => {
|
{progressSections.map((section, index) => {
|
||||||
const progressPercentage = (section.current / section.total) * 100
|
const progressPercentage = (section.current / section.total) * 100
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index} className="space-y-1">
|
<div key={index} className="space-y-1">
|
||||||
{/* Section Title and Progress */}
|
{/* Section Title and Progress */}
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-1">
|
||||||
<h3 className="text-sm font-semibold text-gray-900">
|
<h3 className="text-sm font-semibold text-gray-900">
|
||||||
{section.title}: {section.current}/{section.total}
|
{section.title}: {section.current}/{section.total}
|
||||||
</h3>
|
</h3>
|
||||||
|
|||||||
@@ -4,24 +4,13 @@ import React, { useState } from "react";
|
|||||||
import MultiRingCircularProgress from "./MultiRingCircularProgress";
|
import MultiRingCircularProgress from "./MultiRingCircularProgress";
|
||||||
import CampaignTracker from "./CampaignTracker";
|
import CampaignTracker from "./CampaignTracker";
|
||||||
import {
|
import {
|
||||||
ArrowLeft, Menu, FileText,
|
ArrowLeft,
|
||||||
TrendingUp,
|
|
||||||
Info,
|
|
||||||
ArrowUp,
|
|
||||||
Link,
|
|
||||||
ChevronDown,
|
|
||||||
MapPin,
|
|
||||||
Sparkles
|
Sparkles
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import MetricCard from "./shared/MetricCard";
|
|
||||||
import UrlDropdown from "./shared/UrlDropdown";
|
|
||||||
import HeaderPage from "./shared/HeaderPage";
|
import HeaderPage from "./shared/HeaderPage";
|
||||||
import Google from "../assets/icons/google-original-logo.svg";
|
import Google from "../assets/icons/google-original-logo.svg";
|
||||||
import Gemini from "../assets/icons/gemini.svg";
|
|
||||||
import Gemini2 from "../assets/icons/gemini2.svg";
|
import Gemini2 from "../assets/icons/gemini2.svg";
|
||||||
import Perplexity from "../assets/icons/perplexity-dark-logo.svg";
|
import Perplexity from "../assets/icons/perplexity-dark-logo.svg";
|
||||||
import Vector from "../assets/icons/Vector.png";
|
|
||||||
import Vector2 from "../assets/icons/Vector2.png";
|
|
||||||
import GPT from "../assets/icons/gpt.svg";
|
import GPT from "../assets/icons/gpt.svg";
|
||||||
import Map from "../assets/icons/maps.svg";
|
import Map from "../assets/icons/maps.svg";
|
||||||
|
|
||||||
@@ -336,10 +325,6 @@ const competitors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
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'
|
|
||||||
: 'bg-gray-100 text-gray-700 font-bold';
|
|
||||||
|
|
||||||
export default function DashboardGrid() {
|
export default function DashboardGrid() {
|
||||||
const [selectedCampaigns, setSelectedCampaigns] = useState<string[]>([]);
|
const [selectedCampaigns, setSelectedCampaigns] = useState<string[]>([]);
|
||||||
@@ -380,9 +365,6 @@ export default function DashboardGrid() {
|
|||||||
setShowKeywordAnalysis(campaignName);
|
setShowKeywordAnalysis(campaignName);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseKeywordAnalysis = () => {
|
|
||||||
setShowKeywordAnalysis(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TagComponent = ({ content, color = "#4285F4", faded = false }: Tag & { faded?: boolean }) => {
|
const TagComponent = ({ content, color = "#4285F4", faded = false }: Tag & { faded?: boolean }) => {
|
||||||
const getIconContent = (item: TagContent) => {
|
const getIconContent = (item: TagContent) => {
|
||||||
@@ -473,16 +455,7 @@ export default function DashboardGrid() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 border-r-2 border-gray-200 pr-4 last:border-r-0 w-full lg:w-[32%] py-2 lg:py-0"
|
<div className="flex items-center gap-2 border-r-2 border-gray-200 pr-4 last:border-r-0 w-full lg:w-[32%] py-2 lg:py-0"
|
||||||
onMouseEnter={() => {
|
>
|
||||||
if (tooltipText) {
|
|
||||||
setIsHovered(true)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
if (tooltipText) {
|
|
||||||
setIsHovered(false)
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<img src={icon} alt="Active Keywords" className="w-12 h-12 sm:w-14 sm:h-14" />
|
<img src={icon} alt="Active Keywords" className="w-12 h-12 sm:w-14 sm:h-14" />
|
||||||
|
|
||||||
<div className="flex flex-col px-2 sm:px-4">
|
<div className="flex flex-col px-2 sm:px-4">
|
||||||
@@ -490,7 +463,19 @@ export default function DashboardGrid() {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xl sm:text-2xl font-bold">{value}</span>
|
<span className="text-xl sm:text-2xl font-bold">{value}</span>
|
||||||
|
|
||||||
{tooltipText && <div className="relative">
|
{tooltipText && <div className="relative w-[10%]"
|
||||||
|
|
||||||
|
onMouseEnter={() => {
|
||||||
|
if (tooltipText) {
|
||||||
|
setIsHovered(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
if (tooltipText) {
|
||||||
|
setIsHovered(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* <Info size={16} className="text-gray-800 cursor-pointer" /> */}
|
{/* <Info size={16} className="text-gray-800 cursor-pointer" /> */}
|
||||||
|
|
||||||
<img src={InfoBadge} alt="Info" className="w-4 h-4 text-gray-800 cursor-pointer" />
|
<img src={InfoBadge} alt="Info" className="w-4 h-4 text-gray-800 cursor-pointer" />
|
||||||
@@ -534,13 +519,13 @@ export default function DashboardGrid() {
|
|||||||
{CARDS.map((card, idx) => (
|
{CARDS.map((card, idx) => (
|
||||||
<div
|
<div
|
||||||
key={idx}
|
key={idx}
|
||||||
className="[perspective:1000px] h-[560px]"
|
className="[perspective:1000px] h-[480px]"
|
||||||
onClick={() => handleCardClick(card.title, card.paused || false)}
|
onClick={() => handleCardClick(card.title, card.paused || false)}
|
||||||
>
|
>
|
||||||
<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)]' : ''
|
<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 */}
|
{/* Front of card */}
|
||||||
<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" : ""}
|
<div className={`absolute w-full h-full [backface-visibility:hidden] bg-white rounded-xl 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'
|
${selectedCampaigns.includes(card.title) ? 'shadow-md scale-[1.02]' : 'hover:scale-135 hover:shadow-md'
|
||||||
}`}
|
}`}
|
||||||
style={{
|
style={{
|
||||||
@@ -554,7 +539,7 @@ export default function DashboardGrid() {
|
|||||||
<div className="bg-[#f6f8fe] rounded-xl shadow-sm border border-gray-200 p-6 px-20 h-full">
|
<div className="bg-[#f6f8fe] rounded-xl shadow-sm border border-gray-200 p-6 px-20 h-full">
|
||||||
{/* New Keyword Badge */}
|
{/* New Keyword Badge */}
|
||||||
|
|
||||||
<div className="flex justify-center mb-4">
|
<div className="flex justify-center mb-2">
|
||||||
<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%)" }}>
|
<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" />
|
<Sparkles className="w-4 h-4" />
|
||||||
NEW High-Value Keyword Found
|
NEW High-Value Keyword Found
|
||||||
@@ -562,12 +547,12 @@ export default function DashboardGrid() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Keyword Title */}
|
{/* Keyword Title */}
|
||||||
<h2 className="text-2xl font-bold text-gray-900 text-center mb-6">Tax Prep Attorney Los Angeles</h2>
|
<h2 className="text-2xl font-bold text-gray-900 text-center mb-4">Tax Prep Attorney Los Angeles</h2>
|
||||||
|
|
||||||
{/* Competitors List */}
|
{/* Competitors List */}
|
||||||
<div className="space-y-4 mb-6">
|
<div className="space-y-3 mb-4">
|
||||||
{competitors.map((competitor, index) => (
|
{competitors.map((competitor, index) => (
|
||||||
<div key={index} className="space-y-2">
|
<div key={index} className="space-y-0">
|
||||||
<div className="text-md text-gray-600 font-bold">{competitor.domain}</div>
|
<div className="text-md text-gray-600 font-bold">{competitor.domain}</div>
|
||||||
<div className="flex items-center gap-3 flex-wrap">
|
<div className="flex items-center gap-3 flex-wrap">
|
||||||
{competitor.tags.map((tag, i) => (
|
{competitor.tags.map((tag, i) => (
|
||||||
@@ -594,25 +579,45 @@ export default function DashboardGrid() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="p-5 flex flex-col items-center h-full">
|
<div className={`p-5 pt-8 flex flex-col items-center h-full `}>
|
||||||
{card.badge && (
|
{card.badge && (
|
||||||
<div className="absolute top-0 right-0 overflow-hidden w-32 h-32 pointer-events-none">
|
<div className="absolute top-0 right-0 overflow-hidden w-40 h-40 pointer-events-none">
|
||||||
<div className="absolute top-6 right-[-100px] w-[320px] bg-[#0CAA75] text-white font-semibold py-4 flex items-center justify-center gap-3 rotate-45 shadow-lg">
|
<div className="absolute top-8 -right-10 w-48 bg-[#0CAA75] text-white font-bold py-2 text-center shadow-lg transform rotate-45">
|
||||||
<div className="flex items-center justify-center gap-1 text-xs font-bold whitespace-nowrap">
|
<div className="flex items-center justify-center gap-2 text-xs whitespace-nowrap px-8">
|
||||||
<svg width="14" height="11" viewBox="0 0 14 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="11" viewBox="0 0 15 11" fill="none">
|
||||||
<path d="M6.20122 0.94856L9.60703 1.3343C11.8086 1.58456 12.9094 1.70875 13.0543 2.33535C13.1991 2.96195 12.2508 3.50763 10.3588 4.59994L10.18 4.70343C9.4979 5.09764 9.15638 5.29427 9.06888 5.6358L9.06417 5.65367C8.98326 5.99802 9.18836 6.35365 9.59857 7.06304C10.3371 8.34164 10.7069 8.98046 10.4434 9.42077L10.4293 9.44241C10.1527 9.87331 9.43957 9.7924 8.0095 9.63058L4.60462 9.2439C2.40307 8.99552 1.30323 8.87039 1.15834 8.24379C1.01345 7.61719 1.96088 7.07057 3.85289 5.97826L4.03165 5.87477C4.71376 5.48244 5.05434 5.28486 5.14372 4.94334L5.14842 4.92547C5.22839 4.58206 5.02329 4.22643 4.61403 3.5161C3.87547 2.2375 3.50573 1.59868 3.76916 1.15837L3.78327 1.13673C4.058 0.705826 4.77303 0.786737 6.20122 0.94856Z" stroke="white" strokeWidth="1.625" />
|
<path d="M6.45122 0.948562L9.85703 1.3343C12.0586 1.58457 13.1594 1.70876 13.3043 2.33535C13.4491 2.96195 12.5008 3.50763 10.6088 4.59994L10.43 4.70343C9.7479 5.09764 9.40638 5.29428 9.31888 5.6358L9.31417 5.65367C9.23326 5.99802 9.43836 6.35365 9.84857 7.06304C10.5871 8.34164 10.9569 8.98046 10.6934 9.42077L10.6793 9.44241C10.4027 9.87331 9.68957 9.7924 8.2595 9.63058L4.85462 9.2439C2.65307 8.99552 1.55323 8.87039 1.40834 8.24379C1.26345 7.6172 2.21088 7.07057 4.10289 5.97826L4.28165 5.87477C4.96376 5.48244 5.30434 5.28487 5.39372 4.94334L5.39842 4.92547C5.47839 4.58206 5.27329 4.22643 4.86403 3.5161C4.12547 2.2375 3.75573 1.59868 4.01916 1.15837L4.03327 1.13673C4.308 0.705828 5.02303 0.786739 6.45122 0.948562Z" stroke="white" stroke-width="1.625" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<span>{card.badge}</span>
|
<span>{card.badge}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{idx === 3 && (
|
||||||
|
<div className="absolute top-4 left-4">
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-2 rounded-full text-sm font-bold bg-[#ffebef] border-[#f8d0de] border-2 border-solid mr-2 h-[30px]" style={{ color: "#FFFFFF" }}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16" fill="none">
|
||||||
|
<path d="M5.83716 4.23774C7.31896 4.23774 8.74008 4.81435 9.78788 5.84071C10.8357 6.86707 11.4243 8.25912 11.4243 9.71062C11.4243 11.1621 10.8357 12.5542 9.78788 13.5805C8.74008 14.6069 7.31896 15.1835 5.83716 15.1835C4.35535 15.1835 2.93424 14.6069 1.88644 13.5805C0.838645 12.5542 0.25 11.1621 0.25 9.71062C0.25 8.25912 0.838645 6.86707 1.88644 5.84071C2.93424 4.81435 4.35535 4.23774 5.83716 4.23774ZM5.83716 5.60596C4.7258 5.60596 3.65997 6.03841 2.87412 6.80819C2.08827 7.57796 1.64679 8.62199 1.64679 9.71062C1.64679 10.7992 2.08827 11.8433 2.87412 12.613C3.65997 13.3828 4.7258 13.8153 5.83716 13.8153C6.94851 13.8153 8.01435 13.3828 8.8002 12.613C9.58604 11.8433 10.0275 10.7992 10.0275 9.71062C10.0275 8.62199 9.58604 7.57796 8.8002 6.80819C8.01435 6.03841 6.94851 5.60596 5.83716 5.60596ZM5.83716 6.63212L6.76044 8.46554L8.82629 8.7597L7.33172 10.1861L7.68441 12.2015L5.83716 11.2499L3.9899 12.2008L4.34259 10.1861L2.84803 8.75902L4.91388 8.46485L5.83716 6.63212ZM10.0275 0.817195V2.86952L9.07561 3.64804C8.28592 3.24152 7.42338 2.98853 6.53555 2.90304V0.817195H10.0275ZM5.13876 0.816511V2.90304C4.25123 2.98841 3.38893 3.24116 2.5994 3.64736L1.64679 2.86952V0.817195L5.13876 0.816511Z" fill="#D55169" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-[#D55169]">Top rankings</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="inline-flex items-center gap-2 px-3 py-2 rounded-full text-sm font-bold border-[#9af2b3] border-2 border-solid h-[30px]"
|
||||||
|
style={{
|
||||||
|
color: "#FFFFFF",
|
||||||
|
background: "linear-gradient(278deg, rgba(240, 250, 181, 0.60) 0.47%, rgba(193, 254, 207, 0.60) 46.54%)"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16" fill="none">
|
||||||
|
<path d="M5.95435 4.23774C7.43615 4.23774 8.85727 4.81435 9.90506 5.84071C10.9529 6.86707 11.5415 8.25912 11.5415 9.71062C11.5415 11.1621 10.9529 12.5542 9.90506 13.5805C8.85727 14.6069 7.43615 15.1835 5.95435 15.1835C4.47254 15.1835 3.05142 14.6069 2.00363 13.5805C0.955833 12.5542 0.367188 11.1621 0.367188 9.71062C0.367188 8.25912 0.955833 6.86707 2.00363 5.84071C3.05142 4.81435 4.47254 4.23774 5.95435 4.23774ZM5.95435 5.60596C4.84299 5.60596 3.77715 6.03841 2.99131 6.80819C2.20546 7.57796 1.76398 8.62199 1.76398 9.71062C1.76398 10.7992 2.20546 11.8433 2.99131 12.613C3.77715 13.3828 4.84299 13.8153 5.95435 13.8153C7.0657 13.8153 8.13154 13.3828 8.91738 12.613C9.70323 11.8433 10.1447 10.7992 10.1447 9.71062C10.1447 8.62199 9.70323 7.57796 8.91738 6.80819C8.13154 6.03841 7.0657 5.60596 5.95435 5.60596ZM5.95435 6.63212L6.87762 8.46554L8.94348 8.7597L7.44891 10.1861L7.8016 12.2015L5.95435 11.2499L4.10709 12.2008L4.45978 10.1861L2.96522 8.75902L5.03107 8.46485L5.95435 6.63212ZM10.1447 0.817195V2.86952L9.1928 3.64804C8.40311 3.24152 7.54056 2.98853 6.65274 2.90304V0.817195H10.1447ZM5.25595 0.816511V2.90304C4.36841 2.98841 3.50612 3.24116 2.71659 3.64736L1.76398 2.86952V0.817195L5.25595 0.816511Z" fill="#30A372" /></svg>
|
||||||
|
<span className="text-[#197232]">Top rankings</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<MultiRingCircularProgress
|
<MultiRingCircularProgress
|
||||||
card={card}
|
card={card}
|
||||||
hoveredIndex={hoverState.cardId === card.title ? hoverState.ringIndex : null}
|
hoveredIndex={hoverState.cardId === card.title ? hoverState.ringIndex : null}
|
||||||
onHover={(index) => handleRingHover(card.title, index)}
|
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"}`}>
|
<div className={`mt-1 font-bold text-lg text-center ${card.faded ? "text-gray-400" : "text-gray-900"}`}>
|
||||||
{card.title}
|
{card.title}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import { PieChart, Pie, Cell } from "recharts";
|
||||||
import { PieChart, Pie, Cell } from "recharts";
|
|
||||||
|
|
||||||
interface Ring {
|
interface Ring {
|
||||||
color: string;
|
color: string;
|
||||||
@@ -15,17 +14,16 @@ interface MultiRingCircularProgressProps {
|
|||||||
card: Card;
|
card: Card;
|
||||||
hoveredIndex: number | null;
|
hoveredIndex: number | null;
|
||||||
onHover: (index: number | null) => void;
|
onHover: (index: number | null) => void;
|
||||||
cardId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MultiRingCircularProgress({ card, hoveredIndex, onHover, cardId }: MultiRingCircularProgressProps) {
|
export default function MultiRingCircularProgress({ card, hoveredIndex, onHover }: MultiRingCircularProgressProps) {
|
||||||
const { percent, rings } = card;
|
const { percent, rings } = card;
|
||||||
|
|
||||||
// Create ring data with proper outer and inner radius calculations
|
// Create ring data with proper outer and inner radius calculations
|
||||||
const ringData = rings.map((ring, index) => ({
|
const ringData = rings.map((ring, index) => ({
|
||||||
...ring,
|
...ring,
|
||||||
outerRadius: 125 - (index * 20), // Decrease by 20px for each ring
|
outerRadius: 110 - (index * 18), // Decrease by 18px for each ring
|
||||||
innerRadius: 110 - (index * 20), // Decrease by 20px for each ring
|
innerRadius: 95 - (index * 18), // Decrease by 18px for each ring
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// When a ring is hovered, other rings become gray
|
// When a ring is hovered, other rings become gray
|
||||||
@@ -45,7 +43,7 @@ export default function MultiRingCircularProgress({ card, hoveredIndex, onHover,
|
|||||||
style={{ outline: "none", border: "none" }}
|
style={{ outline: "none", border: "none" }}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<PieChart width={400} height={400} className="focus-visible:outline-none focus-visible:ring-0 focus-visible:border-none" >
|
<PieChart width={300} height={300} className="focus-visible:outline-none focus-visible:ring-0 focus-visible:border-none" >
|
||||||
{ringData.map((ring, index) => (
|
{ringData.map((ring, index) => (
|
||||||
<Pie
|
<Pie
|
||||||
key={index}
|
key={index}
|
||||||
@@ -74,8 +72,8 @@ export default function MultiRingCircularProgress({ card, hoveredIndex, onHover,
|
|||||||
</Pie>
|
</Pie>
|
||||||
))}
|
))}
|
||||||
<text
|
<text
|
||||||
x={200}
|
x={150}
|
||||||
y={204}
|
y={154}
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
dominantBaseline="middle"
|
dominantBaseline="middle"
|
||||||
style={{ fontSize: "1.3rem", fontWeight: "bold" }}
|
style={{ fontSize: "1.3rem", fontWeight: "bold" }}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import UrlDropdown from "./UrlDropdown"
|
|||||||
const HeaderPage = ({ title }: { title: string }) => {
|
const HeaderPage = ({ title }: { title: string }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex space-x-4 my-0 md:my-4 lg:flex-row flex-col items-baseline">
|
<div className="flex space-x-4 my-0 md:my-4 lg:flex-row flex-col items-baseline">
|
||||||
<h1 className="text-3xl font-bold text-gray-800 mb:mb-0 mb-4">{title}</h1>
|
<h1 className="text-xl font-bold text-gray-800 mb:mb-0 mb-4">{title}</h1>
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="4" height="4" viewBox="0 0 4 4" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="4" height="4" viewBox="0 0 4 4" fill="none">
|
||||||
<circle cx="2" cy="2" r="2" fill="#E9EAF1"/>
|
<circle cx="2" cy="2" r="2" fill="#E9EAF1"/>
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { useState } from "react";
|
|||||||
// Reusable Metric Card Component
|
// Reusable Metric Card Component
|
||||||
const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChange, size, extraStyle, disabled }: { icon?: any, img?: any, value?: any, label?: any, tooltipText?: any, valueChange?: any, size?: any, extraStyle?: any, disabled?: any }) => {
|
const MetricCard = ({ icon: Icon, img: Img, value, label, tooltipText, valueChange, size, extraStyle, disabled }: { icon?: any, img?: any, value?: any, label?: any, tooltipText?: any, valueChange?: any, size?: any, extraStyle?: any, disabled?: any }) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
console.log(Img);
|
console.log(Img);
|
||||||
if (Img) {
|
if (Img) {
|
||||||
return (
|
return (
|
||||||
<div className="relative cursor-pointer"
|
<div className="relative cursor-pointer"
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
onMouseLeave={() => setIsHovered(false)}>
|
onMouseLeave={() => setIsHovered(false)}>
|
||||||
<div className={`${extraStyle} ${disabled ? "opacity-30" : ""}`}>
|
<div className={`${extraStyle} ${disabled ? "opacity-30" : ""}`}>
|
||||||
<img src={Img} alt="Img" className={` ${disabled ? "w-6 2xl:w-6 h-6 2xl:h-6" : "w-6 2xl:w-8 h-6 2xl:h-8"}${value === 'Map' ? ' scale-125' : ""} ` } />
|
<img src={Img} alt="Img" className={` ${disabled ? "w-6 2xl:w-6 h-6 2xl:h-6" : "w-6 2xl:w-8 h-6 2xl:h-8"}${value === 'Map' ? ' scale-125' : ""} `} />
|
||||||
</div>
|
</div>
|
||||||
<div className="">
|
<div className="">
|
||||||
{tooltipText && (
|
{tooltipText && (
|
||||||
@@ -45,12 +45,12 @@ console.log(Img);
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex-1">
|
<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`}>
|
<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 p-[3px] justify-between `}>
|
||||||
<span className="text-sm text-gray-400">{!tooltipText && label}</span>
|
<span className="text-sm text-gray-400">{!tooltipText && label}</span>
|
||||||
|
|
||||||
<span className="text-[#787B91] bg-gray-200 px-1 py-1 rounded-md">{value}</span>
|
<span className="text-[#787B91] bg-gray-200 px-1 py-0 rounded-md">{value}</span>
|
||||||
{valueChange && (
|
{valueChange && (
|
||||||
<div className="flex items-center text-sm font-semibold text-green-500">
|
<div className="flex items-center text-md font-semibold text-green-500">
|
||||||
{Icon && (
|
{Icon && (
|
||||||
<ArrowUp size={14} className="inline-block mr-1" />
|
<ArrowUp size={14} className="inline-block mr-1" />
|
||||||
)}
|
)}
|
||||||
@@ -58,9 +58,9 @@ console.log(Img);
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center space-x-1 mt-1 text-gray-500">
|
{tooltipText && (
|
||||||
<span className="text-sm">{tooltipText && label}</span>
|
<div className="flex items-center space-x-1 mt-1 text-gray-500">
|
||||||
{tooltipText && (
|
<span className="text-sm">{label}</span>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Info size={16} className="text-gray-400 cursor-pointer" />
|
<Info size={16} className="text-gray-400 cursor-pointer" />
|
||||||
{isHovered && (
|
{isHovered && (
|
||||||
@@ -71,8 +71,8 @@ console.log(Img);
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,18 +22,18 @@ export default function UrlDropdown() {
|
|||||||
<div className="relative text-sm max-w-[400px] min-w-[220px] mb:mb-0 mb-4">
|
<div className="relative text-sm max-w-[400px] min-w-[220px] mb:mb-0 mb-4">
|
||||||
{/* Input box */}
|
{/* Input box */}
|
||||||
<div
|
<div
|
||||||
className="flex justify-between items-center border border-gray-300 bg-white px-2 py-1 rounded cursor-pointer focus:border-2 focus:border-blue-500"
|
className={`flex justify-between items-center border-2 bg-white px-2 py-1 rounded-lg cursor-pointer ${isOpen ? "border-blue-500" : "border-gray-300"} transition-all duration-100`}
|
||||||
onClick={toggleDropdown}
|
onClick={toggleDropdown}
|
||||||
>
|
>
|
||||||
<span className="truncate text-gray-800">{selected}</span>
|
<span className="truncate text-gray-800">{selected}</span>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M9 5L5 1L1 5" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M9 5L5 1L1 5" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M1 1L5 5L9 1" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M1 1L5 5L9 1" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -41,7 +41,7 @@ export default function UrlDropdown() {
|
|||||||
|
|
||||||
{/* Dropdown list */}
|
{/* Dropdown list */}
|
||||||
{isOpen && (
|
{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 bg-white border border-gray-200 rounded shadow max-h-60 overflow-y-auto z-10 w-[110%]">
|
||||||
{urlOptions.map((url, index) => (
|
{urlOptions.map((url, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
@@ -51,9 +51,10 @@ export default function UrlDropdown() {
|
|||||||
>
|
>
|
||||||
<span className="truncate">{url}</span>
|
<span className="truncate">{url}</span>
|
||||||
{selected === url && (
|
{selected === url && (
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="18" viewBox="0 0 66 18" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="12" viewBox="0 0 15 12" fill="none">
|
||||||
<path d="M47 7.25L51 11.25L59.5 2.75" stroke="#4C60E5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M1 6.25L5 10.25L13.5 1.75" stroke="#4C60E5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.custom-scrollbar-table {
|
.custom-scrollbar-table {
|
||||||
max-height: 460px;
|
max-height: 380px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const categories = [
|
|||||||
{
|
{
|
||||||
name: 'Social',
|
name: 'Social',
|
||||||
color: ' border-[#4285F4] bg-[#001EE21C]',
|
color: ' border-[#4285F4] bg-[#001EE21C]',
|
||||||
|
after: "bg-[#4C60E5]",
|
||||||
rows: [
|
rows: [
|
||||||
{
|
{
|
||||||
icon: Amazing, title: 'Questions to ask your CPA httpAmazon', DR: 90, DA: 97, traffic: '3,902,293',
|
icon: Amazing, title: 'Questions to ask your CPA httpAmazon', DR: 90, DA: 97, traffic: '3,902,293',
|
||||||
@@ -40,6 +41,7 @@ const categories = [
|
|||||||
{
|
{
|
||||||
name: 'Citation',
|
name: 'Citation',
|
||||||
color: ' border-[#0ea5e9] bg-[#3C87FF2B]',
|
color: ' border-[#0ea5e9] bg-[#3C87FF2B]',
|
||||||
|
after: "bg-[#4285F4]",
|
||||||
rows: [
|
rows: [
|
||||||
{ 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: '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: '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' },
|
||||||
@@ -49,6 +51,7 @@ const categories = [
|
|||||||
{
|
{
|
||||||
name: 'Web 2.0',
|
name: 'Web 2.0',
|
||||||
color: 'border-[#22c55e] bg-[#f0fdf4]',
|
color: 'border-[#22c55e] bg-[#f0fdf4]',
|
||||||
|
after: "bg-[#34A853]",
|
||||||
rows: [
|
rows: [
|
||||||
{ 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: '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: 'Apple Music DR 97 DA 95 Traffic', DR: 90, DA: 97, traffic: '3,902,293', indexed: done, interlinked: nA, date: '9/16/25' },
|
||||||
@@ -76,9 +79,9 @@ function Portfolio() {
|
|||||||
<RoadmapSidebar mode={"portfolio"} selectedKeyword={selectedKeyword} onKeywordSelect={setSelectedKeyword} />
|
<RoadmapSidebar mode={"portfolio"} selectedKeyword={selectedKeyword} onKeywordSelect={setSelectedKeyword} />
|
||||||
|
|
||||||
{/* Table Section */}
|
{/* Table Section */}
|
||||||
<section className='flex-1 bg-white border rounded-2xl shadow-sm px-4 sm:px-6 py-4 overflow-x-auto'>
|
<section className='flex-1 bg-white border rounded-2xl shadow-sm py-4 overflow-x-auto'>
|
||||||
{/* Title Bar */}
|
{/* Title Bar */}
|
||||||
<div className='flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 mb-4'>
|
<div className='flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 mb-4 px-4'>
|
||||||
<div className='flex flex-col items-start gap-2'>
|
<div className='flex flex-col items-start gap-2'>
|
||||||
<span className='text-xl sm:text-2xl font-bold '>CPA Los Angeles</span>
|
<span className='text-xl sm:text-2xl font-bold '>CPA Los Angeles</span>
|
||||||
<span className='text-gray-500 rounded-md text-sm sm:text-md font-normal'>
|
<span className='text-gray-500 rounded-md text-sm sm:text-md font-normal'>
|
||||||
@@ -105,9 +108,9 @@ function Portfolio() {
|
|||||||
|
|
||||||
<button className='bg-[#fff] border px-3 sm:px-4 py-2 rounded-lg text-sm sm:text-md font-bold transition-colors flex items-center gap-2'>
|
<button className='bg-[#fff] border px-3 sm:px-4 py-2 rounded-lg text-sm sm:text-md font-bold transition-colors flex items-center gap-2'>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19" fill="none">
|
||||||
<path d="M1.80154 10.583C1.7998 10.2479 1.7998 9.88794 1.7998 9.49999C1.7998 6.80829 1.7998 5.46245 2.37857 4.45999C2.75773 3.80327 3.30308 3.25792 3.95981 2.87876C4.96226 2.29999 6.30811 2.29999 8.9998 2.29999C11.6915 2.29999 13.0373 2.29999 14.0398 2.87876C14.6965 3.25792 15.2419 3.80327 15.621 4.45999C16.1998 5.46245 16.1998 6.80829 16.1998 9.49999C16.1998 12.1917 16.1998 13.5375 15.621 14.54C15.2419 15.1967 14.6965 15.7421 14.0398 16.1212C13.0373 16.7 11.6915 16.7 8.9998 16.7C8.60253 16.7 8.23457 16.7 7.8927 16.6981" stroke="#65677D" stroke-width="1.5" stroke-linecap="round"/>
|
<path d="M1.80154 10.583C1.7998 10.2479 1.7998 9.88794 1.7998 9.49999C1.7998 6.80829 1.7998 5.46245 2.37857 4.45999C2.75773 3.80327 3.30308 3.25792 3.95981 2.87876C4.96226 2.29999 6.30811 2.29999 8.9998 2.29999C11.6915 2.29999 13.0373 2.29999 14.0398 2.87876C14.6965 3.25792 15.2419 3.80327 15.621 4.45999C16.1998 5.46245 16.1998 6.80829 16.1998 9.49999C16.1998 12.1917 16.1998 13.5375 15.621 14.54C15.2419 15.1967 14.6965 15.7421 14.0398 16.1212C13.0373 16.7 11.6915 16.7 8.9998 16.7C8.60253 16.7 8.23457 16.7 7.8927 16.6981" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" />
|
||||||
<path d="M6.99503 6.79999H11.7002M11.7002 6.79999V11.5059M11.7002 6.79999L2.7002 15.8" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M6.99503 6.79999H11.7002M11.7002 6.79999V11.5059M11.7002 6.79999L2.7002 15.8" stroke="#65677D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<span>Export</span>
|
<span>Export</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -115,8 +118,8 @@ function Portfolio() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Global Filter/Sort Header Row */}
|
{/* Global Filter/Sort Header Row */}
|
||||||
<div className='hidden lg:flex items-center justify-end gap-4 mb-2 px-4 py-3 '>
|
<div className='hidden lg:flex items-center justify-end gap-4 mb-2 px-4 py-3 border-b border-gray-100 border-solid'>
|
||||||
<div className='flex items-center gap-4 xl:gap-8 text-xs xl:text-sm font-medium text-gray-600'>
|
<div className='flex items-center gap-4 xl:gap-8 text-xs xl:text-sm font-medium text-gray-600 pr-6'>
|
||||||
<span className='flex items-center cursor-pointer text-[#65677D] hover:text-[#4285F4] transition-colors '>
|
<span className='flex items-center cursor-pointer text-[#65677D] hover:text-[#4285F4] transition-colors '>
|
||||||
DR <SortIcon />
|
DR <SortIcon />
|
||||||
</span>
|
</span>
|
||||||
@@ -145,6 +148,7 @@ function Portfolio() {
|
|||||||
<div className='flex items-center gap-3'>
|
<div className='flex items-center gap-3'>
|
||||||
<div className='flex items-center gap-2'>
|
<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> */}
|
||||||
|
<div className={`w-2 h-5 rounded ${cat.after}`}></div>
|
||||||
<span>{cat.name}</span>
|
<span>{cat.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<span className='text-md font-bold bg-white p-1 px-2 rounded-full'>{cat.rows.length}</span>
|
<span className='text-md font-bold bg-white p-1 px-2 rounded-full'>{cat.rows.length}</span>
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم