Refactor LED strip configuration interface layout
- Separate LED control panels from display preview areas - Add dedicated LED count control section at bottom of page - Create new LedCountControlPanel component with 4-column grid layout - Fix display container height to prevent layout overflow - Remove embedded LED controls from DisplayView component - Improve text color for display info panel title - Hide spinner buttons on number inputs for cleaner UI - Enhance input field styling with centered text and larger font
This commit is contained in:
@ -24,7 +24,7 @@ export const DisplayInfoPanel: Component<DisplayInfoPanelProps> = (props) => {
|
||||
<div {...rootProps} class={'card bg-base-100/95 backdrop-blur shadow-lg border border-base-300 ' + rootProps.class}>
|
||||
<div class="card-body p-4">
|
||||
<div class="card-title text-sm mb-3 flex items-center justify-between">
|
||||
<span>显示器信息</span>
|
||||
<span class="text-base-content">显示器信息</span>
|
||||
{localProps.display.is_primary && (
|
||||
<div class="badge badge-primary badge-sm">主显示器</div>
|
||||
)}
|
||||
|
@ -6,6 +6,7 @@ import { DisplayInfoPanel } from './display-info-panel';
|
||||
import { LedStripPart } from './led-strip-part';
|
||||
import { ScreenView } from './screen-view';
|
||||
|
||||
|
||||
type DisplayViewProps = {
|
||||
display: DisplayInfo;
|
||||
};
|
||||
|
@ -0,0 +1,155 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { Component, createMemo, For, JSX, splitProps } from 'solid-js';
|
||||
import { DisplayInfo } from '../../models/display-info.model';
|
||||
import { ledStripStore } from '../../stores/led-strip.store';
|
||||
import { Borders } from '../../constants/border';
|
||||
|
||||
type LedCountControlItemProps = {
|
||||
displayId: number;
|
||||
border: Borders;
|
||||
label: string;
|
||||
};
|
||||
|
||||
const LedCountControlItem: Component<LedCountControlItemProps> = (props) => {
|
||||
const config = createMemo(() => {
|
||||
return ledStripStore.strips.find(
|
||||
(s) => s.display_id === props.displayId && s.border === props.border
|
||||
);
|
||||
});
|
||||
|
||||
const handleDecrease = () => {
|
||||
if (config()) {
|
||||
invoke('patch_led_strip_len', {
|
||||
displayId: props.displayId,
|
||||
border: props.border,
|
||||
deltaLen: -1,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleIncrease = () => {
|
||||
if (config()) {
|
||||
invoke('patch_led_strip_len', {
|
||||
displayId: props.displayId,
|
||||
border: props.border,
|
||||
deltaLen: 1,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const newValue = parseInt(target.value);
|
||||
const currentLen = config()?.len || 0;
|
||||
|
||||
if (!isNaN(newValue) && newValue >= 0 && newValue <= 1000) {
|
||||
const deltaLen = newValue - currentLen;
|
||||
if (deltaLen !== 0) {
|
||||
invoke('patch_led_strip_len', {
|
||||
displayId: props.displayId,
|
||||
border: props.border,
|
||||
deltaLen: deltaLen,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
// Reset input value on error
|
||||
target.value = currentLen.toString();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Reset invalid input
|
||||
target.value = (config()?.len || 0).toString();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="card bg-base-100 border border-base-300/50 p-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="text-center">
|
||||
<span class="text-xs font-medium text-base-content">
|
||||
{props.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
<button
|
||||
class="btn btn-xs btn-circle btn-outline flex-shrink-0"
|
||||
onClick={handleDecrease}
|
||||
disabled={!config() || (config()?.len || 0) <= 0}
|
||||
title="减少LED数量"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
class="input input-xs flex-1 text-center min-w-0 text-sm font-medium [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||
value={config()?.len || 0}
|
||||
min="0"
|
||||
max="1000"
|
||||
onBlur={handleInputChange}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleInputChange(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<button
|
||||
class="btn btn-xs btn-circle btn-outline flex-shrink-0"
|
||||
onClick={handleIncrease}
|
||||
disabled={!config() || (config()?.len || 0) >= 1000}
|
||||
title="增加LED数量"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type LedCountControlPanelProps = {
|
||||
display: DisplayInfo;
|
||||
} & JSX.HTMLAttributes<HTMLElement>;
|
||||
|
||||
export const LedCountControlPanel: Component<LedCountControlPanelProps> = (props) => {
|
||||
const [localProps, rootProps] = splitProps(props, ['display']);
|
||||
|
||||
const borders: { border: Borders; label: string }[] = [
|
||||
{ border: 'Top', label: '上' },
|
||||
{ border: 'Bottom', label: '下' },
|
||||
{ border: 'Left', label: '左' },
|
||||
{ border: 'Right', label: '右' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div {...rootProps} class={'card bg-base-200 shadow-lg border border-base-300 ' + (rootProps.class || '')}>
|
||||
<div class="card-body p-4">
|
||||
<div class="card-title text-base mb-3 flex items-center justify-between">
|
||||
<span>LED数量控制</span>
|
||||
<div class="badge badge-info badge-outline">显示器 {localProps.display.id}</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<For each={borders}>
|
||||
{(item) => (
|
||||
<LedCountControlItem
|
||||
displayId={localProps.display.id}
|
||||
border={item.border}
|
||||
label={item.label}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-base-content/50 mt-3 p-2 bg-base-300/50 rounded">
|
||||
💡 提示:点击 +/- 按钮或直接输入数值来调整LED数量(范围:0-1000)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -7,6 +7,7 @@ import { LedStripConfigContainer } from '../../models/led-strip-config';
|
||||
import { setLedStripStore } from '../../stores/led-strip.store';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { LedStripPartsSorter } from './led-strip-parts-sorter';
|
||||
import { LedCountControlPanel } from './led-count-control-panel';
|
||||
import { createStore } from 'solid-js/store';
|
||||
import {
|
||||
LedStripConfigurationContext,
|
||||
@ -132,15 +133,30 @@ export const LedStripConfiguration = () => {
|
||||
<span>显示器配置</span>
|
||||
<div class="badge badge-secondary badge-outline">可视化编辑</div>
|
||||
</div>
|
||||
<div class="h-96 mb-4">
|
||||
<DisplayListContainer>
|
||||
{displayStore.displays.map((display) => {
|
||||
console.log('LedStripConfiguration: Rendering DisplayView for display:', display);
|
||||
return <DisplayView display={display} />;
|
||||
})}
|
||||
</DisplayListContainer>
|
||||
<div class="text-xs text-base-content/50 mt-2">
|
||||
💡 提示:鼠标滚轮调整灯条长度,悬停查看详细信息
|
||||
</div>
|
||||
<div class="text-xs text-base-content/50">
|
||||
💡 提示:悬停显示器查看详细信息,使用下方控制面板调整LED数量
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LED Count Control Panels */}
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<h2 class="text-lg font-semibold text-base-content">LED数量控制</h2>
|
||||
<div class="badge badge-info badge-outline">实时调整</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{displayStore.displays.map((display) => (
|
||||
<LedCountControlPanel display={display} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</LedStripConfigurationContext.Provider>
|
||||
|
@ -34,7 +34,7 @@ export const Pixel: Component<PixelProps> = (props) => {
|
||||
title={props.color}
|
||||
>
|
||||
<div
|
||||
class="absolute top-1/2 -translate-y-1/2 h-1.5 w-1.5 rounded-full ring-1 ring-stone-300/30"
|
||||
class="absolute top-1/2 -translate-y-1/2 h-2.5 w-2.5 rounded-full ring-1 ring-stone-300/50"
|
||||
style={style()}
|
||||
/>
|
||||
</div>
|
||||
@ -60,16 +60,32 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
|
||||
);
|
||||
|
||||
if (index === -1) {
|
||||
console.log('🔍 LED: Strip config not found', {
|
||||
displayId: localProps.config.display_id,
|
||||
border: localProps.config.border,
|
||||
availableStrips: ledStripStore.strips.length
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const mapper = ledStripStore.mappers[index];
|
||||
if (!mapper) {
|
||||
console.log('🔍 LED: Mapper not found', { index, mappersCount: ledStripStore.mappers.length });
|
||||
return;
|
||||
}
|
||||
|
||||
const offset = mapper.start * 3;
|
||||
|
||||
console.log('🎨 LED: Updating colors', {
|
||||
displayId: localProps.config.display_id,
|
||||
border: localProps.config.border,
|
||||
stripLength: localProps.config.len,
|
||||
mapperPos: mapper.pos,
|
||||
offset,
|
||||
colorsArrayLength: ledStripStore.colors.length,
|
||||
firstFewColors: Array.from(ledStripStore.colors.slice(offset, offset + 9))
|
||||
});
|
||||
|
||||
const colors = new Array(localProps.config.len).fill(null).map((_, i) => {
|
||||
const index = offset + i * 3;
|
||||
const r = ledStripStore.colors[index] || 0;
|
||||
@ -78,6 +94,12 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
});
|
||||
|
||||
console.log('🎨 LED: Generated colors', {
|
||||
border: localProps.config.border,
|
||||
colorsCount: colors.length,
|
||||
sampleColors: colors.slice(0, 3)
|
||||
});
|
||||
|
||||
setColors(colors);
|
||||
});
|
||||
|
||||
@ -102,19 +124,7 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
|
||||
},
|
||||
});
|
||||
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
if (localProps.config) {
|
||||
invoke('patch_led_strip_len', {
|
||||
displayId: localProps.config.display_id,
|
||||
border: localProps.config.border,
|
||||
deltaLen: e.deltaY > 0 ? 1 : -1,
|
||||
})
|
||||
.then(() => {})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<section
|
||||
@ -130,7 +140,7 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
|
||||
stripConfiguration.selectedStripPart?.displayId ===
|
||||
localProps.config?.display_id,
|
||||
}}
|
||||
onWheel={onWheel}
|
||||
|
||||
>
|
||||
<For each={colors()}>{(item) => <Pixel color={item} />}</For>
|
||||
</section>
|
||||
|
Reference in New Issue
Block a user