import React from "react"; import { Store } from "../../lib/store"; import { MuralEx, MuralOld, MuralStatus } from "../../interfaces"; import styled from "styled-components"; import { A, Border, Btn, Flex, SELECTED_COLOR } from "../styles"; import { CanvasToCanvasJSX } from "./canvasToCanvasJSX"; import { convertOldMuralToNewMural, formatNumber, getMuralHeight, getMuralWidth, getPixelStatusMural } from "../../lib/utils"; import { IconDefinition, faDownload, faLayerGroup, faLocation, faPenToSquare, faRefresh, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Coordinates, CordType } from "../../lib/coordinates"; import { BIN_FORMATS } from "../importMural"; import saveAs from "file-saver"; import { Popup } from "./Popup"; import { Palette } from "../../lib/palette"; import { Mural } from "../../lib/mural"; const Margin = styled.div` margin: 2px; margin-left: 6px; `; const H5 = styled.h5` font-weight: bolder; margin-right: 4px; `; const Line = styled.div` font-size: 10pt; display: flex; flex-direction: row; `; const Strong = styled.strong` margin-right: 2px; `; export const BtnSmall = styled.button` border: 1px solid white; font-size: 10pt; width: 22px; background-color: rgba(255, 255, 255, 0.75); color: rgb(10, 10, 10); border-radius: 12px; border: 2px solid black; margin: 1px; margin-left: 3px; display: flex; padding: 3px; outline: none !important; text-decoration: none; &:hover { background-color: rgba(158, 158, 158, 0.75); } &:visited { text-decoration: none; } &:disabled { color: gray; border-color: gray; cursor: not-allowed; } transition: background-color 250ms; `; interface Props { mural: MuralEx; selected: boolean; store: Store; palette: Palette; cords: Coordinates; } interface State { width: number; height: number; overlay: boolean; progress?: MuralStatus | (() => void /* loading */); link: string; } export class MuralView extends React.Component { private readonly MAX_SIZE = 100; constructor(props:Props) { super(props); this.state = { height: this.MAX_SIZE, width: this.MAX_SIZE, overlay: false, link: "" }; } componentDidMount () { this.updateSize(); this.props.cords.on(CordType.Url, this.onCordUpdate); } componentWillUnmount () { this.props.cords.off(CordType.Url, this.onCordUpdate); } componentDidUpdate(prevProps: Readonly ) { if (this.props.mural.ref !== prevProps.mural.ref) { this.updateSize(); if (typeof this.state.progress === "function") { typeof this.state.progress(); this.setState({progress: undefined, link: this.link}); } } } onCordUpdate = () => { this.setState({ link: this.link }); }; updateSize = () => { const w = this.props.mural.ref.width; const h = this.props.mural.ref.height; let width = w; let height = h; if (w > h) { if (w > this.MAX_SIZE) { height = this.MAX_SIZE * (h / w); width = this.MAX_SIZE; } } else { if (h > this.MAX_SIZE) { width = this.MAX_SIZE * (w / h); height = this.MAX_SIZE; } } this.setState({ height, width }); }; renderInfoLine(title: string, description: string | React.JSX.Element) { return
{title}:
{description}
; } btn(context: string, icon: IconDefinition, onClick: () => void, selected?: boolean) { return onClick()}>{context} ; } get s() { return this.props.store; } onLoad = (event: React.MouseEvent) => { const tr = event.target as HTMLElement; if ("tagName" in tr) { const ignore = ["button", "svg", "path"]; if (!ignore.includes(tr.tagName.toLowerCase())) { this.s.select(this.props.selected ? undefined : this.props.mural ); } } }; onModify = async () => { const mural = this.props.mural; this.props.store.setOverlayModify({ pixels: this.props.mural.pixels, cb: (name, x, y, confirm) => { if (confirm) { mural.name = name; mural.x = x; mural.y = y; this.props.store.updateMural(mural); } }, muralObj: { name: this.props.mural.name, x: this.props.mural.x, y: this.props.mural.y } }); // let x: number | null = null; // let y: number | null = null; // await Popup.custom(
//
Enter new coordinates
//
// X: // processNumberEvent(ev, n => {x = n})} /> //
//
// Y: // processNumberEvent(ev, n => {y = n})} /> //
//
, [ // { // content: "Confirm", // click: () => { // Popup.close(); // } // }, // { // content: "Close", // click: () => { // x = null; // y = null; // Popup.close(); // } // } // ]); // if (typeof x === "number" && typeof y === "number") { // this.props.mural.x = x; // this.props.mural.y = y; // this.props.store.updateMural(this.props.mural); // } }; onExport = async () => { const rawMural: MuralOld = { name: this.props.mural.name, x: this.props.mural.x, y: this.props.mural.y, pixels: this.props.mural.pixels, }; const mural = convertOldMuralToNewMural(rawMural); const buffer = await mural.getBuffer(); const blob = new Blob([buffer], { type: "octet/stream" }); const saveName = rawMural.name .replace(/ /, "_") .replace(/[^a-zA-Z0-9-_]/g, ""); saveAs(blob, `${saveName}.${BIN_FORMATS[0]}`); }; onDelete = async () => { if (await Popup.confirm(`Are you sure you want to remove "${this.props.mural.name}"`)) { this.s.remove(this.props.mural); } }; onEnter = () => { this.props.store.addPhantomOverlay(this.props.mural); }; onLeave = () => { this.props.store.removePhantomOverlay(); }; get link() { const weight = getMuralWidth(this.props.mural); const height = getMuralHeight(this.props.mural); const x = this.props.mural.x + Math.round(weight / 2); const y = this.props.mural.y + Math.round(height / 2); const o = origin === "null" ? `${location.href}` : `${origin}/`; return `${o}@${x},${y},${this.props.cords.uScale}`; } onGoto = () => { location.href = this.link; }; onPreview = () => { if (this.props.store.hasOverlay(this.props.mural)) { this.props.store.removeOverlay(this.props.mural); } else { this.props.store.addOverlay(this.props.mural); } }; updateProgress = async () => { let canceled = false; const cancelFn = () => { canceled = true; }; this.setState({progress: cancelFn}); const data = await getPixelStatusMural(this.props.mural, this.props.palette.palette); if (!canceled) { this.setState({progress: data}); } }; renderProgress() { if (typeof this.state.progress === "function") { return "Loading..."; } const ref = ; if (this.state.progress && this.state.progress.total !== 0) { const { total, bad, good } = this.state.progress; return {Math.floor(good / total * 100)}% {bad > 0 ? formatNumber(bad) : ""}{ref}; } else { return ref; } } render() { return {this.renderInfoLine("Name", this.props.mural.name)} {this.renderInfoLine("Pixel count", formatNumber(this.props.mural.pixelCount))} {this.renderInfoLine("X", this.props.mural.x.toString() )} {this.renderInfoLine("Y", this.props.mural.y.toString() )} {this.renderInfoLine("Size", `${getMuralWidth(this.props.mural)}x${getMuralHeight(this.props.mural)}`)} {this.renderInfoLine("Progress", this.renderProgress())} {this.btn("Preview", faLayerGroup, this.onPreview, this.props.store.hasOverlay(this.props.mural))} {this.btn("Modify", faPenToSquare, this.onModify)} {this.btn("Export", faDownload, this.onExport)} {this.btn("Delete", faTrash, this.onDelete)} Goto ; } }