add manual sorting to unit cards

This commit is contained in:
NilsUeter
2025-04-27 17:20:45 +02:00
parent 0578503235
commit 7949218076
3 changed files with 102 additions and 36 deletions
+75 -12
View File
@@ -60,7 +60,11 @@ export const Roster = ({
const Force = ({ force, onePerPage, colorUserChoice }) => { const Force = ({ force, onePerPage, colorUserChoice }) => {
const { units, factionRules, rules, catalog } = force; const { units, factionRules, rules, catalog } = force;
const mergedRules = new Map([...factionRules, ...rules]); const mergedRules = new Map([...factionRules, ...rules]);
// units with role "Character" are sorted to the top, then "Battleline", then "Other"
// State to manage the order of units
const [unitOrder, setUnitOrder] = useState([]);
useEffect(() => {
const sortedUnits = units.sort((a, b) => { const sortedUnits = units.sort((a, b) => {
if (a.role === "Character" && b.role !== "Character") return -1; if (a.role === "Character" && b.role !== "Character") return -1;
if (a.role !== "Character" && b.role === "Character") return 1; if (a.role !== "Character" && b.role === "Character") return 1;
@@ -68,6 +72,8 @@ const Force = ({ force, onePerPage, colorUserChoice }) => {
if (a.role !== "Battleline" && b.role === "Battleline") return 1; if (a.role !== "Battleline" && b.role === "Battleline") return 1;
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
setUnitOrder(sortedUnits);
}, [units]);
return ( return (
<div <div
@@ -75,30 +81,87 @@ const Force = ({ force, onePerPage, colorUserChoice }) => {
display: "contents", display: "contents",
}} }}
> >
{sortedUnits.map((unit, index) => ( {unitOrder.map((unit, index) => (
<div key={unit.name + index} className="relative">
<div className="flex items-center justify-start gap-1 absolute text-[13px] -top-2.5 z-10 print-display-none">
<button
disabled={index === 0}
type="button"
className="py-0.5 px-1.5 pl-1"
onClick={() =>
// move unit up in the order
setUnitOrder((prevOrder) => {
const newOrder = [...prevOrder];
const unitToMove = newOrder.splice(index, 1)[0];
newOrder.splice(index - 1, 0, unitToMove);
return newOrder;
})
}
>
<svg
viewBox="0 0 24 24"
width={16}
height={16}
fill="#111113"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4V20M12 4L8 8M12 4L16 8"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Up
</button>
<button
disabled={index === unitOrder.length - 1}
type="button"
className="py-0.5 px-1.5 pl-1"
onClick={() =>
// move unit down in the order
setUnitOrder((prevOrder) => {
const newOrder = [...prevOrder];
const unitToMove = newOrder.splice(index, 1)[0];
newOrder.splice(index + 1, 0, unitToMove);
return newOrder;
})
}
>
<svg
viewBox="0 0 24 24"
width={16}
height={16}
fill="#111113"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4V20M12 20L8 16M12 20L16 16"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Down
</button>
</div>
<Unit <Unit
key={unit.name + index}
index={index}
unit={unit} unit={unit}
catalog={catalog} catalog={catalog}
onePerPage={onePerPage} onePerPage={onePerPage}
forceRules={rules} forceRules={rules}
colorUserChoice={colorUserChoice} colorUserChoice={colorUserChoice}
/> />
</div>
))} ))}
<ForceRules rules={mergedRules} onePerPage={onePerPage} /> <ForceRules rules={mergedRules} onePerPage={onePerPage} />
</div> </div>
); );
}; };
const Unit = ({ const Unit = ({ unit, catalog, onePerPage, forceRules, colorUserChoice }) => {
unit,
index,
catalog,
onePerPage,
forceRules,
colorUserChoice,
}) => {
const [hide, setHide] = useState(false); const [hide, setHide] = useState(false);
const [hideModelCount, setHideModelCount] = useState(false); const [hideModelCount, setHideModelCount] = useState(false);
const uploadRef = useRef(); const uploadRef = useRef();
+1 -1
View File
@@ -24,7 +24,7 @@ export const ShortSummaryTable = ({ force, primaryColor, name, points }) => {
const [hide, setHide] = useState(false); const [hide, setHide] = useState(false);
const { units, factionRules, rules, catalog } = force; const { units, factionRules, rules, catalog } = force;
const sortedUnits = units.sort((a, b) => { const sortedUnits = units.slice().sort((a, b) => {
// sort by points cost desc first, then by name // sort by points cost desc first, then by name
if (a.cost.points < b.cost.points) return 1; if (a.cost.points < b.cost.points) return 1;
if (a.cost.points > b.cost.points) return -1; if (a.cost.points > b.cost.points) return -1;
+12 -9
View File
@@ -4,9 +4,8 @@
@layer base { @layer base {
:root { :root {
font-family: font-family: "Noto Sans", sans-serif, Inter, system-ui, Avenir, Helvetica,
"Noto Sans", sans-serif, Inter, system-ui, Avenir, Helvetica, Arial, Arial, sans-serif;
sans-serif;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
font-size: 13px; font-size: 13px;
@@ -80,7 +79,7 @@
font-weight: 500; font-weight: 500;
font-family: inherit; font-family: inherit;
cursor: pointer; cursor: pointer;
transition: border-color 0.25s; transition: border-color 0.15s;
} }
button:hover, button:hover,
.button:hover { .button:hover {
@@ -94,6 +93,13 @@
outline: 4px auto -webkit-focus-ring-color; outline: 4px auto -webkit-focus-ring-color;
} }
button:disabled,
.button[disabled] {
background-color: #f0f0f0;
color: #999;
border-color: #999;
}
.body { .body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -139,11 +145,8 @@
font-size: 1.5rem; font-size: 1.5rem;
text-transform: uppercase; text-transform: uppercase;
cursor: pointer; cursor: pointer;
transition: transition: color 0.15s, border 0.15s, font-size 0.15s, background-color
color 0.25s, 0.15s;
border 0.25s,
font-size 0.25s,
background-color 0.25s;
} }
.rosterUpload:hover { .rosterUpload:hover {