diff --git a/concert/concert.html b/concert/concert.html
index 6c54c44..c5d582b 100644
--- a/concert/concert.html
+++ b/concert/concert.html
@@ -97,15 +97,62 @@
box-shadow: 0 0 10px rgba(255, 204, 0, 0.35);
}
- #concert-search-result {
+ .concert-search-result {
display: block;
width: 100%;
margin: 0;
+ }
+
+ .concert-search-summary {
+ margin: 0 0 12px;
text-align: center;
font-size: 0.95rem;
line-height: 1.6;
color: #fff;
}
+
+ .concert-search-hits {
+ list-style: none;
+ margin: 0 auto;
+ padding: 0;
+ max-width: 720px;
+ text-align: left;
+ }
+
+ .concert-search-hits li {
+ padding: 10px 14px;
+ margin-bottom: 8px;
+ background: rgba(255, 248, 223, 0.1);
+ border: 1px solid rgba(255, 204, 0, 0.35);
+ border-radius: 12px;
+ color: #fff;
+ font-size: 0.88rem;
+ line-height: 1.5;
+ }
+
+ .concert-search-hits .hit-track {
+ display: block;
+ font-weight: 700;
+ color: #ffdd00;
+ }
+
+ .concert-search-hits .hit-meta {
+ display: block;
+ margin-top: 4px;
+ color: rgba(255, 255, 255, 0.78);
+ font-size: 0.82rem;
+ }
+
+ .concert-search-hits .hit-more {
+ text-align: center;
+ border-style: dashed;
+ color: rgba(255, 255, 255, 0.85);
+ }
+
+ .track-item.is-search-hit .track {
+ color: #ffdd00;
+ font-weight: 700;
+ }
@@ -128,7 +175,9 @@
- 輸入後按「查詢」,會顯示比對結果。
+
+
輸入後按「查詢」,會在下方列出比對到的曲目。
+
diff --git a/concert/search.js b/concert/search.js
index be467e1..42ab4cd 100644
--- a/concert/search.js
+++ b/concert/search.js
@@ -2,59 +2,119 @@
let myQuery = document.querySelector("#concert-query");
let myMember = document.querySelector("#concert-member");
let myBtn = document.querySelector("#concert-search-btn");
-let mySpan = document.querySelector("#concert-search-result");
+let myResult = document.querySelector("#concert-search-result");
-console.log("myQuery", myQuery);
-console.log("myMember", myMember);
-console.log("myBtn", myBtn);
-console.log("mySpan", mySpan);
+const SEARCH_LIST_MAX = 12;
-function countMatchingTracks(keyword, member) {
+function getTrackContext(trackEl) {
+ const venueBlock = trackEl.closest(".track-list")?.parentElement;
+ const tourCard = trackEl.closest(".con-1, .con-2, .con-3, .con-4");
+ return {
+ trackName: trackEl.textContent.trim(),
+ tourTitle: tourCard?.querySelector(".title")?.textContent.trim().replace(/\s+/g, " ") || "",
+ location: venueBlock?.querySelector(".location")?.textContent.trim() || ""
+ };
+}
+
+function findMatchingTracks(keyword, member) {
const tracks = document.querySelectorAll(".track-item .track");
const k = keyword.trim().toLowerCase();
const m = member.trim().toLowerCase();
- let count = 0;
+ const hits = [];
tracks.forEach(function (trackEl) {
const text = trackEl.textContent.toLowerCase();
const matchKeyword = !k || text.includes(k);
const matchMember = !m || text.includes(m);
if (matchKeyword && matchMember) {
- count += 1;
+ hits.push({
+ el: trackEl.closest(".track-item"),
+ ...getTrackContext(trackEl)
+ });
}
});
- return count;
+ return hits;
+}
+
+function clearSearchHighlights() {
+ document.querySelectorAll(".track-item.is-search-hit").forEach(function (item) {
+ item.classList.remove("is-search-hit");
+ });
+}
+
+function renderSearchResults(getQuery, getMember, hits) {
+ if (!myResult) return;
+
+ clearSearchHighlights();
+
+ const summary = document.createElement("p");
+ summary.className = "concert-search-summary";
+
+ if (!hits.length) {
+ summary.textContent = `關鍵字「${getQuery || "(未填)"}」${getMember.trim() ? `、成員「${getMember}」` : ""}:沒有比對到曲目,請換字再試。`;
+ myResult.replaceChildren(summary);
+ return;
+ }
+
+ if (getMember.trim()) {
+ summary.textContent = `關鍵字「${getQuery || "(未填)"}」、成員「${getMember}」:共 ${hits.length} 筆,以下列出前 ${Math.min(hits.length, SEARCH_LIST_MAX)} 筆。`;
+ } else {
+ summary.textContent = `關鍵字「${getQuery}」:共 ${hits.length} 筆,以下列出前 ${Math.min(hits.length, SEARCH_LIST_MAX)} 筆。`;
+ }
+
+ const list = document.createElement("ul");
+ list.className = "concert-search-hits";
+
+ hits.slice(0, SEARCH_LIST_MAX).forEach(function (hit) {
+ if (hit.el) hit.el.classList.add("is-search-hit");
+
+ const li = document.createElement("li");
+ const trackLine = document.createElement("span");
+ trackLine.className = "hit-track";
+ trackLine.textContent = hit.trackName;
+
+ const metaLine = document.createElement("span");
+ metaLine.className = "hit-meta";
+ metaLine.textContent = [hit.tourTitle, hit.location].filter(Boolean).join(" · ");
+
+ li.appendChild(trackLine);
+ if (metaLine.textContent) li.appendChild(metaLine);
+ list.appendChild(li);
+ });
+
+ if (hits.length > SEARCH_LIST_MAX) {
+ const more = document.createElement("li");
+ more.className = "hit-more";
+ more.textContent = `另有 ${hits.length - SEARCH_LIST_MAX} 筆未顯示,請縮小關鍵字。`;
+ list.appendChild(more);
+ }
+
+ myResult.replaceChildren(summary, list);
+
+ const firstHit = hits[0]?.el;
+ if (firstHit) {
+ firstHit.scrollIntoView({ behavior: "smooth", block: "nearest" });
+ }
}
// 2.action
-if (myBtn && mySpan) {
+if (myBtn && myResult) {
myBtn.addEventListener("click", function () {
- console.log("myBtn", myBtn);
-
- // 1.抓 input
let getQuery = myQuery ? myQuery.value : "";
let getMember = myMember ? myMember.value : "";
- console.log("getQuery", getQuery);
- console.log("getMember", getMember);
if (!getQuery.trim() && !getMember.trim()) {
- mySpan.innerText = "請至少輸入曲目/場次,或成員其中一項。";
+ myResult.replaceChildren();
+ const summary = document.createElement("p");
+ summary.className = "concert-search-summary";
+ summary.textContent = "請至少輸入曲目/場次,或成員其中一項。";
+ myResult.appendChild(summary);
+ clearSearchHighlights();
return;
}
- const count = countMatchingTracks(getQuery, getMember);
-
- // 2.組成 text
- let tmpText;
- if (getMember.trim()) {
- tmpText = `關鍵字「${getQuery || "(未填)"}」、成員「${getMember}」:在巡迴歌單中共 ${count} 筆曲目。`;
- } else {
- tmpText = `關鍵字「${getQuery}」:在巡迴歌單中共 ${count} 筆曲目。`;
- }
- console.log("tmpText", tmpText);
-
- // 3.顯示在 span
- mySpan.innerText = tmpText;
+ const hits = findMatchingTracks(getQuery, getMember);
+ renderSearchResults(getQuery, getMember, hits);
});
}