AnayShukla commited on
Commit
2b58a06
·
1 Parent(s): d15d3e1
frontend/src/components/PitchView.jsx CHANGED
@@ -33,45 +33,66 @@ export const PitchView = ({
33
  </div>
34
 
35
  {/* STARTERS */}
36
- <div className="flex-1 w-full overflow-x-auto custom-scrollbar">
37
- <div className="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 min-w-max sm:min-w-0 min-h-full h-full mx-auto">
38
- {["G", "D", "M", "F"].map((pos) => {
39
- const rowPlayers = teamData.slice(0, 11).filter((p) => p.Pos === pos);
40
- if (rowPlayers.length === 0) return null;
41
- return (
42
- <div key={pos} className="flex justify-center gap-[26px] sm:gap-8 md:gap-12 xl:gap-16 w-full px-2">
43
- {rowPlayers.map((p) => (
44
- <DraggablePlayer
45
- key={p.ID}
46
- player={p}
47
- isBench={false}
48
- isActiveDrag={activeDragPlayer !== null}
49
- isValidTarget={isValidSwap(activeDragPlayer, p)}
50
- captainId={captainId}
51
- viceId={viceId}
52
- handleCapChange={handleCapChange}
53
- playerCardGWs={playerCardGWs}
54
- fixtures={fixtures}
55
- activeGW={activeGW}
56
- onPlayerClick={(player) => setSelectedPlayer(player)}
57
- onUndo={handleUndoTransfer}
58
- isHighlighted={Array.from(highlightTransferIds[activeGW] || []).includes(p.ID)}
59
- onSolverUndo={(solverTransferPairs[activeGW] || {})[p.ID] ? () => resetHighlightedTransfer(p) : undefined}
60
- activeChipType={chipsByGw[activeGW]}
61
- />
62
- ))}
63
- </div>
64
- );
65
- })}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  </div>
67
  </div>
68
 
69
  {/* BENCH */}
70
- <div
71
- className={`mt-auto w-full border-t-2 z-10 transition-colors duration-300 overflow-x-auto custom-scrollbar ${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"
72
- }`}
73
- >
74
- <div className="min-h-[140px] sm:min-h-[160px] md:min-h-[180px] min-w-max sm:min-w-0 mx-auto flex justify-center items-center gap-[26px] sm:gap-8 md:gap-12 xl:gap-16 pb-10 pt-6 px-4">
 
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.5 sm:gap-2 py-[2.5px] shadow-inner">
241
- <span className={`text-[10px] sm:text-xs font-black flex items-baseline gap-0.5 ${isBlankThisGw ? 'text-slate-400' : 'text-slate-800'}`}>
242
  {isBlankThisGw ? "-" : (player[`${activeGW}_xMins`] ?? 90)}{" "}
243
- <span className="text-[7px] sm:text-[8px] font-bold text-slate-500 uppercase tracking-tight">
244
- xMins
245
  </span>
246
  </span>
247
- <span className="text-slate-400 font-light text-[10px]">|</span>
248
- <span className="text-[10px] sm:text-xs font-black text-emerald-700">
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)}