fix(web): center active filters and compact mobile cards

This commit is contained in:
kairee committed 2026-10-31 23:50:19 +08:00
1 parent d18ebbfb2f
commit 60d7b0f24f
6 files changed
+25 -5

No files matched your search

+9
View File
@@ -127,6 +127,15 @@ export function metricChips(metrics, active, dataName = "metric") {
)).join(""); )).join("");
} }
export function centerActiveChips(root) {
root.querySelectorAll(".chip-row.scroll-x").forEach((row) => {
const active = row.querySelector(".chip.active");
if (!active) return;
const target = active.offsetLeft - row.clientWidth / 2 + active.clientWidth / 2;
row.scrollLeft = Math.max(0, target);
});
}
export function pager(page, pages) { export function pager(page, pages) {
if (!pages || pages <= 1) return ""; if (!pages || pages <= 1) return "";
return `<div class="pager"> return `<div class="pager">
+6 -1
View File
@@ -258,9 +258,10 @@ h1, h2, h3, p { margin: 0; }
.notice-row { .notice-row {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: 4px 12px;
padding: 11px 14px; padding: 11px 14px;
border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border));
border-radius: 13px; border-radius: 13px;
@@ -501,6 +502,10 @@ h1, h2, h3, p { margin: 0; }
.select { max-width: 170px; } .select { max-width: 170px; }
.filter-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .filter-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.filter-row > .chip-row { flex: 1; min-width: 200px; } .filter-row > .chip-row { flex: 1; min-width: 200px; }
@media (max-width: 619px) {
.filter-row > .chip-row { flex-basis: 100%; min-width: 0; }
.filter-row .select { width: 100%; max-width: none; }
}
.growth-days { padding-top: 2px; } .growth-days { padding-top: 2px; }
.rank-list { display: flex; flex-direction: column; gap: 8px; } .rank-list { display: flex; flex-direction: column; gap: 8px; }
+2 -1
View File
@@ -1,5 +1,5 @@
import { api } from "../api.js"; import { api } from "../api.js";
import { emptyState, sectionHeader } from "../components.js"; import { centerActiveChips, emptyState, sectionHeader } from "../components.js";
import { lineChart } from "../charts.js"; import { lineChart } from "../charts.js";
import { import {
escapeAttr, escapeHtml, formatCount, formatDate, formatDelta, escapeAttr, escapeHtml, formatCount, formatDate, formatDelta,
@@ -75,6 +75,7 @@ export async function renderFans(root, { query }) {
root.querySelector("#fan-mid")?.addEventListener("change", (event) => { root.querySelector("#fan-mid")?.addEventListener("change", (event) => {
replaceQuery({ mid: event.target.value }); replaceQuery({ mid: event.target.value });
}); });
centerActiveChips(root);
const chartElement = root.querySelector("#fans-chart"); const chartElement = root.querySelector("#fans-chart");
if (chartElement) { if (chartElement) {
lineChart(chartElement, { lineChart(chartElement, {
+2 -1
View File
@@ -1,6 +1,6 @@
import { api, apiUrl } from "../api.js"; import { api, apiUrl } from "../api.js";
import { import {
chip, emptyState, pager, sectionHeader, upCard, videoCard, centerActiveChips, chip, emptyState, pager, sectionHeader, upCard, videoCard,
} from "../components.js"; } from "../components.js";
import { escapeAttr, escapeHtml, formatCount } from "../format.js"; import { escapeAttr, escapeHtml, formatCount } from "../format.js";
import { replaceQuery } from "../router.js"; import { replaceQuery } from "../router.js";
@@ -161,4 +161,5 @@ export async function renderRankings(root, { query }) {
if (button.disabled) return; if (button.disabled) return;
replaceQuery({ page: button.dataset.page }); replaceQuery({ page: button.dataset.page });
})); }));
centerActiveChips(root);
} }
+3 -1
View File
@@ -1,6 +1,7 @@
import { api } from "../api.js"; import { api } from "../api.js";
import { import {
badge, cover, emptyState, metricChips, metricGrid, sectionHeader, videoCard, badge, centerActiveChips, cover, emptyState, metricChips, metricGrid,
sectionHeader, videoCard,
} from "../components.js"; } from "../components.js";
import { lineChart, emptyChart } from "../charts.js"; import { lineChart, emptyChart } from "../charts.js";
import { import {
@@ -110,6 +111,7 @@ export async function renderVideo(root, { params, query }) {
root.querySelectorAll("[data-range]").forEach((button) => button.addEventListener("click", () => { root.querySelectorAll("[data-range]").forEach((button) => button.addEventListener("click", () => {
replaceQuery({ range: button.dataset.range }); replaceQuery({ range: button.dataset.range });
})); }));
centerActiveChips(root);
const chartElement = root.querySelector("#video-trend"); const chartElement = root.querySelector("#video-trend");
if (chartElement) { if (chartElement) {
+3 -1
View File
@@ -484,6 +484,7 @@ def seed_preview(
rows: list[tuple[str, int, dict[str, int], float]] = [] rows: list[tuple[str, int, dict[str, int], float]] = []
inserted_first_seen = 0 inserted_first_seen = 0
expected_rows = 0
for video in selected: for video in selected:
aid = int(video["aid"]) aid = int(video["aid"])
first_seen_ts = first_seen_map[aid] first_seen_ts = first_seen_map[aid]
@@ -500,6 +501,7 @@ def seed_preview(
synthetic_days = max(0, (latest_day - snapshot_start).days) synthetic_days = max(0, (latest_day - snapshot_start).days)
if synthetic_days <= 0: if synthetic_days <= 0:
continue continue
expected_rows += synthetic_days
age_days = max( age_days = max(
0.0, 0.0,
(latest_day - shanghai_datetime(int(video["pubdate"] or 0)).date()).days, (latest_day - shanghai_datetime(int(video["pubdate"] or 0)).date()).days,
@@ -661,7 +663,7 @@ def seed_preview(
"first_seen_updated": inserted_first_seen, "first_seen_updated": inserted_first_seen,
"snapshots_inserted": len(rows) - failed, "snapshots_inserted": len(rows) - failed,
"snapshots_failed": failed, "snapshots_failed": failed,
"snapshots_missing": (len(selected) * days) - len(rows), "snapshots_missing": expected_rows - len(rows),
"up_stat_rows": up_rows, "up_stat_rows": up_rows,
"preview_marker": "preview:seeded=1", "preview_marker": "preview:seeded=1",
} }