feat(website): show project description as always-visible desc-row on category pages

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vinta Chen
2026-05-03 12:47:17 +08:00
parent d7a916837c
commit 1468ae78ff
4 changed files with 84 additions and 10 deletions

2
uv.lock generated
View File

@@ -3,7 +3,7 @@ revision = 3
requires-python = ">=3.13"
[options]
exclude-newer = "2026-04-30T04:22:17.540198Z"
exclude-newer = "2026-04-30T04:38:39.45925Z"
exclude-newer-span = "P3D"
[[package]]

View File

@@ -113,7 +113,12 @@ document
rows.forEach(function (row, i) {
row._origIndex = i;
row._expandRow = row.nextElementSibling;
let next = row.nextElementSibling;
if (next && next.classList.contains("desc-row")) {
row._descRow = next;
next = next.nextElementSibling;
}
row._expandRow = next;
});
function collapseAll() {
@@ -142,9 +147,11 @@ function applyFilters() {
if (show && query) {
if (!row._searchText) {
let text = row.textContent.toLowerCase();
const next = row.nextElementSibling;
if (next && next.classList.contains("expand-row")) {
text += " " + next.textContent.toLowerCase();
if (row._descRow) {
text += " " + row._descRow.textContent.toLowerCase();
}
if (row._expandRow) {
text += " " + row._expandRow.textContent.toLowerCase();
}
row._searchText = text;
}
@@ -152,6 +159,9 @@ function applyFilters() {
}
if (row.hidden !== !show) row.hidden = !show;
if (row._descRow && row._descRow.hidden !== !show) {
row._descRow.hidden = !show;
}
if (show) {
visibleCount++;
@@ -262,7 +272,8 @@ function sortRows() {
const frag = document.createDocumentFragment();
arr.forEach(function (row) {
frag.appendChild(row);
frag.appendChild(row._expandRow);
if (row._descRow) frag.appendChild(row._descRow);
if (row._expandRow) frag.appendChild(row._expandRow);
});
tbody.appendChild(frag);
applyFilters();
@@ -291,7 +302,11 @@ if (tbody) {
// Don't toggle if clicking a link or tag button
if (e.target.closest("a") || e.target.closest(".tag")) return;
const row = e.target.closest("tr.row");
let row = e.target.closest("tr.row");
if (!row) {
const descRow = e.target.closest("tr.desc-row");
if (descRow) row = descRow.previousElementSibling;
}
if (!row) return;
const isOpen = row.classList.contains("open");

View File

@@ -788,6 +788,11 @@ kbd {
box-shadow: inset 3px 0 0 var(--accent);
}
.row:has(+ .desc-row) td {
border-bottom-color: transparent;
padding-bottom: 0.35rem;
}
.row.open td {
background: linear-gradient(180deg, var(--row-open-start), var(--row-open-end));
border-bottom-color: transparent;
@@ -919,10 +924,58 @@ th[data-sort].sort-asc::after {
transform: rotate(90deg);
}
.desc-row td {
padding-top: 0;
padding-bottom: 1rem;
border-bottom: 1px solid var(--line);
color: var(--ink-soft);
font-size: var(--text-sm);
line-height: 1.6;
text-wrap: pretty;
overflow-wrap: break-word;
transition:
background-color 180ms ease,
border-color 180ms ease;
}
.row:not(.open) + .desc-row td {
border-bottom: 1px solid var(--line);
}
.row + .desc-row {
cursor: pointer;
}
.row:not(.open):hover td,
.row:not(.open):hover + .desc-row td {
background: var(--row-hover);
}
.row.open + .desc-row td {
background: linear-gradient(180deg, var(--row-open-start), var(--row-open-end));
border-bottom-color: transparent;
}
.desc-text {
max-width: none;
}
.desc-text a {
color: var(--accent-deep);
}
.desc-text a:hover {
color: var(--accent);
text-decoration: underline;
text-decoration-color: var(--accent-underline);
text-underline-offset: 0.2em;
}
.expand-row {
display: none;
}
.row.open + .desc-row + .expand-row,
.row.open + .expand-row {
display: table-row;
}

View File

@@ -204,13 +204,19 @@
</td>
<td class="col-arrow"><span class="arrow">&rarr;</span></td>
</tr>
{% if entry.description %}
<tr class="desc-row" aria-hidden="true">
<td class="col-num"></td>
<td colspan="5">
<div class="desc-text">{{ entry.description | safe }}</div>
</td>
</tr>
{% endif %}
<tr class="expand-row" id="expand-{{ loop.index }}">
<td></td>
<td colspan="4">
<div class="expand-content">
{% if entry.description %}
<div class="expand-desc">{{ entry.description | safe }}</div>
{% endif %} {% if entry.also_see %}
{% if entry.also_see %}
<div class="expand-also-see">
Also see: {% for see in entry.also_see %}<a
href="{{ see.url }}"