zsbqb-static 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/css/app.css CHANGED
@@ -808,17 +808,20 @@ th { color: var(--muted); font-weight: 600; font-size: 13px; background: var(--b
808
808
  --alpha-rail-pad-start: 14px;
809
809
  --alpha-rail-pad-end: 20px;
810
810
  --alpha-rail-pad-y: 10px;
811
+ --alpha-rail-viewport: calc(100vh - 16px);
812
+ --alpha-rail-viewport: calc(100svh - 16px);
811
813
  position: sticky;
812
- top: 0;
814
+ top: 8px;
813
815
  z-index: 15;
814
816
  display: flex;
815
817
  flex-direction: column;
816
- gap: 4px;
818
+ justify-content: space-between;
819
+ gap: 0;
817
820
  width: 28px;
818
821
  box-sizing: content-box;
819
- max-height: calc(100vh - 40px);
820
- overflow-y: auto;
821
- overflow-x: hidden;
822
+ height: calc(var(--alpha-rail-viewport) - 2 * var(--alpha-rail-pad-y));
823
+ max-height: calc(var(--alpha-rail-viewport) - 2 * var(--alpha-rail-pad-y));
824
+ overflow: hidden;
822
825
  overscroll-behavior: contain;
823
826
  padding: var(--alpha-rail-pad-y) var(--alpha-rail-pad-end) var(--alpha-rail-pad-y) var(--alpha-rail-pad-start);
824
827
  margin: calc(var(--alpha-rail-pad-y) * -1) calc(var(--alpha-rail-pad-end) * -1) calc(var(--alpha-rail-pad-y) * -1) calc(var(--alpha-rail-pad-start) * -1);
@@ -846,17 +849,18 @@ th { color: var(--muted); font-weight: 600; font-size: 13px; background: var(--b
846
849
  display: grid;
847
850
  place-items: center;
848
851
  width: 28px;
849
- min-height: 22px;
850
- padding: 2px 0;
852
+ flex: 1 1 0;
853
+ min-height: 0;
854
+ padding: 0;
851
855
  border-radius: 5px;
852
856
  color: var(--muted);
853
- font-size: 13px;
857
+ font-size: clamp(10px, 2.2vh, 13px);
858
+ font-size: clamp(10px, 2.2svh, 13px);
854
859
  font-weight: 600;
855
860
  font-family: var(--font-sans);
856
861
  font-variant-numeric: tabular-nums;
857
862
  line-height: 1;
858
863
  letter-spacing: 0;
859
- flex: 0 0 auto;
860
864
  }
861
865
  .alpha-rail__item:hover,
862
866
  .alpha-rail__item.is-scrub {
package/js/app.js CHANGED
@@ -1416,11 +1416,11 @@ function bindClientQueryFilters() {
1416
1416
 
1417
1417
  window.__setQueryLetterFilter = function (label) {
1418
1418
  const next = (label || "").trim();
1419
- if (filterState.letter.toLowerCase() === next.toLowerCase()) {
1420
- filterState.letter = "";
1421
- } else {
1422
- filterState.letter = next;
1423
- }
1419
+ if (!next) return;
1420
+ const sameLetter = filterState.letter.toLowerCase() === next.toLowerCase();
1421
+ const qDisplay = (searchInput?.value || filterState.q || "").trim();
1422
+ if (sameLetter && !qDisplay) return;
1423
+ filterState.letter = next;
1424
1424
  // 选字母时清空搜索关键词
1425
1425
  if (searchInput) {
1426
1426
  searchInput.value = "";
@@ -1562,6 +1562,7 @@ function bindAlphaRail() {
1562
1562
  let dragging = false;
1563
1563
  let current = null;
1564
1564
  let navigating = false;
1565
+ let pointerHandled = false;
1565
1566
 
1566
1567
  function pickItem(clientY) {
1567
1568
  let best = null;
@@ -1592,9 +1593,9 @@ function bindAlphaRail() {
1592
1593
 
1593
1594
  function goTo(item) {
1594
1595
  if (!item || navigating) return;
1595
- if (document.querySelector(".song-list")) {
1596
- const label = item.textContent.trim();
1597
- window.__setQueryLetterFilter?.(label);
1596
+ const label = item.textContent.trim();
1597
+ if (typeof window.__setQueryLetterFilter === "function") {
1598
+ window.__setQueryLetterFilter(label);
1598
1599
  return;
1599
1600
  }
1600
1601
  const next = item.href;
@@ -1626,7 +1627,11 @@ function bindAlphaRail() {
1626
1627
  dragging = false;
1627
1628
  const target = pickItem(event.clientY) || current;
1628
1629
  clearScrub();
1630
+ pointerHandled = true;
1629
1631
  goTo(target);
1632
+ window.setTimeout(() => {
1633
+ pointerHandled = false;
1634
+ }, 400);
1630
1635
  }
1631
1636
 
1632
1637
  function onPointerCancel() {
@@ -1642,6 +1647,8 @@ function bindAlphaRail() {
1642
1647
  items.forEach((item) => {
1643
1648
  item.addEventListener("click", (event) => {
1644
1649
  event.preventDefault();
1650
+ if (pointerHandled) return;
1651
+ goTo(item);
1645
1652
  });
1646
1653
  });
1647
1654
  }
@@ -263,10 +263,15 @@
263
263
  const letter = String((filters && filters.letter) || "").trim();
264
264
  const bpmBucket = String((filters && filters.bpmBucket) || "").trim();
265
265
  const bpmExact = (filters && filters.bpmExact) || "";
266
+ const browseDefault = !filters || filters.browseDefault !== false;
267
+ // 与 search_index/catalog.search_catalog 一致:无关键词、无字母/星级/BPM 时只展示 # 桶。
268
+ const browseOnly = browseDefault && !needle && !letter && !star && !bpmBucket && !String(bpmExact || "").trim();
266
269
  const exact = [];
267
270
  list.forEach((entry) => {
268
271
  if (star && String(entry.star) !== star) return;
269
- if (!letterMatches(entry, letter)) return;
272
+ if (browseOnly) {
273
+ if (!entry.title_lead_non_zh_en) return;
274
+ } else if (!letterMatches(entry, letter)) return;
270
275
  if (!bpmMatches(entry, bpmBucket, bpmExact)) return;
271
276
  if (!needle) {
272
277
  exact.push({ entry, score: 0, fuzzy: false });
package/js/query-app.js CHANGED
@@ -185,6 +185,30 @@
185
185
  >${inner}</button>`;
186
186
  }
187
187
 
188
+ function letterHintLabel(letter) {
189
+ const key = String(letter || "").trim();
190
+ if (!key) return "";
191
+ return key === "#" ? "特殊" : key.toUpperCase();
192
+ }
193
+
194
+ function syncLetterHint(letter) {
195
+ const el = document.querySelector("[data-query-letter-hint]");
196
+ if (!el) return;
197
+ const label = letterHintLabel(letter);
198
+ el.textContent = label ? `${label}开头` : "";
199
+ el.hidden = !label;
200
+ }
201
+
202
+ function syncAlphaRail(letter) {
203
+ const key = String(letter || "").trim().toLowerCase();
204
+ document.querySelectorAll("[data-alpha-item]").forEach((el) => {
205
+ const active = Boolean(key) && el.textContent.trim().toLowerCase() === key;
206
+ el.classList.toggle("is-on", active);
207
+ if (active) el.setAttribute("aria-current", "true");
208
+ else el.removeAttribute("aria-current");
209
+ });
210
+ }
211
+
188
212
  function syncHint(visibleCount) {
189
213
  if (countEl) countEl.textContent = String(visibleCount);
190
214
  const qDisplay = (searchInput && searchInput.value ? searchInput.value : filterState.q || "").trim();
@@ -192,6 +216,7 @@
192
216
  qHint.textContent = qDisplay ? `[${qDisplay}]` : "";
193
217
  qHint.hidden = !qDisplay;
194
218
  }
219
+ syncLetterHint(qDisplay ? "" : filterState.letter);
195
220
  if (hintTail) {
196
221
  if (fuzzySuggest && qDisplay) {
197
222
  hintTail.textContent = "。未精确匹配,是否你想找以下结果?";
@@ -245,11 +270,7 @@
245
270
  }
246
271
  syncHint(ranked.length);
247
272
  syncLetterField(filterState.letter);
248
- document.querySelectorAll("[data-alpha-item]").forEach((el) => {
249
- const active =
250
- filterState.letter && el.textContent.trim().toLowerCase() === filterState.letter.toLowerCase();
251
- el.classList.toggle("is-on", Boolean(active));
252
- });
273
+ syncAlphaRail(filterState.letter);
253
274
  const params = new URLSearchParams(window.location.search);
254
275
  if (family) params.set("family", family);
255
276
  if (filterState.q) params.set("q", filterState.q);
@@ -276,8 +297,11 @@
276
297
 
277
298
  window.__setQueryLetterFilter = function (label) {
278
299
  const next = (label || "").trim();
279
- if (filterState.letter.toLowerCase() === next.toLowerCase()) filterState.letter = "";
280
- else filterState.letter = next;
300
+ if (!next) return;
301
+ const sameLetter = filterState.letter.toLowerCase() === next.toLowerCase();
302
+ const qDisplay = (searchInput && searchInput.value ? searchInput.value : filterState.q || "").trim();
303
+ if (sameLetter && !qDisplay) return;
304
+ filterState.letter = next;
281
305
  if (searchInput) {
282
306
  searchInput.value = "";
283
307
  filterState.q = "";
@@ -285,6 +309,12 @@
285
309
  if (clearBtn) clearBtn.classList.remove("is-on");
286
310
  }
287
311
  applyFilters();
312
+ const toolbar = document.querySelector(".query-toolbar");
313
+ if (!toolbar) return;
314
+ const nextTop = toolbar.getBoundingClientRect().top + window.scrollY;
315
+ if (Math.abs(window.scrollY - nextTop) > 8) {
316
+ window.scrollTo(0, Math.max(0, nextTop));
317
+ }
288
318
  };
289
319
 
290
320
  window.__queryLoadFamily = function (nextFamily, nextStar) {