Importiertes Bild landet mittig auf der gewaehlten Slide

Der Import legte das Bild bisher nur ab und liess die Zuordnung in einem
Auswahlfeld liegen. Auf der Slide war damit nichts zu sehen, und der Import
wirkte wie ein Fehlschlag -- zu Recht, denn ohne den Weg ueber "Inhalt" war
das Bild nirgends.

Jetzt landet es sofort auf der gerade gewaehlten Slide, mittig, und ist
gleich ausgewaehlt. Die Mitte wird gemessen statt gerechnet: das Blatt ist
gepolstert und die Mockups stehen perspektivisch im Raum, ein Dreisatz ueber
left und bottom laege daneben. Der Versatz wandert in die Bearbeitung, das
Bild bleibt also frei verschiebbar.

Ein zweites Bild gibt es dafuer jetzt auf jeder Slide, nicht nur auf
Feature-Slides -- sonst waere die Zusage "landet auf der gewaehlten Slide"
auf der Titel-Slide gebrochen.

Geprueft ueber den echten Weg (Datei ins Feld, change ausloesen) auf einer
Feature- und auf der Titel-Slide: Versatz 0/0 px in beiden Faellen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-07 18:39:45 +02:00
1 parent 11eaf3f3e7
commit cbb5141d8b
1 file changed
+63 -29
+63 -29
View File
@@ -814,8 +814,9 @@
<summary>Eigene Bilder</summary>
<input type="file" id="bild-datei" accept="image/png,image/jpeg,image/webp,image/gif,image/avif" multiple hidden>
<button class="btn secondary" id="bild-waehlen" style="width:100%">Bilder importieren …</button>
<div class="hint" id="bild-hinweis">Oder eine Datei auf eine Slide ziehen — sie wird
dort das zweite Bild und lässt sich im Bearbeiten-Modus frei schieben.
<div class="hint" id="bild-hinweis">Das Bild landet mittig auf der gewählten Slide.
Auf eine andere Slide ziehen legt es dort ab. Mit <b>E</b> lässt es sich schieben
und über <b>A−</b>/<b>A+</b> in der Größe ändern.<br>
Die Datei landet unverändert unter <b>assets/eigene/</b> und gehört mit in den Commit.</div>
</details>
@@ -1792,19 +1793,6 @@
'<img class="laptop-shot" alt="" src="' + assets[sl.img] + '"></div>';
page.appendChild(mock);
if (sl.media2) {
const m2 = sl.media2;
const el2 = document.createElement("div");
el2.className = "mock mock-2";
el2.style.cssText =
"--mock-w:" + m2.w + "px;--mock-ar:" + m2.ar +
";--mock-left:" + m2.left + "px;--m2-bottom:" + m2.bottom +
"px;--m2-z:" + m2.z + ";--rot:" + (m2.rot || 0) + "deg";
el2.innerHTML =
'<div class="mock-inner"><img class="laptop-shot" alt="" src="' +
assets[m2.img] + '"></div>';
page.appendChild(el2);
}
if (sl.note) {
const nt = sl.note;
@@ -1822,6 +1810,23 @@
}
}
/* Ein zweites Bild gibt es auf jeder Slide, nicht nur auf Feature-Slides:
ein importiertes Bild soll auf der gewaehlten Slide landen, egal
welche das ist. */
if (sl.media2) {
const m2 = sl.media2;
const el2 = document.createElement("div");
el2.className = "mock mock-2";
el2.style.cssText =
"--mock-w:" + m2.w + "px;--mock-ar:" + m2.ar +
";--mock-left:" + m2.left + "px;--m2-bottom:" + m2.bottom +
"px;--m2-z:" + m2.z + ";--rot:" + (m2.rot || 0) + "deg";
el2.innerHTML =
'<div class="mock-inner"><img class="laptop-shot" alt="" src="' +
assets[m2.img] + '"></div>';
page.appendChild(el2);
}
renderPage(page, j);
return page;
}
@@ -2532,19 +2537,46 @@
});
}
async function alsZweitesBild(i, pfad) {
/* Ein Element genau auf die Mitte der Slide setzen. Gerechnet wird nicht,
sondern gemessen: das Blatt ist gepolstert, die Mockups stehen schief im
Raum, und ein Dreisatz ueber left und bottom laege daneben. Der Versatz
wandert in die Bearbeitung, ist also nachtraeglich frei verschiebbar. */
function mittigSetzen(i, key) {
const node = deck.querySelector(
'.page[data-j="' + i + '"] [data-edit="' + key + '"]');
if (!node) return;
const slide = node.closest(".slide");
if (!slide) return;
const sr = slide.getBoundingClientRect(), nr = node.getBoundingClientRect();
if (!sr.width || !nr.width) return;
const k = sr.width / 1080;
const dx = ((nr.left + nr.width / 2) - (sr.left + sr.width / 2)) / k;
const dy = ((nr.top + nr.height / 2) - (sr.top + sr.height / 2)) / k;
const set = (edits[i][key] = edits[i][key] || {});
set.dx = Math.round((set.dx || 0) - dx);
set.dy = Math.round((set.dy || 0) - dy);
applyEditsAll();
}
async function alsZweitesBild(i, pfad, mittig) {
const ar = await seitenverhaeltnis(pfad);
const w = werteVon(i);
const alt = w.media2 || SLIDES[i].media2 || {};
const vorher = w.media2 || SLIDES[i].media2 || {};
w.media2 = {
img: pfad, w: alt.w || 400, ar: +ar.toFixed(4),
left: alt.left != null ? alt.left : 500,
bottom: alt.bottom != null ? alt.bottom : 60,
z: alt.z || 2, rot: alt.rot || 0,
img: pfad, w: vorher.w || 480, ar: +ar.toFixed(4),
left: vorher.left != null ? vorher.left : 300,
bottom: vorher.bottom != null ? vorher.bottom : 400,
z: vorher.z || 2, rot: mittig ? 0 : (vorher.rot || 0),
};
slidesNeuAufbauen();
deckNeuBauen();
show(i);
// Ein frisch importiertes Bild soll man sehen, nicht suchen.
if (mittig) {
edits[i]["mock-2"] = {};
mittigSetzen(i, "mock-2");
pick(i, "mock-2");
}
saveState();
}
@@ -2561,14 +2593,16 @@
}
// Beim Ablegen auf einer Slide wandert das erste Bild gleich dorthin. Ueber
// den Knopf importiert man nur; zugeordnet wird dann in den Feldern.
if (typeof zielSlide === "number") {
await alsZweitesBild(zielSlide, pfade[0]);
setStatus(pfade.length + " Bild(er) importiert, erstes auf Slide " +
(zielSlide + 1) + " gelegt", "ok");
} else {
syncInhalt();
setStatus(pfade.length + " Bild(er) importiert · unter Inhalt zuweisen", "ok");
}
/* Ohne Ziel gilt die gewaehlte Slide. Frueher wurde nur importiert und
die Zuordnung blieb in einem Auswahlfeld liegen -- das Bild war damit
nirgends zu sehen und der Import wirkte wie ein Fehlschlag. */
const ziel = typeof zielSlide === "number" ? zielSlide : current;
await alsZweitesBild(ziel, pfade[0], true);
syncInhalt();
setStatus(pfade.length === 1
? "Bild auf Slide " + (ziel + 1) + " gelegt · mit E verschieben"
: pfade.length + " Bilder importiert, erstes auf Slide " + (ziel + 1) +
" gelegt · Rest unter Inhalt", "ok");
}
document.getElementById("bild-waehlen").addEventListener("click",