@@ -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; }
|
||||
|
||||
+40
-14
@@ -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;
|
||||
|
||||
@@ -353,8 +353,20 @@
|
||||
<p class="map-hint">点击地图节点,进入对应维度的视频流</p>
|
||||
</section>
|
||||
<section class="video-browser">
|
||||
<div class="filter-row ability-filters" id="ability-filters"></div>
|
||||
<div class="filter-row discipline-filters" id="discipline-filters"></div>
|
||||
<div class="filter-row">
|
||||
<div class="filter-dropdown" id="ability-filter">
|
||||
<button class="filter-dropdown-toggle" id="ability-toggle" aria-expanded="false" aria-haspopup="listbox">
|
||||
<span id="ability-label">全部维度</span><b>▾</b>
|
||||
</button>
|
||||
<div class="filter-dropdown-panel hidden" id="ability-panel" role="listbox"></div>
|
||||
</div>
|
||||
<div class="filter-dropdown" id="discipline-filter">
|
||||
<button class="filter-dropdown-toggle" id="discipline-toggle" aria-expanded="false" aria-haspopup="listbox">
|
||||
<span id="discipline-label">全部专业</span><b>▾</b>
|
||||
</button>
|
||||
<div class="filter-dropdown-panel hidden" id="discipline-panel" role="listbox"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-section-heading"><div><span class="kicker">VIDEO STREAM</span><h2 id="video-stream-title">全部视频</h2></div><span id="video-result-count">0 条内容</span></div>
|
||||
<div id="video-list" class="video-grid loading">正在读取视频流…</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user