mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 14:05:24 +02:00
Optimize Grid header UI: reduce font sizes, padding, and improve alignment of metric columns
This commit is contained in:
+29
-24
@@ -703,8 +703,8 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSortIcon = (key: string) => {
|
const getSortIcon = (key: string) => {
|
||||||
if (sortConfig.key !== key) return <span className="text-slate-600 ml-1">⇅</span>;
|
if (sortConfig.key !== key) return <span className="text-slate-600 opacity-20 group-hover:opacity-100 transition-opacity ml-0.5">↕</span>;
|
||||||
return <span className="text-primary ml-1">{sortConfig.direction === 'asc' ? '↑' : '↓'}</span>;
|
return <span className="text-primary ml-0.5">{sortConfig.direction === 'asc' ? '↑' : '↓'}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
@@ -1256,11 +1256,11 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
return (
|
return (
|
||||||
<th
|
<th
|
||||||
key={dim}
|
key={dim}
|
||||||
className={`px-4 py-3 border-b border-border group bg-slate-950 ${dim === 'title' ? 'min-w-[450px]' : 'min-w-[150px]'}`}
|
className={`px-2.5 py-3 border-b border-border group bg-slate-950 ${dim === 'title' ? 'min-w-[400px]' : 'min-w-[140px]'}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between gap-1">
|
||||||
<div
|
<div
|
||||||
className="flex items-center cursor-pointer hover:text-white"
|
className="flex items-center cursor-pointer hover:text-white text-[11px] font-bold uppercase tracking-wide truncate"
|
||||||
onClick={() => requestSort(dim)}
|
onClick={() => requestSort(dim)}
|
||||||
>
|
>
|
||||||
{label} {getSortIcon(dim)}
|
{label} {getSortIcon(dim)}
|
||||||
@@ -1268,6 +1268,7 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
<ExcelFilter
|
<ExcelFilter
|
||||||
columnKey={dim}
|
columnKey={dim}
|
||||||
title={label}
|
title={label}
|
||||||
|
buttonClassName={`p-1 rounded hover:bg-white/10 transition-all ${columnFilters[dim] ? 'text-indigo-400 bg-indigo-500/10' : 'text-slate-500'}`}
|
||||||
uniqueValues={uniqueValues}
|
uniqueValues={uniqueValues}
|
||||||
currentFilter={columnFilters[dim]}
|
currentFilter={columnFilters[dim]}
|
||||||
onFilterChange={handleColumnFilterChange}
|
onFilterChange={handleColumnFilterChange}
|
||||||
@@ -1283,38 +1284,42 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
return (
|
return (
|
||||||
<React.Fragment key={year}>
|
<React.Fragment key={year}>
|
||||||
{/* Sell Out & Units */}
|
{/* Sell Out & Units */}
|
||||||
<th className="px-4 py-3 border-b border-border text-right bg-slate-950 min-w-[120px]">
|
<th className="px-2 py-2.5 border-b border-border bg-slate-950 min-w-[105px]">
|
||||||
<div className="flex items-center justify-end gap-2">
|
<div className="flex items-center justify-end gap-1 leading-none">
|
||||||
<div
|
|
||||||
className="flex items-center cursor-pointer hover:text-white"
|
|
||||||
onClick={() => requestSort(`total_sellOut_${year}`)}
|
|
||||||
>
|
|
||||||
Sell Out {year} {getSortIcon(`total_sellOut_${year}`)}
|
|
||||||
</div>
|
|
||||||
<ExcelFilter
|
<ExcelFilter
|
||||||
columnKey={`total_sellOut_${year}`}
|
columnKey={`total_sellOut_${year}`}
|
||||||
title={`Sell Out ${year}`}
|
title={`Sell Out ${year}`}
|
||||||
|
buttonClassName={`w-4 h-4 flex items-center justify-center rounded hover:bg-white/10 transition-all ${columnFilters[`total_sellOut_${year}`] ? 'text-indigo-400 bg-indigo-500/10' : 'text-slate-600'}`}
|
||||||
uniqueValues={Array.from(new Set(pivotRows.map(r => String(r.totalsByYear[year]?.sellOut || 0)))).sort((a, b) => parseFloat(a as string) - parseFloat(b as string))}
|
uniqueValues={Array.from(new Set(pivotRows.map(r => String(r.totalsByYear[year]?.sellOut || 0)))).sort((a, b) => parseFloat(a as string) - parseFloat(b as string))}
|
||||||
currentFilter={columnFilters[`total_sellOut_${year}`]}
|
currentFilter={columnFilters[`total_sellOut_${year}`]}
|
||||||
onFilterChange={handleColumnFilterChange}
|
onFilterChange={handleColumnFilterChange}
|
||||||
|
icon={<FunnelIcon className="w-2.5 h-2.5" />}
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="flex items-center cursor-pointer hover:text-white text-[10px] font-black uppercase tracking-tight"
|
||||||
|
onClick={() => requestSort(`total_sellOut_${year}`)}
|
||||||
|
>
|
||||||
|
{year} SO {getSortIcon(`total_sellOut_${year}`)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-3 border-b border-border text-right bg-slate-950 min-w-[100px]">
|
<th className="px-2 py-2.5 border-b border-border bg-slate-950 min-w-[85px]">
|
||||||
<div className="flex items-center justify-end gap-2">
|
<div className="flex items-center justify-end gap-1 leading-none">
|
||||||
<div
|
|
||||||
className="flex items-center cursor-pointer hover:text-white"
|
|
||||||
onClick={() => requestSort(`total_units_${year}`)}
|
|
||||||
>
|
|
||||||
Units {year} {getSortIcon(`total_units_${year}`)}
|
|
||||||
</div>
|
|
||||||
<ExcelFilter
|
<ExcelFilter
|
||||||
columnKey={`total_units_${year}`}
|
columnKey={`total_units_${year}`}
|
||||||
title={`Units ${year}`}
|
title={`Units ${year}`}
|
||||||
|
buttonClassName={`w-4 h-4 flex items-center justify-center rounded hover:bg-white/10 transition-all ${columnFilters[`total_units_${year}`] ? 'text-indigo-400 bg-indigo-500/10' : 'text-slate-600'}`}
|
||||||
uniqueValues={Array.from(new Set(pivotRows.map(r => String(r.totalsByYear[year]?.units || 0)))).sort((a, b) => parseFloat(a as string) - parseFloat(b as string))}
|
uniqueValues={Array.from(new Set(pivotRows.map(r => String(r.totalsByYear[year]?.units || 0)))).sort((a, b) => parseFloat(a as string) - parseFloat(b as string))}
|
||||||
currentFilter={columnFilters[`total_units_${year}`]}
|
currentFilter={columnFilters[`total_units_${year}`]}
|
||||||
onFilterChange={handleColumnFilterChange}
|
onFilterChange={handleColumnFilterChange}
|
||||||
|
icon={<FunnelIcon className="w-2.5 h-2.5" />}
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="flex items-center cursor-pointer hover:text-white text-[10px] font-black uppercase tracking-tight"
|
||||||
|
onClick={() => requestSort(`total_units_${year}`)}
|
||||||
|
>
|
||||||
|
{year} U {getSortIcon(`total_units_${year}`)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
@@ -1370,7 +1375,7 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
{paginatedRows.map((row) => (
|
{paginatedRows.map((row) => (
|
||||||
<tr key={row.id} className="hover:bg-slate-800/50 transition-colors group relative hover:z-50">
|
<tr key={row.id} className="hover:bg-slate-800/50 transition-colors group relative hover:z-50">
|
||||||
{effectiveDimensions.map(dim => (
|
{effectiveDimensions.map(dim => (
|
||||||
<td key={dim} className="px-4 py-3 font-medium text-slate-200 break-words max-w-xs">
|
<td key={dim} className="px-2.5 py-3 font-medium text-slate-200 break-words max-w-xs">
|
||||||
{dim === 'title'
|
{dim === 'title'
|
||||||
? <div className="flex items-start gap-2 max-w-sm relative group/title">
|
? <div className="flex items-start gap-2 max-w-sm relative group/title">
|
||||||
<span className="line-clamp-2 cursor-help decoration-dotted underline underline-offset-2 decoration-slate-600">
|
<span className="line-clamp-2 cursor-help decoration-dotted underline underline-offset-2 decoration-slate-600">
|
||||||
@@ -1435,10 +1440,10 @@ const DataGrid: React.FC<DataGridProps> = ({ data, filters, hasCustomerFilter, a
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={year}>
|
<React.Fragment key={year}>
|
||||||
<td className="px-4 py-3 text-right font-medium text-white group-hover:text-emerald-400 transition-colors">
|
<td className="px-2 py-3 text-right font-medium text-white group-hover:text-emerald-400 transition-colors">
|
||||||
{data ? `€${data.sellOut.toLocaleString('de-DE', { maximumFractionDigits: 0 })}` : '-'}
|
{data ? `€${data.sellOut.toLocaleString('de-DE', { maximumFractionDigits: 0 })}` : '-'}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 text-right text-slate-400">
|
<td className="px-2 py-3 text-right text-slate-400">
|
||||||
{data ? data.units.toLocaleString('de-DE') : '-'}
|
{data ? data.units.toLocaleString('de-DE') : '-'}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ export const ExcelFilter: React.FC<ExcelFilterProps> = ({
|
|||||||
uniqueValues,
|
uniqueValues,
|
||||||
currentFilter,
|
currentFilter,
|
||||||
onFilterChange,
|
onFilterChange,
|
||||||
icon
|
icon,
|
||||||
|
buttonClassName
|
||||||
}) => {
|
}) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [operator, setOperator] = useState<typeof OPERATORS[number]['value']>(currentFilter?.textFilter?.operator || '');
|
const [operator, setOperator] = useState<typeof OPERATORS[number]['value']>(currentFilter?.textFilter?.operator || '');
|
||||||
@@ -113,16 +114,16 @@ export const ExcelFilter: React.FC<ExcelFilterProps> = ({
|
|||||||
const hasActiveFilter = !!(currentFilter?.textFilter || currentFilter?.selectedValues);
|
const hasActiveFilter = !!(currentFilter?.textFilter || currentFilter?.selectedValues);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative inline-block ml-1" ref={containerRef}>
|
<div className="relative inline-block" ref={containerRef}>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
}}
|
}}
|
||||||
className={`flex flex-col items-center gap-0.5 p-1 rounded hover:bg-white/10 transition-all ${hasActiveFilter ? 'text-indigo-400 bg-indigo-500/10' : 'text-slate-500'}`}
|
className={buttonClassName || `flex items-center justify-center p-1 rounded hover:bg-white/10 transition-all ${hasActiveFilter ? 'text-indigo-400 bg-indigo-500/10' : 'text-slate-500'}`}
|
||||||
title={`Filter by ${title}`}
|
title={`Filter by ${title}`}
|
||||||
>
|
>
|
||||||
{icon || <FunnelIcon className="w-3 h-3" />}
|
{icon || <FunnelIcon className={buttonClassName?.includes('w-') ? '' : "w-3 h-3"} />}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
|
|||||||
Reference in New Issue
Block a user