enable upload of own images

This commit is contained in:
NilsUeter
2023-06-07 18:41:09 +02:00
parent 12ae008e9c
commit b20470dc5c
6 changed files with 112 additions and 14 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+79 -11
View File
@@ -1,4 +1,4 @@
import { useState } from "react"; import { useRef, useState, useEffect } from "react";
import factionBackground from "./assets/factionBackground.png"; import factionBackground from "./assets/factionBackground.png";
import adeptusAstartesIcon from "./assets/adeptusAstartesIcon.png"; import adeptusAstartesIcon from "./assets/adeptusAstartesIcon.png";
import rangedIcon from "./assets/rangedIcon.png"; import rangedIcon from "./assets/rangedIcon.png";
@@ -63,6 +63,8 @@ const Force = ({ force, onePerPage }) => {
const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => { const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
const [hide, setHide] = useState(false); const [hide, setHide] = useState(false);
const uploadRef = useRef();
const [image, setImage] = useState(null);
let { let {
name, name,
weapons, weapons,
@@ -118,6 +120,20 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
const overridePrimary = getOverridePrimary(factions, keywords); const overridePrimary = getOverridePrimary(factions, keywords);
useEffect(() => {
// Check if the browser is Safari, and if so, remove the accept attribute
// from the file input element. This is because Safari doesn't support
// extensions on the accept attribute for input type=file
// (https://caniuse.com/input-file-accept). If set, they will not allow any
// file to be selected.
if (
navigator.userAgent.match(/AppleWebKit.*Safari/) &&
!navigator.userAgent.includes("Chrome")
) {
uploadRef.current?.removeAttribute("accept");
}
}, []);
return ( return (
<div <div
className={ className={
@@ -153,6 +169,8 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
background: background:
"linear-gradient(90deg, rgba(20,21,25,1) 0%, rgba(48,57,62,1) 45%, rgba(73,74,79,1) 100%)", "linear-gradient(90deg, rgba(20,21,25,1) 0%, rgba(48,57,62,1) 45%, rgba(73,74,79,1) 100%)",
color: "#fff", color: "#fff",
minHeight: 200,
position: "relative",
}} }}
> >
<div <div
@@ -203,7 +221,10 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
</div> </div>
<div <div
style={{ style={{
fontSize: "1.7em", fontFamily: "ConduitITCStd",
fontSize: "2.5em",
letterSpacing: "1px",
lineHeight: "1",
fontWeight: 800, fontWeight: 800,
textTransform: "uppercase", textTransform: "uppercase",
zIndex: 1, zIndex: 1,
@@ -211,10 +232,11 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
alignItems: "center", alignItems: "center",
marginBottom: 2,
}} }}
> >
{name} {name}
<span style={{ textTransform: "initial", fontSize: "1.1rem" }}> <span style={{ textTransform: "initial", fontSize: "1.2rem" }}>
{cost.points}pts {cost.points}pts
</span> </span>
</div> </div>
@@ -241,9 +263,62 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
} }
/> />
))} ))}
<WoundTracker woundTracker={woundTracker} /> <WoundTracker woundTracker={woundTracker} />
</div> </div>
</div> </div>
<div
style={{
position: "absolute",
right: 0,
top: 0,
height: "100%",
bottom: 0,
width: "50%",
}}
>
{image && (
<img
src={image}
alt=""
style={{ width: "100%", height: "100%", objectFit: "contain" }}
/>
)}
<label
className="button print-display-none"
style={{
position: "absolute",
top: 0,
right: 0,
border: "1px solid #999",
top: 1,
right: 1,
padding: "1px 4px",
fontSize: "0.8rem",
backgroundColor: "#f0f0f0",
}}
>
<input
ref={uploadRef}
type="file"
className="print-display-none"
accept=".jpg,.png,.jpeg,.gif,.bmp,.tif,.tiff,.webp,.svg,.jfif,.pjpeg,.pjp,.avif,.apng,.ico,.cur,.ani"
onChange={(e) => {
if (e.target.files && e.target.files[0]) {
let reader = new FileReader();
reader.onload = function (ev) {
setImage(ev.target.result);
}.bind(this);
reader.readAsDataURL(e.target.files[0]);
}
}}
style={{
display: "none",
}}
/>
Upload image
</label>
</div>
</div> </div>
<div <div
style={{ style={{
@@ -358,14 +433,7 @@ const Unit = ({ unit, index, catalog, onePerPage, forceRules }) => {
); );
}; };
const ModelStats = ({ const ModelStats = ({ modelStat, index, showName, showWeapons, modelList }) => {
modelStats,
modelStat,
index,
showName,
showWeapons,
modelList,
}) => {
let { move, toughness, save, wounds, leadership, name, bs, ws, attacks } = let { move, toughness, save, wounds, leadership, name, bs, ws, attacks } =
modelStat; modelStat;
if (!wounds) { if (!wounds) {
+8
View File
@@ -112,6 +112,7 @@ const Weapon = ({ weapon, modelStats, isMelee, className, forceRules }) => {
replaceAbilityWithType( replaceAbilityWithType(
[ [
"Each time an attack is made with this weapon, that attack automatically hits the target.", "Each time an attack is made with this weapon, that attack automatically hits the target.",
"Each time an attack is made with this weapon profile, that attack automatically hits the target.",
"This weapon automatically hits its target.", "This weapon automatically hits its target.",
"This weapon automatically hits its targets.", "This weapon automatically hits its targets.",
"When resolving an attack made with this weapon, do not make a hit roll: it automatically scores a hit.", "When resolving an attack made with this weapon, do not make a hit roll: it automatically scores a hit.",
@@ -119,6 +120,13 @@ const Weapon = ({ weapon, modelStats, isMelee, className, forceRules }) => {
"Torrent", "Torrent",
"When resolving an attack made with this weapon, do not make a hit roll: it automatically scores a hit." "When resolving an attack made with this weapon, do not make a hit roll: it automatically scores a hit."
); );
replaceAbilityWithType(
[
"Each time an attack is made with this weapon, you can re-roll the wound roll.",
],
"Twin-Linked",
"Each time an attack is made with this weapon, you can re-roll the wound roll."
);
replaceAbilityWithType( replaceAbilityWithType(
["This weapon can target units that are not visible to the bearer."], ["This weapon can target units that are not visible to the bearer."],
"Indirect Fire", "Indirect Fire",
+25 -3
View File
@@ -20,6 +20,22 @@
--size-32: 32px; --size-32: 32px;
} }
@font-face {
font-family: "ConduitITCStd";
src: url("fonts/ConduitITCStd ExtraBold.woff2") format("woff2");
font-weight: 800;
}
@font-face {
font-family: "ConduitITCStd";
src: url("fonts/ConduitITCStd Bold.woff2") format("woff2");
font-weight: 700;
}
@font-face {
font-family: "ConduitITCStd";
src: url("fonts/ConduitITCStd-Regular.woff2") format("woff2");
font-weight: 400;
}
* { * {
box-sizing: border-box; box-sizing: border-box;
print-color-adjust: exact; print-color-adjust: exact;
@@ -46,7 +62,10 @@ h1 {
line-height: 1.1; line-height: 1.1;
} }
button { button,
.button {
background-color: #f0f0f0;
color: #111113;
border-radius: 8px; border-radius: 8px;
border: 2px solid #999; border: 2px solid #999;
padding: 0.6em 1.2em; padding: 0.6em 1.2em;
@@ -56,12 +75,15 @@ button {
cursor: pointer; cursor: pointer;
transition: border-color 0.25s; transition: border-color 0.25s;
} }
button:hover { button:hover,
.button:hover {
border-color: var(--primary-color); border-color: var(--primary-color);
background-color: var(--primary-color-transparent); background-color: var(--primary-color-transparent);
} }
button:focus, button:focus,
button:focus-visible { button:focus-visible,
.button:focus,
.button:focus-visible {
outline: 4px auto -webkit-focus-ring-color; outline: 4px auto -webkit-focus-ring-color;
} }