90 lines
3.1 KiB
TypeScript
Executable File
90 lines
3.1 KiB
TypeScript
Executable File
import React from 'react';
|
|
import Button from './Button';
|
|
import { ArrowLeftIcon, ArrowRightIcon } from './icons'; // Assuming these are added to icons.tsx
|
|
|
|
interface NavigableItem {
|
|
id: string;
|
|
title: string;
|
|
}
|
|
|
|
interface ItemDetailNavigationProps {
|
|
previousItem?: NavigableItem;
|
|
nextItem?: NavigableItem;
|
|
onNavigate: (itemId: string) => void;
|
|
previousItemButtonLabel: string;
|
|
nextItemButtonLabel: string;
|
|
noPreviousItemText: string;
|
|
noNextItemText: string;
|
|
themeColorClass?: 'blue' | 'teal' | 'indigo' | 'amber' | 'slate';
|
|
}
|
|
|
|
const ItemDetailNavigation: React.FC<ItemDetailNavigationProps> = ({
|
|
previousItem,
|
|
nextItem,
|
|
onNavigate,
|
|
previousItemButtonLabel,
|
|
nextItemButtonLabel,
|
|
noPreviousItemText,
|
|
noNextItemText,
|
|
themeColorClass = 'slate', // Default theme
|
|
}) => {
|
|
|
|
const themeStyles: Record<string, string> = {
|
|
blue: 'border-blue-500 text-blue-600 hover:bg-blue-50',
|
|
teal: 'border-teal-500 text-teal-600 hover:bg-teal-50',
|
|
indigo: 'border-indigo-500 text-indigo-600 hover:bg-indigo-50',
|
|
amber: 'border-amber-500 text-amber-600 hover:bg-amber-50',
|
|
slate: 'border-slate-400 text-slate-700 hover:bg-slate-100',
|
|
}
|
|
|
|
const buttonBaseClasses = themeStyles[themeColorClass] || themeStyles.slate;
|
|
const disabledClasses = "opacity-50 cursor-not-allowed";
|
|
|
|
return (
|
|
<div className="flex justify-between items-center py-8 my-8 border-t border-b border-slate-200">
|
|
{previousItem ? (
|
|
<Button
|
|
variant="outline"
|
|
size="md"
|
|
onClick={() => onNavigate(previousItem.id)}
|
|
leftIcon={<ArrowLeftIcon className="w-5 h-5" />}
|
|
className={buttonBaseClasses}
|
|
aria-label={`${previousItemButtonLabel}: ${previousItem.title}`}
|
|
>
|
|
<div className="text-left">
|
|
<span className="block text-xs uppercase tracking-wider opacity-75">{previousItemButtonLabel}</span>
|
|
<span className="block font-semibold truncate max-w-[150px] sm:max-w-[200px] md:max-w-[250px]">{previousItem.title}</span>
|
|
</div>
|
|
</Button>
|
|
) : (
|
|
<div className={`flex items-center text-sm text-slate-500 ${disabledClasses}`}>
|
|
<ArrowLeftIcon className="w-5 h-5 mr-2" />
|
|
{noPreviousItemText}
|
|
</div>
|
|
)}
|
|
|
|
{nextItem ? (
|
|
<Button
|
|
variant="outline"
|
|
size="md"
|
|
onClick={() => onNavigate(nextItem.id)}
|
|
rightIcon={<ArrowRightIcon className="w-5 h-5" />}
|
|
className={buttonBaseClasses}
|
|
aria-label={`${nextItemButtonLabel}: ${nextItem.title}`}
|
|
>
|
|
<div className="text-right">
|
|
<span className="block text-xs uppercase tracking-wider opacity-75">{nextItemButtonLabel}</span>
|
|
<span className="block font-semibold truncate max-w-[150px] sm:max-w-[200px] md:max-w-[250px]">{nextItem.title}</span>
|
|
</div>
|
|
</Button>
|
|
) : (
|
|
<div className={`flex items-center text-sm text-slate-500 ${disabledClasses}`}>
|
|
{noNextItemText}
|
|
<ArrowRightIcon className="w-5 h-5 ml-2" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ItemDetailNavigation; |