Vorschau-Kuli in der App: identisch zu Directus (blau, 1.4, dezenter Wobble-Filter mit eindeutiger ID pro Inline-SVG), weisser Grund, PNG in natuerlicher Groesse
All checks were successful
Build & Deploy / deploy (push) Successful in 43s
All checks were successful
Build & Deploy / deploy (push) Successful in 43s
This commit is contained in:
@@ -13,6 +13,23 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
export type PreviewDoc = { art: 'brief' | 'umschlag'; svg: string };
|
||||
|
||||
// Vorschau-Optik „Kugelschreiber" – IDENTISCH zu Directus (neuauftrag): blaue
|
||||
// Tinte, etwas dicker (1.4) + dezenter Wobble (feTurbulence/Displacement) für die
|
||||
// typische Kuli-Linie. non-scaling-stroke bleibt (Glyphen skalieren per transform),
|
||||
// weißer Grund. Nur Anzeige/Download – die an die Produktion gehenden SVGs bleiben
|
||||
// schwarz. Inline-SVGs brauchen eine EINDEUTIGE Filter-ID pro Dokument.
|
||||
let inkSeq = 0;
|
||||
const inkify = (svg: string): string => {
|
||||
if (typeof svg !== 'string') return svg;
|
||||
const id = `skink${inkSeq++}`;
|
||||
return svg
|
||||
.replace(/stroke="#0{3,6}"/gi, 'stroke="#1a2a6c" stroke-opacity="0.95"')
|
||||
.replace(/stroke-width="0\.6"/gi, 'stroke-width="1.4"')
|
||||
.replace(/(<svg[^>]*>)/i, `$1<defs><filter id="${id}" x="-4%" y="-4%" width="108%" height="108%" color-interpolation-filters="sRGB"><feTurbulence type="fractalNoise" baseFrequency="0.05" numOctaves="1" seed="4" result="n"/><feDisplacementMap in="SourceGraphic" in2="n" scale="1.3" xChannelSelector="R" yChannelSelector="G"/></filter></defs>`)
|
||||
.replace(/(<rect[^>]*fill="#FFFFFF"[^>]*\/>)/i, `$1<g filter="url(#${id})">`)
|
||||
.replace(/<\/svg>\s*$/i, '</g></svg>');
|
||||
};
|
||||
|
||||
/** Ein Empfänger-Dokument: Schriftstück + optional zugehöriger Umschlag. */
|
||||
type Gruppe = { brief?: PreviewDoc; umschlag?: PreviewDoc };
|
||||
|
||||
@@ -81,10 +98,12 @@ export default function PreviewPanel({
|
||||
const m = zoomSvg.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/);
|
||||
const w = Math.round(m ? Number(m[1]) : 794);
|
||||
const h = Math.round(m ? Number(m[2]) : 1123);
|
||||
const scale = 2; // für ein scharfes Musterbild
|
||||
// Gespeicherte Vorschau in Kugelschreiber-Blau (wie die Anzeige); die
|
||||
// an die Produktion gehenden SVGs bleiben davon unberührt (schwarz).
|
||||
const inkSvg = zoomSvg.replace(/stroke="#0{3,6}"/gi, 'stroke="#1a2a6c"');
|
||||
// Natürliche Größe (nicht 2×): non-scaling-stroke wirkt konstant in
|
||||
// Gerätepixeln – bei 2× würde die Linie relativ dünn. So sieht das PNG aus
|
||||
// wie die Großansicht. Gespeicherte Vorschau in Kuli-Optik (wie Anzeige);
|
||||
// die an die Produktion gehenden SVGs bleiben schwarz.
|
||||
const scale = 1;
|
||||
const inkSvg = inkify(zoomSvg);
|
||||
const url = URL.createObjectURL(new Blob([inkSvg], { type: 'image/svg+xml;charset=utf-8' }));
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
@@ -142,7 +161,7 @@ export default function PreviewPanel({
|
||||
>
|
||||
<figcaption className="sk-preview-doc-label">{label}</figcaption>
|
||||
{/* Das SVG stammt aus unserer eigenen Generierung, nicht aus Nutzereingaben. */}
|
||||
<div className="sk-preview-doc-sheet" dangerouslySetInnerHTML={{ __html: svg }} />
|
||||
<div className="sk-preview-doc-sheet" dangerouslySetInnerHTML={{ __html: inkify(svg) }} />
|
||||
</figure>
|
||||
);
|
||||
|
||||
@@ -199,7 +218,7 @@ export default function PreviewPanel({
|
||||
aria-label="Vergrößerte Vorschau">
|
||||
<div className="sk-lightbox-sheet" style={{ aspectRatio: seitenverhaeltnis(zoomSvg) }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
dangerouslySetInnerHTML={{ __html: zoomSvg }} />
|
||||
dangerouslySetInnerHTML={{ __html: inkify(zoomSvg) }} />
|
||||
<div className="sk-lightbox-actions">
|
||||
<button className="sk-lightbox-close" onClick={(e) => { e.stopPropagation(); bildSpeichern(); }}>
|
||||
Bild speichern
|
||||
|
||||
@@ -460,21 +460,18 @@ button { font-family: inherit; }
|
||||
text-transform: uppercase;
|
||||
color: var(--sk-muted);
|
||||
}
|
||||
/* Kugelschreiber-Optik (blau, dickere Striche, Wobble) kommt aus inkify();
|
||||
der Untergrund ist weiß (das SVG bringt seinen weißen Grund selbst mit). */
|
||||
.sk-preview-doc-sheet {
|
||||
border: 1px solid var(--sk-border);
|
||||
border-radius: var(--sk-radius);
|
||||
background: var(--sk-bg-1);
|
||||
background: var(--sk-white);
|
||||
padding: var(--sk-space-2);
|
||||
overflow: hidden;
|
||||
}
|
||||
.sk-preview-doc-sheet svg { display: block; width: 100%; height: auto; }
|
||||
.sk-preview-doc:hover .sk-preview-doc-sheet { border-color: var(--sk-accent); }
|
||||
|
||||
/* Vorschau-Optik „Kugelschreiber": nur die Anzeige färbt die schwarzen Striche
|
||||
in Kuli-Blau. Die SVG-Daten (und damit die Produktion) bleiben schwarz. */
|
||||
.sk-preview-doc-sheet svg [stroke],
|
||||
.sk-lightbox-sheet svg [stroke] { stroke: #1a2a6c; }
|
||||
|
||||
/* ── Blättern: Pfeile als klare Buttons + deutliche Nummer ─ */
|
||||
.sk-preview-pager {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user