ML
Mikael Luca

Dashboard Grid - Copy this React, Tailwind Component to your project

add this : Agora merge as funcionalidades sem remover nenhuma úti: import React, { useState, useRef, useEffect } from "react"; import { FiSettings, FiBarChart2, FiPieChart, FiTrendingUp, FiMoreVertical } from "react-icons/fi"; import { BsTable, BsGraphUp, BsGear, BsSearch } from "react-icons/bs"; import { Line, Bar, Pie } from "react-chartjs-2"; import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend } from "chart.js"; ChartJS.register( CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend ); const DashboardGrid = () => { const [activeChart, setActiveChart] = useState("line"); const [showConfig, setShowConfig] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [loading, setLoading] = useState(false); const [items, setItems] = useState([]); const [activeOptionsMenu, setActiveOptionsMenu] = useState(null); const observerTarget = useRef(null); const handleOptionsClick = (blockId) => { setActiveOptionsMenu(activeOptionsMenu === blockId ? null : blockId); }; const chartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: "top", labels: { padding: 20, font: { size: 12 } } }, tooltip: { backgroundColor: "rgba(0, 0, 0, 0.8)", padding: 12, titleFont: { size: 14 }, bodyFont: { size: 13 } } }, scales: { y: { beginAtZero: true, grid: { color: "rgba(0, 0, 0, 0.05)" } }, x: { grid: { display: false } } } }; const chartData = { labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], datasets: [ { label: "Sales", data: [12, 19, 3, 5, 2, 3], backgroundColor: "rgba(75, 192, 192, 0.2)", borderColor: "rgba(75, 192, 192, 1)", borderWidth: 2, tension: 0.4, fill: true, pointRadius: 4, pointHoverRadius: 6, pointBackgroundColor: "#fff", pointBorderColor: "rgba(75, 192, 192, 1)", pointHoverBackgroundColor: "rgba(75, 192, 192, 1)", pointHoverBorderColor: "#fff" } ] }; const tableData = [ { id: 1, name: "Product A", sales: 100, revenue: "$1000" }, { id: 2, name: "Product B", sales: 150, revenue: "$1500" }, { id: 3, name: "Product C", sales: 200, revenue: "$2000" } ]; const kpiData = [ { title: "Total Sales", value: "$5,670", icon: <FiBarChart2 /> }, { title: "Conversion Rate", value: "2.4%", icon: <FiTrendingUp /> }, { title: "Average Order", value: "$340", icon: <FiPieChart /> } ]; useEffect(() => { const observer = new IntersectionObserver( entries => { if (entries[0].isIntersecting && !loading) { loadMoreItems(); } }, { threshold: 1.0 } ); if (observerTarget.current) { observer.observe(observerTarget.current); } return () => { if (observerTarget.current) { observer.unobserve(observerTarget.current); } }; }, [loading]); const loadMoreItems = () => { setLoading(true); setTimeout(() => { setItems(prev => [...prev, ...tableData]); setLoading(false); }, 1000); }; const filteredData = tableData.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const renderChart = () => { switch (activeChart) { case "line": return <Line data={chartData} options={chartOptions} />; case "bar": return <Bar data={chartData} options={chartOptions} />; case "pie": return <Pie data={chartData} options={{ ...chartOptions, aspectRatio: 2 }} />; default: return null; } }; const OptionsMenu = ({ blockId }) => ( <div className={`absolute right-2 top-2 z-10 ${activeOptionsMenu === blockId ? "" : "hidden"}`}> <div className="bg-white rounded-lg shadow-lg py-2 w-48 border border-gray-100"> <button className="w-full text-left px-4 py-2 hover:bg-gray-50 text-sm">Edit Block</button> <button className="w-full text-left px-4 py-2 hover:bg-gray-50 text-sm">Duplicate Block</button> <button className="w-full text-left px-4 py-2 hover:bg-gray-50 text-sm text-red-500">Remove Block</button> </div> </div> ); return ( <div className="min-h-screen bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:20px_20px] p-4"> <div className="max-w-7xl mx-auto bg-white/80 backdrop-blur-sm rounded-xl shadow-lg p-6"> <div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4"> {kpiData.map((kpi, index) => ( <div key={index} className="bg-white rounded-lg p-4 shadow-sm border border-gray-100 relative"> <button onClick={() => handleOptionsClick(`kpi-${index}`)} className="absolute right-2 top-2 p-1 hover:bg-gray-100 rounded-full" > <FiMoreVertical /> </button> <OptionsMenu blockId={`kpi-${index}`} /> <div className="flex items-center justify-between"> <div> <h3 className="text-gray-500 text-xs">{kpi.title}</h3> <p className="text-lg font-bold mt-0.5">{kpi.value}</p> </div> <div className="text-blue-500 text-xl">{kpi.icon}</div> </div> </div> ))} <div className="bg-white rounded-lg p-4 shadow-sm border border-gray-100 col-span-full lg:col-span-2 relative"> <button onClick={() => handleOptionsClick("chart")} className="absolute right-2 top-2 p-1 hover:bg-gray-100 rounded-full" > <FiMoreVertical /> </button> <OptionsMenu blockId="chart" /> <div className="flex items-center justify-between mb-4"> <h2 className="text-lg font-bold">Analytics Overview</h2> <div className="flex space-x-2"> <button onClick={() => setActiveChart("line")} className={`p-2 rounded-lg ${activeChart === "line" ? "bg-blue-500 text-white" : "bg-gray-100"}`} > <FiTrendingUp /> </button> <button onClick={() => setActiveChart("bar")} className={`p-2 rounded-lg ${activeChart === "bar" ? "bg-blue-500 text-white" : "bg-gray-100"}`} > <FiBarChart2 /> </button> <button onClick={() => setActiveChart("pie")} className={`p-2 rounded-lg ${activeChart === "pie" ? "bg-blue-500 text-white" : "bg-gray-100"}`} > <FiPieChart /> </button> </div> </div> <div className="h-[400px] w-full">{renderChart()}</div> </div> <div className="bg-white rounded-lg p-4 shadow-sm border border-gray-100 col-span-full lg:col-span-2 relative"> <button onClick={() => handleOptionsClick("table")} className="absolute right-2 top-2 p-1 hover:bg-gray-100 rounded-full" > <FiMoreVertical /> </button> <OptionsMenu blockId="table" /> <div className="flex items-center justify-between mb-4"> <h2 className="text-lg font-bold">Products Overview</h2> <div className="relative"> <input type="text" placeholder="Search products..." className="pl-8 pr-4 py-2 text-sm rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500/50" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> <BsSearch className="absolute left-3 top-2.5 text-gray-400 text-sm" /> </div> </div> <div className="overflow-y-auto max-h-64"> <table className="w-full"> <thead className="sticky top-0 bg-white"> <tr className="border-b text-sm"> <th className="py-2 text-left">Name</th> <th className="py-2 text-left">Sales</th> <th className="py-2 text-left">Revenue</th> </tr> </thead> <tbody className="text-sm"> {items.map((item, index) => ( <tr key={`${item.id}-${index}`} className="border-b hover:bg-gray-50"> <td className="py-2">{item.name}</td> <td className="py-2">{item.sales}</td> <td className="py-2">{item.revenue}</td> </tr> ))} </tbody> </table> <div ref={observerTarget} className="h-4 w-full"> {loading && <p className="text-center text-gray-500 text-sm">Loading...</p>} </div> </div> </div> </div> </div> <button onClick={() => setShowConfig(!showConfig)} className="fixed bottom-4 right-4 p-3 bg-blue-500 text-white rounded-full shadow-lg hover:bg-blue-600 transition-colors" > <FiSettings className="text-lg" /> </button> {showConfig && ( <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"> <div className="bg-white rounded-lg p-6 w-96"> <div className="flex justify-between items-center mb-4"> <h2 className="text-lg font-bold">Dashboard Settings</h2> <button onClick={() => setShowConfig(false)} className="text-gray-500 hover:text-gray-700 text-xl" > × </button> </div> <div className="space-y-4"> <div className="flex items-center justify-between"> <span className="text-sm">Show KPI Cards</span> <input type="checkbox" defaultChecked className="form-checkbox rounded text-blue-500" /> </div> <div className="flex items-center justify-between"> <span className="text-sm">Show Charts</span> <input type="checkbox" defaultChecked className="form-checkbox rounded text-blue-500" /> </div> <div className="flex items-center justify-between"> <span className="text-sm">Show Table</span> <input type="checkbox" defaultChecked className="form-checkbox rounded text-blue-500" /> </div> </div> </div> </div> )} </div> ); }; export default DashboardGrid;

Prompt

About

DashboardGrid - A responsive grid layout with a floating block for all options, designed for easy customization and organization, bui. Copy component code!

Share

Last updated 1 month ago