Write custom Path and Segment classes

Also fixes how pinning works in some edge cases.
This commit is contained in:
Joscha 2025-02-09 19:41:35 +01:00
parent 0b485e6cfe
commit b29b3c1e4e
6 changed files with 149 additions and 77 deletions

View file

@ -1,47 +1,49 @@
import { pathAncestors, pathLiesOn, pathSlice } from "@/util";
import { Segment, Path as UiPath } from "@/lib/path";
import { defineStore } from "pinia";
import { ref, watchEffect } from "vue";
export const useUiStore = defineStore("ui", () => {
const anchorId = ref<string>();
const focusPath = ref<string>("");
const focusPath = ref<UiPath>(new UiPath());
const openPaths = ref<Set<string>>(new Set());
const pinned = ref<string>(); // The last two segments of the path
const pinned = ref<{ segment: Segment; parentId?: string }>();
// Ensure all nodes on the focusPath are unfolded.
watchEffect(() => {
// The node pointed to by the path itself doesn't need to be unfolded.
for (const ancestor of pathAncestors(focusPath.value).slice(1)) {
openPaths.value.add(ancestor);
for (const ancestor of focusPath.value.ancestors().slice(1)) {
setOpen(ancestor, true);
}
});
function isOpen(path: string): boolean {
return openPaths.value.has(path);
function isOpen(path: UiPath): boolean {
return openPaths.value.has(path.fmt());
}
function setOpen(path: string, value: boolean) {
// Move the focusPath if necessary
if (!value && isOpen(path) && pathLiesOn(path, focusPath.value)) {
focusPath.value = path;
}
function setOpen(path: UiPath, value: boolean) {
// Don't update openPaths unnecessarily.
// Just in case vue itself doesn't debounce Set operations.
if (value && !isOpen(path)) openPaths.value.add(path);
else if (!value && isOpen(path)) openPaths.value.delete(path);
if (value && !isOpen(path)) {
openPaths.value.add(path.fmt());
} else if (!value && isOpen(path)) {
// Move the focusPath if necessary
if (path.isPrefixOf(focusPath.value)) focusPath.value = path;
openPaths.value.delete(path.fmt());
}
}
function toggleOpen(path: string) {
function toggleOpen(path: UiPath) {
setOpen(path, !isOpen(path));
}
function isPinned(path: string): boolean {
return pathSlice(path, -2) === pinned.value;
function isPinned(segment: Segment, parentId?: string): boolean {
if (!pinned.value) return false;
return pinned.value.segment.eq(segment) && pinned.value.parentId === parentId;
}
function setPinned(path: string) {
pinned.value = pathSlice(path, -2);
function setPinned(segment: Segment, parentId?: string) {
pinned.value = { segment, parentId };
}
function unsetPinned() {