From f857f4d33740cb0b839b8365d1ec23b3a4aea1eb Mon Sep 17 00:00:00 2001 From: Peter Li Date: Fri, 17 Jul 2026 07:52:23 +0800 Subject: [PATCH] feat: restyle semantic callouts --- src/components/_callouts.scss | 56 ++++++++++++++++++++++++++-- tests/components.test.mjs | 69 +++++++++++++++++++++++++++++++++-- tests/helpers/css.mjs | 7 ++++ theme.css | 45 +++++++++++++++++++++-- 4 files changed, 168 insertions(+), 9 deletions(-) diff --git a/src/components/_callouts.scss b/src/components/_callouts.scss index bdd7f70..a4808fc 100644 --- a/src/components/_callouts.scss +++ b/src/components/_callouts.scss @@ -1,9 +1,59 @@ body { - --callout-border-width: 1px; - --callout-border-opacity: 0.25; - --callout-radius: 6px; + --callout-border-width: 0px; + --callout-border-opacity: 0; + --callout-radius: 7px; --callout-blend-mode: normal; --callout-title-size: var(--font-small); --callout-title-weight: 600; --callout-content-background: transparent; } + +.callout { + position: relative; + overflow: hidden; + background-color: rgba( + var(--callout-color), + var(--aera-callout-background-opacity) + ); + color: color-mix( + in srgb, + rgb(var(--callout-color)) 72%, + var(--text-normal) + ); + border: 0; +} + +.callout-title { + padding-inline-end: var(--size-4-12); + color: color-mix( + in srgb, + rgb(var(--callout-color)) 84%, + var(--text-normal) + ); +} + +.callout-content { + padding-inline-end: var(--size-4-12); +} + +.callout-icon { + position: absolute; + inset-inline-end: var(--size-4-2); + inset-block-end: calc(var(--size-4-2) * -1); + opacity: 0.09; + pointer-events: none; +} + +.callout-icon svg { + width: 48px; + height: 48px; +} + +.callout-fold { + position: relative; + z-index: 2; +} + +.callout.is-collapsed .callout-icon { + display: none; +} diff --git a/tests/components.test.mjs b/tests/components.test.mjs index 72ce383..4aecc2a 100644 --- a/tests/components.test.mjs +++ b/tests/components.test.mjs @@ -14,6 +14,13 @@ const allowedSelectors = new Set([ ".theme-light", ".theme-dark", "body", + ".callout", + ".callout-title", + ".callout-content", + ".callout-icon", + ".callout-icon svg", + ".callout-fold", + ".callout.is-collapsed .callout-icon", ":where(.markdown-rendered pre:not(.frontmatter))", ":where(.markdown-source-view.mod-cm6 .HyperMD-codeblock)", ]); @@ -85,9 +92,9 @@ test("styles callouts without replacing semantic type colors", () => { "--callout-padding": "var(--size-4-3) var(--size-4-4)", "--callout-title-padding": "0", "--callout-content-padding": "var(--size-4-2) 0 0", - "--callout-border-width": "1px", - "--callout-border-opacity": "0.25", - "--callout-radius": "6px", + "--callout-border-width": "0px", + "--callout-border-opacity": "0", + "--callout-radius": "7px", "--callout-blend-mode": "normal", "--callout-title-size": "var(--font-small)", "--callout-title-weight": "600", @@ -99,6 +106,62 @@ test("styles callouts without replacing semantic type colors", () => { } }); +test("uses a borderless semantic callout surface", () => { + const callout = declarationsFor(css, ".callout"); + + assert.deepEqual(Object.fromEntries(callout), { + position: "relative", + overflow: "hidden", + "background-color": + "rgba(var(--callout-color), var(--aera-callout-background-opacity))", + color: + "color-mix(in srgb, rgb(var(--callout-color)) 72%, var(--text-normal))", + border: "0", + }); +}); + +test("keeps callout text clear of the watermark", () => { + const title = declarationsFor(css, ".callout-title"); + const content = declarationsFor(css, ".callout-content"); + + assert.equal(title.has("position"), false); + assert.deepEqual(Object.fromEntries(title), { + "padding-inline-end": "var(--size-4-12)", + color: + "color-mix(in srgb, rgb(var(--callout-color)) 84%, var(--text-normal))", + }); + assert.deepEqual(Object.fromEntries(content), { + "padding-inline-end": "var(--size-4-12)", + }); +}); + +test("renders the native callout icon as a non-interactive watermark", () => { + assert.deepEqual(Object.fromEntries(declarationsFor(css, ".callout-icon")), { + position: "absolute", + "inset-inline-end": "var(--size-4-2)", + "inset-block-end": "calc(var(--size-4-2) * -1)", + opacity: "0.09", + "pointer-events": "none", + }); + assert.deepEqual( + Object.fromEntries(declarationsFor(css, ".callout-icon svg")), + { + width: "48px", + height: "48px", + }, + ); + assert.deepEqual(Object.fromEntries(declarationsFor(css, ".callout-fold")), { + position: "relative", + "z-index": "2", + }); + assert.deepEqual( + Object.fromEntries( + declarationsFor(css, ".callout.is-collapsed .callout-icon"), + ), + { display: "none" }, + ); +}); + test("defines the complete table component variables", () => { assertPrefixedDeclarations(["--table-"], { "--table-background": "transparent", diff --git a/tests/helpers/css.mjs b/tests/helpers/css.mjs index 30a9a70..140e5d1 100644 --- a/tests/helpers/css.mjs +++ b/tests/helpers/css.mjs @@ -4,6 +4,13 @@ const allowedThemeSelectors = new Set([ ".theme-light", ".theme-dark", "body", + ".callout", + ".callout-title", + ".callout-content", + ".callout-icon", + ".callout-icon svg", + ".callout-fold", + ".callout.is-collapsed .callout-icon", ":where(.markdown-rendered pre:not(.frontmatter))", ":where(.markdown-source-view.mod-cm6 .HyperMD-codeblock)", ]); diff --git a/theme.css b/theme.css index 2e702bd..fa7d177 100644 --- a/theme.css +++ b/theme.css @@ -216,15 +216,54 @@ body { } body { - --callout-border-width: 1px; - --callout-border-opacity: 0.25; - --callout-radius: 6px; + --callout-border-width: 0px; + --callout-border-opacity: 0; + --callout-radius: 7px; --callout-blend-mode: normal; --callout-title-size: var(--font-small); --callout-title-weight: 600; --callout-content-background: transparent; } +.callout { + position: relative; + overflow: hidden; + background-color: rgba(var(--callout-color), var(--aera-callout-background-opacity)); + color: color-mix(in srgb, rgb(var(--callout-color)) 72%, var(--text-normal)); + border: 0; +} + +.callout-title { + padding-inline-end: var(--size-4-12); + color: color-mix(in srgb, rgb(var(--callout-color)) 84%, var(--text-normal)); +} + +.callout-content { + padding-inline-end: var(--size-4-12); +} + +.callout-icon { + position: absolute; + inset-inline-end: var(--size-4-2); + inset-block-end: calc(var(--size-4-2) * -1); + opacity: 0.09; + pointer-events: none; +} + +.callout-icon svg { + width: 48px; + height: 48px; +} + +.callout-fold { + position: relative; + z-index: 2; +} + +.callout.is-collapsed .callout-icon { + display: none; +} + body { --table-background: transparent; --table-border-width: 1px;