Compare commits
4 Commits
629690d29e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dfb42c11b4 | |||
| 14b0f1b805 | |||
| 2484cf8191 | |||
| 3e0452c4d7 |
@@ -1,3 +1,6 @@
|
||||
# Coord-Keeper
|
||||
|
||||
Una pequeñisima app que estoy haciendo para almacenar localmente coordenadas de minecraft
|
||||
|
||||
|
||||
[Live Demo](https://fedesrv.ddns.net/coords)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default function Barra ({active, setType}) {
|
||||
export default function Barra({ active, setType }) {
|
||||
return (
|
||||
<nav class="navbar navbar-expand-lg bg-dark-subtle h-fit w-100">
|
||||
<div class="container-fluid">
|
||||
@@ -6,33 +6,87 @@ export default function Barra ({active, setType}) {
|
||||
Coords-Keeper
|
||||
</a>
|
||||
|
||||
<div class="justify-content-end">
|
||||
<ul class="navbar-nav">
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`btn bg-primary mx-2 ${active === "overworld" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("overworld")}
|
||||
>
|
||||
Overworld
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`btn bg-danger mx-2 ${active === "nether" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("nether")}
|
||||
>
|
||||
Nether
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`btn bg-success mx-2 ${active === "end" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("end")}
|
||||
>
|
||||
End
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#offcanvasNavbar"
|
||||
aria-controls="offcanvasNavbar"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasNavbar">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title">Coords-Keeper</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="offcanvas"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<ul class="navbar-nav justify-content-end flex-grow-1">
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link d-lg-none ${active === "overworld" ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setType("overworld");
|
||||
document
|
||||
.querySelector('[data-bs-dismiss="offcanvas"]')
|
||||
.click();
|
||||
}}
|
||||
>
|
||||
Overworld
|
||||
</a>
|
||||
<button
|
||||
className={`btn bg-primary mx-2 d-none d-lg-block ${active === "overworld" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("overworld")}
|
||||
>
|
||||
Overworld
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link d-lg-none ${active === "nether" ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setType("nether");
|
||||
document
|
||||
.querySelector('[data-bs-dismiss="offcanvas"]')
|
||||
.click();
|
||||
}}
|
||||
>
|
||||
Nether
|
||||
</a>
|
||||
<button
|
||||
className={`btn bg-danger mx-2 d-none d-lg-block ${active === "nether" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("nether")}
|
||||
>
|
||||
Nether
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link d-lg-none ${active === "end" ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setType("end");
|
||||
document
|
||||
.querySelector('[data-bs-dismiss="offcanvas"]')
|
||||
.click();
|
||||
}}
|
||||
>
|
||||
End
|
||||
</a>
|
||||
<button
|
||||
className={`btn bg-success mx-2 d-none d-lg-block ${active === "end" ? "text-black active" : "text-gray-100"}`}
|
||||
onClick={() => setType("end")}
|
||||
>
|
||||
End
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
22
src/components/BotonAdd.jsx
Normal file
22
src/components/BotonAdd.jsx
Normal file
@@ -0,0 +1,22 @@
|
||||
export default function BotonAdd({ show, setshow }) {
|
||||
if (!show) return null;
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn btn-primary rounded-circle position-fixed bottom-0 end-0 m-4 d-flex align-items-center justify-content-center"
|
||||
style={{ width: "60px", height: "60px" }}
|
||||
onClick={() => setshow(true)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
className="bi bi-plus"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
|
||||
</svg>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
export default function EditarModal({ tipo, coord, show, close, setCoords }) {
|
||||
if (coord == null) return null;
|
||||
const [hasY, setHasY] = useState(coord.y !== null);
|
||||
|
||||
const [showY, setShowY] = React.useState(coord.y !== null);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
@@ -11,6 +13,7 @@ export default function EditarModal({ tipo, coord, show, close, setCoords }) {
|
||||
const y = formData.get("y");
|
||||
const z = formData.get("z");
|
||||
const descripcion = formData.get("descripcion");
|
||||
const hasY = formData.get("hasY") === "true";
|
||||
|
||||
let storedTipo = localStorage.getItem(tipo);
|
||||
if (storedTipo) {
|
||||
@@ -20,7 +23,7 @@ export default function EditarModal({ tipo, coord, show, close, setCoords }) {
|
||||
arr[index] = {
|
||||
...coord,
|
||||
x: Number(x),
|
||||
y: y ? Number(y) : null,
|
||||
y: hasY ? Number(y) : null,
|
||||
z: Number(z),
|
||||
descripcion: descripcion,
|
||||
};
|
||||
@@ -57,12 +60,11 @@ export default function EditarModal({ tipo, coord, show, close, setCoords }) {
|
||||
<div className="mb-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="hasY"
|
||||
value="true"
|
||||
className="form-check-input me-2"
|
||||
checked={hasY}
|
||||
onChange={(e) => {
|
||||
coord.y = e.target.checked ? "0" : null;
|
||||
setHasY(e.target.checked);
|
||||
}}
|
||||
defaultChecked={coord.y !== null}
|
||||
onChange={(e) => setShowY(e.target.checked)}
|
||||
/>
|
||||
<label className="form-label">Lleva coordenada Y?</label>
|
||||
</div>
|
||||
@@ -75,7 +77,7 @@ export default function EditarModal({ tipo, coord, show, close, setCoords }) {
|
||||
defaultValue={coord.x}
|
||||
/>
|
||||
</div>
|
||||
{hasY && (
|
||||
{showY && (
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Coordenada Y</label>
|
||||
<input
|
||||
|
||||
52
src/components/ModalImport.jsx
Normal file
52
src/components/ModalImport.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
export default function ModalImport({ show, handleAddCoord, close }) {
|
||||
if (!show) return null;
|
||||
let coord = "";
|
||||
return (
|
||||
<div
|
||||
className="modal"
|
||||
tabIndex="-1"
|
||||
style={{ display: "block", backgroundColor: "rgba(0,0,0,0.3)" }}
|
||||
>
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title">Añadir Coordenadas</h5>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={() => close(false)}
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="form-floating mb-3">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="coordInput"
|
||||
placeholder="Coordenadas"
|
||||
onChange={(event) => (coord = event.target.value)}
|
||||
/>
|
||||
<label htmlFor="coordInput">Pega la coord</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer d-flex justify-content-between">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
onClick={() => close(false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => handleAddCoord(coord)}
|
||||
>
|
||||
Guardar Coord
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import RemoveIcon from "./RemoveIcon";
|
||||
import StaticModal from "./StaticModal";
|
||||
import EditarModal from "./EditarModal";
|
||||
import TimedToast from "./TimedToast";
|
||||
import BotonAdd from "./BotonAdd";
|
||||
import ModalImport from "./ModalImport";
|
||||
|
||||
function Modall({ show, CloseModal, Coord, Coords, EliminarCoord, tipo }) {
|
||||
if (show === true && Coord !== null) {
|
||||
@@ -34,18 +36,40 @@ export default function Keeper({ tipo }) {
|
||||
const [showEditar, setEditar] = useState(false);
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
const [selCoord, setCoord] = useState(null);
|
||||
const [showImport, setShowImport] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const storedCoords = JSON.parse(localStorage.getItem(tipo) || "[]");
|
||||
|
||||
console.log(storedCoords);
|
||||
if (storedCoords) {
|
||||
setCoords(storedCoords);
|
||||
}
|
||||
}, [tipo]);
|
||||
|
||||
const añadirCoord = (coord) => {
|
||||
const regex = /- (.*), X: (-?\d+)(?:\s*Y:\s*(-?\d+))?\s*Z:\s*(-?\d+)/;
|
||||
const match = coord.match(regex);
|
||||
|
||||
if (match) {
|
||||
const [_, descripcion, x, y, z] = match;
|
||||
const newCoord = {
|
||||
descripcion,
|
||||
x: parseInt(x),
|
||||
y: y ? parseInt(y) : null,
|
||||
z: parseInt(z),
|
||||
num: coords.length + 1,
|
||||
};
|
||||
|
||||
const newCoords = [...coords, newCoord];
|
||||
setCoords(newCoords);
|
||||
localStorage.setItem(tipo, JSON.stringify(newCoords));
|
||||
setShowToast(true);
|
||||
setShowImport(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handlePaste = async (e) => {
|
||||
const handlePaste = async () => {
|
||||
const text = await navigator.clipboard.readText();
|
||||
const regex = /- (.*), X: (-?\d+)(?:\s*Y:\s*(-?\d+))?\s*Z:\s*(-?\d+)/;
|
||||
const match = text.match(regex);
|
||||
@@ -74,8 +98,8 @@ export default function Keeper({ tipo }) {
|
||||
});
|
||||
|
||||
/*return () => {
|
||||
document.removeEventListener("keydown", handlePaste);
|
||||
};*/
|
||||
document.removeEventListener("keydown", handlePaste);
|
||||
};*/
|
||||
}, [coords, tipo]);
|
||||
|
||||
const Editar = (coord) => {
|
||||
@@ -104,6 +128,15 @@ export default function Keeper({ tipo }) {
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="d-lg-none">
|
||||
<BotonAdd show={true} setshow={setShowImport} />
|
||||
</div>
|
||||
|
||||
<ModalImport
|
||||
show={showImport}
|
||||
handleAddCoord={añadirCoord}
|
||||
close={setShowImport}
|
||||
/>
|
||||
<Modall
|
||||
show={showModal}
|
||||
CloseModal={() => setModal(false)}
|
||||
@@ -112,7 +145,6 @@ export default function Keeper({ tipo }) {
|
||||
EliminarCoord={setCoords}
|
||||
tipo={tipo}
|
||||
/>
|
||||
|
||||
<EditarModal
|
||||
show={showEditar}
|
||||
close={() => setEditar(false)}
|
||||
@@ -120,14 +152,12 @@ export default function Keeper({ tipo }) {
|
||||
coord={selCoord}
|
||||
setCoords={setCoords}
|
||||
/>
|
||||
|
||||
<TimedToast
|
||||
durationMs={5000}
|
||||
setShow={setShowToast}
|
||||
show={showToast}
|
||||
message={`Copiada Coordenada [${selCoord?.descripcion}]`}
|
||||
/>
|
||||
|
||||
<div className="accordion" id="accordionNuevaCoord">
|
||||
<div className="accordion-item">
|
||||
<h2 className="accordion-header" id="headingNuevaCoord">
|
||||
@@ -162,13 +192,11 @@ export default function Keeper({ tipo }) {
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
{coords.length == 0 && (
|
||||
<h2 className="list-group-item text-center">
|
||||
No hay Coordenadas que Mostrar.
|
||||
</h2>
|
||||
)}
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user