feat: Der Zuschnitt ist ein Rahmen, den man aufzieht

Zoomen war das falsche Werkzeug. Man konnte nur naeher heran, aber nicht
sagen, WAS man behalten will – und das Ergebnis war immer quadratisch, auch
wenn das Logo breit ist.

Jetzt liegt ein Rahmen auf dem Bild: ziehen zum Verschieben, acht Griffe zum
Aufziehen. Aussen abgedunkelt, Drittel-Linien zum Ausrichten, und darunter
steht, wie gross der Ausschnitt gerade ist. "Ganzes Bild" setzt zurueck.

Das Seitenverhaeltnis des Ausschnitts bleibt. Ein breites Logo wird ein
breites Logo, kein quadratisches mit Luft an den Seiten.

Der Ausschnitt wird in BILDPUNKTEN gefuehrt, nicht in Bildschirmpunkten –
umgerechnet wird nur fuer die Anzeige. So trifft das Ergebnis genau den
Bereich im Rahmen, ohne dass sich ueber viele Zieh-Bewegungen Rundungsfehler
aufaddieren.

Am Bildrand haelt die gegenueberliegende Kante still, statt dass der Rahmen
beim Anschlag mitwandert; zieht man einen Griff ueber die eigene Kante
hinaus, bleibt sie stehen, statt sich umzustuelpen. Auf dem Telefon sind die
Griffe groesser – mit dem Finger waeren vierzehn Pixel nicht zu treffen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-07 19:59:11 +02:00
co-authored by Claude Opus 5
parent 9b9ce77267
commit 26718b1301
4 changed files with 223 additions and 117 deletions
+70 -20
View File
@@ -1774,38 +1774,88 @@ tr.row-dup {
/* --- Logo zuschneiden ---------------------------------------------------- */
/* Der Rahmen IST der Ausschnitt: Was hier steht, wird gespeichert. Deshalb
nichts abdunkeln und keine Hilfslinien – man soll das Ergebnis sehen, nicht
eine Vorschau davon. */
.zuschnitt-rahmen {
.zuschnitt-flaeche {
position: relative;
overflow: hidden;
margin: 0 auto var(--sp-3);
border: 1px solid var(--border-strong);
margin: 0 auto var(--sp-2);
border-radius: var(--radius);
/* Schachbrett: zeigt, wo das Bild durchsichtig ist. Bei einem freigestellten
Logo ist das der Unterschied zwischen "weisser Kasten" und "nichts da". */
background:
repeating-conic-gradient(var(--border) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
touch-action: none;
user-select: none;
overflow: hidden;
}
.zuschnitt-rahmen.beweglich { cursor: grab; }
.zuschnitt-rahmen.beweglich:active { cursor: grabbing; }
.zuschnitt-rahmen img {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50%;
margin-top: 0;
translate: 0 -50%;
max-width: none;
.zuschnitt-flaeche img {
display: block;
width: 100%;
height: 100%;
pointer-events: none;
}
.zuschnitt-regler {
.zuschnitt-rahmen {
position: absolute;
box-sizing: border-box;
border: 1px solid #fff;
cursor: move;
/* Alles ausserhalb abdunkeln – mit EINEM Schatten statt vier Kacheln.
So bleibt der Ausschnitt das Helle, und man sieht sofort, was bleibt. */
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.55);
}
/* Drittel-Linien: helfen beim Ausrichten, ohne den Ausschnitt zuzustellen. */
.zuschnitt-rahmen::before,
.zuschnitt-rahmen::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.35;
}
.zuschnitt-rahmen::before {
border-left: 1px solid #fff;
border-right: 1px solid #fff;
left: 33.33%;
right: 33.33%;
}
.zuschnitt-rahmen::after {
border-top: 1px solid #fff;
border-bottom: 1px solid #fff;
top: 33.33%;
bottom: 33.33%;
}
.zuschnitt-griff {
position: absolute;
width: 14px;
height: 14px;
background: #fff;
border-radius: 3px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}
.griff-nw { left: -7px; top: -7px; cursor: nwse-resize; }
.griff-n { left: calc(50% - 7px); top: -7px; cursor: ns-resize; }
.griff-ne { right: -7px; top: -7px; cursor: nesw-resize; }
.griff-w { left: -7px; top: calc(50% - 7px); cursor: ew-resize; }
.griff-e { right: -7px; top: calc(50% - 7px); cursor: ew-resize; }
.griff-sw { left: -7px; bottom: -7px; cursor: nesw-resize; }
.griff-s { left: calc(50% - 7px); bottom: -7px; cursor: ns-resize; }
.griff-se { right: -7px; bottom: -7px; cursor: nwse-resize; }
.zuschnitt-fuss {
display: flex;
align-items: center;
gap: var(--sp-2);
margin-bottom: var(--sp-2);
}
.zuschnitt-regler input[type="range"] { flex: 1; width: auto; }
.zuschnitt-regler .icon { color: var(--muted); flex: none; }
.zuschnitt-fuss span { flex: 1; font-variant-numeric: tabular-nums; }
/* Auf dem Telefon sind die Griffe mit dem Finger sonst nicht zu treffen. */
@media (pointer: coarse) {
.zuschnitt-griff { width: 20px; height: 20px; }
.griff-nw, .griff-w, .griff-sw { left: -10px; }
.griff-ne, .griff-e, .griff-se { right: -10px; }
.griff-nw, .griff-n, .griff-ne { top: -10px; }
.griff-sw, .griff-s, .griff-se { bottom: -10px; }
.griff-n, .griff-s { left: calc(50% - 10px); }
.griff-w, .griff-e { top: calc(50% - 10px); }
}