release: bump version to 0.27.4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,13 @@ This project follows the repository versioning rule:
|
||||
- `improvement` -> `+0.0.1`(bugfix + 小功能混合)
|
||||
- `bugfix` -> `+0.0.1`
|
||||
|
||||
## [0.27.4] — 2026-04-14
|
||||
|
||||
### 🔧 Improvements
|
||||
- info-card 改为懒加载动态挂载:页面初始 DOM 不再含隐藏的 `#info-panel` 节点,仅首次点击交互元素时创建
|
||||
|
||||
---
|
||||
|
||||
## [0.27.3] — 2026-04-14
|
||||
|
||||
### 🔧 Improvements
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
## Current Version
|
||||
|
||||
- `main` 当前主线历史推导到:`0.16.5`
|
||||
- `dev` 当前开发分支历史推导到:`0.27.3`
|
||||
- `dev` 当前开发分支历史推导到:`0.27.4`
|
||||
|
||||
## Timeline
|
||||
|
||||
| Version | Type | Branch | Commit | Summary |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `0.27.4` | improvement | `dev` | — | info-card 懒加载动态挂载,页面初始不再有隐藏节点 |
|
||||
| `0.27.3` | improvement | `dev` | — | TV panel 折叠方向稳定、视频跳动修复、图例折叠按钮修复、搜索图标调整 |
|
||||
| `0.27.2` | improvement | `dev` | — | 修复 brand copy 宽度问题,提取 --brand-copy-width CSS 变量 |
|
||||
| `0.27.1` | improvement | `dev` | — | HUD 面板拖拽 L 形边界约束、brand 组件整体缩放、图层面板宽度优化、搜索叉叉修复 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planet-frontend",
|
||||
"version": "0.27.3",
|
||||
"version": "0.27.4",
|
||||
"private": true,
|
||||
"packageManager": "bun@1",
|
||||
"dependencies": {
|
||||
|
||||
@@ -145,20 +145,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Floating detail panel — positioned near click by JS -->
|
||||
<div id="info-panel" class="hud-panel hud-panel-info hud-panel-draggable" aria-live="polite">
|
||||
<div id="info-card" class="info-card">
|
||||
<div class="info-card-header hud-panel-drag-handle">
|
||||
<span class="info-card-icon" id="info-card-icon">🛰️</span>
|
||||
<h3 id="info-card-title">详情</h3>
|
||||
<button class="info-card-close hud-panel-close" type="button" aria-label="关闭详情">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="info-card-content" class="info-card-content"></div>
|
||||
</div>
|
||||
<div id="error-message" class="hud-error-message"></div>
|
||||
</div>
|
||||
<div id="error-message" class="hud-error-message"></div>
|
||||
|
||||
<div id="right-toolbar-group" class="earth-toolbar-group">
|
||||
<div id="control-toolbar" class="earth-toolbar">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { showStatusMessage } from './ui.js';
|
||||
|
||||
let currentType = null;
|
||||
let cardMounted = false;
|
||||
|
||||
const CARD_CONFIG = {
|
||||
cable: {
|
||||
@@ -105,6 +106,138 @@ function getPanel() {
|
||||
return document.getElementById('info-panel');
|
||||
}
|
||||
|
||||
function setupInfoCardDrag(panel) {
|
||||
const app = document.getElementById('container');
|
||||
if (!app) return;
|
||||
|
||||
const handle = panel.querySelector('.hud-panel-drag-handle');
|
||||
if (!handle) return;
|
||||
|
||||
let isDragging = false;
|
||||
let startPointerX = 0;
|
||||
let startPointerY = 0;
|
||||
let startLeft = 0;
|
||||
let startTop = 0;
|
||||
|
||||
const stopDragging = () => {
|
||||
isDragging = false;
|
||||
panel.classList.remove('is-dragging');
|
||||
document.body.style.userSelect = '';
|
||||
};
|
||||
|
||||
const onMove = (event) => {
|
||||
if (!isDragging) return;
|
||||
const appRect = app.getBoundingClientRect();
|
||||
const panelRect = panel.getBoundingClientRect();
|
||||
const nextLeft = Math.min(
|
||||
Math.max(startLeft + (event.clientX - startPointerX), 0),
|
||||
appRect.width - panelRect.width,
|
||||
);
|
||||
const nextTop = Math.min(
|
||||
Math.max(startTop + (event.clientY - startPointerY), 0),
|
||||
appRect.height - panelRect.height,
|
||||
);
|
||||
panel.style.left = `${nextLeft}px`;
|
||||
panel.style.top = `${nextTop}px`;
|
||||
};
|
||||
|
||||
handle.addEventListener('pointerdown', (event) => {
|
||||
if (event.target.closest('.hud-panel-close, .info-card-close')) return;
|
||||
isDragging = true;
|
||||
startPointerX = event.clientX;
|
||||
startPointerY = event.clientY;
|
||||
const appRect = app.getBoundingClientRect();
|
||||
const panelRect = panel.getBoundingClientRect();
|
||||
startLeft = panelRect.left - appRect.left;
|
||||
startTop = panelRect.top - appRect.top;
|
||||
panel.style.left = `${startLeft}px`;
|
||||
panel.style.top = `${startTop}px`;
|
||||
panel.style.right = 'auto';
|
||||
panel.style.bottom = 'auto';
|
||||
panel.classList.add('is-dragging');
|
||||
document.body.style.userSelect = 'none';
|
||||
handle.setPointerCapture?.(event.pointerId);
|
||||
});
|
||||
|
||||
handle.addEventListener('pointermove', onMove);
|
||||
handle.addEventListener('pointerup', stopDragging);
|
||||
handle.addEventListener('pointercancel', stopDragging);
|
||||
handle.addEventListener('lostpointercapture', stopDragging);
|
||||
}
|
||||
|
||||
function mountCard() {
|
||||
if (cardMounted) return;
|
||||
|
||||
const container = document.getElementById('container');
|
||||
if (!container) return;
|
||||
|
||||
const panel = document.createElement('div');
|
||||
panel.id = 'info-panel';
|
||||
panel.className = 'hud-panel hud-panel-info';
|
||||
panel.setAttribute('aria-live', 'polite');
|
||||
panel.innerHTML = `
|
||||
<div id="info-card" class="info-card">
|
||||
<div class="info-card-header hud-panel-drag-handle">
|
||||
<span class="info-card-icon" id="info-card-icon">🛰️</span>
|
||||
<h3 id="info-card-title">详情</h3>
|
||||
<button class="info-card-close hud-panel-close" type="button" aria-label="关闭详情">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="info-card-content" class="info-card-content"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(panel);
|
||||
|
||||
const card = panel.querySelector('#info-card');
|
||||
const content = panel.querySelector('#info-card-content');
|
||||
|
||||
// Prevent pointer events from reaching the earth canvas
|
||||
const stopEvent = (event) => { event.stopPropagation(); };
|
||||
[
|
||||
'mousemove', 'mousedown', 'mouseup', 'click', 'dblclick', 'wheel',
|
||||
'pointerdown', 'pointerup', 'pointermove',
|
||||
'touchstart', 'touchmove', 'touchend',
|
||||
].forEach((evt) => card.addEventListener(evt, stopEvent, { passive: false }));
|
||||
|
||||
// Close button
|
||||
const closeBtn = card.querySelector('.info-card-close');
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
hideInfoCard();
|
||||
});
|
||||
}
|
||||
|
||||
// Copy value on label click
|
||||
content.addEventListener('click', async (event) => {
|
||||
const label = event.target.closest('.info-card-label');
|
||||
if (!label) return;
|
||||
|
||||
const property = label.closest('.info-card-property');
|
||||
const valueEl = property?.querySelector('.info-card-value');
|
||||
const value = valueEl?.textContent?.trim();
|
||||
|
||||
if (!value || value === '-') {
|
||||
showStatusMessage('无可复制内容', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(value);
|
||||
showStatusMessage(`已复制${label.textContent}:${value}`, 'success');
|
||||
} catch (error) {
|
||||
console.error('Copy failed:', error);
|
||||
showStatusMessage('复制失败', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
setupInfoCardDrag(panel);
|
||||
|
||||
cardMounted = true;
|
||||
}
|
||||
|
||||
function positionPanel(panel, x, y) {
|
||||
if (!panel) return;
|
||||
const margin = 12;
|
||||
@@ -142,71 +275,8 @@ function hidePanel() {
|
||||
if (panel) panel.classList.remove('is-visible');
|
||||
}
|
||||
|
||||
export function initInfoCard() {
|
||||
const card = document.getElementById('info-card');
|
||||
const content = document.getElementById('info-card-content');
|
||||
if (!card || !content) return;
|
||||
|
||||
if (card.dataset.interactionBound !== 'true') {
|
||||
const stopEvent = (event) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
[
|
||||
'mousemove',
|
||||
'mousedown',
|
||||
'mouseup',
|
||||
'click',
|
||||
'dblclick',
|
||||
'wheel',
|
||||
'pointerdown',
|
||||
'pointerup',
|
||||
'pointermove',
|
||||
'touchstart',
|
||||
'touchmove',
|
||||
'touchend',
|
||||
].forEach((eventName) => {
|
||||
card.addEventListener(eventName, stopEvent, { passive: false });
|
||||
});
|
||||
|
||||
// Close button wires the panel hide
|
||||
const closeBtn = card.querySelector('.info-card-close');
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
hideInfoCard();
|
||||
});
|
||||
}
|
||||
|
||||
card.dataset.interactionBound = 'true';
|
||||
}
|
||||
|
||||
if (content.dataset.copyBound === 'true') return;
|
||||
|
||||
content.addEventListener('click', async (event) => {
|
||||
const label = event.target.closest('.info-card-label');
|
||||
if (!label) return;
|
||||
|
||||
const property = label.closest('.info-card-property');
|
||||
const valueEl = property?.querySelector('.info-card-value');
|
||||
const value = valueEl?.textContent?.trim();
|
||||
|
||||
if (!value || value === '-') {
|
||||
showStatusMessage('无可复制内容', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(value);
|
||||
showStatusMessage(`已复制${label.textContent}:${value}`, 'success');
|
||||
} catch (error) {
|
||||
console.error('Copy failed:', error);
|
||||
showStatusMessage('复制失败', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
content.dataset.copyBound = 'true';
|
||||
}
|
||||
// No-op: event binding now happens lazily in mountCard()
|
||||
export function initInfoCard() {}
|
||||
|
||||
export function setInfoCardNoBorder(noBorder = true) {
|
||||
const card = document.getElementById('info-card');
|
||||
@@ -222,6 +292,8 @@ export function showInfoCard(type, data, options = {}) {
|
||||
return;
|
||||
}
|
||||
|
||||
mountCard();
|
||||
|
||||
currentType = type;
|
||||
const card = document.getElementById('info-card');
|
||||
const icon = document.getElementById('info-card-icon');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "planet"
|
||||
version = "0.27.3"
|
||||
version = "0.27.4"
|
||||
description = "智能星球计划 - 态势感知系统"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
|
||||
Reference in New Issue
Block a user