feat: Introduce card size slider for unified scaling across grid and stack views, and add smart preview suppression.
This commit is contained in:
@@ -125,8 +125,17 @@ export const CardHoverWrapper: React.FC<{ card: DraftCard; children: React.React
|
||||
setCoords({ x: e.clientX, y: e.clientY });
|
||||
};
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (!isMobile) setIsHovering(true);
|
||||
const handleMouseEnter = (e: React.MouseEvent) => {
|
||||
if (isMobile) return;
|
||||
|
||||
// Check if the card is already "big enough" on screen
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
// Width > 240 && Height > 300 targets large grid items but excludes thin list rows
|
||||
if (rect.width > 240 && rect.height > 300) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsHovering(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { StackView } from './StackView';
|
||||
interface PackCardProps {
|
||||
pack: Pack;
|
||||
viewMode: 'list' | 'grid' | 'stack';
|
||||
cardWidth?: number;
|
||||
}
|
||||
|
||||
import { CardHoverWrapper, FoilOverlay } from './CardPreview';
|
||||
@@ -41,7 +42,7 @@ const ListItem: React.FC<{ card: DraftCard }> = ({ card }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const PackCard: React.FC<PackCardProps> = ({ pack, viewMode }) => {
|
||||
export const PackCard: React.FC<PackCardProps> = ({ pack, viewMode, cardWidth = 150 }) => {
|
||||
const mythics = pack.cards.filter(c => c.rarity === 'mythic');
|
||||
const rares = pack.cards.filter(c => c.rarity === 'rare');
|
||||
const uncommons = pack.cards.filter(c => c.rarity === 'uncommon');
|
||||
@@ -97,10 +98,10 @@ export const PackCard: React.FC<PackCardProps> = ({ pack, viewMode }) => {
|
||||
)}
|
||||
|
||||
{viewMode === 'grid' && (
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3">
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{pack.cards.map((card) => (
|
||||
<CardHoverWrapper key={card.id} card={card}>
|
||||
<div className="relative group bg-slate-900 rounded-lg">
|
||||
<div style={{ width: cardWidth }} className="relative group bg-slate-900 rounded-lg shrink-0">
|
||||
{/* Visual Card */}
|
||||
<div className={`relative aspect-[2.5/3.5] overflow-hidden rounded-lg shadow-xl border transition-all duration-200 group-hover:ring-2 group-hover:ring-purple-400 group-hover:shadow-purple-500/30 cursor-pointer ${isFoil(card) ? 'border-purple-400 shadow-purple-500/20' : 'border-slate-800'}`}>
|
||||
{isFoil(card) && <FoilOverlay />}
|
||||
@@ -126,7 +127,7 @@ export const PackCard: React.FC<PackCardProps> = ({ pack, viewMode }) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{viewMode === 'stack' && <StackView cards={pack.cards} />}
|
||||
{viewMode === 'stack' && <StackView cards={pack.cards} cardWidth={cardWidth} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CardHoverWrapper, FoilOverlay } from './CardPreview';
|
||||
|
||||
interface StackViewProps {
|
||||
cards: DraftCard[];
|
||||
cardWidth?: number;
|
||||
}
|
||||
|
||||
const CATEGORY_ORDER = [
|
||||
@@ -18,7 +19,7 @@ const CATEGORY_ORDER = [
|
||||
'Other'
|
||||
];
|
||||
|
||||
export const StackView: React.FC<StackViewProps> = ({ cards }) => {
|
||||
export const StackView: React.FC<StackViewProps> = ({ cards, cardWidth = 150 }) => {
|
||||
|
||||
const categorizedCards = useMemo(() => {
|
||||
const categories: Record<string, DraftCard[]> = {};
|
||||
@@ -59,7 +60,7 @@ export const StackView: React.FC<StackViewProps> = ({ cards }) => {
|
||||
if (catCards.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div key={category} className="flex-shrink-0 w-44 snap-start">
|
||||
<div key={category} className="flex-shrink-0 snap-start" style={{ width: cardWidth }}>
|
||||
{/* Header */}
|
||||
<div className="flex justify-between items-center mb-2 px-1 border-b border-slate-700 pb-1">
|
||||
<span className="text-xs font-bold text-slate-400 uppercase tracking-wider">{category}</span>
|
||||
|
||||
@@ -101,6 +101,11 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
||||
return saved ? parseInt(saved) : 3;
|
||||
});
|
||||
|
||||
const [cardWidth, setCardWidth] = useState(() => {
|
||||
const saved = localStorage.getItem('cube_cardWidth');
|
||||
return saved ? parseInt(saved) : 140;
|
||||
});
|
||||
|
||||
// --- Persistence Effects ---
|
||||
useEffect(() => localStorage.setItem('cube_inputText', inputText), [inputText]);
|
||||
useEffect(() => localStorage.setItem('cube_filters', JSON.stringify(filters)), [filters]);
|
||||
@@ -108,6 +113,7 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
||||
useEffect(() => localStorage.setItem('cube_sourceMode', sourceMode), [sourceMode]);
|
||||
useEffect(() => localStorage.setItem('cube_selectedSets', JSON.stringify(selectedSets)), [selectedSets]);
|
||||
useEffect(() => localStorage.setItem('cube_numBoxes', numBoxes.toString()), [numBoxes]);
|
||||
useEffect(() => localStorage.setItem('cube_cardWidth', cardWidth.toString()), [cardWidth]);
|
||||
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -660,6 +666,22 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
||||
{copySuccess ? <Check className="w-4 h-4 text-emerald-400" /> : <Copy className="w-4 h-4" />}
|
||||
<span className="hidden sm:inline">{copySuccess ? 'Copied!' : 'Copy'}</span>
|
||||
</button>
|
||||
|
||||
{/* Size Slider */}
|
||||
<div className="flex items-center gap-2 bg-slate-800 rounded-lg px-2 py-1 border border-slate-700 h-9 mr-2 hidden sm:flex">
|
||||
<div className="w-3 h-4 rounded border border-slate-500 bg-slate-700" title="Small Cards" />
|
||||
<input
|
||||
type="range"
|
||||
min="100"
|
||||
max="300"
|
||||
step="10"
|
||||
value={cardWidth}
|
||||
onChange={(e) => setCardWidth(parseInt(e.target.value))}
|
||||
className="w-24 accent-purple-500 cursor-pointer h-1.5 bg-slate-600 rounded-lg appearance-none"
|
||||
title={`Card Size: ${cardWidth}px`}
|
||||
/>
|
||||
<div className="w-4 h-6 rounded border border-slate-500 bg-slate-700" title="Large Cards" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -679,7 +701,7 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
||||
) : (
|
||||
<div className="grid grid-cols-1 gap-6 pb-20">
|
||||
{packs.map((pack) => (
|
||||
<PackCard key={pack.id} pack={pack} viewMode={viewMode} />
|
||||
<PackCard key={pack.id} pack={pack} viewMode={viewMode} cardWidth={cardWidth} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user