Spaces:
Running
Running
Commit ·
2b58a06
1
Parent(s): d15d3e1
updates
Browse files
frontend/src/components/PitchView.jsx
CHANGED
|
@@ -33,45 +33,66 @@ export const PitchView = ({
|
|
| 33 |
</div>
|
| 34 |
|
| 35 |
{/* STARTERS */}
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
</div>
|
| 67 |
</div>
|
| 68 |
|
| 69 |
{/* BENCH */}
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
| 75 |
{teamData.slice(11, 15).map((p, benchIndex) => (
|
| 76 |
<DraggablePlayer
|
| 77 |
key={p.ID}
|
|
@@ -95,6 +116,7 @@ export const PitchView = ({
|
|
| 95 |
))}
|
| 96 |
</div>
|
| 97 |
</div>
|
|
|
|
| 98 |
</div>
|
| 99 |
);
|
| 100 |
};
|
|
|
|
| 33 |
</div>
|
| 34 |
|
| 35 |
{/* STARTERS */}
|
| 36 |
+
{/*
|
| 37 |
+
Mobile scaling strategy:
|
| 38 |
+
- We wrap the entire starters grid in a scaler div that uses CSS transform: scale()
|
| 39 |
+
This lets every card, label, EV number, and gap shrink proportionally as one unit —
|
| 40 |
+
no individual element needs touching. The outer div reserves the correct height via
|
| 41 |
+
a paddingBottom trick so the layout below (bench) isn't eaten by the scaled content.
|
| 42 |
+
- On xs phones (~390px) we scale to ~0.72. On slightly larger phones (430px) ~0.80.
|
| 43 |
+
sm (640px+) gets scale-100, desktop is untouched.
|
| 44 |
+
- overflow-hidden on the parent already clips any tiny bleed.
|
| 45 |
+
*/}
|
| 46 |
+
<div className="flex-1 w-full relative">
|
| 47 |
+
{/* scale-wrapper: origin top-center so rows stay centred; scale via CSS var */}
|
| 48 |
+
<div
|
| 49 |
+
className="absolute inset-0 flex flex-col justify-evenly gap-y-4 sm:gap-y-10 z-10 pt-6 sm:pt-8 pb-10 sm:pb-12 px-2 sm:px-4"
|
| 50 |
+
style={{
|
| 51 |
+
// CSS custom property lets us animate or override easily
|
| 52 |
+
transformOrigin: "top center",
|
| 53 |
+
}}
|
| 54 |
+
>
|
| 55 |
+
{/* Inner wrapper that actually scales on small screens */}
|
| 56 |
+
<div className="w-full h-full flex flex-col justify-evenly [transform:scale(0.72)] xs:[transform:scale(0.80)] sm:[transform:scale(1)] origin-top">
|
| 57 |
+
{["G", "D", "M", "F"].map((pos) => {
|
| 58 |
+
const rowPlayers = teamData.slice(0, 11).filter((p) => p.Pos === pos);
|
| 59 |
+
if (rowPlayers.length === 0) return null;
|
| 60 |
+
return (
|
| 61 |
+
<div key={pos} className="flex justify-center gap-8 sm:gap-8 md:gap-12 xl:gap-16 w-full px-2">
|
| 62 |
+
{rowPlayers.map((p) => (
|
| 63 |
+
<DraggablePlayer
|
| 64 |
+
key={p.ID}
|
| 65 |
+
player={p}
|
| 66 |
+
isBench={false}
|
| 67 |
+
isActiveDrag={activeDragPlayer !== null}
|
| 68 |
+
isValidTarget={isValidSwap(activeDragPlayer, p)}
|
| 69 |
+
captainId={captainId}
|
| 70 |
+
viceId={viceId}
|
| 71 |
+
handleCapChange={handleCapChange}
|
| 72 |
+
playerCardGWs={playerCardGWs}
|
| 73 |
+
fixtures={fixtures}
|
| 74 |
+
activeGW={activeGW}
|
| 75 |
+
onPlayerClick={(player) => setSelectedPlayer(player)}
|
| 76 |
+
onUndo={handleUndoTransfer}
|
| 77 |
+
isHighlighted={Array.from(highlightTransferIds[activeGW] || []).includes(p.ID)}
|
| 78 |
+
onSolverUndo={(solverTransferPairs[activeGW] || {})[p.ID] ? () => resetHighlightedTransfer(p) : undefined}
|
| 79 |
+
activeChipType={chipsByGw[activeGW]}
|
| 80 |
+
/>
|
| 81 |
+
))}
|
| 82 |
+
</div>
|
| 83 |
+
);
|
| 84 |
+
})}
|
| 85 |
+
</div>
|
| 86 |
</div>
|
| 87 |
</div>
|
| 88 |
|
| 89 |
{/* BENCH */}
|
| 90 |
+
<div
|
| 91 |
+
className={`mt-auto w-full border-t-2 z-10 transition-colors duration-300 ${chipsByGw[activeGW] === "bb" ? "bg-emerald-950/60 border-emerald-500/50 shadow-[0_0_24px_rgba(16,185,129,0.2)]" : "bg-slate-950/90 border-slate-800"}`}
|
| 92 |
+
>
|
| 93 |
+
{/* Same scale treatment for bench row */}
|
| 94 |
+
<div className="min-h-[120px] sm:min-h-[160px] md:min-h-[180px] mx-auto flex justify-center items-center pb-10 pt-6 px-4 overflow-hidden">
|
| 95 |
+
<div className="flex justify-center items-center gap-8 sm:gap-8 md:gap-12 xl:gap-16 [transform:scale(0.72)] xs:[transform:scale(0.80)] sm:[transform:scale(1)] origin-center">
|
| 96 |
{teamData.slice(11, 15).map((p, benchIndex) => (
|
| 97 |
<DraggablePlayer
|
| 98 |
key={p.ID}
|
|
|
|
| 116 |
))}
|
| 117 |
</div>
|
| 118 |
</div>
|
| 119 |
+
</div>
|
| 120 |
</div>
|
| 121 |
);
|
| 122 |
};
|
frontend/src/components/PlayerCardVisual.jsx
CHANGED
|
@@ -148,7 +148,7 @@ export const PlayerCardVisual = ({
|
|
| 148 |
// 1. Removed outer borders entirely to kill the "double bar" glitch.
|
| 149 |
// 2. Lifted them slightly higher (-translate-y-3).
|
| 150 |
// 3. Added a heavy, static cast shadow on the grass below them so the brain instantly registers the 3D levitation!
|
| 151 |
-
className={`relative w-[64px] sm:w-[76px] md:w-[88px] h-[85px] sm:h-[105px] md:h-[120px] flex flex-col items-center justify-end rounded-[10px] cursor-grab transition-transform duration-200 transform-gpu origin-bottom
|
| 152 |
${isTransferIn
|
| 153 |
? "bg-gradient-to-t from-cyan-900/60 via-cyan-900/5 to-transparent -translate-y-3 shadow-[0_25px_20px_-10px_rgba(0,0,0,0.8)] z-30"
|
| 154 |
: "bg-transparent border border-transparent hover:border-slate-700/50 z-10"
|
|
@@ -229,6 +229,13 @@ export const PlayerCardVisual = ({
|
|
| 229 |
/>
|
| 230 |
)}
|
| 231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
<div
|
| 233 |
draggable="false"
|
| 234 |
className={`absolute bottom-[-24px] sm:bottom-[-28px] w-[135%] flex flex-col items-center z-30 pointer-events-none ${isBench ? "opacity-80" : "opacity-100"}`}
|
|
@@ -237,20 +244,20 @@ export const PlayerCardVisual = ({
|
|
| 237 |
{player.Name}
|
| 238 |
</div>
|
| 239 |
|
| 240 |
-
<div className="w-full bg-slate-200 border-x border-slate-700 flex justify-center items-center gap-1
|
| 241 |
-
<span className={`text-[
|
| 242 |
{isBlankThisGw ? "-" : (player[`${activeGW}_xMins`] ?? 90)}{" "}
|
| 243 |
-
<span className="text-[
|
| 244 |
-
|
| 245 |
</span>
|
| 246 |
</span>
|
| 247 |
-
<span className="text-slate-400 font-light text-[10px]">|</span>
|
| 248 |
-
<span className="text-[
|
| 249 |
£{getPlayerPrice(player).toFixed(1)}
|
| 250 |
</span>
|
| 251 |
</div>
|
| 252 |
<div
|
| 253 |
-
className="w-full bg-slate-900 border-x border-b border-slate-700 flex items-center rounded-b shadow-md h-[21px] px-0.5 overflow-hidden"
|
| 254 |
>
|
| 255 |
<div className="flex items-center justify-center w-full whitespace-nowrap overflow-hidden text-ellipsis">
|
| 256 |
{renderFixtures(player.Team, activeGW)}
|
|
|
|
| 148 |
// 1. Removed outer borders entirely to kill the "double bar" glitch.
|
| 149 |
// 2. Lifted them slightly higher (-translate-y-3).
|
| 150 |
// 3. Added a heavy, static cast shadow on the grass below them so the brain instantly registers the 3D levitation!
|
| 151 |
+
className={`relative w-[64px] sm:w-[76px] md:w-[88px] h-[85px] sm:h-[105px] md:h-[120px] flex flex-col items-center justify-end rounded-[10px] cursor-grab transition-transform duration-200 transform-gpu origin-bottom overflow-visible
|
| 152 |
${isTransferIn
|
| 153 |
? "bg-gradient-to-t from-cyan-900/60 via-cyan-900/5 to-transparent -translate-y-3 shadow-[0_25px_20px_-10px_rgba(0,0,0,0.8)] z-30"
|
| 154 |
: "bg-transparent border border-transparent hover:border-slate-700/50 z-10"
|
|
|
|
| 229 |
/>
|
| 230 |
)}
|
| 231 |
|
| 232 |
+
{/*
|
| 233 |
+
Label strip: sits below the card image. Uses bottom-[-24px] to float under the photo.
|
| 234 |
+
w-[135%] gives it breathing room for the name. overflow-visible on the card wrapper
|
| 235 |
+
(set above) means this never gets clipped by the card bounds — it was already working
|
| 236 |
+
fine on desktop; we just need to make sure the parent chain doesn't add overflow:hidden.
|
| 237 |
+
The scale() wrapper in PitchView shrinks everything uniformly so these offsets scale too.
|
| 238 |
+
*/}
|
| 239 |
<div
|
| 240 |
draggable="false"
|
| 241 |
className={`absolute bottom-[-24px] sm:bottom-[-28px] w-[135%] flex flex-col items-center z-30 pointer-events-none ${isBench ? "opacity-80" : "opacity-100"}`}
|
|
|
|
| 244 |
{player.Name}
|
| 245 |
</div>
|
| 246 |
|
| 247 |
+
<div className="w-full bg-slate-200 border-x border-slate-700 flex justify-center items-center gap-1 sm:gap-2 py-[2.5px] shadow-inner">
|
| 248 |
+
<span className={`text-[9px] sm:text-xs font-black flex items-baseline gap-0.5 ${isBlankThisGw ? 'text-slate-400' : 'text-slate-800'}`}>
|
| 249 |
{isBlankThisGw ? "-" : (player[`${activeGW}_xMins`] ?? 90)}{" "}
|
| 250 |
+
<span className="text-[6px] sm:text-[8px] font-bold text-slate-500 uppercase tracking-tight">
|
| 251 |
+
xM
|
| 252 |
</span>
|
| 253 |
</span>
|
| 254 |
+
<span className="text-slate-400 font-light text-[9px] sm:text-[10px]">|</span>
|
| 255 |
+
<span className="text-[9px] sm:text-xs font-black text-emerald-700">
|
| 256 |
£{getPlayerPrice(player).toFixed(1)}
|
| 257 |
</span>
|
| 258 |
</div>
|
| 259 |
<div
|
| 260 |
+
className="w-full bg-slate-900 border-x border-b border-slate-700 flex items-center rounded-b shadow-md h-[18px] sm:h-[21px] px-0.5 overflow-hidden"
|
| 261 |
>
|
| 262 |
<div className="flex items-center justify-center w-full whitespace-nowrap overflow-hidden text-ellipsis">
|
| 263 |
{renderFixtures(player.Team, activeGW)}
|