From 80a6b4526c7718be2e1d4a03ce26542282e72dd8 Mon Sep 17 00:00:00 2001 From: hypercross Date: Sun, 1 Mar 2026 10:26:37 +0800 Subject: [PATCH] refactor: attribute editing --- src/components/index.ts | 1 - .../md-commander/AttributeEditor.tsx | 103 ------------- .../md-commander/AttributeTooltip.tsx | 139 ++++++++++++++++++ src/components/md-commander/TrackerView.tsx | 59 +++++++- src/components/md-commander/index.tsx | 30 +--- 5 files changed, 197 insertions(+), 135 deletions(-) delete mode 100644 src/components/md-commander/AttributeEditor.tsx create mode 100644 src/components/md-commander/AttributeTooltip.tsx diff --git a/src/components/index.ts b/src/components/index.ts index c61fb6d..5dba801 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -37,7 +37,6 @@ export type { } from './md-commander/types'; export { TabBar } from './md-commander/TabBar'; export { TrackerView } from './md-commander/TrackerView'; -export { AttributeEditor } from './md-commander/AttributeEditor'; export { CommanderEntries } from './md-commander/CommanderEntries'; export { CommanderInput } from './md-commander/CommanderInput'; export { useCommander, defaultCommands } from './md-commander/hooks'; \ No newline at end of file diff --git a/src/components/md-commander/AttributeEditor.tsx b/src/components/md-commander/AttributeEditor.tsx deleted file mode 100644 index 6f067ae..0000000 --- a/src/components/md-commander/AttributeEditor.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { type Component, Show } from "solid-js"; -import type { TrackerAttribute, TrackerAttributeType } from "./types"; - -export interface AttributeEditorProps { - attribute: () => TrackerAttribute; - onUpdate: (attr: TrackerAttribute) => void; - onClose: () => void; -} - -export const AttributeEditor: Component = (props) => { - const updateValue = (value: any) => { - props.onUpdate({ - ...props.attribute(), - value, - }); - }; - - const renderEditor = () => { - const attr = props.attribute(); - - if (attr.type === "progress") { - const val = attr.value as { x: number; y: number }; - return ( -
- updateValue({ x: parseInt(e.target.value) || 0, y: val.y })} - class="w-16 px-2 py-1 border border-gray-300 rounded text-center" - min="0" - /> - / - updateValue({ x: val.x, y: parseInt(e.target.value) || 0 })} - class="w-16 px-2 py-1 border border-gray-300 rounded text-center" - min="0" - /> -
- ); - } - - if (attr.type === "count") { - return ( - updateValue(parseInt(e.target.value) || 0)} - class="w-24 px-2 py-1 border border-gray-300 rounded text-center" - min="0" - /> - ); - } - - if (attr.type === "string") { - return ( - updateValue(e.target.value)} - class="w-full px-2 py-1 border border-gray-300 rounded" - /> - ); - } - - return null; - }; - - return ( -
-
-
-

编辑属性:{props.attribute().name}

- -
-
- - - {props.attribute().type} - -
-
- - {renderEditor()} -
-
- -
-
-
- ); -}; diff --git a/src/components/md-commander/AttributeTooltip.tsx b/src/components/md-commander/AttributeTooltip.tsx new file mode 100644 index 0000000..79eb93b --- /dev/null +++ b/src/components/md-commander/AttributeTooltip.tsx @@ -0,0 +1,139 @@ +import { type Component, Show, For, createSignal, createEffect, onCleanup } from "solid-js"; +import type { TrackerAttribute } from "./types"; + +export interface AttributeTooltipProps { + position: { x: number; y: number }; + attributes: Record; + onUpdate: (attrName: string, attr: TrackerAttribute) => void; + onClose: () => void; +} + +export const AttributeTooltip: Component = (props) => { + const [position, setPosition] = createSignal(props.position); + + // 点击外部关闭 + createEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + const target = e.target as HTMLElement; + if (!target.closest(".attribute-tooltip")) { + props.onClose(); + } + }; + document.addEventListener("click", handleClickOutside); + onCleanup(() => document.removeEventListener("click", handleClickOutside)); + }); + + // 处理属性更新 + const handleUpdate = (attrName: string, value: any) => { + const attr = props.attributes[attrName]; + props.onUpdate(attrName, { ...attr, value }); + }; + + // 渲染不同类型的属性编辑器 + const renderEditor = (attrName: string, attr: TrackerAttribute) => { + if (attr.type === "progress") { + const val = attr.value as { x: number; y: number }; + const percentage = val.y > 0 ? (val.x / val.y) * 100 : 0; + return ( +
+ {/* 进度条 */} +
+
+
+ {/* 输入框 */} +
+ handleUpdate(attrName, { x: parseInt(e.target.value) || 0, y: val.y })} + class="w-14 px-1 py-0.5 border border-gray-300 rounded text-center text-sm" + min="0" + /> + / + handleUpdate(attrName, { x: val.x, y: parseInt(e.target.value) || 0 })} + class="w-14 px-1 py-0.5 border border-gray-300 rounded text-center text-sm" + min="0" + /> +
+
+ ); + } + + if (attr.type === "count") { + const value = attr.value as number; + return ( +
+ + handleUpdate(attrName, parseInt(e.target.value) || 0)} + class="w-12 px-1 py-0.5 border border-gray-300 rounded text-center text-sm" + min="0" + /> + +
+ ); + } + + if (attr.type === "string") { + return ( + handleUpdate(attrName, e.target.value)} + class="w-full px-2 py-1 border border-gray-300 rounded text-sm" + /> + ); + } + + return 未知类型; + }; + + return ( +
e.stopPropagation()} + > +
+ 编辑属性 + +
+
+ + {([name, attr]) => ( +
+ + {renderEditor(name, attr)} +
+ )} +
+
+
+ ); +}; diff --git a/src/components/md-commander/TrackerView.tsx b/src/components/md-commander/TrackerView.tsx index b27eb5c..c20f809 100644 --- a/src/components/md-commander/TrackerView.tsx +++ b/src/components/md-commander/TrackerView.tsx @@ -1,5 +1,6 @@ -import { type Component, For, Show, Index } from "solid-js"; +import { type Component, For, Show, createSignal } from "solid-js"; import type { TrackerItem, TrackerAttribute } from "./types"; +import { AttributeTooltip } from "./AttributeTooltip"; export interface TrackerViewProps { items: () => TrackerItem[]; @@ -11,6 +12,11 @@ export interface TrackerViewProps { } export const TrackerView: Component = (props) => { + const [editingItem, setEditingItem] = createSignal<{ + index: number; + position: { x: number; y: number }; + } | null>(null); + const formatAttributeValue = (attr: TrackerAttribute): string => { if (attr.type === "progress") { const val = attr.value as { x: number; y: number }; @@ -27,6 +33,26 @@ export const TrackerView: Component = (props) => { return `${name}=${val}`; }; + const handleAttributeClick = (e: MouseEvent, index: number, attrName: string, attr: TrackerAttribute) => { + e.preventDefault(); + e.stopPropagation(); + const rect = (e.target as HTMLElement).getBoundingClientRect(); + setEditingItem({ + index, + position: { + x: rect.left, + y: rect.bottom + 5, + }, + }); + }; + + const handleUpdateAttribute = (attrName: string, attr: TrackerAttribute) => { + const data = editingItem(); + if (data) { + props.onEditAttribute?.(data.index, attrName, attr); + } + }; + return (
= (props) => { 0}> .{item.classes.join(".")} - {/* 属性简写 */} + {/* 属性链接 - 可点击编辑 */} 0}> - - [{Object.entries(item.attributes).map(([k, v]) => formatAttributeShort(k, v)).join(" ")}] + + [ + + {([name, attr], attrIndex) => ( + <> + 0}> + + + )} + + ]
@@ -85,6 +126,16 @@ export const TrackerView: Component = (props) => {
+ + {/* 属性编辑工具提示 */} + + setEditingItem(null)} + /> + ); }; diff --git a/src/components/md-commander/index.tsx b/src/components/md-commander/index.tsx index fa2eb30..9452441 100644 --- a/src/components/md-commander/index.tsx +++ b/src/components/md-commander/index.tsx @@ -1,11 +1,10 @@ import { customElement, noShadowDOM } from "solid-element"; -import { onMount, onCleanup, createSignal, Show } from "solid-js"; +import { onMount, onCleanup, Show } from "solid-js"; import { useCommander } from "./hooks"; import { CommanderInput } from "./CommanderInput"; import { CommanderEntries } from "./CommanderEntries"; import { TrackerView } from "./TrackerView"; import { TabBar } from "./TabBar"; -import { AttributeEditor } from "./AttributeEditor"; import type { MdCommanderProps, TrackerAttribute } from "./types"; customElement( @@ -15,11 +14,6 @@ customElement( noShadowDOM(); const commander = useCommander(props.commands); - const [editingAttr, setEditingAttr] = createSignal<{ - index: number; - attrName: string; - attr: TrackerAttribute; - } | null>(null); const handleKeyDown = (e: KeyboardEvent) => { if (commander.showCompletions() && commander.completions().length > 0) { @@ -43,11 +37,7 @@ customElement( return; } if (e.key === "Escape") { - if (editingAttr()) { - setEditingAttr(null); - } else { - commander.setShowCompletions(false); - } + commander.setShowCompletions(false); return; } } @@ -100,7 +90,7 @@ customElement( - setEditingAttr({ index, attrName, attr }) + commander.updateTrackerAttributeByIndex(index, attrName, attr) } onRemoveClass={commander.removeTrackerItemClassByIndex} onMoveUp={(index) => commander.moveTrackerItemByIndex(index, "up")} @@ -138,20 +128,6 @@ customElement( onAcceptCompletion={commander.acceptCompletion} /> - - {/* 属性编辑器弹窗 */} - - editingAttr()!.attr} - onUpdate={(attr) => { - const data = editingAttr(); - if (data) { - commander.updateTrackerAttributeByIndex(data.index, data.attrName, attr); - } - }} - onClose={() => setEditingAttr(null)} - /> - ); },