Skip to content

Commit

Permalink
upgrades to crosshair color
Browse files Browse the repository at this point in the history
  • Loading branch information
mastercoms committed Jul 11, 2024
1 parent 9d93550 commit a8d1941
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 44 deletions.
9 changes: 7 additions & 2 deletions astro.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ const pwa = AstroPWA({

const rootDir = new URL(".", import.meta.url).pathname;

const nonce = crypto.randomBytes(16).toString("base64");

const astroCSPHashExporter: AstroIntegration = {
name: "astro-csp-hash-exporter",
hooks: {
Expand All @@ -88,8 +90,8 @@ const astroCSPHashExporter: AstroIntegration = {
scriptSrcHashes,
);
// Not ideal, but protects against non-targeted attacks. We don't really have options for non-dynamic content.
const scriptSrcNonce = `'nonce-${crypto.randomBytes(16).toString("base64")}'`;
headersFile = headersFile.replace("{{SCRIPT_SRC_NONCE}}", scriptSrcNonce);
const srcNonce = `'nonce-${nonce}'`;
headersFile = headersFile.replaceAll("{{SRC_NONCE}}", srcNonce);
const styleSrcElementHashes = `'${sriHashes.inlineStyleHashes.join("' '")}'`;
headersFile = headersFile.replace(
"{{STYLE_SRC_ELEM_HASHES}}",
Expand Down Expand Up @@ -139,6 +141,9 @@ export default defineConfig({
sourcemap: true,
assetsInlineLimit: 0,
},
html: {
cspNonce: nonce,
},
resolve: {
alias: {
"~bootstrap": resolve(rootDir, "node_modules", "bootstrap"),
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"react": "^18.3.1",
"react-bootstrap": "^2.10.3",
"react-color": "^2.19.3",
"react-colorful": "^5.6.1",
"react-compare-slider": "^3.1.0",
"react-dom": "^18.3.1",
"react-minisearch": "^6.3.0",
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion public/_headers
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
! Access-Control-Allow-Origin
Permissions-Policy: document-domain=()
Document-Policy: js-profiling
Content-Security-Policy: upgrade-insecure-requests; default-src 'none'; script-src {{SCRIPT_SRC_NONCE}} {{SCRIPT_SRC_HASHES}} 'self' blob: https://static.cloudflareinsights.com; frame-src https://www.youtube-nocookie.com; img-src data: https:; connect-src https:; media-src blob: https:; style-src 'self'; style-src-elem {{STYLE_SRC_ELEM_HASHES}} 'self'; style-src-attr 'unsafe-inline'; manifest-src 'self'; font-src 'self'; worker-src blob: 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'; sandbox allow-downloads allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts;
Content-Security-Policy: upgrade-insecure-requests; default-src 'none'; script-src {{SRC_NONCE}} {{SCRIPT_SRC_HASHES}} 'self' blob: https://static.cloudflareinsights.com; frame-src https://www.youtube-nocookie.com; img-src data: https:; connect-src https:; media-src blob: https:; style-src 'self'; style-src-elem {{SRC_NONCE}} {{STYLE_SRC_ELEM_HASHES}} 'self'; style-src-attr 'unsafe-inline'; manifest-src 'self'; font-src 'self'; worker-src blob: 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'; sandbox allow-downloads allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts;
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Expand Down
188 changes: 157 additions & 31 deletions src/components/items/ItemsInner.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { useMemo, useState, useEffect } from "react";
import { Button, Tab, Row, Col, Nav, FormCheck, Form } from "react-bootstrap";
import crosshairPreviewImg from "@img/app/crosshairs/crosspreview.webp";
import debounce from "lodash/debounce";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Button, Col, Form, FormCheck, Nav, Row, Tab } from "react-bootstrap";
import { type RgbaColor, RgbaColorPicker, setNonce } from "react-colorful";

import useItemStore from "@store/items";

import ItemsSelector from "./ItemsSelector";
import crosshairPreviewImg from "@img/app/crosshairs/crosspreview.webp";
import { ChromePicker } from "react-color";

const dataUrl =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==";
const cspNonce =
document.querySelector<HTMLMetaElement>("meta[property=csp-nonce]")?.nonce ??
null;

export class ServerCanvas {
toDataURL: () => string;
getContext: () => { fillRect: () => void; translate: () => void };
constructor() {
this.toDataURL = () => dataUrl;
this.getContext = () => ({
fillRect: () => {},
translate: () => {},
});
}
if (cspNonce) {
setNonce(cspNonce);
}

function calculateItemSlots(playerClass, items) {
Expand Down Expand Up @@ -145,12 +141,16 @@ export default function ItemsInner({ playerClass, items, setResetKey }) {
const selectedExplosion = itemStore.explosioneffects;
const selectedPlayerExplosion = itemStore.playerexplosions;

const [liveCrosshairColor, setLiveCrosshairColor] = useState(undefined);
const [liveCrosshairScale, setLiveCrosshairScale] = useState(undefined);
const [liveCrosshairColor, setLiveCrosshairColor] = useState<
RgbaColor | undefined
>(undefined);
const [liveCrosshairScale, setLiveCrosshairScale] = useState<
number | undefined
>(undefined);

const currentCrosshairColor = liveCrosshairColor ??
selectedCrosshairColor ??
itemStore.crosshairColors?.default ?? { r: 200, g: 200, b: 200, a: 0.784 };
itemStore.crosshairColors?.default ?? { r: 200, g: 200, b: 200, a: 0.78 };
const defaultCrosshairScale =
selectedCrosshairScale ?? itemStore.crosshairScales?.default ?? 32;
const currentCrosshairScale = liveCrosshairScale ?? defaultCrosshairScale;
Expand Down Expand Up @@ -197,6 +197,16 @@ export default function ItemsInner({ playerClass, items, setResetKey }) {
state.delPlayerExplosionEffect,
]);

const crosshairColorDebounce = useCallback(
debounce((color) => {
setCrosshairColor(
playerClass === "All-Class" ? "default" : playerClass,
color,
);
}, 300),
[setCrosshairColor, playerClass],
);

const isDefault = itemClasses[0].classname === "default";

return (
Expand Down Expand Up @@ -269,6 +279,7 @@ export default function ItemsInner({ playerClass, items, setResetKey }) {
transform: `scale(${currentCrosshairScale / 32})`,
}}
colorize={currentCrosshairColor}
colorizePreviewInvertClass="crosshair-preview-inverted"
>
{selectedZoomCrosshairs &&
zoomable.has(item.classname) && (
Expand Down Expand Up @@ -336,22 +347,137 @@ export default function ItemsInner({ playerClass, items, setResetKey }) {
}}
/>
<h6>Crosshair Color</h6>
<ChromePicker
<RgbaColorPicker
className="w-100"
renderers={{ canvas: ServerCanvas }}
color={currentCrosshairColor}
onChange={(color) => {
setLiveCrosshairColor(color.rgb);
}}
onChangeComplete={(color) => {
setCrosshairColor(
playerClass === "All-Class"
? "default"
: playerClass,
color.rgb,
);
setLiveCrosshairColor(color);
crosshairColorDebounce(color);
}}
/>
<Row className="w-100 my-1 g-0">
<Col xs={"auto"} className="mx-2">
<small className="text-muted">Preview</small>
</Col>
<Col
style={{
backgroundColor:
Math.sqrt(
Math.pow(currentCrosshairColor.r, 2) +
Math.pow(currentCrosshairColor.g, 2) +
Math.pow(currentCrosshairColor.b, 2),
) <= 127
? "#fff"
: "#000",
}}
className="rounded-end-3"
>
<div
style={{
backgroundColor: `rgba(${currentCrosshairColor.r} ${currentCrosshairColor.g} ${currentCrosshairColor.b} / ${currentCrosshairColor.a})`,
}}
className="rounded-end-3 w-100 h-100"
></div>
</Col>
</Row>
<Row className="w-100 g-0">
<Col>
<Form.Control
placeholder="Red"
value={currentCrosshairColor.r}
type="number"
min={0}
max={255}
step={1}
onBlur={(e) => {
const newVal = parseInt(e.target.value);
const color = {
...currentCrosshairColor,
r: newVal,
};
setCrosshairColor(
playerClass === "All-Class"
? "default"
: playerClass,
color,
);
}}
/>
<Form.Text>Red</Form.Text>
</Col>
<Col>
<Form.Control
placeholder="Blue"
value={currentCrosshairColor.b}
type="number"
min={0}
max={255}
step={1}
onBlur={(e) => {
const newVal = parseInt(e.target.value);
const color = {
...currentCrosshairColor,
b: newVal,
};
setCrosshairColor(
playerClass === "All-Class"
? "default"
: playerClass,
color,
);
}}
/>
<Form.Text>Blue</Form.Text>
</Col>
<Col>
<Form.Control
placeholder="Green"
value={currentCrosshairColor.g}
type="number"
min={0}
max={255}
step={1}
onBlur={(e) => {
const newVal = parseInt(e.target.value);
const color = {
...currentCrosshairColor,
g: newVal,
};
setCrosshairColor(
playerClass === "All-Class"
? "default"
: playerClass,
color,
);
}}
/>
<Form.Text>Green</Form.Text>
</Col>
<Col>
<Form.Control
placeholder="Alpha"
value={currentCrosshairColor.a}
type="number"
min={0}
max={1}
step={0.01}
onBlur={(e) => {
const newVal = parseFloat(e.target.value);
const color = {
...currentCrosshairColor,
a: newVal,
};
setCrosshairColor(
playerClass === "All-Class"
? "default"
: playerClass,
color,
);
}}
/>
<Form.Text>Alpha</Form.Text>
</Col>
</Row>
<Button
className="w-100"
variant="danger"
Expand All @@ -366,7 +492,7 @@ export default function ItemsInner({ playerClass, items, setResetKey }) {
r: 200,
g: 200,
b: 200,
a: 0.784,
a: 0.78,
});
}}
>
Expand Down
24 changes: 16 additions & 8 deletions src/components/items/ItemsSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState } from "react";
import { FormSelect } from "react-bootstrap";
import { components } from "react-select";
import Select from "react-select";
import Select, { components } from "react-select";

function onMenuOpen() {
setTimeout(() => {
Expand Down Expand Up @@ -187,14 +186,15 @@ export default function ItemsSelector({
type,
previewPath,
previews,
previewClass,
previewClass = "",
previewStyle,
previewImgClass,
previewImgStyle,
useAdvancedSelect,
groups,
children,
colorize,
colorizePreviewInvertClass,
hidePreview,
}) {
const [selected, setSelected] = useState(selection ?? defaultValue);
Expand Down Expand Up @@ -247,6 +247,18 @@ export default function ItemsSelector({
}
}

let currentPreviewClass = previewClass;
if (colorize && colorizePreviewInvertClass) {
currentPreviewClass +=
Math.sqrt(
Math.pow(colorize.r, 2) +
Math.pow(colorize.g, 2) +
Math.pow(colorize.b, 2),
) <= 127
? ""
: ` ${colorizePreviewInvertClass}`;
}

return (
<div className="row">
<div className={hidePreview ? "col-12" : "col-4"}>
Expand Down Expand Up @@ -313,7 +325,7 @@ export default function ItemsSelector({
{(selected !== defaultValue || !isDefaultWeapon) && !hidePreview && (
<div className="col-8">
<div
className={`col-8 preview-container ${previewClass}`}
className={`col-8 preview-container ${currentPreviewClass}`}
style={previewStyle}
>
{getPreviewImage(
Expand All @@ -330,7 +342,3 @@ export default function ItemsSelector({
</div>
);
}

ItemsSelector.defaultProps = {
previewClass: "",
};
4 changes: 4 additions & 0 deletions src/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ a.addon-card:hover {
}

.crosshair-preview:hover {
background: #fff !important;
}

.crosshair-preview.crosshair-preview-inverted:hover {
background: #000 !important;
}

Expand Down
Loading

0 comments on commit a8d1941

Please sign in to comment.