feat: add ranking mode selector (日榜/周榜/月榜 etc.)
Add a sub-toolbar in the ranking tab with 7 modes: day/week/month/ day_male/day_female/week_original/week_rookie. Clicking a mode clears the grid and reloads with the new mode parameter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
0f1e087d64
commit
f1553d2eeb
@@ -190,6 +190,44 @@
|
||||
.px-login-tab.active { background: #2a2a3e; color: #cba6f7; }
|
||||
.px-login-tab:hover { color: #cdd6f4; }
|
||||
|
||||
/* Ranking pane */
|
||||
.px-ranking-pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.px-rank-bar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 6px 8px;
|
||||
border-bottom: 1px solid #3a3a5c;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
background: #181825;
|
||||
}
|
||||
|
||||
.px-rank-btn {
|
||||
padding: 3px 10px;
|
||||
background: transparent;
|
||||
border: 1px solid #45475a;
|
||||
color: #7f849c;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
}
|
||||
.px-rank-btn:hover { color: #cdd6f4; border-color: #7f849c; }
|
||||
.px-rank-btn.active { background: #313244; color: #cba6f7; border-color: #cba6f7; }
|
||||
|
||||
.px-rank-grid-wrap {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* Artist pane */
|
||||
.px-artist-pane {
|
||||
display: flex;
|
||||
|
||||
+55
-6
@@ -36,6 +36,7 @@ function initNodeBrowser(container, idsWidget) {
|
||||
loading: false,
|
||||
activeArtistId: null,
|
||||
artistNextUrl: null,
|
||||
rankingMode: "day",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -256,11 +257,58 @@ function switchTab(ctx, tabName) {
|
||||
renderSelectedPane(ctx);
|
||||
} else if (tabName === "artists") {
|
||||
renderArtistPane(ctx);
|
||||
} else if (tabName === "ranking") {
|
||||
renderRankingPane(ctx);
|
||||
} else {
|
||||
openMainBrowser(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Ranking pane ──────────────────────────────────────────────────────────────
|
||||
const RANKING_MODES = [
|
||||
{ id: "day", label: "日榜" },
|
||||
{ id: "week", label: "周榜" },
|
||||
{ id: "month", label: "月榜" },
|
||||
{ id: "day_male", label: "男性向" },
|
||||
{ id: "day_female", label: "女性向" },
|
||||
{ id: "week_original", label: "原创" },
|
||||
{ id: "week_rookie", label: "新人" },
|
||||
];
|
||||
|
||||
function renderRankingPane(ctx) {
|
||||
const { contentEl, S } = ctx;
|
||||
contentEl.innerHTML = `
|
||||
<div class="px-ranking-pane">
|
||||
<div class="px-rank-bar">
|
||||
${RANKING_MODES.map(m =>
|
||||
`<button class="px-rank-btn${S.rankingMode === m.id ? " active" : ""}" data-mode="${m.id}">${m.label}</button>`
|
||||
).join("")}
|
||||
</div>
|
||||
<div class="px-rank-grid-wrap">
|
||||
<div class="px-grid-pane">
|
||||
<div class="px-grid"></div>
|
||||
<div class="px-loading" style="display:none">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
contentEl.querySelectorAll(".px-rank-btn").forEach(btn => {
|
||||
btn.addEventListener("click", () => {
|
||||
if (S.rankingMode === btn.dataset.mode) return;
|
||||
S.rankingMode = btn.dataset.mode;
|
||||
S.nextUrls["ranking"] = undefined;
|
||||
contentEl.querySelectorAll(".px-rank-btn").forEach(b => b.classList.remove("active"));
|
||||
btn.classList.add("active");
|
||||
const grid = contentEl.querySelector(".px-grid");
|
||||
if (grid) grid.innerHTML = "";
|
||||
loadMoreImages(ctx, "ranking");
|
||||
});
|
||||
});
|
||||
S.nextUrls["ranking"] = undefined;
|
||||
loadMoreImages(ctx, "ranking");
|
||||
setupInfiniteScroll(ctx, "ranking");
|
||||
}
|
||||
|
||||
// ── Main image browser ────────────────────────────────────────────────────────
|
||||
async function openMainBrowser(ctx) {
|
||||
const { contentEl, S } = ctx;
|
||||
@@ -276,12 +324,13 @@ async function openMainBrowser(ctx) {
|
||||
setupInfiniteScroll(ctx, tab);
|
||||
}
|
||||
|
||||
async function fetchImages(tab, nextUrl) {
|
||||
const params = nextUrl ? `?next_url=${encodeURIComponent(nextUrl)}` : "";
|
||||
async function fetchImages(tab, nextUrl, S) {
|
||||
const np = nextUrl ? `&next_url=${encodeURIComponent(nextUrl)}` : "";
|
||||
const q = nextUrl ? `?next_url=${encodeURIComponent(nextUrl)}` : "";
|
||||
const urls = {
|
||||
recommended: `/pixiv/recommended${params}`,
|
||||
ranking: `/pixiv/ranking${params}`,
|
||||
bookmarks: `/pixiv/bookmarks${params}`,
|
||||
recommended: `/pixiv/recommended${q}`,
|
||||
ranking: `/pixiv/ranking?mode=${encodeURIComponent(S?.rankingMode || "day")}${np}`,
|
||||
bookmarks: `/pixiv/bookmarks${q}`,
|
||||
};
|
||||
const resp = await fetch(urls[tab]);
|
||||
if (!resp.ok) {
|
||||
@@ -304,7 +353,7 @@ async function loadMoreImages(ctx, tab) {
|
||||
if (loadEl) loadEl.style.display = "flex";
|
||||
|
||||
try {
|
||||
const data = await fetchImages(tab, nextUrl);
|
||||
const data = await fetchImages(tab, nextUrl, S);
|
||||
if (S.activeTab !== tab) return; // switched while awaiting
|
||||
S.nextUrls[tab] = data.next_url ?? null;
|
||||
const gridEl = contentEl.querySelector(".px-grid");
|
||||
|
||||
Reference in New Issue
Block a user