Show detected tape colors in UI
This commit is contained in:
@@ -11,6 +11,7 @@ Die Weboberflaeche bildet die wichtigsten P-touch-Editor-Funktionen nach:
|
|||||||
- QR-Code und Code128-Barcode
|
- QR-Code und Code128-Barcode
|
||||||
- Layout speichern/laden im Browser
|
- Layout speichern/laden im Browser
|
||||||
- serverseitige Vorschau und Druck ueber `ptouch-print`
|
- serverseitige Vorschau und Druck ueber `ptouch-print`
|
||||||
|
- Band-Erkennung mit Breite, Bandtyp, Hintergrundfarbe und Schriftfarbe
|
||||||
- einfache Text-only Mobile-Webansicht unter `/mobile`
|
- einfache Text-only Mobile-Webansicht unter `/mobile`
|
||||||
- Schnittmodi: normal, Kettendruck/Streifen, Schnittmarke und Streifen mit Schnittmarke
|
- Schnittmodi: normal, Kettendruck/Streifen, Schnittmarke und Streifen mit Schnittmarke
|
||||||
|
|
||||||
|
|||||||
+85
-7
@@ -375,7 +375,76 @@ def should_render_copies_as_strip(design: dict[str, Any], copies: int) -> bool:
|
|||||||
return str(design.get("cutMode", "auto")) in {"chain", "cutmark-chain"}
|
return str(design.get("cutMode", "auto")) in {"chain", "cutmark-chain"}
|
||||||
|
|
||||||
|
|
||||||
def detect_tape_width() -> tuple[float | None, str]:
|
COLOR_HEX_BY_NAME = {
|
||||||
|
"white": "#ffffff",
|
||||||
|
"black": "#111111",
|
||||||
|
"red": "#d92d20",
|
||||||
|
"blue": "#2563eb",
|
||||||
|
"yellow": "#facc15",
|
||||||
|
"green": "#16a34a",
|
||||||
|
"clear": "#f8fafc",
|
||||||
|
"transparent": "#f8fafc",
|
||||||
|
"silver": "#c0c0c0",
|
||||||
|
"gold": "#d4af37",
|
||||||
|
"matte white": "#f5f5f0",
|
||||||
|
"matte black": "#1f1f1f",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COLOR_NAME_DE = {
|
||||||
|
"white": "Weiss",
|
||||||
|
"black": "Schwarz",
|
||||||
|
"red": "Rot",
|
||||||
|
"blue": "Blau",
|
||||||
|
"yellow": "Gelb",
|
||||||
|
"green": "Gruen",
|
||||||
|
"clear": "Transparent",
|
||||||
|
"transparent": "Transparent",
|
||||||
|
"silver": "Silber",
|
||||||
|
"gold": "Gold",
|
||||||
|
"matte white": "Matt weiss",
|
||||||
|
"matte black": "Matt schwarz",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MEDIA_TYPE_DE = {
|
||||||
|
"laminated tape": "Laminiertes Band",
|
||||||
|
"non-laminated tape": "Nicht laminiertes Band",
|
||||||
|
"fabric tape": "Textilband",
|
||||||
|
"heat shrink tube": "Schrumpfschlauch",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def color_info_from_line(output: str, key: str) -> dict[str, str] | None:
|
||||||
|
match = re.search(rf"^{re.escape(key)}\s*=\s*([0-9a-fA-F]+)(?:\s*\(([^)]+)\))?", output, re.MULTILINE)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
code = match.group(1)
|
||||||
|
raw_name = (match.group(2) or f"Code {code}").strip()
|
||||||
|
normalized = raw_name.lower()
|
||||||
|
return {
|
||||||
|
"code": code,
|
||||||
|
"name": COLOR_NAME_DE.get(normalized, raw_name),
|
||||||
|
"rawName": raw_name,
|
||||||
|
"css": COLOR_HEX_BY_NAME.get(normalized, "#d1d5db"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def media_type_from_output(output: str) -> dict[str, str] | None:
|
||||||
|
match = re.search(r"^media type\s*=\s*([0-9a-fA-F]+)(?:\s*\(([^)]+)\))?", output, re.MULTILINE)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
code = match.group(1)
|
||||||
|
raw_name = (match.group(2) or f"Code {code}").strip()
|
||||||
|
normalized = raw_name.lower()
|
||||||
|
return {
|
||||||
|
"code": code,
|
||||||
|
"name": MEDIA_TYPE_DE.get(normalized, raw_name),
|
||||||
|
"rawName": raw_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def detect_tape_info() -> dict[str, Any]:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["ptouch-print", "--info"],
|
["ptouch-print", "--info"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
@@ -387,6 +456,7 @@ def detect_tape_width() -> tuple[float | None, str]:
|
|||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise RuntimeError(format_print_error(result))
|
raise RuntimeError(format_print_error(result))
|
||||||
|
|
||||||
|
width = None
|
||||||
candidates: list[float] = []
|
candidates: list[float] = []
|
||||||
for pattern in [
|
for pattern in [
|
||||||
r"(?:tape|media|band|width|breite|size|groesse|printing)[^\n:=-]*[:=-]?\s*(\d+(?:[.,]\d+)?)\s*mm",
|
r"(?:tape|media|band|width|breite|size|groesse|printing)[^\n:=-]*[:=-]?\s*(\d+(?:[.,]\d+)?)\s*mm",
|
||||||
@@ -397,8 +467,16 @@ def detect_tape_width() -> tuple[float | None, str]:
|
|||||||
|
|
||||||
for supported in TAPE_WIDTHS_MM:
|
for supported in TAPE_WIDTHS_MM:
|
||||||
if any(abs(candidate - supported) < 0.26 for candidate in candidates):
|
if any(abs(candidate - supported) < 0.26 for candidate in candidates):
|
||||||
return supported, output
|
width = supported
|
||||||
return None, output
|
break
|
||||||
|
|
||||||
|
return {
|
||||||
|
"width": width,
|
||||||
|
"mediaType": media_type_from_output(output),
|
||||||
|
"tapeColor": color_info_from_line(output, "tape color"),
|
||||||
|
"textColor": color_info_from_line(output, "text color"),
|
||||||
|
"raw": output,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def format_print_error(result: subprocess.CompletedProcess[str]) -> str:
|
def format_print_error(result: subprocess.CompletedProcess[str]) -> str:
|
||||||
@@ -503,10 +581,10 @@ def api_print():
|
|||||||
@app.get("/api/tape-info")
|
@app.get("/api/tape-info")
|
||||||
def api_tape_info():
|
def api_tape_info():
|
||||||
try:
|
try:
|
||||||
width, raw = detect_tape_width()
|
info = detect_tape_info()
|
||||||
if width is None:
|
if info["width"] is None:
|
||||||
return jsonify({"ok": False, "error": "Bandbreite konnte nicht erkannt werden.", "raw": raw}), 400
|
return jsonify({"ok": False, "error": "Bandbreite konnte nicht erkannt werden.", **info}), 400
|
||||||
return jsonify({"ok": True, "width": width, "raw": raw})
|
return jsonify({"ok": True, **info})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return jsonify({"ok": False, "error": str(exc)}), 400
|
return jsonify({"ok": False, "error": str(exc)}), 400
|
||||||
|
|
||||||
|
|||||||
+35
-6
@@ -13,6 +13,7 @@ const state = {
|
|||||||
zoom: 1.5,
|
zoom: 1.5,
|
||||||
selectedId: null,
|
selectedId: null,
|
||||||
dragging: null,
|
dragging: null,
|
||||||
|
tapeInfo: null,
|
||||||
design: {
|
design: {
|
||||||
tapeWidthMm: 24,
|
tapeWidthMm: 24,
|
||||||
lengthMm: 70,
|
lengthMm: 70,
|
||||||
@@ -36,6 +37,12 @@ const controls = {
|
|||||||
marginMm: document.getElementById("marginMm"),
|
marginMm: document.getElementById("marginMm"),
|
||||||
cutMode: document.getElementById("cutMode"),
|
cutMode: document.getElementById("cutMode"),
|
||||||
copies: document.getElementById("copies"),
|
copies: document.getElementById("copies"),
|
||||||
|
tapeInfo: document.getElementById("tapeInfo"),
|
||||||
|
tapeInfoType: document.getElementById("tapeInfoType"),
|
||||||
|
tapeBgSwatch: document.getElementById("tapeBgSwatch"),
|
||||||
|
tapeBgText: document.getElementById("tapeBgText"),
|
||||||
|
tapeTextSwatch: document.getElementById("tapeTextSwatch"),
|
||||||
|
tapeTextText: document.getElementById("tapeTextText"),
|
||||||
zoomLabel: document.getElementById("zoomLabel"),
|
zoomLabel: document.getElementById("zoomLabel"),
|
||||||
previewImage: document.getElementById("previewImage"),
|
previewImage: document.getElementById("previewImage"),
|
||||||
noSelection: document.getElementById("noSelection"),
|
noSelection: document.getElementById("noSelection"),
|
||||||
@@ -82,6 +89,10 @@ function printablePxPerMm() {
|
|||||||
return (PRINTABLE_TAPE_PX[tape] || (tape * 180) / 25.4) / tape;
|
return (PRINTABLE_TAPE_PX[tape] || (tape * 180) / 25.4) / tape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inkColor() {
|
||||||
|
return state.tapeInfo?.textColor?.css || "#000";
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(value, min, max) {
|
function clamp(value, min, max) {
|
||||||
return Math.min(max, Math.max(min, value));
|
return Math.min(max, Math.max(min, value));
|
||||||
}
|
}
|
||||||
@@ -106,6 +117,20 @@ function setMessage(text, type = "") {
|
|||||||
message.className = `message-line ${type}`;
|
message.className = `message-line ${type}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTapeInfo(info) {
|
||||||
|
state.tapeInfo = info || null;
|
||||||
|
controls.tapeInfo.hidden = !info;
|
||||||
|
if (!info) return;
|
||||||
|
const media = info.mediaType?.name || "Unbekannt";
|
||||||
|
const bg = info.tapeColor || { name: "Unbekannt", css: "#d1d5db" };
|
||||||
|
const text = info.textColor || { name: "Unbekannt", css: "#111111" };
|
||||||
|
controls.tapeInfoType.textContent = `${info.width} mm · ${media}${info.mediaType?.code ? ` (${info.mediaType.code})` : ""}`;
|
||||||
|
controls.tapeBgText.textContent = `${bg.name}${bg.code ? ` (${bg.code})` : ""}`;
|
||||||
|
controls.tapeBgSwatch.style.background = bg.css;
|
||||||
|
controls.tapeTextText.textContent = `${text.name}${text.code ? ` (${text.code})` : ""}`;
|
||||||
|
controls.tapeTextSwatch.style.background = text.css;
|
||||||
|
}
|
||||||
|
|
||||||
function syncDesignControls() {
|
function syncDesignControls() {
|
||||||
state.design.tapeWidthMm = Number(controls.tapeWidth.value);
|
state.design.tapeWidthMm = Number(controls.tapeWidth.value);
|
||||||
state.design.lengthMm = Number(controls.lengthMm.value);
|
state.design.lengthMm = Number(controls.lengthMm.value);
|
||||||
@@ -164,7 +189,7 @@ function drawTextObject(obj) {
|
|||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.rect(x, y, w, h);
|
ctx.rect(x, y, w, h);
|
||||||
ctx.clip();
|
ctx.clip();
|
||||||
ctx.fillStyle = "#000";
|
ctx.fillStyle = inkColor();
|
||||||
const fontPx = (obj.fontSizeMm || 5) * printablePxPerMm() * state.zoom;
|
const fontPx = (obj.fontSizeMm || 5) * printablePxPerMm() * state.zoom;
|
||||||
ctx.font = `${obj.bold ? "700 " : ""}${fontPx}px DejaVu Sans, Arial, system-ui, sans-serif`;
|
ctx.font = `${obj.bold ? "700 " : ""}${fontPx}px DejaVu Sans, Arial, system-ui, sans-serif`;
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
@@ -188,8 +213,8 @@ function drawObject(obj) {
|
|||||||
const h = mmToPx(obj.h);
|
const h = mmToPx(obj.h);
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.lineWidth = Math.max(1, mmToPx(obj.lineMm || 0.25));
|
ctx.lineWidth = Math.max(1, mmToPx(obj.lineMm || 0.25));
|
||||||
ctx.strokeStyle = "#000";
|
ctx.strokeStyle = inkColor();
|
||||||
ctx.fillStyle = "#000";
|
ctx.fillStyle = inkColor();
|
||||||
|
|
||||||
if (obj.type === "text" || obj.type === "symbol") {
|
if (obj.type === "text" || obj.type === "symbol") {
|
||||||
drawTextObject(obj);
|
drawTextObject(obj);
|
||||||
@@ -250,7 +275,8 @@ function draw() {
|
|||||||
canvas.style.width = `${canvas.width}px`;
|
canvas.style.width = `${canvas.width}px`;
|
||||||
canvas.style.height = `${canvas.height}px`;
|
canvas.style.height = `${canvas.height}px`;
|
||||||
|
|
||||||
ctx.fillStyle = "#fff";
|
const tapeColor = state.tapeInfo?.tapeColor?.css || "#fff";
|
||||||
|
ctx.fillStyle = tapeColor;
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
const margin = mmToPx(state.design.marginMm);
|
const margin = mmToPx(state.design.marginMm);
|
||||||
ctx.strokeStyle = "#b7b7b7";
|
ctx.strokeStyle = "#b7b7b7";
|
||||||
@@ -261,7 +287,7 @@ function draw() {
|
|||||||
for (const obj of state.design.objects) drawObject(obj);
|
for (const obj of state.design.objects) drawObject(obj);
|
||||||
|
|
||||||
if (state.design.cutMode === "cutmark" || state.design.cutMode === "cutmark-chain") {
|
if (state.design.cutMode === "cutmark" || state.design.cutMode === "cutmark-chain") {
|
||||||
ctx.strokeStyle = "#111";
|
ctx.strokeStyle = inkColor();
|
||||||
ctx.setLineDash([4, 4]);
|
ctx.setLineDash([4, 4]);
|
||||||
const x = canvas.width - mmToPx(1.5);
|
const x = canvas.width - mmToPx(1.5);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
@@ -477,8 +503,11 @@ document.getElementById("detectTape").addEventListener("click", async () => {
|
|||||||
}
|
}
|
||||||
controls.tapeWidth.value = String(payload.width);
|
controls.tapeWidth.value = String(payload.width);
|
||||||
state.design.tapeWidthMm = Number(payload.width);
|
state.design.tapeWidthMm = Number(payload.width);
|
||||||
|
updateTapeInfo(payload);
|
||||||
draw();
|
draw();
|
||||||
setMessage(`Band erkannt: ${payload.width} mm`, "success");
|
const bg = payload.tapeColor?.name ? `, ${payload.tapeColor.name}` : "";
|
||||||
|
const text = payload.textColor?.name ? ` / ${payload.textColor.name}` : "";
|
||||||
|
setMessage(`Band erkannt: ${payload.width} mm${bg}${text}`, "success");
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("saveLayout").addEventListener("click", () => {
|
document.getElementById("saveLayout").addEventListener("click", () => {
|
||||||
|
|||||||
@@ -174,6 +174,42 @@ button.primary {
|
|||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tape-info {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #444;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: #2f2f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info span {
|
||||||
|
color: #b7b7b7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info strong {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
color: #f2f2f2;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info i {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 1px solid #777;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.bottom-actions {
|
.bottom-actions {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
+23
-1
@@ -7,6 +7,12 @@ const fields = {
|
|||||||
align: document.getElementById("mobileAlign"),
|
align: document.getElementById("mobileAlign"),
|
||||||
bold: document.getElementById("mobileBold"),
|
bold: document.getElementById("mobileBold"),
|
||||||
frame: document.getElementById("mobileFrame"),
|
frame: document.getElementById("mobileFrame"),
|
||||||
|
tapeInfo: document.getElementById("mobileTapeInfo"),
|
||||||
|
tapeInfoType: document.getElementById("mobileTapeInfoType"),
|
||||||
|
tapeBgSwatch: document.getElementById("mobileTapeBgSwatch"),
|
||||||
|
tapeBgText: document.getElementById("mobileTapeBgText"),
|
||||||
|
tapeTextSwatch: document.getElementById("mobileTapeTextSwatch"),
|
||||||
|
tapeTextText: document.getElementById("mobileTapeTextText"),
|
||||||
preview: document.getElementById("mobilePreview"),
|
preview: document.getElementById("mobilePreview"),
|
||||||
message: document.getElementById("mobileMessage"),
|
message: document.getElementById("mobileMessage"),
|
||||||
};
|
};
|
||||||
@@ -23,6 +29,19 @@ function setMessage(text, type = "") {
|
|||||||
fields.message.className = `message ${type}`;
|
fields.message.className = `message ${type}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTapeInfo(info) {
|
||||||
|
fields.tapeInfo.hidden = !info;
|
||||||
|
if (!info) return;
|
||||||
|
const media = info.mediaType?.name || "Unbekannt";
|
||||||
|
const bg = info.tapeColor || { name: "Unbekannt", css: "#d1d5db" };
|
||||||
|
const text = info.textColor || { name: "Unbekannt", css: "#111111" };
|
||||||
|
fields.tapeInfoType.textContent = `${info.width} mm · ${media}${info.mediaType?.code ? ` (${info.mediaType.code})` : ""}`;
|
||||||
|
fields.tapeBgText.textContent = `${bg.name}${bg.code ? ` (${bg.code})` : ""}`;
|
||||||
|
fields.tapeBgSwatch.style.background = bg.css;
|
||||||
|
fields.tapeTextText.textContent = `${text.name}${text.code ? ` (${text.code})` : ""}`;
|
||||||
|
fields.tapeTextSwatch.style.background = text.css;
|
||||||
|
}
|
||||||
|
|
||||||
function mobileDesign() {
|
function mobileDesign() {
|
||||||
const tapeWidth = Number(fields.tape.value);
|
const tapeWidth = Number(fields.tape.value);
|
||||||
const margin = Number(fields.margin.value);
|
const margin = Number(fields.margin.value);
|
||||||
@@ -94,7 +113,10 @@ document.getElementById("mobileDetect").addEventListener("click", async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fields.tape.value = String(payload.width);
|
fields.tape.value = String(payload.width);
|
||||||
setMessage(`Band erkannt: ${payload.width} mm`, "success");
|
updateTapeInfo(payload);
|
||||||
|
const bg = payload.tapeColor?.name ? `, ${payload.tapeColor.name}` : "";
|
||||||
|
const text = payload.textColor?.name ? ` / ${payload.textColor.name}` : "";
|
||||||
|
setMessage(`Band erkannt: ${payload.width} mm${bg}${text}`, "success");
|
||||||
});
|
});
|
||||||
|
|
||||||
["text", "font", "margin", "frame", "bold", "align", "tape"].forEach((name) => {
|
["text", "font", "margin", "frame", "bold", "align", "tape"].forEach((name) => {
|
||||||
|
|||||||
@@ -163,6 +163,42 @@ textarea {
|
|||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tape-info {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #444;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: #2f2f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info span {
|
||||||
|
color: #b7b7b7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info strong {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
color: #f2f2f2;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-info i {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 1px solid #777;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar label {
|
.sidebar label {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|||||||
@@ -52,6 +52,20 @@
|
|||||||
<button id="detectTape" type="button">Erkennen</button>
|
<button id="detectTape" type="button">Erkennen</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
<div id="tapeInfo" class="tape-info" hidden>
|
||||||
|
<div>
|
||||||
|
<span>Band</span>
|
||||||
|
<strong id="tapeInfoType">-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Hintergrund</span>
|
||||||
|
<strong><i id="tapeBgSwatch"></i><span id="tapeBgText">-</span></strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Schrift</span>
|
||||||
|
<strong><i id="tapeTextSwatch"></i><span id="tapeTextText">-</span></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<label>
|
<label>
|
||||||
Laenge
|
Laenge
|
||||||
<input id="lengthMm" type="number" min="10" max="500" step="1" value="70">
|
<input id="lengthMm" type="number" min="10" max="500" step="1" value="70">
|
||||||
|
|||||||
@@ -41,6 +41,20 @@
|
|||||||
<input id="mobileCopies" type="number" min="1" max="20" step="1" value="1">
|
<input id="mobileCopies" type="number" min="1" max="20" step="1" value="1">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="mobileTapeInfo" class="tape-info" hidden>
|
||||||
|
<div>
|
||||||
|
<span>Band</span>
|
||||||
|
<strong id="mobileTapeInfoType">-</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Hintergrund</span>
|
||||||
|
<strong><i id="mobileTapeBgSwatch"></i><span id="mobileTapeBgText">-</span></strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Schrift</span>
|
||||||
|
<strong><i id="mobileTapeTextSwatch"></i><span id="mobileTapeTextText">-</span></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid-2">
|
<div class="grid-2">
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
Reference in New Issue
Block a user