feat: add spatial workspace refactor design document and implement dirty tracking for layout persistence.

This commit is contained in:
2025-11-26 20:39:49 +01:00
parent 39e3ac2a87
commit ee1c5dc606
+27 -7
View File
@@ -26,6 +26,7 @@ export class LayoutCard implements LayoutCardState {
public store: LayoutStore;
public dragStartX: number = 0;
public dragStartY: number = 0;
public isDirty: boolean = false;
private dragOffset: { x: number, y: number } | null = null;
constructor(id: string, store: LayoutStore, initialData: Partial<LayoutCardState> = {}, ref: HTMLElement | null = null) {
@@ -56,18 +57,23 @@ export class LayoutCard implements LayoutCardState {
this.update({
x: newX,
y: newY
});
}, { markDirty: true });
}
finishDrag() {
this.dragOffset = null;
}
update(changes: Partial<LayoutCardState>) {
update(changes: Partial<LayoutCardState>, options: { markDirty?: boolean } = {}) {
Object.assign(this, changes);
if (changes.width !== undefined || changes.height !== undefined) {
this.recalculateRadii();
}
if (options.markDirty) {
this.isDirty = true;
}
this.applyTransform();
}
@@ -181,7 +187,7 @@ export class LayoutCard implements LayoutCardState {
}
snapTo(x: number, y: number) {
this.update({ x, y });
this.update({ x, y }, { markDirty: true });
if (!this.ref)
return;
@@ -273,9 +279,15 @@ export class LayoutStore {
height,
z
}, ref);
// If it was a saved layout, it's not dirty.
if (!saved) {
card.isDirty = true;
}
this.items.set(id, card);
} else {
card.update({ width, height });
card.update({ width, height }, { markDirty: false });
}
// Always update ref and ensure transform is applied
@@ -334,7 +346,7 @@ export class LayoutStore {
// Assign new Z-indices
for (const card of cards) {
card.update({ z: this.zCounter++ });
card.update({ z: this.zCounter++ }, { markDirty: true });
}
}
@@ -371,7 +383,7 @@ export class LayoutStore {
for (const [id, card] of this.items) {
const saved = this.savedLayouts.get(id);
if (saved) {
card.update(saved);
card.update(saved, { markDirty: false });
}
}
}
@@ -379,7 +391,10 @@ export class LayoutStore {
async saveLayout() {
if (!this.tenantId || !this.viewId) return;
const entries = Array.from(this.items.values()).map(card => ({
const dirtyCards = Array.from(this.items.values()).filter(card => card.isDirty);
if (dirtyCards.length === 0) return;
const entries = dirtyCards.map(card => ({
documentId: card.id,
centerX: card.x,
centerY: card.y,
@@ -393,5 +408,10 @@ export class LayoutStore {
viewId: this.viewId,
entries
});
// Reset dirty flag for saved cards
for (const card of dirtyCards) {
card.isDirty = false;
}
}
}