release: bump version to 0.31.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planet-frontend",
|
||||
"version": "0.31.0",
|
||||
"version": "0.31.1",
|
||||
"private": true,
|
||||
"packageManager": "bun@1",
|
||||
"dependencies": {
|
||||
|
||||
@@ -235,6 +235,7 @@
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.18s ease;
|
||||
}
|
||||
|
||||
.layer-row-toggle-track {
|
||||
@@ -247,6 +248,11 @@
|
||||
transition: background 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.layer-row-toggle:disabled {
|
||||
cursor: progress;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Thumb */
|
||||
.layer-row-toggle-track::after {
|
||||
content: "";
|
||||
@@ -261,6 +267,24 @@
|
||||
transition: transform 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
|
||||
.layer-row-toggle.is-loading .layer-row-toggle-track {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(104, 147, 221, 0.38),
|
||||
rgba(143, 185, 255, 0.72),
|
||||
rgba(104, 147, 221, 0.38)
|
||||
);
|
||||
background-size: 180% 100%;
|
||||
border-color: rgba(223, 236, 252, 0.28);
|
||||
animation: layer-toggle-loading-track 1.2s linear infinite;
|
||||
}
|
||||
|
||||
.layer-row-toggle.is-loading .layer-row-toggle-track::after {
|
||||
background: #f0f6ff;
|
||||
transform: translateX(calc(7px * var(--hud-scale)));
|
||||
animation: layer-toggle-loading-thumb 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Active (ON) state */
|
||||
.layer-row-toggle.active .layer-row-toggle-track {
|
||||
background: linear-gradient(180deg, rgba(143, 185, 255, 0.72), rgba(104, 147, 221, 0.78));
|
||||
@@ -272,5 +296,24 @@
|
||||
transform: translateX(calc(14px * var(--hud-scale)));
|
||||
}
|
||||
|
||||
@keyframes layer-toggle-loading-track {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 180% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes layer-toggle-loading-thumb {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 2px 6px rgba(1, 8, 18, 0.3), 0 0 0 rgba(174, 205, 255, 0.18);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 2px 6px rgba(1, 8, 18, 0.3), 0 0 calc(10px * var(--hud-scale)) rgba(174, 205, 255, 0.42);
|
||||
}
|
||||
}
|
||||
|
||||
/* Layout-expanded: layer panel slides off with .earth-left-column — no
|
||||
individual rule needed since the whole column translates together. */
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<span class="layer-row-label">地形</span>
|
||||
<span class="layer-row-meta">Terrain</span>
|
||||
</div>
|
||||
<button id="toggle-terrain" class="layer-row-toggle" type="button" role="switch" aria-checked="false" title="切换地形显示">
|
||||
<button id="toggle-terrain" class="layer-row-toggle" type="button" role="switch" aria-checked="false" title="切换地形显示" data-status-target="terrain-status">
|
||||
<span class="layer-row-toggle-track"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
111
frontend/public/earth/js/controls.js
vendored
111
frontend/public/earth/js/controls.js
vendored
@@ -30,6 +30,11 @@ import {
|
||||
ensureNewsPanelReady,
|
||||
updateNewsToggleUI,
|
||||
} from "./news.js";
|
||||
import {
|
||||
setButtonTooltip,
|
||||
setLayerButtonState,
|
||||
updateLayerButtonState,
|
||||
} from "./layer-button-state.js";
|
||||
|
||||
export let autoRotate = true;
|
||||
export let zoomLevel = 1.0;
|
||||
@@ -67,6 +72,8 @@ const SETTINGS_SHEET_MAX_SCALE_Y = 0.18;
|
||||
let settingsModalTimer = null;
|
||||
let settingsSheetAnimation = null;
|
||||
let terrainToggleToken = 0;
|
||||
let terrainPrefetchStarted = false;
|
||||
let terrainPrefetchScheduled = false;
|
||||
let focusViewAnimationToken = 0;
|
||||
|
||||
function getViewRotation(targetLat, targetRotLon) {
|
||||
@@ -91,10 +98,40 @@ function dispatchRotationModeChange() {
|
||||
function applyTerrainUiState(button, enabled) {
|
||||
showTerrain = enabled;
|
||||
toggleTerrain(enabled);
|
||||
updateLayerButtonState(button, enabled);
|
||||
setButtonTooltip(button, enabled ? "隐藏地形" : "显示地形");
|
||||
const terrainStatus = document.getElementById("terrain-status");
|
||||
if (terrainStatus) terrainStatus.textContent = enabled ? "开启" : "关闭";
|
||||
setLayerButtonState(button, {
|
||||
active: enabled,
|
||||
loading: false,
|
||||
tooltip: enabled ? "隐藏地形" : "显示地形",
|
||||
statusText: enabled ? "开启" : "关闭",
|
||||
});
|
||||
}
|
||||
|
||||
function prewarmTerrainIfNeeded() {
|
||||
if (terrainPrefetchStarted || isTerrainReady()) return;
|
||||
terrainPrefetchStarted = true;
|
||||
ensureTerrainReady().catch((error) => {
|
||||
terrainPrefetchStarted = false;
|
||||
console.warn("地形预热加载失败:", error);
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleTerrainPrefetch() {
|
||||
if (terrainPrefetchScheduled || terrainPrefetchStarted || isTerrainReady()) {
|
||||
return;
|
||||
}
|
||||
terrainPrefetchScheduled = true;
|
||||
|
||||
const runPrefetch = () => {
|
||||
terrainPrefetchScheduled = false;
|
||||
prewarmTerrainIfNeeded();
|
||||
};
|
||||
|
||||
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
||||
window.requestIdleCallback(runPrefetch, { timeout: 2200 });
|
||||
return;
|
||||
}
|
||||
|
||||
window.setTimeout(runPrefetch, 1400);
|
||||
}
|
||||
|
||||
export function applyImmediateView(targetEarthObj, camera, options = {}) {
|
||||
@@ -670,24 +707,6 @@ function setFloatingMenuOpen(group, shouldOpen) {
|
||||
group?.classList.toggle("open", shouldOpen);
|
||||
}
|
||||
|
||||
function setButtonTooltip(button, text) {
|
||||
const tooltip = button?.querySelector(".earth-toolbar-tooltip");
|
||||
if (tooltip) {
|
||||
tooltip.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
export function updateLayerButtonState(button, isActive) {
|
||||
if (!button) return;
|
||||
button.classList.toggle("active", isActive);
|
||||
button.setAttribute("aria-checked", isActive ? "true" : "false");
|
||||
// Legacy badge text (kept for compatibility)
|
||||
const state = button.querySelector(".earth-layer-btn__state");
|
||||
if (state) {
|
||||
state.textContent = isActive ? "ON" : "OFF";
|
||||
}
|
||||
}
|
||||
|
||||
function clearSelectionIfHiding(shouldHide) {
|
||||
if (shouldHide) {
|
||||
clearLockedObject();
|
||||
@@ -1070,15 +1089,30 @@ function setupTerrainControls() {
|
||||
setupLayerPanel();
|
||||
|
||||
if (trailsBtn) {
|
||||
updateLayerButtonState(trailsBtn, true);
|
||||
setButtonTooltip(trailsBtn, "隐藏轨迹");
|
||||
setLayerButtonState(trailsBtn, {
|
||||
active: true,
|
||||
tooltip: "隐藏轨迹",
|
||||
});
|
||||
}
|
||||
|
||||
bindListener(searchBtn, "click", () => {
|
||||
showStatusMessage("搜索功能待开发", "info");
|
||||
});
|
||||
|
||||
bindListener(terrainBtn, "pointerenter", () => {
|
||||
prewarmTerrainIfNeeded();
|
||||
});
|
||||
|
||||
bindListener(terrainBtn, "focus", () => {
|
||||
prewarmTerrainIfNeeded();
|
||||
});
|
||||
|
||||
scheduleTerrainPrefetch();
|
||||
|
||||
bindListener(terrainBtn, "click", async function () {
|
||||
if (this.classList.contains("is-loading")) {
|
||||
return;
|
||||
}
|
||||
const nextShowTerrain = !showTerrain;
|
||||
const toggleToken = ++terrainToggleToken;
|
||||
|
||||
@@ -1090,6 +1124,11 @@ function setupTerrainControls() {
|
||||
|
||||
try {
|
||||
if (!isTerrainReady()) {
|
||||
setLayerButtonState(this, {
|
||||
loading: true,
|
||||
tooltip: "地形加载中...",
|
||||
statusText: "加载中",
|
||||
});
|
||||
showStatusMessage("正在加载真实地形数据...", "info");
|
||||
await ensureTerrainReady();
|
||||
}
|
||||
@@ -1108,6 +1147,13 @@ function setupTerrainControls() {
|
||||
const showSats = !getShowSatellites();
|
||||
clearSelectionIfHiding(!showSats);
|
||||
try {
|
||||
if (showSats) {
|
||||
setLayerButtonState(this, {
|
||||
active: false,
|
||||
loading: true,
|
||||
tooltip: "卫星加载中...",
|
||||
});
|
||||
}
|
||||
await setSatellitesEnabled(showSats);
|
||||
if (!showSats) {
|
||||
showStatusMessage("卫星已隐藏", "info");
|
||||
@@ -1119,6 +1165,11 @@ function setupTerrainControls() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("切换卫星显示失败:", error);
|
||||
setLayerButtonState(this, {
|
||||
active: false,
|
||||
loading: false,
|
||||
tooltip: "显示卫星",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1129,8 +1180,10 @@ function setupTerrainControls() {
|
||||
if (!showNextBGP && rotationMode === ROTATION_MODE.CRUISE && autoRotate) {
|
||||
setAutoRotate(false);
|
||||
}
|
||||
updateLayerButtonState(this, showNextBGP);
|
||||
setButtonTooltip(this, showNextBGP ? "隐藏BGP观测" : "显示BGP观测");
|
||||
setLayerButtonState(this, {
|
||||
active: showNextBGP,
|
||||
tooltip: showNextBGP ? "隐藏BGP观测" : "显示BGP观测",
|
||||
});
|
||||
const bgpCountEl = document.getElementById("bgp-anomaly-count");
|
||||
if (bgpCountEl) {
|
||||
bgpCountEl.textContent = `${getBGPCount()} 条`;
|
||||
@@ -1142,8 +1195,10 @@ function setupTerrainControls() {
|
||||
const isActive = this.classList.contains("active");
|
||||
const nextShowTrails = !isActive;
|
||||
toggleTrails(nextShowTrails);
|
||||
updateLayerButtonState(this, nextShowTrails);
|
||||
setButtonTooltip(this, nextShowTrails ? "隐藏轨迹" : "显示轨迹");
|
||||
setLayerButtonState(this, {
|
||||
active: nextShowTrails,
|
||||
tooltip: nextShowTrails ? "隐藏轨迹" : "显示轨迹",
|
||||
});
|
||||
showStatusMessage(nextShowTrails ? "轨迹已显示" : "轨迹已隐藏", "info");
|
||||
});
|
||||
|
||||
|
||||
46
frontend/public/earth/js/layer-button-state.js
Normal file
46
frontend/public/earth/js/layer-button-state.js
Normal file
@@ -0,0 +1,46 @@
|
||||
export function setButtonTooltip(button, text) {
|
||||
if (button instanceof HTMLElement) {
|
||||
button.title = text;
|
||||
}
|
||||
const tooltip = button?.querySelector(".earth-toolbar-tooltip");
|
||||
if (tooltip) {
|
||||
tooltip.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
export function updateLayerButtonState(button, isActive) {
|
||||
if (!button) return;
|
||||
button.classList.toggle("active", isActive);
|
||||
button.setAttribute("aria-checked", isActive ? "true" : "false");
|
||||
const state = button.querySelector(".earth-layer-btn__state");
|
||||
if (state) {
|
||||
state.textContent = isActive ? "ON" : "OFF";
|
||||
}
|
||||
}
|
||||
|
||||
export function setLayerButtonState(button, options = {}) {
|
||||
if (!(button instanceof HTMLButtonElement)) return;
|
||||
const {
|
||||
active = null,
|
||||
loading = false,
|
||||
tooltip = null,
|
||||
statusText = null,
|
||||
} = options;
|
||||
button.classList.toggle("is-loading", loading);
|
||||
button.toggleAttribute("aria-busy", loading);
|
||||
button.disabled = loading;
|
||||
if (typeof active === "boolean") {
|
||||
updateLayerButtonState(button, active);
|
||||
}
|
||||
if (tooltip) {
|
||||
setButtonTooltip(button, tooltip);
|
||||
}
|
||||
if (statusText) {
|
||||
const statusTarget = button.dataset.statusTarget
|
||||
? document.getElementById(button.dataset.statusTarget)
|
||||
: null;
|
||||
if (statusTarget) {
|
||||
statusTarget.textContent = statusText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,8 +134,10 @@ import {
|
||||
focusEarthView,
|
||||
getZoomLevel,
|
||||
teardownControls,
|
||||
updateLayerButtonState,
|
||||
} from "./controls.js";
|
||||
import {
|
||||
setLayerButtonState,
|
||||
} from "./layer-button-state.js";
|
||||
import {
|
||||
initInfoCard,
|
||||
showInfoCard,
|
||||
@@ -1502,9 +1504,11 @@ function buildLoadErrorMessage(errors) {
|
||||
function updateSatelliteToggleUi(enabled, satelliteCount = getSatelliteCount()) {
|
||||
const satBtn = document.getElementById("toggle-satellites");
|
||||
if (satBtn) {
|
||||
updateLayerButtonState(satBtn, enabled);
|
||||
const tooltip = satBtn.querySelector(".earth-toolbar-tooltip");
|
||||
if (tooltip) tooltip.textContent = enabled ? "隐藏卫星" : "显示卫星";
|
||||
setLayerButtonState(satBtn, {
|
||||
active: enabled,
|
||||
loading: false,
|
||||
tooltip: enabled ? "隐藏卫星" : "显示卫星",
|
||||
});
|
||||
}
|
||||
|
||||
const satelliteCountEl = document.getElementById("satellite-count");
|
||||
@@ -1516,9 +1520,11 @@ function updateSatelliteToggleUi(enabled, satelliteCount = getSatelliteCount())
|
||||
function updateCableToggleUi(enabled) {
|
||||
const cableBtn = document.getElementById("toggle-cables");
|
||||
if (cableBtn) {
|
||||
updateLayerButtonState(cableBtn, enabled);
|
||||
const tooltip = cableBtn.querySelector(".earth-toolbar-tooltip");
|
||||
if (tooltip) tooltip.textContent = enabled ? "隐藏线缆" : "显示线缆";
|
||||
setLayerButtonState(cableBtn, {
|
||||
active: enabled,
|
||||
loading: false,
|
||||
tooltip: enabled ? "隐藏线缆" : "显示线缆",
|
||||
});
|
||||
}
|
||||
|
||||
const cableCountEl = document.getElementById("cable-count");
|
||||
|
||||
Reference in New Issue
Block a user