fix: issues
This commit is contained in:
parent
c23bff5a89
commit
fdaf79e7ed
|
|
@ -1,13 +1,13 @@
|
||||||
import { type Component, For, Show } from "solid-js";
|
import { type Component, For, Show, Index } from "solid-js";
|
||||||
import type { TrackerItem, TrackerAttribute } from "./types";
|
import type { TrackerItem, TrackerAttribute } from "./types";
|
||||||
|
|
||||||
export interface TrackerViewProps {
|
export interface TrackerViewProps {
|
||||||
items: () => TrackerItem[];
|
items: () => TrackerItem[];
|
||||||
onEditAttribute?: (itemId: string, attrName: string, attr: TrackerAttribute) => void;
|
onEditAttribute?: (index: number, attrName: string, attr: TrackerAttribute) => void;
|
||||||
onRemoveClass?: (itemId: string, className: string) => void;
|
onRemoveClass?: (index: number, className: string) => void;
|
||||||
onMoveUp?: (itemId: string) => void;
|
onMoveUp?: (index: number) => void;
|
||||||
onMoveDown?: (itemId: string) => void;
|
onMoveDown?: (index: number) => void;
|
||||||
onRemove?: (itemId: string) => void;
|
onRemove?: (index: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TrackerView: Component<TrackerViewProps> = (props) => {
|
export const TrackerView: Component<TrackerViewProps> = (props) => {
|
||||||
|
|
@ -32,7 +32,7 @@ export const TrackerView: Component<TrackerViewProps> = (props) => {
|
||||||
>
|
>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<For each={props.items()}>
|
<For each={props.items()}>
|
||||||
{(item) => (
|
{(item, index) => (
|
||||||
<div class="border border-gray-200 rounded-lg p-3 bg-gray-50">
|
<div class="border border-gray-200 rounded-lg p-3 bg-gray-50">
|
||||||
{/* 头部:tag、id 和操作按钮 */}
|
{/* 头部:tag、id 和操作按钮 */}
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
|
@ -41,27 +41,26 @@ export const TrackerView: Component<TrackerViewProps> = (props) => {
|
||||||
<Show when={item.id}>
|
<Show when={item.id}>
|
||||||
<span class="text-xs text-purple-600 font-mono">#{item.id}</span>
|
<span class="text-xs text-purple-600 font-mono">#{item.id}</span>
|
||||||
</Show>
|
</Show>
|
||||||
<span class="text-xs text-gray-500 font-mono">• {item.uuid.slice(-6)}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
class="p-1 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded"
|
class="p-1 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded"
|
||||||
title="上移"
|
title="上移"
|
||||||
onClick={() => props.onMoveUp?.(item.id)}
|
onClick={() => props.onMoveUp?.(index())}
|
||||||
>
|
>
|
||||||
↑
|
↑
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="p-1 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded"
|
class="p-1 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded"
|
||||||
title="下移"
|
title="下移"
|
||||||
onClick={() => props.onMoveDown?.(item.id)}
|
onClick={() => props.onMoveDown?.(index())}
|
||||||
>
|
>
|
||||||
↓
|
↓
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="p-1 text-gray-500 hover:text-red-600 hover:bg-red-50 rounded"
|
class="p-1 text-gray-500 hover:text-red-600 hover:bg-red-50 rounded"
|
||||||
title="移除"
|
title="移除"
|
||||||
onClick={() => props.onRemove?.(item.id)}
|
onClick={() => props.onRemove?.(index())}
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -71,20 +70,20 @@ export const TrackerView: Component<TrackerViewProps> = (props) => {
|
||||||
{/* Classes */}
|
{/* Classes */}
|
||||||
<Show when={item.classes.length > 0}>
|
<Show when={item.classes.length > 0}>
|
||||||
<div class="flex flex-wrap gap-1 mb-2">
|
<div class="flex flex-wrap gap-1 mb-2">
|
||||||
<For each={item.classes}>
|
<Index each={item.classes}>
|
||||||
{(cls) => (
|
{(cls) => (
|
||||||
<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded">
|
<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded">
|
||||||
{cls}
|
{cls()}
|
||||||
<button
|
<button
|
||||||
class="hover:text-red-600"
|
class="hover:text-red-600"
|
||||||
onClick={() => props.onRemoveClass?.(item.id, cls)}
|
onClick={() => props.onRemoveClass?.(index(), cls())}
|
||||||
title="移除类"
|
title="移除类"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</For>
|
</Index>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
|
@ -94,7 +93,7 @@ export const TrackerView: Component<TrackerViewProps> = (props) => {
|
||||||
{(attr: TrackerAttribute) => (
|
{(attr: TrackerAttribute) => (
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between px-2 py-1 bg-white rounded border border-gray-200 cursor-pointer hover:border-blue-400"
|
class="flex items-center justify-between px-2 py-1 bg-white rounded border border-gray-200 cursor-pointer hover:border-blue-400"
|
||||||
onClick={() => props.onEditAttribute?.(item.id, attr.name, attr)}
|
onClick={() => props.onEditAttribute?.(index(), attr.name, attr)}
|
||||||
>
|
>
|
||||||
<span class="text-xs text-gray-600">{attr.name}</span>
|
<span class="text-xs text-gray-600">{attr.name}</span>
|
||||||
<span class="text-sm font-mono text-gray-800">
|
<span class="text-sm font-mono text-gray-800">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { MdCommanderCommand, MdCommanderCommandMap } from "../types";
|
import type { MdCommanderCommand } from "../types";
|
||||||
import { parseEmmet } from "../utils/emmetParser";
|
import { parseEmmet } from "../utils";
|
||||||
import { addTrackerItem, removeTrackerItem, getTrackerItems } from "../stores";
|
import { addTrackerItem, removeTrackerItem, getTrackerItems, findTrackerItem } from "../stores";
|
||||||
|
|
||||||
export const trackCommand: MdCommanderCommand = {
|
export const trackCommand: MdCommanderCommand = {
|
||||||
command: "track",
|
command: "track",
|
||||||
|
|
@ -42,24 +42,32 @@ export const trackCommand: MdCommanderCommand = {
|
||||||
|
|
||||||
export const untrackCommand: MdCommanderCommand = {
|
export const untrackCommand: MdCommanderCommand = {
|
||||||
command: "untrack",
|
command: "untrack",
|
||||||
description: "移除一个追踪项目",
|
description: "移除一个追踪项目 - 支持 Emmet 语法:untrack #g2 或 untrack goblin.warrior",
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "emmet",
|
||||||
description: "追踪项目的 ID",
|
description: "Emmet 格式:#id 或 tag.class",
|
||||||
type: "string",
|
type: "string",
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
handler: (args) => {
|
handler: (args) => {
|
||||||
const id = args.params.id;
|
const emmet = args.params.emmet;
|
||||||
if (!id) {
|
if (!emmet) {
|
||||||
return { message: "错误:缺少 id 参数", type: "error" };
|
return { message: "错误:缺少 Emmet 参数", type: "error" };
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTrackerItem(id);
|
const found = findTrackerItem(emmet);
|
||||||
|
if (!found) {
|
||||||
|
return { message: `未找到匹配的追踪项目:${emmet}`, type: "error" };
|
||||||
|
}
|
||||||
|
|
||||||
return { message: `已移除追踪项目:${id}`, type: "success" };
|
const success = removeTrackerItem(emmet);
|
||||||
|
if (!success) {
|
||||||
|
return { message: `移除失败:${emmet}`, type: "error" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { message: `已移除追踪项目:${found.tag}${found.id ? '#' + found.id : ''}`, type: "success" };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import {
|
||||||
removeTrackerClass as removeClassFromTracker,
|
removeTrackerClass as removeClassFromTracker,
|
||||||
getTrackerItems,
|
getTrackerItems,
|
||||||
getTrackerHistory,
|
getTrackerHistory,
|
||||||
|
findTrackerIndex,
|
||||||
} from "../stores";
|
} from "../stores";
|
||||||
|
|
||||||
// ==================== 默认命令 ====================
|
// ==================== 默认命令 ====================
|
||||||
|
|
@ -250,10 +251,14 @@ export interface UseCommanderReturn {
|
||||||
setTrackerItems: (updater: (prev: TrackerItem[]) => TrackerItem[]) => void;
|
setTrackerItems: (updater: (prev: TrackerItem[]) => TrackerItem[]) => void;
|
||||||
trackerHistory: () => TrackerCommand[];
|
trackerHistory: () => TrackerCommand[];
|
||||||
addTrackerItem: (item: Omit<TrackerItem, 'id'>) => void;
|
addTrackerItem: (item: Omit<TrackerItem, 'id'>) => void;
|
||||||
removeTrackerItem: (itemId: string) => void;
|
removeTrackerItem: (emmet: string) => boolean;
|
||||||
updateTrackerAttribute: (itemId: string, attrName: string, attr: TrackerAttribute) => void;
|
removeTrackerItemByIndex: (index: number) => void;
|
||||||
moveTrackerItem: (itemId: string, direction: 'up' | 'down') => void;
|
updateTrackerAttribute: (emmet: string, attrName: string, attr: TrackerAttribute) => boolean;
|
||||||
removeTrackerItemClass: (itemId: string, className: string) => void;
|
updateTrackerAttributeByIndex: (index: number, attrName: string, attr: TrackerAttribute) => void;
|
||||||
|
moveTrackerItem: (emmet: string, direction: 'up' | 'down') => boolean;
|
||||||
|
moveTrackerItemByIndex: (index: number, direction: 'up' | 'down') => void;
|
||||||
|
removeTrackerItemClass: (emmet: string, className: string) => boolean;
|
||||||
|
removeTrackerItemClassByIndex: (index: number, className: string) => void;
|
||||||
recordTrackerCommand: (cmd: Omit<TrackerCommand, 'timestamp'>) => void;
|
recordTrackerCommand: (cmd: Omit<TrackerCommand, 'timestamp'>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,20 +436,56 @@ export function useCommander(
|
||||||
return addTracker(item);
|
return addTracker(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTrackerItem = (itemId: string) => {
|
const removeTrackerItem = (emmet: string) => {
|
||||||
removeTracker(itemId);
|
return removeTracker(emmet);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrackerAttribute = (itemId: string, attrName: string, attr: TrackerAttribute) => {
|
const removeTrackerItemByIndex = (index: number) => {
|
||||||
updateTrackerAttr(itemId, attrName, attr);
|
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('.') : ''}`;
|
||||||
|
removeTracker(emmet);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveTrackerItem = (itemId: string, direction: 'up' | 'down') => {
|
const updateTrackerAttribute = (emmet: string, attrName: string, attr: TrackerAttribute) => {
|
||||||
moveTracker(itemId, direction);
|
return updateTrackerAttr(emmet, attrName, attr);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTrackerItemClass = (itemId: string, className: string) => {
|
const updateTrackerAttributeByIndex = (index: number, attrName: string, attr: TrackerAttribute) => {
|
||||||
removeClassFromTracker(itemId, className);
|
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('.') : ''}`;
|
||||||
|
updateTrackerAttr(emmet, attrName, attr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveTrackerItem = (emmet: string, direction: 'up' | 'down') => {
|
||||||
|
return moveTracker(emmet, direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveTrackerItemByIndex = (index: number, direction: 'up' | 'down') => {
|
||||||
|
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('.') : ''}`;
|
||||||
|
moveTracker(emmet, direction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeTrackerItemClass = (emmet: string, className: string) => {
|
||||||
|
return removeClassFromTracker(emmet, className);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeTrackerItemClassByIndex = (index: number, className: 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('.') : ''}`;
|
||||||
|
removeClassFromTracker(emmet, className);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const trackerItems = () => getTrackerItems();
|
const trackerItems = () => getTrackerItems();
|
||||||
|
|
@ -491,9 +532,13 @@ export function useCommander(
|
||||||
trackerHistory,
|
trackerHistory,
|
||||||
addTrackerItem,
|
addTrackerItem,
|
||||||
removeTrackerItem,
|
removeTrackerItem,
|
||||||
|
removeTrackerItemByIndex,
|
||||||
updateTrackerAttribute,
|
updateTrackerAttribute,
|
||||||
|
updateTrackerAttributeByIndex,
|
||||||
moveTrackerItem,
|
moveTrackerItem,
|
||||||
|
moveTrackerItemByIndex,
|
||||||
removeTrackerItemClass,
|
removeTrackerItemClass,
|
||||||
|
removeTrackerItemClassByIndex,
|
||||||
recordTrackerCommand,
|
recordTrackerCommand,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ customElement<MdCommanderProps>(
|
||||||
|
|
||||||
const commander = useCommander(props.commands);
|
const commander = useCommander(props.commands);
|
||||||
const [editingAttr, setEditingAttr] = createSignal<{
|
const [editingAttr, setEditingAttr] = createSignal<{
|
||||||
itemId: string;
|
index: number;
|
||||||
attrName: string;
|
attrName: string;
|
||||||
attr: TrackerAttribute;
|
attr: TrackerAttribute;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
@ -99,13 +99,13 @@ customElement<MdCommanderProps>(
|
||||||
fallback={
|
fallback={
|
||||||
<TrackerView
|
<TrackerView
|
||||||
items={commander.trackerItems}
|
items={commander.trackerItems}
|
||||||
onEditAttribute={(itemId, attrName, attr) =>
|
onEditAttribute={(index, attrName, attr) =>
|
||||||
setEditingAttr({ itemId, attrName, attr })
|
setEditingAttr({ index, attrName, attr })
|
||||||
}
|
}
|
||||||
onRemoveClass={commander.removeTrackerItemClass}
|
onRemoveClass={commander.removeTrackerItemClassByIndex}
|
||||||
onMoveUp={(itemId) => commander.moveTrackerItem(itemId, "up")}
|
onMoveUp={(index) => commander.moveTrackerItemByIndex(index, "up")}
|
||||||
onMoveDown={(itemId) => commander.moveTrackerItem(itemId, "down")}
|
onMoveDown={(index) => commander.moveTrackerItemByIndex(index, "down")}
|
||||||
onRemove={commander.removeTrackerItem}
|
onRemove={(index) => commander.removeTrackerItemByIndex(index)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -146,7 +146,7 @@ customElement<MdCommanderProps>(
|
||||||
onUpdate={(attr) => {
|
onUpdate={(attr) => {
|
||||||
const data = editingAttr();
|
const data = editingAttr();
|
||||||
if (data) {
|
if (data) {
|
||||||
commander.updateTrackerAttribute(data.itemId, data.attrName, attr);
|
commander.updateTrackerAttributeByIndex(data.index, data.attrName, attr);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClose={() => setEditingAttr(null)}
|
onClose={() => setEditingAttr(null)}
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,7 @@ export {
|
||||||
getTrackerItems,
|
getTrackerItems,
|
||||||
getTrackerHistory,
|
getTrackerHistory,
|
||||||
clearTrackerHistory,
|
clearTrackerHistory,
|
||||||
|
findTrackerIndex,
|
||||||
|
findTrackerItem,
|
||||||
} from "./trackerStore";
|
} from "./trackerStore";
|
||||||
export type { TrackerStore } from "./trackerStore";
|
export type { TrackerStore } from "./trackerStore";
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,51 @@ const [tracker, setTracker] = createStore<TrackerStore>({
|
||||||
history: [],
|
history: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Emmet 语法查找匹配的项目
|
||||||
|
* 支持:
|
||||||
|
* - #id - 匹配 id
|
||||||
|
* - tag - 匹配 tag
|
||||||
|
* - tag.class - 匹配 tag 和 class
|
||||||
|
* - .class - 匹配 class
|
||||||
|
*/
|
||||||
|
export function findTrackerIndex(emmet: string): number {
|
||||||
|
const trimmed = emmet.trim();
|
||||||
|
|
||||||
|
// 解析 #id
|
||||||
|
if (trimmed.startsWith('#')) {
|
||||||
|
const id = trimmed.slice(1).split('.')[0];
|
||||||
|
return tracker.items.findIndex(item => item.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 tag 和 classes
|
||||||
|
const match = trimmed.match(/^([^.#]+)?(?:#([^.#]+))?(?:\.(.+))?$/);
|
||||||
|
if (!match) return -1;
|
||||||
|
|
||||||
|
const tag = match[1];
|
||||||
|
const classes = match[3] ? match[3].split('.') : [];
|
||||||
|
|
||||||
|
return tracker.items.findIndex(item => {
|
||||||
|
// 匹配 tag
|
||||||
|
if (tag && item.tag !== tag) return false;
|
||||||
|
// 匹配所有 classes
|
||||||
|
if (classes.length > 0) {
|
||||||
|
for (const cls of classes) {
|
||||||
|
if (!item.classes.includes(cls)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findTrackerItem(emmet: string): TrackerItem | undefined {
|
||||||
|
const index = findTrackerIndex(emmet);
|
||||||
|
return index >= 0 ? tracker.items[index] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function addTrackerItem(item: Omit<TrackerItem, "uuid">): TrackerItem {
|
export function addTrackerItem(item: Omit<TrackerItem, "uuid">): TrackerItem {
|
||||||
const newItem: TrackerItem = {
|
const newItem: TrackerItem = {
|
||||||
...item,
|
...item,
|
||||||
uuid: Date.now().toString() + Math.random().toString(36).slice(2),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setTracker("items", (prev) => [...prev, newItem]);
|
setTracker("items", (prev) => [...prev, newItem]);
|
||||||
|
|
@ -31,29 +72,38 @@ export function addTrackerItem(item: Omit<TrackerItem, "uuid">): TrackerItem {
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeTrackerItem(itemId: string) {
|
export function removeTrackerItem(emmet: string): boolean {
|
||||||
const item = tracker.items.find((i) => i.uuid === itemId);
|
const index = findTrackerIndex(emmet);
|
||||||
|
if (index === -1) return false;
|
||||||
|
|
||||||
setTracker("items", (prev) => prev.filter((i) => i.uuid !== itemId));
|
const item = tracker.items[index];
|
||||||
|
|
||||||
|
setTracker("items", (prev) => prev.filter((_, i) => i !== index));
|
||||||
setTracker("history", (prev) => [
|
setTracker("history", (prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
type: "remove",
|
type: "remove",
|
||||||
itemId,
|
itemId: `${item.tag}${item.id ? '#' + item.id : ''}`,
|
||||||
data: item,
|
data: item,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateTrackerAttribute(
|
export function updateTrackerAttribute(
|
||||||
itemId: string,
|
emmet: string,
|
||||||
attrName: string,
|
attrName: string,
|
||||||
attr: TrackerAttribute
|
attr: TrackerAttribute
|
||||||
) {
|
): boolean {
|
||||||
|
const index = findTrackerIndex(emmet);
|
||||||
|
if (index === -1) return false;
|
||||||
|
|
||||||
|
const item = tracker.items[index];
|
||||||
setTracker("items", (prev) =>
|
setTracker("items", (prev) =>
|
||||||
prev.map((i) =>
|
prev.map((i, idx) =>
|
||||||
i.uuid === itemId
|
idx === index
|
||||||
? { ...i, attributes: { ...i.attributes, [attrName]: attr } }
|
? { ...i, attributes: { ...i.attributes, [attrName]: attr } }
|
||||||
: i
|
: i
|
||||||
)
|
)
|
||||||
|
|
@ -62,23 +112,24 @@ export function updateTrackerAttribute(
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
type: "update",
|
type: "update",
|
||||||
itemId,
|
itemId: `${item.tag}${item.id ? '#' + item.id : ''}`,
|
||||||
attributeUpdates: { [attrName]: attr },
|
attributeUpdates: { [attrName]: attr },
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moveTrackerItem(itemId: string, direction: "up" | "down") {
|
export function moveTrackerItem(emmet: string, direction: "up" | "down"): boolean {
|
||||||
const index = tracker.items.findIndex((i) => i.uuid === itemId);
|
const index = findTrackerIndex(emmet);
|
||||||
if (index === -1) return;
|
if (index === -1) return false;
|
||||||
|
|
||||||
const newIndex = direction === "up" ? index - 1 : index + 1;
|
const newIndex = direction === "up" ? index - 1 : index + 1;
|
||||||
if (newIndex < 0 || newIndex >= tracker.items.length) return;
|
if (newIndex < 0 || newIndex >= tracker.items.length) return false;
|
||||||
|
|
||||||
const newItems = [...tracker.items];
|
const newItems = [...tracker.items];
|
||||||
[newItems[index], newItems[newIndex]] = [newItems[newIndex], newItems[index]];
|
[newItems[index], newItems[newIndex]] = [newItems[newIndex], newItems[index]];
|
||||||
|
|
||||||
setTracker("items", newItems);
|
setTracker("items", newItems);
|
||||||
setTracker("history", (prev) => [
|
setTracker("history", (prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
|
|
@ -88,12 +139,17 @@ export function moveTrackerItem(itemId: string, direction: "up" | "down") {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeTrackerClass(itemId: string, className: string) {
|
export function removeTrackerClass(emmet: string, className: string): boolean {
|
||||||
|
const index = findTrackerIndex(emmet);
|
||||||
|
if (index === -1) return false;
|
||||||
|
|
||||||
|
const item = tracker.items[index];
|
||||||
setTracker("items", (prev) =>
|
setTracker("items", (prev) =>
|
||||||
prev.map((i) =>
|
prev.map((i, idx) =>
|
||||||
i.uuid === itemId
|
idx === index
|
||||||
? { ...i, classes: i.classes.filter((c) => c !== className) }
|
? { ...i, classes: i.classes.filter((c) => c !== className) }
|
||||||
: i
|
: i
|
||||||
)
|
)
|
||||||
|
|
@ -102,10 +158,11 @@ export function removeTrackerClass(itemId: string, className: string) {
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
type: "update",
|
type: "update",
|
||||||
itemId,
|
itemId: `${item.tag}${item.id ? '#' + item.id : ''}`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTrackerItems(): TrackerItem[] {
|
export function getTrackerItems(): TrackerItem[] {
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,8 @@ export interface TrackerAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TrackerItem {
|
export interface TrackerItem {
|
||||||
uuid: string; // 内部唯一标识符
|
|
||||||
tag: string;
|
tag: string;
|
||||||
id?: string; // Emmet ID (#id),可选的用户定义 ID
|
id?: string; // Emmet ID (#id)
|
||||||
classes: string[];
|
classes: string[];
|
||||||
attributes: Record<string, TrackerAttribute>;
|
attributes: Record<string, TrackerAttribute>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue