Improve the inventory page 3

This commit is contained in:
Urtzi Alfaro
2025-09-18 08:06:32 +02:00
parent dcb3ce441b
commit ae77a0e1c5
31 changed files with 2376 additions and 1774 deletions

View File

@@ -1,11 +1,19 @@
import React, { forwardRef } from 'react';
import { clsx } from 'clsx';
import { baseColors, statusColors } from '../../../styles/colors';
/**
* ProgressBar component with global color system integration
*
* Supports both base color variants (with gradients) and status color variants (solid colors)
* - Base variants: default, success, warning, danger, info (use gradients from color scales)
* - Status variants: pending, inProgress, completed (use solid colors from statusColors)
*/
export interface ProgressBarProps {
value: number;
max?: number;
size?: 'sm' | 'md' | 'lg';
variant?: 'default' | 'success' | 'warning' | 'danger';
variant?: 'default' | 'success' | 'warning' | 'danger' | 'info' | 'pending' | 'inProgress' | 'completed';
showLabel?: boolean;
label?: string;
className?: string;
@@ -33,11 +41,43 @@ const ProgressBar = forwardRef<HTMLDivElement, ProgressBarProps>(({
lg: 'h-4',
};
const variantClasses = {
default: 'bg-[var(--color-info)]',
success: 'bg-[var(--color-success)]',
warning: 'bg-[var(--color-warning)]',
danger: 'bg-[var(--color-error)]',
const getVariantStyle = (variant: string) => {
// Map base color variants
const baseColorMap = {
default: baseColors.primary,
success: baseColors.success,
warning: baseColors.warning,
danger: baseColors.error,
info: baseColors.info,
};
// Map status color variants (these use single colors from statusColors)
const statusColorMap = {
pending: statusColors.pending.primary,
inProgress: statusColors.inProgress.primary,
completed: statusColors.completed.primary,
};
// Check if it's a base color variant (has color scales)
if (variant in baseColorMap) {
const colors = baseColorMap[variant as keyof typeof baseColorMap];
return {
background: `linear-gradient(to right, ${colors[400]}, ${colors[500]})`,
};
}
// Check if it's a status color variant (single color)
if (variant in statusColorMap) {
const color = statusColorMap[variant as keyof typeof statusColorMap];
return {
backgroundColor: color,
};
}
// Default fallback
return {
background: `linear-gradient(to right, ${baseColors.primary[400]}, ${baseColors.primary[500]})`,
};
};
return (
@@ -61,18 +101,22 @@ const ProgressBar = forwardRef<HTMLDivElement, ProgressBarProps>(({
<div
className={clsx(
'h-full rounded-full transition-all duration-300 ease-out relative overflow-hidden',
!customColor && variantClasses[variant],
{
'animate-pulse': animated && percentage < 100,
}
)}
style={{
width: `${percentage}%`,
backgroundColor: customColor || undefined
...(customColor ? { backgroundColor: customColor } : getVariantStyle(variant))
}}
>
{animated && percentage < 100 && (
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent opacity-20 animate-pulse" />
<div
className="absolute inset-0 opacity-20 animate-pulse"
style={{
background: 'linear-gradient(to right, transparent, var(--text-inverse), transparent)'
}}
/>
)}
</div>
</div>

View File

@@ -241,69 +241,68 @@ export const StatusCard: React.FC<StatusCardProps> = ({
</div>
)}
{/* Elegant Action System */}
{/* Simplified Action System */}
{actions.length > 0 && (
<div className="pt-5">
{/* Primary Actions Row */}
{primaryActions.length > 0 && (
<div className="flex gap-3 mb-3">
<Button
variant={primaryActions[0].destructive ? 'outline' : 'primary'}
size="md"
className={`
flex-1 h-11 font-medium justify-center
${primaryActions[0].destructive
? 'border-red-300 text-red-600 hover:bg-red-50 hover:border-red-400'
: 'bg-gradient-to-r from-[var(--color-primary-600)] to-[var(--color-primary-500)] hover:from-[var(--color-primary-700)] hover:to-[var(--color-primary-600)] text-white border-transparent shadow-md hover:shadow-lg'
}
transition-all duration-200 transform hover:scale-[1.02] active:scale-[0.98]
`}
<div className="pt-4 border-t border-[var(--border-primary)]">
{/* All actions in a clean horizontal layout */}
<div className="flex items-center justify-between gap-2">
{/* Primary action as a subtle text button */}
{primaryActions.length > 0 && (
<button
onClick={primaryActions[0].onClick}
className={`
flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-lg
transition-all duration-200 hover:scale-105 active:scale-95
${primaryActions[0].destructive
? 'text-red-600 hover:bg-red-50 hover:text-red-700'
: 'text-[var(--color-primary-600)] hover:bg-[var(--color-primary-50)] hover:text-[var(--color-primary-700)]'
}
`}
>
{primaryActions[0].icon && React.createElement(primaryActions[0].icon, { className: "w-4 h-4 mr-2" })}
{primaryActions[0].icon && React.createElement(primaryActions[0].icon, { className: "w-4 h-4" })}
<span>{primaryActions[0].label}</span>
</Button>
</button>
)}
{/* Secondary Action Button */}
{primaryActions.length > 1 && (
<Button
variant="outline"
size="md"
className="h-11 w-11 p-0 border-[var(--border-secondary)] hover:border-[var(--color-primary-400)] hover:bg-[var(--color-primary-50)] transition-all duration-200"
onClick={primaryActions[1].onClick}
title={primaryActions[1].label}
>
{primaryActions[1].icon && React.createElement(primaryActions[1].icon, { className: "w-4 h-4" })}
</Button>
)}
</div>
)}
{/* Secondary Actions Row - Smaller buttons */}
{secondaryActions.length > 0 && (
<div className="flex flex-wrap gap-2">
{/* Action icons for secondary actions */}
<div className="flex items-center gap-1">
{secondaryActions.map((action, index) => (
<Button
key={`secondary-${index}`}
variant="outline"
size="sm"
className={`
h-8 px-3 text-xs font-medium border-[var(--border-secondary)]
${action.destructive
? 'text-red-600 border-red-200 hover:bg-red-50 hover:border-red-300'
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:border-[var(--color-primary-300)] hover:bg-[var(--color-primary-50)]'
}
transition-all duration-200 flex items-center gap-1.5
`}
<button
key={`action-${index}`}
onClick={action.onClick}
title={action.label}
className={`
p-2 rounded-lg transition-all duration-200 hover:scale-110 active:scale-95
${action.destructive
? 'text-red-500 hover:bg-red-50 hover:text-red-600'
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--surface-secondary)]'
}
`}
>
{action.icon && React.createElement(action.icon, { className: "w-3.5 h-3.5" })}
<span>{action.label}</span>
</Button>
{action.icon && React.createElement(action.icon, { className: "w-4 h-4" })}
</button>
))}
{/* Include additional primary actions as icons */}
{primaryActions.slice(1).map((action, index) => (
<button
key={`primary-icon-${index}`}
onClick={action.onClick}
title={action.label}
className={`
p-2 rounded-lg transition-all duration-200 hover:scale-110 active:scale-95
${action.destructive
? 'text-red-500 hover:bg-red-50 hover:text-red-600'
: 'text-[var(--color-primary-500)] hover:text-[var(--color-primary-600)] hover:bg-[var(--color-primary-50)]'
}
`}
>
{action.icon && React.createElement(action.icon, { className: "w-4 h-4" })}
</button>
))}
</div>
)}
</div>
</div>
)}
</div>