feat(notice): add click-to-toggle between compact and detailed display modes

Click anywhere on the notice content area to toggle between compact and
detailed (normal) display modes. A subtle hint label '▸ 简洁' / '▸ 详细'
appears on hover.

CSS transitions animate the layout switch:
- Content area: max-width + opacity crossfade (280ms cubic-bezier)
- Message text: max-height expand/collapse + opacity fade (280ms)
- Actions: max-height + margin collapse + opacity fade (260ms)
- Container: grid-template-columns + padding + border-radius morph (260ms)

The switch uses a two-phase animation: content fades out (180ms), layout
changes via CSS transition, then content fades back in (60ms delay). This
prevents jarring content jumps during the layout shift.
This commit is contained in:
Youzini-afk
2026-04-29 17:19:47 +08:00
parent 07adcf30a8
commit fe48e3eec9

View File

@@ -58,6 +58,11 @@ function ensureStyle(doc) {
font-family: "Noto Sans SC", "PingFang SC", "Microsoft YaHei UI", sans-serif;
backdrop-filter: blur(10px) saturate(125%);
-webkit-backdrop-filter: blur(10px) saturate(125%);
transition:
grid-template-columns 260ms cubic-bezier(0.22, 1, 0.36, 1),
padding 260ms cubic-bezier(0.22, 1, 0.36, 1),
border-radius 260ms cubic-bezier(0.22, 1, 0.36, 1),
width 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
.st-bme-notice[data-layout="compact"] {
@@ -70,6 +75,40 @@ function ensureStyle(doc) {
padding: 10px;
}
.st-bme-notice__content {
min-width: 0;
overflow: hidden;
transition: max-width 280ms cubic-bezier(0.22, 1, 0.36, 1),
opacity 220ms ease;
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__content {
display: flex;
align-items: center;
min-width: 0;
}
.st-bme-notice__message {
margin: 4px 0 0;
font-size: 14px;
line-height: 1.38;
color: rgba(240, 246, 255, 0.86);
white-space: pre-wrap;
word-break: break-word;
transition: max-height 280ms cubic-bezier(0.22, 1, 0.36, 1),
opacity 220ms ease,
margin 260ms ease;
}
.st-bme-notice__actions {
display: flex;
gap: 8px;
margin-top: 10px;
transition: max-height 260ms cubic-bezier(0.22, 1, 0.36, 1),
opacity 220ms ease,
margin 260ms ease;
}
.st-bme-notice::after {
content: "";
position: absolute;
@@ -104,16 +143,6 @@ function ensureStyle(doc) {
animation: stBmeNoticeBusy 900ms linear infinite;
}
.st-bme-notice__content {
min-width: 0;
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__content {
display: flex;
align-items: center;
min-width: 0;
}
.st-bme-notice__title {
margin: 0;
font-size: 17px;
@@ -151,21 +180,6 @@ function ensureStyle(doc) {
-webkit-mask-image: linear-gradient(90deg, transparent 0%, black 6%, black 88%, transparent 100%);
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__message,
.st-bme-notice[data-layout="compact"] .st-bme-notice__progress {
display: none !important;
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__actions {
margin: 0 0 0 8px;
}
.st-bme-notice__actions {
display: flex;
gap: 8px;
margin-top: 10px;
}
.st-bme-notice__action {
min-height: 30px;
padding: 0 12px;
@@ -213,6 +227,64 @@ function ensureStyle(doc) {
outline: none;
}
.st-bme-notice__toggle-hint {
position: absolute;
bottom: 6px;
right: 32px;
font-size: 10px;
color: rgba(240, 246, 255, 0.35);
pointer-events: none;
transition: opacity 180ms ease;
opacity: 0;
}
.st-bme-notice:hover .st-bme-notice__toggle-hint {
opacity: 1;
}
.st-bme-notice[data-layout="normal"] .st-bme-notice__toggle-hint::after {
content: "▸ 简洁";
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__toggle-hint::after {
content: "▸ 详细";
}
.st-bme-notice--switching {
pointer-events: none;
}
.st-bme-notice--switching .st-bme-notice__content {
opacity: 0;
}
.st-bme-notice[data-layout="normal"] .st-bme-notice__content {
max-width: 360px;
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__actions {
max-height: 0;
opacity: 0;
margin-top: 0;
overflow: hidden;
}
.st-bme-notice[data-layout="normal"] .st-bme-notice__actions {
max-height: 60px;
opacity: 1;
}
.st-bme-notice[data-layout="normal"] .st-bme-notice__message {
max-height: 200px;
opacity: 1;
}
.st-bme-notice[data-layout="compact"] .st-bme-notice__message {
max-height: 0;
opacity: 0;
margin-top: 0;
}
.st-bme-notice__progress {
position: absolute;
left: 0;
@@ -334,7 +406,7 @@ function applyNoticeState(item, input, progress) {
const message = item.querySelector(".st-bme-notice__message");
if (message) {
message.textContent = input.message || "";
message.hidden = isCompact || !String(input.message || "").trim();
message.hidden = !String(input.message || "").trim();
if (input.marquee) {
message.classList.add("st-bme-notice__message--marquee");
} else {
@@ -346,12 +418,10 @@ function applyNoticeState(item, input, progress) {
const actionButton = item.querySelector(".st-bme-notice__action");
if (actionWrap && actionButton) {
if (input.action?.label) {
actionWrap.style.display = "";
actionButton.style.display = "";
actionButton.textContent = input.action.label;
actionButton.dataset.kind = input.action.kind || "neutral";
} else {
actionWrap.style.display = "none";
actionButton.style.display = "none";
actionButton.textContent = "";
actionButton.dataset.kind = "neutral";
@@ -405,6 +475,9 @@ export function showManagedBmeNotice(input) {
const progress = doc.createElement("div");
progress.className = "st-bme-notice__progress";
const toggleHint = doc.createElement("span");
toggleHint.className = "st-bme-notice__toggle-hint";
content.appendChild(title);
content.appendChild(message);
actions.appendChild(actionButton);
@@ -412,11 +485,13 @@ export function showManagedBmeNotice(input) {
item.appendChild(icon);
item.appendChild(content);
item.appendChild(closeButton);
item.appendChild(toggleHint);
item.appendChild(progress);
let currentInput = input || {};
let closed = false;
let closeTimer = null;
let switching = false;
const clearCloseTimer = () => {
if (!closeTimer) return;
@@ -465,6 +540,47 @@ export function showManagedBmeNotice(input) {
close();
});
content.addEventListener("click", (event) => {
if (closed || switching) return;
if (event.target === actionButton || event.target === closeButton) return;
if (actionButton.contains(event.target) || closeButton.contains(event.target)) return;
switching = true;
item.classList.add("st-bme-notice--switching");
const currentLayout = item.dataset.layout || "normal";
const nextLayout = currentLayout === "compact" ? "normal" : "compact";
setTimeout(() => {
item.dataset.layout = nextLayout;
currentInput.displayMode = nextLayout;
if (nextLayout === "normal") {
const msgEl = item.querySelector(".st-bme-notice__message");
if (msgEl) msgEl.hidden = !String(currentInput.message || "").trim();
}
if (nextLayout === "normal" && !currentInput.persist) {
clearCloseTimer();
const duration = Math.max(1400, currentInput.duration_ms || 3200);
closeTimer = setTimeout(close, duration);
const progressEl = item.querySelector(".st-bme-notice__progress");
if (progressEl) {
progressEl.style.display = "";
progressEl.style.animationDuration = `${duration}ms`;
progressEl.style.animation = "none";
void progressEl.offsetHeight;
progressEl.style.animation = "";
}
}
setTimeout(() => {
item.classList.remove("st-bme-notice--switching");
switching = false;
}, 60);
}, 180);
});
host.appendChild(item);
return {