Rebalance printable cards with simpler copy and ivory defaults

This commit is contained in:
2026-09-10 13:45:14 -04:00
parent 1c29fb2a8f
commit 8544c4128b
3 changed files with 27 additions and 1 deletions
@@ -24,7 +24,7 @@ export function GuestSignStudio({ eventId, title, guestUrl, qr, warning, savedUr
eventId: string; title: string; guestUrl: string; qr: SignQr; warning: string | null;
savedUrl: string | null; savedRevision: string | null; canSave: boolean;
}) {
const [design, setDesign] = useState<SignDesign>({ title, headline: "Share your favorite moments", message: "Help us see the day through your eyes. Add your photos to our shared album.", paper: "letter", ink: "indigo", font: "funnel", layout: "typography", background: brandPalette.primary, accent: "#ffffff", decoration: "minimal", showBrand: true, customWidth: 8.5, customHeight: 11, unit: "in" });
const [design, setDesign] = useState<SignDesign>({ title, headline: "Share your photos", message: "Wed love to see what you captured.", paper: "card6x4", ink: "black", font: "funnel", layout: "compact", background: brandPalette.background, accent: brandPalette.ink, decoration: "minimal", showBrand: true, customWidth: 8.5, customHeight: 11, unit: "in" });
const [fontError, setFontError] = useState(false);
const [assetBusy, setAssetBusy] = useState(false);
const [loadingDesign, setLoadingDesign] = useState(Boolean(savedUrl));
+4
View File
@@ -18,6 +18,10 @@ test("text controls change each text independently without resizing the QR", ()
const url = "https://ma.hadlock.tech/e/demo", qr = signQr(url);
const base: SignDesign = { ...design, layout: "compact", paper: "card6x4", title: "Event", headline: "Share", message: "Welcome" };
const normal = guestSignSvg(base, url, qr);
expect(normal).toContain("Scan to upload");
expect(normal).not.toContain("Your photos. Our story.");
expect(normal).not.toContain("Photos and notes welcome.");
expect(normal).not.toContain("No app or account needed.");
for (const [key, label] of [["titleScale", "Event"], ["headlineScale", "Share"], ["messageScale", "Welcome"]] as const) {
const sized = { ...base, [key]: 150 };
const svg = guestSignSvg(sized, url, qr);
+22
View File
@@ -101,6 +101,28 @@ export function guestSignSvg(design: SignDesign, guestUrl: string, qr: SignQr) {
const qrY = compact ? (landscape ? 260 : 530) : landscape ? (photoLed ? 415 : 235) : (photoLed ? 755 : 605);
const messageY = top + (compact ? 310 : photoLed ? 250 : 445);
const brandMarkup = logo ? `<image href="${logo}" x="${cx - 100}" y="${landscape ? 700 : 1005}" width="200" height="48" preserveAspectRatio="xMidYMid meet"/>` : design.showBrand !== false ? `<g data-brand-lockup="manyangles" color="${headingColor}" fill="currentColor" transform="translate(${cx - 96} ${landscape ? 711 : 1016})"><svg width="32" height="32" viewBox="0 0 32 32" fill="none"><path d="M14 4H8a4 4 0 0 0-4 4v6M18 4h6a4 4 0 0 1 4 4v6M28 18v6a4 4 0 0 1-4 4h-6M14 28H8a4 4 0 0 1-4-4v-6" stroke="currentColor" stroke-width="3" stroke-linecap="round"/><circle cx="21" cy="11" r="2.25" fill="currentColor"/><path d="m8.5 22 5-6.2a1.7 1.7 0 0 1 2.6-.1l2.6 2.9 1.7-1.8a1.7 1.7 0 0 1 2.5 0l1.6 1.8" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg><text x="40" y="24" font-family="SignGeologica, sans-serif" font-size="26.5" font-weight="700" letter-spacing="-1.06" style="font-variation-settings:&#39;SHRP&#39; 70">Manyangles</text></g>` : "";
if (!photoLed) {
const textX = landscape ? 100 : 85;
const textWidth = landscape ? 530 : 680;
const codeX = landscape ? 760 : (w - qrSize) / 2;
const codeY = landscape ? 210 : 475;
const footerY = landscape ? 655 : 955;
return `<svg xmlns="http://www.w3.org/2000/svg" width="${paper.width}" height="${paper.height}" viewBox="0 0 850 ${paper.viewHeight}">
<title>${escapeXml(design.title)} — guest photo sign</title><style>${fontFaces}</style>
<rect width="850" height="${paper.viewHeight}" fill="${background}"/>
<g transform="translate(${(850 - w * scale) / 2} ${(paper.viewHeight - h * scale) / 2}) scale(${scale})" font-family="SignInter, sans-serif" fill="${foreground}">
<g font-family="${headingFont}" fill="${headingColor}" letter-spacing="-1.8">
${sizedText(design.headline, textX, landscape ? 260 : 170, 76, design.headlineScale ?? 100, textWidth, 185, 600)}
</g>
${sizedText(design.message, textX, landscape ? 450 : 355, 29, design.messageScale ?? 100, textWidth, landscape ? 150 : 100)}
<svg x="${codeX}" y="${codeY}" width="${qrSize}" height="${qrSize}" viewBox="0 0 ${qr.size + 8} ${qr.size + 8}" shape-rendering="crispEdges"><rect width="100%" height="100%" fill="white"/><path d="${qr.path}" transform="translate(4 4)" fill="black"/></svg>
${sizedText("Scan to upload", codeX + qrSize / 2, codeY + qrSize + 45, 25, 100, qrSize, 40, 500, true)}
${sizedText(guestUrl.replace(/^https?:\/\//, ""), codeX + qrSize / 2, codeY + qrSize + 78, 16, 100, qrSize + 40, 50, 400, true)}
${sizedText(design.title, textX, footerY, 23, design.titleScale ?? 100, landscape ? 530 : 480, 65, 500)}
<g transform="translate(${landscape ? 948 : 598} ${footerY - 21}) scale(.7) translate(${-(cx - 100)} ${-(landscape ? 700 : 1005)})">${brandMarkup}</g>
</g>
</svg>`;
}
return `<svg xmlns="http://www.w3.org/2000/svg" width="${paper.width}" height="${paper.height}" viewBox="0 0 850 ${paper.viewHeight}">
<title>${escapeXml(design.title)} — guest photo sign</title>
<style>${fontFaces}</style>