fix(web): center active filters and compact mobile cards
This commit is contained in:
1 parent
d18ebbfb2f
commit
60d7b0f24f
6 files changed
+25
-5
No files matched your search
@@ -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">
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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, {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user