From 56cabea109ef38a572cc4bf0400d0d92cbacfed9 Mon Sep 17 00:00:00 2001 From: hypercross Date: Mon, 30 Mar 2026 11:40:45 +0800 Subject: [PATCH] refactor: layer editing ui --- .../md-deck/editor-panel/LayerEditorPanel.tsx | 263 +++++++++++++----- 1 file changed, 195 insertions(+), 68 deletions(-) diff --git a/src/components/md-deck/editor-panel/LayerEditorPanel.tsx b/src/components/md-deck/editor-panel/LayerEditorPanel.tsx index 6325d0a..2577e06 100644 --- a/src/components/md-deck/editor-panel/LayerEditorPanel.tsx +++ b/src/components/md-deck/editor-panel/LayerEditorPanel.tsx @@ -1,4 +1,4 @@ -import { For } from 'solid-js'; +import { For, createSignal, onCleanup, onMount } from 'solid-js'; import type { DeckStore } from '../hooks/deckStore'; export interface LayerEditorPanelProps { @@ -13,19 +13,38 @@ const ORIENTATION_OPTIONS = [ ] as const; const ALIGN_OPTIONS = [ - { value: '', label: '对齐' }, + { value: '', label: '默认' }, { value: 'l', label: '← 左' }, { value: 'c', label: '≡ 中' }, { value: 'r', label: '→ 右' } ] as const; -/** - * 图层编辑面板:图层可见性切换、位置编辑、复制代码 - */ -export function LayerEditorPanel(props: LayerEditorPanelProps) { - const { store } = props; +const FONT_PRESETS = [3, 5, 8, 12] as const; + +function OrientationIcon(value: string): string { + switch (value) { + case 'n': return '↑'; + case 'e': return '→'; + case 's': return '↓'; + case 'w': return '←'; + default: return '↑'; + } +} + +function AlignIcon(value: string): string { + switch (value) { + case 'l': return '⫷'; + case 'c': return '≡'; + case 'r': return '⫸'; + default: return '≡'; + } +} + +function LayerEditorPanel(props: LayerEditorPanelProps) { + const { store } = props; + const [openDropdown, setOpenDropdown] = createSignal(null); + let dropdownRef: HTMLDivElement | undefined; - // 根据当前激活的面获取图层配置 const currentLayerConfigs = () => store.state.activeSide === 'front' ? store.state.frontLayerConfigs @@ -36,6 +55,7 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) { ? store.actions.updateFrontLayerConfig : store.actions.updateBackLayerConfig; updateFn(layerProp, { orientation }); + setOpenDropdown(null); }; const updateLayerFontSize = (layerProp: string, fontSize?: number) => { @@ -50,6 +70,7 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) { ? store.actions.updateFrontLayerConfig : store.actions.updateBackLayerConfig; updateFn(layerProp, { align }); + setOpenDropdown(null); }; const toggleLayerVisible = (layerProp: string) => { @@ -65,78 +86,182 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) { ); }; + const handleDropdownClick = (e: MouseEvent) => { + e.stopPropagation(); + }; + + const handleClickOutside = (e: MouseEvent) => { + if (dropdownRef && !dropdownRef.contains(e.target as Node)) { + setOpenDropdown(null); + } + }; + + onMount(() => { + document.addEventListener('click', handleClickOutside); + }); + + onCleanup(() => { + document.removeEventListener('click', handleClickOutside); + }); + + const layerCount = () => currentLayerConfigs().length; + return (

图层 ({store.state.activeSide === 'front' ? '正面' : '背面'})

-
+
- {(layer) => ( -
-
- toggleLayerVisible(layer.prop)} - class="cursor-pointer" - /> - {layer.prop} -
- {layer.visible && ( - <> - + +
+ + {openDropdown() === `orient-${layer.prop}` && ( +
- {store.state.editingLayer === layer.prop ? '✓ 框选' : '框选'} - -
- { + const value = e.target.value; + updateLayerFontSize(layer.prop, value ? Number(value) : undefined); + }} + class="w-14 text-xs px-1.5 py-1 rounded border border-gray-300" + step="0.1" + min="0.1" + /> + mm +
+
+ + {(preset) => ( + )} - - + 重置 +
-
- - { - const value = e.target.value; - updateLayerFontSize(layer.prop, value ? Number(value) : undefined); - }} - class="w-16 text-xs px-2 py-1 rounded border border-gray-300 bg-white" - step="0.1" - min="0.1" - /> -
- - )} + )} +
)} @@ -154,3 +279,5 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) {
); } + +export { LayerEditorPanel }; \ No newline at end of file