mirror of
https://github.com/sakaljurgis/best-choice.git
synced 2026-07-08 21:47:40 +00:00
Add toggle for larger item images
This commit is contained in:
@@ -3,13 +3,14 @@ import { useState } from 'react';
|
|||||||
interface ItemThumbnailProps {
|
interface ItemThumbnailProps {
|
||||||
url: string | null;
|
url: string | null;
|
||||||
alt: string;
|
alt: string;
|
||||||
size?: 'sm' | 'md';
|
size?: 'sm' | 'md' | 'lg';
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeClassMap: Record<Required<ItemThumbnailProps>['size'], string> = {
|
const sizeClassMap: Record<Required<ItemThumbnailProps>['size'], string> = {
|
||||||
sm: 'h-14 w-14',
|
sm: 'h-14 w-14',
|
||||||
md: 'h-20 w-20'
|
md: 'h-20 w-20',
|
||||||
|
lg: 'h-28 w-28'
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ItemThumbnail({ url, alt, size = 'sm', onClick }: ItemThumbnailProps) {
|
export function ItemThumbnail({ url, alt, size = 'sm', onClick }: ItemThumbnailProps) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface ProjectItemsDesktopTableProps {
|
|||||||
onEditItem: (item: Item) => void;
|
onEditItem: (item: Item) => void;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
onViewItemImages: (item: Item) => void;
|
onViewItemImages: (item: Item) => void;
|
||||||
|
showLargeImages: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProjectItemsDesktopTable({
|
export function ProjectItemsDesktopTable({
|
||||||
@@ -22,7 +23,8 @@ export function ProjectItemsDesktopTable({
|
|||||||
onTogglePrices,
|
onTogglePrices,
|
||||||
onEditItem,
|
onEditItem,
|
||||||
projectId,
|
projectId,
|
||||||
onViewItemImages
|
onViewItemImages,
|
||||||
|
showLargeImages
|
||||||
}: ProjectItemsDesktopTableProps) {
|
}: ProjectItemsDesktopTableProps) {
|
||||||
return (
|
return (
|
||||||
<div className="hidden md:block">
|
<div className="hidden md:block">
|
||||||
@@ -64,7 +66,7 @@ export function ProjectItemsDesktopTable({
|
|||||||
<ItemThumbnail
|
<ItemThumbnail
|
||||||
url={item.defaultImageUrl}
|
url={item.defaultImageUrl}
|
||||||
alt={displayName}
|
alt={displayName}
|
||||||
size="sm"
|
size={showLargeImages ? 'md' : 'sm'}
|
||||||
onClick={() => onViewItemImages(item)}
|
onClick={() => onViewItemImages(item)}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-1 flex-col gap-1">
|
<div className="flex flex-1 flex-col gap-1">
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ interface ProjectItemsHeaderProps {
|
|||||||
showDifferencesOnly: boolean;
|
showDifferencesOnly: boolean;
|
||||||
hasAttributeDifferences: boolean;
|
hasAttributeDifferences: boolean;
|
||||||
onToggleDifferences: (value: boolean) => void;
|
onToggleDifferences: (value: boolean) => void;
|
||||||
|
showLargeImages: boolean;
|
||||||
|
onToggleLargeImages: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProjectItemsHeader({
|
export function ProjectItemsHeader({
|
||||||
@@ -11,7 +13,9 @@ export function ProjectItemsHeader({
|
|||||||
isLoading,
|
isLoading,
|
||||||
showDifferencesOnly,
|
showDifferencesOnly,
|
||||||
hasAttributeDifferences,
|
hasAttributeDifferences,
|
||||||
onToggleDifferences
|
onToggleDifferences,
|
||||||
|
showLargeImages,
|
||||||
|
onToggleLargeImages
|
||||||
}: ProjectItemsHeaderProps) {
|
}: ProjectItemsHeaderProps) {
|
||||||
const subtitle = isLoading
|
const subtitle = isLoading
|
||||||
? 'Loading items…'
|
? 'Loading items…'
|
||||||
@@ -25,16 +29,27 @@ export function ProjectItemsHeader({
|
|||||||
<h2 className="text-xl font-semibold text-slate-900">Items</h2>
|
<h2 className="text-xl font-semibold text-slate-900">Items</h2>
|
||||||
<p className="text-sm text-slate-500">{subtitle}</p>
|
<p className="text-sm text-slate-500">{subtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
<label className="flex items-center gap-2 text-xs font-medium uppercase tracking-wide text-slate-500">
|
<div className="flex flex-col gap-3 text-xs font-medium uppercase tracking-wide text-slate-500 md:flex-row md:items-center md:gap-6">
|
||||||
<input
|
<label className="flex items-center gap-2">
|
||||||
type="checkbox"
|
<input
|
||||||
className="h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed disabled:border-slate-200 disabled:text-slate-300"
|
type="checkbox"
|
||||||
checked={showDifferencesOnly}
|
className="h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed disabled:border-slate-200 disabled:text-slate-300"
|
||||||
onChange={(event) => onToggleDifferences(event.target.checked)}
|
checked={showDifferencesOnly}
|
||||||
disabled={!hasAttributeDifferences}
|
onChange={(event) => onToggleDifferences(event.target.checked)}
|
||||||
/>
|
disabled={!hasAttributeDifferences}
|
||||||
Show differences only
|
/>
|
||||||
</label>
|
Show differences only
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500"
|
||||||
|
checked={showLargeImages}
|
||||||
|
onChange={(event) => onToggleLargeImages(event.target.checked)}
|
||||||
|
/>
|
||||||
|
Larger images
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ interface ProjectItemsMobileListProps {
|
|||||||
onEditItem: (item: Item) => void;
|
onEditItem: (item: Item) => void;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
onViewItemImages: (item: Item) => void;
|
onViewItemImages: (item: Item) => void;
|
||||||
|
showLargeImages: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProjectItemsMobileList({
|
export function ProjectItemsMobileList({
|
||||||
@@ -21,7 +22,8 @@ export function ProjectItemsMobileList({
|
|||||||
onTogglePrices,
|
onTogglePrices,
|
||||||
onEditItem,
|
onEditItem,
|
||||||
projectId,
|
projectId,
|
||||||
onViewItemImages
|
onViewItemImages,
|
||||||
|
showLargeImages
|
||||||
}: ProjectItemsMobileListProps) {
|
}: ProjectItemsMobileListProps) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 md:hidden">
|
<div className="space-y-4 md:hidden">
|
||||||
@@ -38,7 +40,7 @@ export function ProjectItemsMobileList({
|
|||||||
<ItemThumbnail
|
<ItemThumbnail
|
||||||
url={item.defaultImageUrl}
|
url={item.defaultImageUrl}
|
||||||
alt={displayName}
|
alt={displayName}
|
||||||
size="md"
|
size={showLargeImages ? 'lg' : 'md'}
|
||||||
onClick={() => onViewItemImages(item)}
|
onClick={() => onViewItemImages(item)}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-1 flex-col gap-2">
|
<div className="flex flex-1 flex-col gap-2">
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export function ProjectItemsSection({
|
|||||||
}: ProjectItemsSectionProps) {
|
}: ProjectItemsSectionProps) {
|
||||||
const [showDifferencesOnly, setShowDifferencesOnly] = useState(false);
|
const [showDifferencesOnly, setShowDifferencesOnly] = useState(false);
|
||||||
const [expandedItemId, setExpandedItemId] = useState<string | null>(null);
|
const [expandedItemId, setExpandedItemId] = useState<string | null>(null);
|
||||||
|
const [showLargeImages, setShowLargeImages] = useState(false);
|
||||||
|
|
||||||
const mismatchedAttributes = useMemo(() => {
|
const mismatchedAttributes = useMemo(() => {
|
||||||
const result = new Set<string>();
|
const result = new Set<string>();
|
||||||
@@ -117,6 +118,8 @@ export function ProjectItemsSection({
|
|||||||
showDifferencesOnly={showDifferencesOnly}
|
showDifferencesOnly={showDifferencesOnly}
|
||||||
hasAttributeDifferences={hasAttributeDifferences}
|
hasAttributeDifferences={hasAttributeDifferences}
|
||||||
onToggleDifferences={(value) => setShowDifferencesOnly(value)}
|
onToggleDifferences={(value) => setShowDifferencesOnly(value)}
|
||||||
|
showLargeImages={showLargeImages}
|
||||||
|
onToggleLargeImages={(value) => setShowLargeImages(value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{error ? (
|
{error ? (
|
||||||
@@ -137,6 +140,7 @@ export function ProjectItemsSection({
|
|||||||
onEditItem={onEditItem}
|
onEditItem={onEditItem}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
onViewItemImages={onViewItemImages}
|
onViewItemImages={onViewItemImages}
|
||||||
|
showLargeImages={showLargeImages}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProjectItemsMobileList
|
<ProjectItemsMobileList
|
||||||
@@ -147,6 +151,7 @@ export function ProjectItemsSection({
|
|||||||
onEditItem={onEditItem}
|
onEditItem={onEditItem}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
onViewItemImages={onViewItemImages}
|
onViewItemImages={onViewItemImages}
|
||||||
|
showLargeImages={showLargeImages}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user