From abaee79198cfea734da594fe6d06a8a643e761ba Mon Sep 17 00:00:00 2001 From: hypercross Date: Sun, 1 Mar 2026 10:33:55 +0800 Subject: [PATCH] feat: edit entry classes --- .../md-commander/AttributeTooltip.tsx | 64 ++++++++++++++++++- src/components/md-commander/TrackerView.tsx | 10 +++ .../md-commander/hooks/useCommander.ts | 12 ++++ src/components/md-commander/index.tsx | 3 + src/components/md-commander/stores/index.ts | 1 + .../md-commander/stores/trackerStore.ts | 23 +++++++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/components/md-commander/AttributeTooltip.tsx b/src/components/md-commander/AttributeTooltip.tsx index 79eb93b..f49f4af 100644 --- a/src/components/md-commander/AttributeTooltip.tsx +++ b/src/components/md-commander/AttributeTooltip.tsx @@ -4,18 +4,21 @@ import type { TrackerAttribute } from "./types"; export interface AttributeTooltipProps { position: { x: number; y: number }; attributes: Record; + classes: string[]; onUpdate: (attrName: string, attr: TrackerAttribute) => void; + onClassesChange: (classes: string[]) => void; onClose: () => void; } export const AttributeTooltip: Component = (props) => { const [position, setPosition] = createSignal(props.position); + const [newClass, setNewClass] = createSignal(""); // 点击外部关闭 createEffect(() => { const handleClickOutside = (e: MouseEvent) => { const target = e.target as HTMLElement; - if (!target.closest(".attribute-tooltip")) { + if (target.closest('body') && !target.closest(".attribute-tooltip")) { props.onClose(); } }; @@ -29,6 +32,22 @@ export const AttributeTooltip: Component = (props) => { props.onUpdate(attrName, { ...attr, value }); }; + // 添加 class + const handleAddClass = () => { + const className = newClass().trim(); + if (className && !props.classes.includes(className)) { + props.onClassesChange([...props.classes, className]); + setNewClass(""); + } + }; + + // 移除 class + const handleRemoveClass = (e: MouseEvent, className: string) => { + e.preventDefault(); + e.stopPropagation(); + props.onClassesChange(props.classes.filter((c) => c !== className)); + }; + // 渲染不同类型的属性编辑器 const renderEditor = (attrName: string, attr: TrackerAttribute) => { if (attr.type === "progress") { @@ -125,6 +144,49 @@ export const AttributeTooltip: Component = (props) => {
+ {/* Class 列表编辑器 */} +
+ +
+ + {(className) => ( + + .{className} + + + )} + +
+
+ setNewClass((e.target as HTMLInputElement).value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + e.stopPropagation(); + handleAddClass(); + } + }} + placeholder="添加 class..." + class="flex-1 px-2 py-1 border border-gray-300 rounded text-sm" + /> + +
+
+ + {/* 属性编辑器 */} {([name, attr]) => (
diff --git a/src/components/md-commander/TrackerView.tsx b/src/components/md-commander/TrackerView.tsx index c20f809..41bab29 100644 --- a/src/components/md-commander/TrackerView.tsx +++ b/src/components/md-commander/TrackerView.tsx @@ -5,6 +5,7 @@ import { AttributeTooltip } from "./AttributeTooltip"; export interface TrackerViewProps { items: () => TrackerItem[]; onEditAttribute?: (index: number, attrName: string, attr: TrackerAttribute) => void; + onClassesChange?: (index: number, classes: string[]) => void; onRemoveClass?: (index: number, className: string) => void; onMoveUp?: (index: number) => void; onMoveDown?: (index: number) => void; @@ -53,6 +54,13 @@ export const TrackerView: Component = (props) => { } }; + const handleClassesChange = (classes: string[]) => { + const data = editingItem(); + if (data) { + props.onClassesChange?.(data.index, classes); + } + }; + return (
= (props) => { setEditingItem(null)} /> diff --git a/src/components/md-commander/hooks/useCommander.ts b/src/components/md-commander/hooks/useCommander.ts index 182d369..4d61edf 100644 --- a/src/components/md-commander/hooks/useCommander.ts +++ b/src/components/md-commander/hooks/useCommander.ts @@ -15,6 +15,7 @@ import { addTrackerItem as addTracker, removeTrackerItem as removeTracker, updateTrackerAttribute as updateTrackerAttr, + updateTrackerClasses as updateTrackerClassesStore, moveTrackerItem as moveTracker, removeTrackerClass as removeClassFromTracker, getTrackerItems, @@ -255,6 +256,7 @@ export interface UseCommanderReturn { removeTrackerItemByIndex: (index: number) => void; updateTrackerAttribute: (emmet: string, attrName: string, attr: TrackerAttribute) => boolean; updateTrackerAttributeByIndex: (index: number, attrName: string, attr: TrackerAttribute) => void; + updateTrackerClassesByIndex: (index: number, classes: string[]) => void; moveTrackerItem: (emmet: string, direction: 'up' | 'down') => boolean; moveTrackerItemByIndex: (index: number, direction: 'up' | 'down') => void; removeTrackerItemClass: (emmet: string, className: string) => boolean; @@ -462,6 +464,15 @@ export function useCommander( } }; + const updateTrackerClassesByIndex = (index: number, classes: string[]) => { + const items = trackerItems(); + if (index >= 0 && index < items.length) { + const item = items[index]; + const emmet = `${item.tag}${item.id ? '#' + item.id : ''}${item.classes.length > 0 ? '.' + item.classes.join('.') : ''}`; + updateTrackerClassesStore(emmet, classes); + } + }; + const moveTrackerItem = (emmet: string, direction: 'up' | 'down') => { return moveTracker(emmet, direction); }; @@ -535,6 +546,7 @@ export function useCommander( removeTrackerItemByIndex, updateTrackerAttribute, updateTrackerAttributeByIndex, + updateTrackerClassesByIndex, moveTrackerItem, moveTrackerItemByIndex, removeTrackerItemClass, diff --git a/src/components/md-commander/index.tsx b/src/components/md-commander/index.tsx index 9452441..b2f7855 100644 --- a/src/components/md-commander/index.tsx +++ b/src/components/md-commander/index.tsx @@ -92,6 +92,9 @@ customElement( onEditAttribute={(index, attrName, attr) => commander.updateTrackerAttributeByIndex(index, attrName, attr) } + onClassesChange={(index, classes) => + commander.updateTrackerClassesByIndex(index, classes) + } onRemoveClass={commander.removeTrackerItemClassByIndex} onMoveUp={(index) => commander.moveTrackerItemByIndex(index, "up")} onMoveDown={(index) => commander.moveTrackerItemByIndex(index, "down")} diff --git a/src/components/md-commander/stores/index.ts b/src/components/md-commander/stores/index.ts index 6c4f38e..5450ced 100644 --- a/src/components/md-commander/stores/index.ts +++ b/src/components/md-commander/stores/index.ts @@ -2,6 +2,7 @@ export { addTrackerItem, removeTrackerItem, updateTrackerAttribute, + updateTrackerClasses, moveTrackerItem, removeTrackerClass, getTrackerItems, diff --git a/src/components/md-commander/stores/trackerStore.ts b/src/components/md-commander/stores/trackerStore.ts index e7741a4..ca4d534 100644 --- a/src/components/md-commander/stores/trackerStore.ts +++ b/src/components/md-commander/stores/trackerStore.ts @@ -161,6 +161,29 @@ export function removeTrackerClass(emmet: string, className: string): boolean { return true; } +export function updateTrackerClasses(emmet: string, classes: string[]): boolean { + const index = findTrackerIndex(emmet); + if (index === -1) return false; + + const item = tracker.items[index]; + setTracker("items", (prev) => + prev.map((i, idx) => + idx === index + ? { ...i, classes: [...classes] } + : i + ) + ); + setTracker("history", (prev) => [ + ...prev, + { + type: "update", + itemId: `${item.tag}${item.id ? '#' + item.id : ''}`, + timestamp: new Date(), + }, + ]); + return true; +} + export function getTrackerItems(): TrackerItem[] { return tracker.items; }