feat: 迁移BimEngine到radial+dock并完善测量/剖切/漫游面板

This commit is contained in:
yuding
2026-03-30 15:56:18 +08:00
parent 2574a11284
commit 819992f331
26 changed files with 9575 additions and 8579 deletions

View File

@@ -23,6 +23,12 @@
box-shadow: var(--bd-shadow, 0 2px 8px rgba(15, 23, 42, 0.1));
transition: transform 220ms ease, opacity 200ms ease;
overflow: visible;
z-index: 1;
}
.bottom-dock-panel:hover,
.bottom-dock-panel:focus-within {
z-index: 10;
}
.bottom-dock-panel.is-entering {

View File

@@ -94,6 +94,7 @@ export interface EngineSettingPreset {
settings: EngineSettings;
readonly?: boolean;
source?: 'sdk-default' | 'external' | 'user';
allowModify?: boolean;
}
export interface PresetListItem {

View File

@@ -4,7 +4,6 @@
padding: 0;
border-radius: 8px;
border: none;
background: color-mix(in srgb, var(--bim-bg-elevated, #e8ecf2) 92%, #ffffff 8%);
box-sizing: border-box;
color: var(--bim-text-secondary, #475569);
font-size: 13px;
@@ -187,7 +186,6 @@
.measure-dock-panel-mode-btn.is-active {
border-color: color-mix(in srgb, var(--bim-primary, #4f88ff) 70%, #9db9ff 30%);
background: color-mix(in srgb, var(--bim-primary-subtle, rgba(96, 140, 255, 0.18)) 72%, #ffffff 28%);
color: color-mix(in srgb, var(--bim-primary, #4f88ff) 78%, #6f9dff 22%);
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bim-primary, #4f88ff) 35%, transparent 65%);
}
@@ -332,4 +330,4 @@
.measure-dock-panel-action-expand.is-expanded {
height: 74px;
}
}
}

View File

@@ -400,23 +400,21 @@ export class RadialToolbar implements IBimComponent {
style.setProperty('--bim-icon-inverse', theme.iconInverse);
style.setProperty('--bim-shadow-glow', theme.shadowGlow);
const isDark = theme.name === 'dark';
style.setProperty('--rt-main-bg', theme.bgBase);
style.setProperty('--rt-main-bg-hover', theme.bgBase);
style.setProperty('--rt-main-border', theme.floatingBtnBorder);
style.setProperty('--rt-main-shadow', theme.floatingBtnShadow);
style.setProperty('--rt-main-shadow-hover', theme.floatingBtnShadowHover);
style.setProperty('--rt-main-icon', theme.floatingIconColor);
style.setProperty('--rt-main-icon-hover', theme.floatingIconColorHover);
style.setProperty('--rt-main-bg', isDark ? 'rgba(55, 68, 86, 0.92)' : theme.floatingBtnBg);
style.setProperty('--rt-main-bg-hover', isDark ? 'rgba(66, 82, 104, 0.96)' : theme.floatingBtnBgHover);
style.setProperty('--rt-main-border', isDark ? 'rgba(117, 133, 154, 0.56)' : theme.floatingBtnBorder);
style.setProperty('--rt-main-shadow', isDark ? '0 2px 8px rgba(15, 23, 42, 0.32), 0 4px 12px rgba(15, 23, 42, 0.24)' : theme.floatingBtnShadow);
style.setProperty('--rt-main-shadow-hover', isDark ? '0 4px 12px rgba(15, 23, 42, 0.38), 0 6px 20px rgba(15, 23, 42, 0.3)' : theme.floatingBtnShadowHover);
style.setProperty('--rt-main-icon', isDark ? '#e2e8f0' : theme.floatingIconColor);
style.setProperty('--rt-main-icon-hover', isDark ? '#f8fafc' : theme.floatingIconColorHover);
style.setProperty('--rt-sub-bg', isDark ? 'rgba(55, 68, 86, 0.92)' : theme.floatingBtnBg);
style.setProperty('--rt-sub-bg-hover', isDark ? 'rgba(66, 82, 104, 0.96)' : theme.floatingBtnBgHover);
style.setProperty('--rt-sub-border', isDark ? 'rgba(117, 133, 154, 0.56)' : theme.floatingBtnBorder);
style.setProperty('--rt-sub-shadow', isDark ? '0 2px 8px rgba(15, 23, 42, 0.32), 0 4px 12px rgba(15, 23, 42, 0.24)' : theme.floatingBtnShadow);
style.setProperty('--rt-sub-shadow-hover', isDark ? '0 4px 12px rgba(15, 23, 42, 0.38), 0 6px 20px rgba(15, 23, 42, 0.3)' : theme.floatingBtnShadowHover);
style.setProperty('--rt-sub-icon', isDark ? '#e2e8f0' : theme.floatingIconColor);
style.setProperty('--rt-sub-icon-hover', isDark ? '#f8fafc' : theme.floatingIconColorHover);
style.setProperty('--rt-sub-bg', theme.bgBase);
style.setProperty('--rt-sub-bg-hover', theme.primaryHover);
style.setProperty('--rt-sub-border', theme.floatingBtnBorder);
style.setProperty('--rt-sub-shadow', theme.floatingBtnShadow);
style.setProperty('--rt-sub-shadow-hover', theme.floatingBtnShadowHover);
style.setProperty('--rt-sub-icon', theme.floatingIconColor);
style.setProperty('--rt-sub-icon-hover', theme.iconHover);
}
public setItemActive(id: string, active: boolean): void {

View File

@@ -0,0 +1,142 @@
.section-dock-panel {
width: fit-content;
max-width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
color: var(--bim-text-secondary, #475569);
}
.section-dock-axis-panel {
display: none;
width: fit-content;
border-radius: 8px;
padding: 0;
gap: 10px;
}
.section-dock-axis-panel.is-visible {
display: flex;
}
.section-dock-axis-btn {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid rgba(148, 163, 184, 0.28);
background: color-mix(in srgb, var(--bim-bg-inset, #edf1f6) 92%, #ffffff 8%);
color: color-mix(in srgb, var(--bim-text-secondary, #64748b) 94%, #475569 6%);
font-size: 16px;
line-height: 1;
box-sizing: border-box;
padding: 0;
cursor: pointer;
transition: all 0.15s ease;
}
.section-dock-axis-btn:hover {
border-color: rgba(148, 163, 184, 0.5);
background: color-mix(in srgb, var(--bim-component-bg-hover, #dce5f2) 64%, #ffffff 36%);
}
.section-dock-axis-btn.is-active {
border-color: color-mix(in srgb, var(--bim-primary, #4f88ff) 70%, #9db9ff 30%);
background: color-mix(in srgb, var(--bim-primary-subtle, rgba(96, 140, 255, 0.18)) 72%, #ffffff 28%);
color: color-mix(in srgb, var(--bim-primary, #4f88ff) 78%, #6f9dff 22%);
}
.section-dock-main {
display: flex;
align-items: center;
gap: 10px;
padding: 0;
border-radius: 8px;
}
.section-dock-types,
.section-dock-tools {
display: flex;
align-items: center;
gap: 10px;
}
.section-dock-divider {
width: 1px;
height: 32px;
background: color-mix(in srgb, var(--bim-border-default, #cbd5e1) 84%, transparent 16%);
}
.section-dock-type-btn,
.section-dock-tool-btn {
width: 32px;
height: 32px;
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 8px;
background: color-mix(in srgb, var(--bim-bg-inset, #edf1f6) 92%, #ffffff 8%);
color: color-mix(in srgb, var(--bim-text-secondary, #64748b) 94%, #475569 6%);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-sizing: border-box;
padding: 0;
transition: all 0.15s ease;
}
.section-dock-type-btn:hover,
.section-dock-tool-btn:hover {
border-color: var(--bim-border-strong, rgba(100, 116, 139, 0.6));
background: color-mix(in srgb, var(--bim-component-bg-hover, #dce5f2) 64%, #ffffff 36%);
}
.section-dock-type-btn.is-active,
.section-dock-tool-btn.is-active {
border-color: color-mix(in srgb, var(--bim-primary, #4f88ff) 70%, #9db9ff 30%);
color: color-mix(in srgb, var(--bim-primary, #4f88ff) 78%, #6f9dff 22%);
}
.section-dock-type-icon,
.section-dock-tool-icon {
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.section-dock-type-icon svg,
.section-dock-tool-icon svg {
width: 100%;
height: 100%;
fill: currentColor;
}
.section-dock-panel [data-tooltip] {
position: relative;
}
.section-dock-panel [data-tooltip]::after {
content: attr(data-tooltip);
position: absolute;
left: 50%;
bottom: calc(100% + 6px);
transform: translateX(-50%);
padding: 4px 8px;
border-radius: 6px;
background: rgba(15, 23, 42, 0.92);
color: #f8fafc;
font-size: 12px;
line-height: 1.2;
white-space: nowrap;
pointer-events: none;
opacity: 0;
visibility: hidden;
z-index: 8;
transition: opacity 60ms ease;
}
.section-dock-panel [data-tooltip]:hover::after,
.section-dock-panel [data-tooltip]:focus-visible::after {
opacity: 1;
visibility: visible;
}

View File

@@ -0,0 +1,330 @@
import './index.css';
import type { ThemeConfig } from '../../themes/types';
import { IBimComponent } from '../../types/component';
import { t } from '../../services/locale';
import { getIcon } from '../../utils/icon-manager';
export type SectionDockType = 'face' | 'axis' | 'box';
export type SectionDockAxis = 'x' | 'y' | 'z';
export interface SectionDockPanelOptions {
defaultType?: SectionDockType;
defaultAxis?: SectionDockAxis;
defaultHidden?: boolean;
onTypeChange?: (type: SectionDockType, axis: SectionDockAxis) => void;
onAxisChange?: (axis: SectionDockAxis) => void;
onHideToggle?: (hidden: boolean) => void;
onReverse?: () => void;
onReset?: (type: SectionDockType, axis: SectionDockAxis) => void;
onFitToModel?: () => void;
}
interface ToolDefinition {
key: 'hide' | 'reverse' | 'reset' | 'fit';
iconName: string;
textKey: string;
onClick: () => void;
isActive?: boolean;
}
export class SectionDockPanel implements IBimComponent {
public readonly element: HTMLElement;
private readonly options: SectionDockPanelOptions;
private readonly typeButtons: Map<SectionDockType, HTMLButtonElement> = new Map();
private readonly axisButtons: Map<SectionDockAxis, HTMLButtonElement> = new Map();
private readonly toolContainer: HTMLElement;
private readonly axisPanel: HTMLElement;
private activeType: SectionDockType;
private activeAxis: SectionDockAxis;
private isHidden: boolean;
constructor(options: SectionDockPanelOptions = {}) {
this.options = options;
this.activeType = options.defaultType ?? 'face';
this.activeAxis = options.defaultAxis ?? 'x';
this.isHidden = options.defaultHidden ?? false;
const { root, toolContainer, axisPanel } = this.createDom();
this.element = root;
this.toolContainer = toolContainer;
this.axisPanel = axisPanel;
}
public init(): void {
this.applyTypeState();
this.applyAxisState();
this.renderTools();
this.setLocales();
}
public setTheme(theme: ThemeConfig): void {
const style = this.element.style;
style.setProperty('--bim-text-primary', theme.textPrimary);
style.setProperty('--bim-text-secondary', theme.textSecondary);
style.setProperty('--bim-border-default', theme.borderDefault);
style.setProperty('--bim-border-strong', theme.borderStrong);
style.setProperty('--bim-bg-inset', theme.bgInset);
style.setProperty('--bim-bg-elevated', theme.bgElevated);
style.setProperty('--bim-primary', theme.primary);
style.setProperty('--bim-primary-subtle', theme.primarySubtle);
style.setProperty('--bim-component-bg-hover', theme.componentBgHover);
}
public setLocales(): void {
this.typeButtons.get('face')!.dataset.tooltip = t('toolbar.sectionPlane');
this.typeButtons.get('axis')!.dataset.tooltip = t('toolbar.sectionAxis');
this.typeButtons.get('box')!.dataset.tooltip = t('toolbar.sectionBox');
this.axisButtons.get('x')!.dataset.label = 'X';
this.axisButtons.get('y')!.dataset.label = 'Y';
this.axisButtons.get('z')!.dataset.label = 'Z';
this.typeButtons.forEach((button) => {
button.setAttribute('aria-label', button.dataset.tooltip ?? '');
});
this.axisButtons.forEach((button) => {
button.setAttribute('aria-label', button.dataset.label ?? '');
});
this.renderTools();
}
public destroy(): void {
this.element.remove();
}
public resetForOpen(): void {
this.activeType = 'face';
this.isHidden = false;
this.applyTypeState();
this.renderTools();
this.options.onTypeChange?.(this.activeType, this.activeAxis);
this.options.onHideToggle?.(false);
}
public getActiveType(): SectionDockType {
return this.activeType;
}
public getActiveAxis(): SectionDockAxis {
return this.activeAxis;
}
private createDom(): { root: HTMLElement; toolContainer: HTMLElement; axisPanel: HTMLElement } {
const root = document.createElement('div');
root.className = 'section-dock-panel';
const axisPanel = document.createElement('div');
axisPanel.className = 'section-dock-axis-panel';
(['x', 'y', 'z'] as SectionDockAxis[]).forEach((axis) => {
const button = document.createElement('button');
button.type = 'button';
button.className = 'section-dock-axis-btn';
button.textContent = axis.toUpperCase();
button.addEventListener('click', () => {
this.handleAxisChange(axis);
});
this.axisButtons.set(axis, button);
axisPanel.appendChild(button);
});
const main = document.createElement('div');
main.className = 'section-dock-main';
const left = document.createElement('div');
left.className = 'section-dock-types';
const faceBtn = this.createTypeButton('face', getIcon('拾曲面剖切'));
const axisBtn = this.createTypeButton('axis', getIcon('轴向剖切'));
const boxBtn = this.createTypeButton('box', getIcon('剖切盒'));
left.appendChild(faceBtn);
left.appendChild(axisBtn);
left.appendChild(boxBtn);
const divider = document.createElement('div');
divider.className = 'section-dock-divider';
const toolContainer = document.createElement('div');
toolContainer.className = 'section-dock-tools';
main.appendChild(left);
main.appendChild(divider);
main.appendChild(toolContainer);
root.appendChild(axisPanel);
root.appendChild(main);
return { root, toolContainer, axisPanel };
}
private createTypeButton(type: SectionDockType, iconSvg: string): HTMLButtonElement {
const button = document.createElement('button');
button.type = 'button';
button.className = 'section-dock-type-btn';
const icon = document.createElement('span');
icon.className = 'section-dock-type-icon';
icon.innerHTML = iconSvg;
button.appendChild(icon);
button.addEventListener('click', () => {
this.handleTypeChange(type);
});
this.typeButtons.set(type, button);
return button;
}
private handleTypeChange(type: SectionDockType): void {
if (this.activeType === type) {
return;
}
this.activeType = type;
this.applyTypeState();
this.renderTools();
if (this.isHidden) {
this.isHidden = false;
this.options.onHideToggle?.(false);
}
this.options.onTypeChange?.(type, this.activeAxis);
}
private handleAxisChange(axis: SectionDockAxis): void {
if (this.activeAxis === axis) {
return;
}
this.activeAxis = axis;
this.applyAxisState();
if (this.activeType === 'axis') {
this.options.onAxisChange?.(axis);
}
}
private applyTypeState(): void {
this.typeButtons.forEach((button, type) => {
button.classList.toggle('is-active', type === this.activeType);
});
const axisVisible = this.activeType === 'axis';
this.axisPanel.classList.toggle('is-visible', axisVisible);
}
private applyAxisState(): void {
this.axisButtons.forEach((button, axis) => {
button.classList.toggle('is-active', axis === this.activeAxis);
});
}
private renderTools(): void {
this.toolContainer.innerHTML = '';
this.getToolsForType(this.activeType).forEach((tool) => {
const button = document.createElement('button');
button.type = 'button';
button.className = 'section-dock-tool-btn';
if (tool.isActive) {
button.classList.add('is-active');
}
const icon = document.createElement('span');
icon.className = 'section-dock-tool-icon';
icon.innerHTML = getIcon(tool.iconName);
button.appendChild(icon);
const text = t(tool.textKey);
button.dataset.tooltip = text;
button.setAttribute('aria-label', text);
button.addEventListener('click', tool.onClick);
this.toolContainer.appendChild(button);
});
}
private getToolsForType(type: SectionDockType): ToolDefinition[] {
const hideTool: ToolDefinition = {
key: 'hide',
iconName: '隐藏',
textKey: type === 'box' ? 'sectionBox.actions.hide' : type === 'axis' ? 'sectionAxis.actions.hide' : 'sectionPlane.actions.hide',
isActive: this.isHidden,
onClick: () => {
this.isHidden = !this.isHidden;
this.options.onHideToggle?.(this.isHidden);
this.renderTools();
}
};
const reverseTool: ToolDefinition = {
key: 'reverse',
iconName: '反向',
textKey: type === 'axis' ? 'sectionAxis.actions.reverse' : type === 'box' ? 'sectionBox.actions.reverse' : 'sectionPlane.actions.reverse',
onClick: () => {
this.options.onReverse?.();
}
};
if (type === 'axis') {
return [
hideTool,
reverseTool,
{
key: 'reset',
iconName: '重置',
textKey: 'sectionAxis.actions.reset',
onClick: () => {
this.isHidden = false;
this.options.onReset?.(this.activeType, this.activeAxis);
this.renderTools();
}
}
];
}
if (type === 'box') {
return [
hideTool,
{
key: 'fit',
iconName: '适应到模型',
textKey: 'sectionBox.actions.fitToModel',
onClick: () => {
this.options.onFitToModel?.();
}
},
{
key: 'reset',
iconName: '重置',
textKey: 'sectionBox.actions.reset',
onClick: () => {
this.isHidden = false;
this.options.onReset?.(this.activeType, this.activeAxis);
this.renderTools();
}
}
];
}
return [
hideTool,
reverseTool,
{
key: 'reset',
iconName: '重置',
textKey: 'sectionPlane.actions.reset',
onClick: () => {
this.isHidden = false;
this.options.onReset?.(this.activeType, this.activeAxis);
this.renderTools();
}
}
];
}
}

View File

@@ -0,0 +1,107 @@
.walk-control-panel.walk-dock-panel {
gap: 10px;
padding: 0;
background: transparent;
border: none;
border-radius: 8px;
box-shadow: none;
color: var(--bim-text-secondary, #64748b);
}
.walk-control-panel.walk-dock-panel .walk-divider {
height: 32px;
}
.walk-control-panel.walk-dock-panel .walk-control-left,
.walk-control-panel.walk-dock-panel .walk-control-settings {
gap: 10px;
}
.walk-control-panel.walk-dock-panel .walk-icon-btn {
width: 32px;
height: 32px;
padding: 0;
border-radius: 8px;
border: 1px solid rgba(148, 163, 184, 0.28);
background: color-mix(in srgb, var(--bim-bg-inset, #edf1f6) 92%, #ffffff 8%);
color: color-mix(in srgb, var(--bim-text-secondary, #64748b) 94%, #475569 6%);
}
.walk-control-panel.walk-dock-panel .walk-icon-btn:hover {
border-color: rgba(148, 163, 184, 0.5);
background: color-mix(in srgb, var(--bim-component-bg-hover, #dce5f2) 64%, #ffffff 36%);
}
.walk-control-panel.walk-dock-panel .walk-icon-btn.active {
border-color: color-mix(in srgb, var(--bim-primary, #4f88ff) 70%, #9db9ff 30%);
background: color-mix(in srgb, var(--bim-primary-subtle, rgba(96, 140, 255, 0.18)) 72%, #ffffff 28%);
color: color-mix(in srgb, var(--bim-primary, #4f88ff) 78%, #6f9dff 22%);
}
.walk-control-panel.walk-dock-panel .walk-icon-btn svg {
width: 20px;
height: 20px;
}
.walk-control-panel.walk-dock-panel .walk-icon-btn.active svg {
fill: currentColor;
}
.walk-control-panel.walk-dock-panel .walk-speed-control {
gap: 8px;
}
.walk-control-panel.walk-dock-panel .walk-speed-label,
.walk-control-panel.walk-dock-panel .walk-checkbox-label,
.walk-control-panel.walk-dock-panel .walk-select-label {
font-size: 12px;
}
.walk-control-panel.walk-dock-panel .walk-speed-group {
padding: 2px;
border: 1px solid rgba(148, 163, 184, 0.28);
background: color-mix(in srgb, var(--bim-bg-inset, #edf1f6) 92%, #ffffff 8%);
}
.walk-control-panel.walk-dock-panel .walk-speed-btn {
width: 24px;
height: 24px;
font-size: 14px;
line-height: 1;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(148, 163, 184, 0.28);
background: color-mix(in srgb, var(--bim-bg-elevated, #f8fafc) 88%, #ffffff 12%);
color: var(--bim-text-primary, #0f172a);
}
.walk-control-panel.walk-dock-panel .walk-speed-display {
min-width: 30px;
font-size: 12px;
color: var(--bim-text-primary, #0f172a);
}
.walk-control-panel.walk-dock-panel .walk-checkbox {
width: 14px;
height: 14px;
accent-color: var(--bim-primary, #3b82f6);
}
.walk-control-panel.walk-dock-panel .walk-select {
min-width: 90px;
height: 24px;
padding: 2px 8px;
font-size: 12px;
border: 1px solid rgba(148, 163, 184, 0.28);
background: color-mix(in srgb, var(--bim-bg-inset, #edf1f6) 92%, #ffffff 8%);
color: var(--bim-text-primary, #0f172a);
}
.walk-control-panel.walk-dock-panel .walk-exit-btn {
height: 32px;
padding: 0 12px;
border-radius: 8px;
font-size: 12px;
}

View File

@@ -0,0 +1,39 @@
import './index.css';
import { IBimComponent } from '../../types/component';
import { WalkControlPanel } from '../walk-control-panel';
import type { WalkControlPanelOptions, WalkControlState } from '../walk-control-panel/types';
import type { ThemeConfig } from '../../themes/types';
export class WalkDockPanel implements IBimComponent {
public readonly element: HTMLElement;
private readonly panel: WalkControlPanel;
constructor(options: WalkControlPanelOptions = {}) {
this.panel = new WalkControlPanel(options);
this.panel.init();
this.element = this.panel.element;
this.element.classList.add('walk-dock-panel');
}
public init(): void {}
public setPlanViewActive(active: boolean): void {
this.panel.setPlanViewActive(active);
}
public setLocales(): void {
this.panel.setLocales();
}
public setTheme(theme: ThemeConfig): void {
this.panel.setTheme(theme);
}
public getState(): WalkControlState {
return this.panel.getState();
}
public destroy(): void {
this.panel.destroy();
}
}

View File

@@ -79,7 +79,7 @@ export class WalkPathPanel implements IBimComponent {
*/
private render(): void {
this.element.innerHTML = '';
// 渲染路径设置区域
const settings = this.createSettingsSection();
this.element.appendChild(settings);
@@ -104,13 +104,13 @@ export class WalkPathPanel implements IBimComponent {
// ===== 漫游时间 =====
const durationGroup = document.createElement('div');
durationGroup.className = 'walk-path-form-group';
const durationLabel = document.createElement('label');
durationLabel.textContent = t('walkControl.path.duration');
const durationWrapper = document.createElement('div');
durationWrapper.className = 'walk-path-input-wrapper';
const durationInput = document.createElement('input');
durationInput.type = 'number';
durationInput.className = 'walk-path-input';
@@ -121,11 +121,11 @@ export class WalkPathPanel implements IBimComponent {
const val = parseInt((e.target as HTMLInputElement).value) || 1;
this.duration = val * 1000;
};
const durationUnit = document.createElement('span');
durationUnit.className = 'walk-path-unit';
durationUnit.textContent = t('walkControl.path.durationUnit');
durationWrapper.appendChild(durationInput);
durationWrapper.appendChild(durationUnit);
durationGroup.appendChild(durationLabel);
@@ -134,7 +134,7 @@ export class WalkPathPanel implements IBimComponent {
// ===== 循环播放 =====
const loopGroup = document.createElement('div');
loopGroup.className = 'walk-path-form-group walk-path-form-group-inline';
const loopCheckbox = document.createElement('input');
loopCheckbox.type = 'checkbox';
loopCheckbox.id = 'walk-path-loop-checkbox';
@@ -144,11 +144,11 @@ export class WalkPathPanel implements IBimComponent {
// 更新循环播放状态
this.loop = (e.target as HTMLInputElement).checked;
};
const loopLabel = document.createElement('label');
loopLabel.htmlFor = 'walk-path-loop-checkbox';
loopLabel.textContent = t('walkControl.path.loop');
loopGroup.appendChild(loopCheckbox);
loopGroup.appendChild(loopLabel);
@@ -390,7 +390,7 @@ export class WalkPathPanel implements IBimComponent {
if (!this.element) return;
// 设置 CSS 变量
this.element.style.setProperty('--bim-text-primary', theme.textPrimary ?? '#fff');
this.element.style.setProperty('--bim-text-secondary', theme.textSecondary ?? '#94a3b8');
this.element.style.setProperty('--bim-text-secondary', theme.textPrimary ?? '#fff');
this.element.style.setProperty('--bim-bg-elevated', theme.bgElevated ?? '#1f2d3e');
this.element.style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
this.element.style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');