Compare commits
3 Commits
e7ecbcabc0
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 836a53e95e | |||
| 0623ba903b | |||
| 96bcc975a7 |
@@ -73,6 +73,26 @@ Two properties of the card header are less obvious than they look:
|
||||
Only the 10th-edition and 11th-edition renderers show lore. Leave the
|
||||
9th-edition renderer in `src/9th/` alone. It lays out its header differently.
|
||||
|
||||
## The header has five layers
|
||||
|
||||
The card header stacks the coloured accent bar (1), the model image (2), the
|
||||
name and the stat line (3) and the two lore elements (4, 5). The order comes
|
||||
from the official cards, where a wide image passes *behind* the text. Every
|
||||
layer therefore carries an explicit `z-index`, and the header sets
|
||||
`isolation: isolate` so those five numbers never meet the rest of the card. A
|
||||
new absolutely positioned element in the header needs a number from this scale;
|
||||
without one it lands under the image.
|
||||
|
||||
The name and the stat line are wide, mostly empty boxes, and they now lie over
|
||||
the image. `pointer-events: none` on the box with `auto` on the text inside
|
||||
keeps the drag and the wheel that place the image (`ImgEditor`) reaching it. A
|
||||
new element on layer 3 needs the same treatment, or it takes the pointer away
|
||||
from the image behind it.
|
||||
|
||||
The image box also carries a `mask-image` (`imageFade` in
|
||||
[`src/10th/Roster.jsx`](src/10th/Roster.jsx)). A picture wider than its box
|
||||
would otherwise end at a hard vertical edge in the middle of the stat line.
|
||||
|
||||
## Tests
|
||||
|
||||
The transforms began as three standalone Python scripts
|
||||
|
||||
+34
-7
@@ -26,6 +26,12 @@ import {
|
||||
import { useLore } from "../helpers/useLore";
|
||||
import { HIDE_UNIT_COMPOSITION, ShortSummaryTable } from "../fork";
|
||||
|
||||
// Soft left edge for the model image in the card header. Opaque over the right
|
||||
// two thirds of the image box, so only the part that reaches across the stat
|
||||
// line is faded.
|
||||
const imageFade =
|
||||
"linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.55) 16%, rgba(0,0,0,1) 36%)";
|
||||
|
||||
const getShortSummarySubtitle = (force) => {
|
||||
const details = [];
|
||||
if (force.forceDisposition) {
|
||||
@@ -388,6 +394,9 @@ const Unit = ({
|
||||
backgroundSize: "cover",
|
||||
color: "#fff",
|
||||
position: "relative",
|
||||
// Keeps the header's five layers to itself, so their z-indices
|
||||
// never have to be compared against the rest of the card.
|
||||
isolation: "isolate",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -406,6 +415,11 @@ const Unit = ({
|
||||
top: 0,
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
// The model image sits between this accent bar and the text,
|
||||
// as it does on the official cards. Every layer of the header
|
||||
// therefore needs an explicit z-index: bar 1, image 2, text 3,
|
||||
// lore 4 and 5.
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -446,22 +460,29 @@ const Unit = ({
|
||||
lineHeight: "1",
|
||||
fontWeight: 800,
|
||||
textTransform: "uppercase",
|
||||
zIndex: 1,
|
||||
zIndex: 3,
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 2,
|
||||
// This box is as wide as the card and now lies over the image,
|
||||
// where it would swallow the drag and the wheel that place the
|
||||
// image. Only the glyphs need the pointer.
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<span style={{ pointerEvents: "auto" }}>{name}</span>
|
||||
</div>
|
||||
<div className="relative flex gap-4">
|
||||
<div className="pointer-events-none relative z-[3] flex gap-4">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 6,
|
||||
// See the note on the name above. The stat boxes are narrow,
|
||||
// but the box around them reaches the far edge of the card.
|
||||
pointerEvents: "auto",
|
||||
}}
|
||||
>
|
||||
{modelStats.map((model, index) => (
|
||||
@@ -489,7 +510,7 @@ const Unit = ({
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: "40%",
|
||||
zIndex: 101,
|
||||
zIndex: 4,
|
||||
pointerEvents: "none",
|
||||
background:
|
||||
"linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.55) 40%, rgba(0,0,0,.7) 100%)",
|
||||
@@ -502,7 +523,7 @@ const Unit = ({
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: "29%",
|
||||
zIndex: 102,
|
||||
zIndex: 5,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "30px 14px 14px 6px",
|
||||
@@ -547,8 +568,14 @@ const Unit = ({
|
||||
height: "100%",
|
||||
bottom: 0,
|
||||
width: hasLore ? "40%" : "60%",
|
||||
zIndex: 100,
|
||||
zIndex: 2,
|
||||
overflow: "hidden",
|
||||
// A picture wider than its box would otherwise end at a hard
|
||||
// vertical edge over the stat line. The official cards let it
|
||||
// fade into the dark background instead. The mask fades the
|
||||
// image itself, so the background stays untouched.
|
||||
maskImage: imageFade,
|
||||
WebkitMaskImage: imageFade,
|
||||
}}
|
||||
>
|
||||
{hasImage && <ImgEditor image={image} name={name} />}
|
||||
@@ -1003,7 +1030,7 @@ const InvulRow = ({ hasInvul }) => {
|
||||
backgroundColor: "var(--primary-color)",
|
||||
}}
|
||||
>
|
||||
INVULNERABLE SAVE{isSpecialInvul ? "*" : ""}
|
||||
INSV{isSpecialInvul ? "*" : ""}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 928 KiB |
@@ -208,6 +208,18 @@
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* The cards get cut apart, so the white border around a cut card comes
|
||||
from two different places: the page margin on the outer edges, and
|
||||
half of the gap between two cards on the edges in between. The gap is
|
||||
therefore twice the page margin, and every edge ends up the same. */
|
||||
@page {
|
||||
margin: 8mm;
|
||||
}
|
||||
|
||||
.avoid-page-break {
|
||||
margin-bottom: 16mm !important;
|
||||
}
|
||||
|
||||
.print-display-none,
|
||||
.print-display-none * {
|
||||
display: none !important;
|
||||
|
||||
Reference in New Issue
Block a user