fix(campaign): stabilize message preview overlays

This commit is contained in:
2026-07-20 17:11:23 +02:00
parent 2e593b7fa4
commit 724ca779d6
3 changed files with 104 additions and 2 deletions

View File

@@ -88,11 +88,11 @@ export default function CampaignMessagePreviewOverlay({
}, [navigation, onClose]); }, [navigation, onClose]);
return ( return (
<div className="overlay-backdrop" role="dialog" aria-modal="true" aria-labelledby="message-preview-title"> <div className="overlay-backdrop message-preview-backdrop" role="dialog" aria-modal="true" aria-labelledby="message-preview-title">
<div className="modal-panel template-preview-modal message-preview-modal"> <div className="modal-panel template-preview-modal message-preview-modal">
<header className="modal-header"> <header className="modal-header">
<h2 id="message-preview-title">{title}</h2> <h2 id="message-preview-title">{title}</h2>
<button className="modal-close" onClick={onClose}>×</button> <button type="button" className="modal-close" aria-label={closeLabel} title={closeLabel} onClick={onClose}>×</button>
</header> </header>
<div className="modal-body"> <div className="modal-body">
{(recipientLabel || recipientNote || navigation) && {(recipientLabel || recipientNote || navigation) &&

View File

@@ -1096,9 +1096,36 @@
} }
/* Shared message preview overlay --------------------------------------- */ /* Shared message preview overlay --------------------------------------- */
.message-preview-modal {
width: min(920px, 100%);
height: min(780px, calc(100dvh - 48px));
max-height: calc(100dvh - 48px);
}
.message-preview-modal .modal-header {
min-width: 0;
}
.message-preview-modal .modal-header h2 {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.message-preview-modal .modal-body { .message-preview-modal .modal-body {
flex: 1 1 auto;
min-height: 0;
display: grid; display: grid;
align-content: start;
gap: 1rem; gap: 1rem;
overflow: auto;
scrollbar-gutter: stable;
}
.message-preview-modal .modal-footer {
align-items: center;
min-height: 68px;
} }
.message-preview-modal .message-display-body, .message-preview-modal .message-display-body,
@@ -1156,6 +1183,38 @@
font-weight: 700; font-weight: 700;
color: var(--text-primary); color: var(--text-primary);
} }
@media (max-width: 720px), (max-height: 700px) {
.message-preview-backdrop {
padding: 8px;
}
.message-preview-modal {
width: 100%;
height: calc(100dvh - 16px);
max-height: calc(100dvh - 16px);
}
.message-preview-modal .modal-header {
min-height: 52px;
padding-inline: 14px;
}
.message-preview-modal .modal-body {
padding: 14px;
}
.message-preview-modal .modal-footer {
min-height: 58px;
padding: 10px 14px;
}
.message-preview-modal .message-display-body,
.message-preview-modal .message-display-html-frame {
height: clamp(210px, 38dvh, 360px);
max-height: clamp(210px, 38dvh, 360px);
}
}
.attachment-source-path-cell { .attachment-source-path-cell {
display: grid; display: grid;
gap: 5px; gap: 5px;

View File

@@ -0,0 +1,43 @@
import { readFileSync } from "node:fs";
function assert(condition, message) {
if (!condition) throw new Error(message);
}
const overlaySource = readFileSync(
"src/features/campaigns/components/MessagePreviewOverlay.tsx",
"utf8"
);
const styles = readFileSync("src/styles/campaign-workspace.css", "utf8");
assert(
overlaySource.includes("overlay-backdrop message-preview-backdrop"),
"message previews expose their responsive backdrop hook"
);
assert(
overlaySource.includes('type="button" className="modal-close" aria-label={closeLabel} title={closeLabel}'),
"the close control has stable button semantics, an accessible name, and a tooltip"
);
assert(
styles.includes("height: min(780px, calc(100dvh - 48px));"),
"desktop previews use a stable responsive height"
);
assert(
styles.includes("flex: 1 1 auto;") &&
styles.includes("min-height: 0;") &&
styles.includes("overflow: auto;") &&
styles.includes("scrollbar-gutter: stable;"),
"the preview body owns scrolling without moving the surrounding actions"
);
assert(
styles.includes(".message-preview-modal .modal-footer") &&
styles.includes("min-height: 68px;"),
"the preview footer keeps a stable desktop action area"
);
assert(
styles.includes("height: calc(100dvh - 16px);") &&
styles.includes("height: clamp(210px, 38dvh, 360px);"),
"small viewports use their available dynamic height"
);
console.log("Message preview overlay structure checks passed.");