From 9f9aa2825ae51b2c11409c81397729a1bf5c54a5 Mon Sep 17 00:00:00 2001 From: huluxia <2056300012@qq.com> Date: Sun, 9 Aug 2026 15:59:09 +0800 Subject: [PATCH] update select video --- backend/static/css/app.css | 14 +++++++--- backend/static/js/app.js | 54 ++++++++++++++++++++++++++---------- backend/templates/index.html | 16 +++++++++-- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/backend/static/css/app.css b/backend/static/css/app.css index c367579..ceb3d21 100644 --- a/backend/static/css/app.css +++ b/backend/static/css/app.css @@ -223,10 +223,16 @@ button { color: inherit; } .pet-node { position: absolute; left: calc(50% - 49px); top: 145px; width: 98px; height: 98px; border: 2px solid #b49d8b; border-radius: 50%; background: white; display: grid; place-items: center; box-shadow: 0 13px 25px rgba(38,48,40,.12); } .pet-node b { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; background: #778990; color: white; font: 22px Georgia, serif; }.pet-node span { position: absolute; bottom: 8px; font-size: 10px; color: var(--muted); } .map-hint { margin: 0; text-align: center; color: #a0a49e; font-size: 11px; } -.video-browser { margin-top: 28px; }.filter-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 11px; } -.filter-chip { border: 1px solid var(--line); border-radius: 99px; padding: 9px 14px; background: rgba(255,255,252,.7); color: var(--muted); cursor: pointer; } -.filter-chip.active { background: var(--ink); border-color: var(--ink); color: white; } -.discipline-filters .filter-chip { border-radius: 9px; } +.video-browser { margin-top: 28px; }.filter-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 11px; } +.filter-dropdown { position: relative; } +.filter-dropdown-toggle { display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 12px; padding: 10px 16px; background: rgba(255,255,252,.82); color: var(--ink); cursor: pointer; font-size: 14px; min-width: 140px; justify-content: space-between; } +.filter-dropdown-toggle b { font-size: 10px; color: var(--muted); transition: transform .2s; } +.filter-dropdown-toggle[aria-expanded="true"] b { transform: rotate(180deg); } +.filter-dropdown-panel { position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; min-width: 200px; max-height: 320px; overflow-y: auto; border: 1px solid var(--line); border-radius: 14px; background: rgba(255,255,252,.96); backdrop-filter: blur(16px); box-shadow: 0 12px 40px rgba(38,48,40,.12); padding: 6px; display: flex; flex-direction: column; gap: 2px; } +.filter-dropdown-panel.hidden { display: none; } +.filter-option { border: 0; border-radius: 10px; padding: 10px 14px; background: transparent; color: var(--ink); cursor: pointer; text-align: left; font-size: 13px; transition: background .15s; } +.filter-option:hover { background: #eef1eb; } +.filter-option.active { background: var(--ink); color: white; } .video-section-heading { margin: 35px 0 16px; display: flex; justify-content: space-between; align-items: end; }.video-section-heading h2 { margin: 8px 0 0; font: 30px Georgia, serif; }.video-section-heading > span { color: var(--muted); font-size: 12px; } .video-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }.video-grid.loading { display: block; color: var(--muted); padding: 35px 0; } .video-card { border: 1px solid var(--line); border-radius: 18px; background: rgba(255,255,252,.82); overflow: hidden; cursor: pointer; transition: .2s ease; } diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 3185c34..a25751e 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -526,27 +526,46 @@ function renderAttempt(attempt) { root.append(label, title, form); } -function filterChip(label, value, type, active) { +function filterOption(label, value, type, active) { const button = document.createElement("button"); - button.className = `filter-chip${active ? " active" : ""}`; + button.className = `filter-option${active ? " active" : ""}`; button.textContent = label; button.dataset[type] = value; + button.setAttribute("role", "option"); button.addEventListener("click", () => { if (type === "ability") state.videoAbility = value; if (type === "discipline") state.videoDiscipline = value; renderVideoFilters(); renderVideos(); + closeFilterDropdowns(); }); return button; } +function closeFilterDropdowns() { + $$(".filter-dropdown-panel").forEach((panel) => panel.classList.add("hidden")); + $$(".filter-dropdown-toggle").forEach((toggle) => toggle.setAttribute("aria-expanded", "false")); +} + +function toggleFilterDropdown(type) { + const panel = $(`#${type}-panel`); + const toggle = $(`#${type}-toggle`); + const isOpen = !panel.classList.contains("hidden"); + closeFilterDropdowns(); + if (!isOpen) { + panel.classList.remove("hidden"); + toggle.setAttribute("aria-expanded", "true"); + } +} + function renderVideoFilters() { if (!state.videoCatalog) return; - const abilityRoot = $("#ability-filters"); - abilityRoot.replaceChildren( - filterChip(`全部 ${state.videoCatalog.total}`, "", "ability", !state.videoAbility), + + const abilityPanel = $("#ability-panel"); + abilityPanel.replaceChildren( + filterOption(`全部 ${state.videoCatalog.total}`, "", "ability", !state.videoAbility), ...state.videoCatalog.abilities.map((ability) => - filterChip( + filterOption( `${ability.icon} ${ability.label} ${ability.count}`, ability.id, "ability", @@ -554,11 +573,14 @@ function renderVideoFilters() { ) ), ); - const disciplineRoot = $("#discipline-filters"); - disciplineRoot.replaceChildren( - filterChip("全部专业", "", "discipline", !state.videoDiscipline), + const abilityLabel = state.videoCatalog.abilities.find((a) => a.id === state.videoAbility); + $("#ability-label").textContent = abilityLabel ? `${abilityLabel.icon} ${abilityLabel.label}` : "全部维度"; + + const disciplinePanel = $("#discipline-panel"); + disciplinePanel.replaceChildren( + filterOption("全部专业", "", "discipline", !state.videoDiscipline), ...state.videoCatalog.disciplines.map((discipline) => - filterChip( + filterOption( `${discipline.icon || "∑"} ${discipline.name}`, discipline.name, "discipline", @@ -566,11 +588,10 @@ function renderVideoFilters() { ) ), ); + const disciplineLabel = state.videoCatalog.disciplines.find((d) => d.name === state.videoDiscipline); + $("#discipline-label").textContent = disciplineLabel ? `${disciplineLabel.icon || "∑"} ${disciplineLabel.name}` : "全部专业"; - const selected = state.videoCatalog.abilities.find( - (item) => item.id === state.videoAbility - ); - $("#video-stream-title").textContent = selected ? `${selected.label}视频流` : "全部视频"; + $("#video-stream-title").textContent = abilityLabel ? `${abilityLabel.label}视频流` : "全部视频"; $$(".ability-node").forEach((node) => { node.classList.toggle("active", node.dataset.ability === state.videoAbility); }); @@ -1128,6 +1149,11 @@ function bindUI() { }); $("#enter-alumni").addEventListener("click", showLifeSkills); $("#back-to-hub").addEventListener("click", showLifeHub); + $("#ability-toggle").addEventListener("click", () => toggleFilterDropdown("ability")); + $("#discipline-toggle").addEventListener("click", () => toggleFilterDropdown("discipline")); + document.addEventListener("click", (event) => { + if (!event.target.closest(".filter-dropdown")) closeFilterDropdowns(); + }); $$(".route-card").forEach((card) => { card.addEventListener("click", (event) => { if (event.target.closest(".route-enter")) return; diff --git a/backend/templates/index.html b/backend/templates/index.html index b4cd826..1f9df21 100644 --- a/backend/templates/index.html +++ b/backend/templates/index.html @@ -353,8 +353,20 @@
点击地图节点,进入对应维度的视频流