diff --git a/src/components/pages/ChangelogPage.astro b/src/components/pages/ChangelogPage.astro
index 03f68a8..0aee89b 100644
--- a/src/components/pages/ChangelogPage.astro
+++ b/src/components/pages/ChangelogPage.astro
@@ -33,9 +33,11 @@ const products = ["lite", "enterprise", "core"] as const;
const count = (id: string) => (id === "all" ? entries.length : entries.filter((e) => e.product === id).length);
const filters = [{ id: "all", label: c.all }, ...products.map((id) => ({ id, label: c.filters[id] }))];
+// The latest release of each product; its tile leads to its notes on this page when it has any.
const latest = products
.map((id) => entries.find((e) => e.product === id))
- .filter((e): e is ChangelogEntry => Boolean(e));
+ .filter((e): e is ChangelogEntry => Boolean(e))
+ .map((e) => ({ ...e, onPage: Boolean(e.notes || e.releaseNotes) || !e.url }));
// Newest month first; releases keep their newest-first order inside it.
const months: { key: string; label: string; items: ChangelogEntry[] }[] = [];
@@ -62,12 +64,12 @@ for (const e of entries) {
{latest.map((e) => (
-
+
{releaseProductName(e.product, lang)}
{e.tag}
))}
@@ -92,38 +94,45 @@ for (const e of entries) {
{m.items.map(async (entry) => {
const name = releaseProductName(entry.product, lang);
const notes = entry.notes;
- const Content = notes ? (await render(notes)).Content : null;
+ const published = notes ? undefined : entry.releaseNotes;
+ const source = notes ?? published;
+ const Content = source ? (await render(source)).Content : null;
+ // Core and Enterprise publish their notes in English only
+ const english = lang === "zh-CN" && published?.data.lang === "en";
+ // A release with notes opens in place to show them
+ const Wrap = Content ? "details" : "div";
+ const Row = Content ? "summary" : "div";
return (
{/* The anchor the release had while the page listed Enterprise alone (#v0.4.0). */}
{entry.legacyId && }
-
-
- {notes && (
-
-
{notes.data.title}
- {notes.data.highlights && (
-
- {notes.data.highlights.map((h) => - {h}
)}
-
- )}
- {Content && (
-
- {c.readNotes}
-
-
- )}
-
- )}
+
+
+
+ {name}
+
+ {entry.tag}
+ {english && EN}
+
+ {entry.url ? (
+
+ {c.github} ↗
+
+ ) : }
+
+
+ {Content && (
+
+ {notes &&
{notes.data.title}
}
+ {notes?.data.highlights && (
+
+ {notes.data.highlights.map((h) => - {h}
)}
+
+ )}
+
+
+ )}
+
);
})}
@@ -319,9 +328,16 @@ for (const e of entries) {
--prod: 168px;
--gap: 20px;
}
+ .cl-wrap > summary {
+ list-style: none;
+ cursor: pointer;
+ }
+ .cl-wrap > summary::-webkit-details-marker {
+ display: none;
+ }
.cl-row {
display: grid;
- grid-template-columns: var(--date) var(--prod) minmax(0, 1fr) 72px;
+ grid-template-columns: var(--date) var(--prod) minmax(0, 1fr) 72px 14px;
align-items: center;
gap: 4px var(--gap);
min-height: 44px;
@@ -331,9 +347,44 @@ for (const e of entries) {
transition: background 150ms;
}
.cl-row:hover,
- .changelog-item:target .cl-row {
+ .changelog-item:target .cl-row,
+ details[open] > .cl-row {
background: rgba(255, 255, 255, 0.03);
}
+ .cl-tagcell {
+ display: flex;
+ min-width: 0;
+ align-items: center;
+ gap: 10px;
+ }
+ .cl-en {
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ border-radius: 4px;
+ padding: 1px 5px;
+ font-family: var(--font-mono);
+ font-size: 9px;
+ letter-spacing: 0.06em;
+ color: var(--color-dim);
+ }
+ /* A chevron on the releases that open to show their notes */
+ .cl-chev {
+ width: 7px;
+ height: 7px;
+ justify-self: center;
+ border-right: 1.5px solid var(--color-dim);
+ border-bottom: 1.5px solid var(--color-dim);
+ transform: translateY(-2px) rotate(45deg);
+ transition: transform 200ms, border-color 150ms;
+ }
+ .cl-row:hover .cl-chev {
+ border-color: var(--color-text);
+ }
+ details[open] > .cl-row .cl-chev {
+ transform: translateY(2px) rotate(225deg);
+ }
+ .cl-chev-none {
+ visibility: hidden;
+ }
.changelog-item:target .cl-row {
box-shadow: inset 2px 0 0 rgb(var(--a1));
}
@@ -367,9 +418,13 @@ for (const e of entries) {
}
@media (max-width: 639px) {
.cl-row {
- grid-template-columns: minmax(0, 1fr) auto;
+ grid-template-columns: minmax(0, 1fr) auto 14px;
padding-block: 10px;
}
+ .cl-chev {
+ grid-column: 3;
+ grid-row: 1 / 3;
+ }
.cl-prod {
grid-column: 1;
grid-row: 1;
@@ -379,7 +434,7 @@ for (const e of entries) {
grid-row: 1;
justify-self: end;
}
- .cl-tag {
+ .cl-tagcell {
grid-column: 1;
grid-row: 2;
}
@@ -390,7 +445,7 @@ for (const e of entries) {
}
.cl-notes {
- padding: 8px 0 28px;
+ padding: 12px 0 32px;
}
/* the notes line up under the version */
@media (min-width: 640px) {
@@ -406,7 +461,7 @@ for (const e of entries) {
color: #fff;
}
.cl-highlights {
- margin: 14px 0 0;
+ margin: 14px 0 20px;
padding: 0;
list-style: none;
display: flex;
@@ -429,35 +484,6 @@ for (const e of entries) {
border-radius: 99px;
background: linear-gradient(135deg, rgb(var(--a1)), rgb(var(--a2)));
}
- .cl-more {
- margin-top: 16px;
- }
- .cl-more summary {
- display: inline-flex;
- min-height: 40px;
- align-items: center;
- gap: 6px;
- cursor: pointer;
- list-style: none;
- font-size: 14px;
- font-weight: 500;
- color: var(--color-text);
- transition: color 150ms;
- }
- .cl-more summary::-webkit-details-marker {
- display: none;
- }
- .cl-more summary::after {
- content: "↓";
- color: var(--color-dim);
- transition: transform 150ms;
- }
- .cl-more[open] summary::after {
- transform: rotate(180deg);
- }
- .cl-more summary:hover {
- color: #fff;
- }
.cl-prose {
margin-top: 12px;
font-size: 0.9rem;
@@ -466,7 +492,11 @@ for (const e of entries) {
margin-top: 1.8em;
font-size: 1.1rem;
}
- .cl-prose :global(h2:first-child) {
+ .cl-prose :global(h3) {
+ margin-top: 1.6em;
+ font-size: 1rem;
+ }
+ .cl-prose :global(:is(h2, h3, p):first-child) {
margin-top: 0;
}
/* Hide the # anchor link appended by rehypeAutolinkHeadings */
@@ -497,6 +527,18 @@ for (const e of entries) {