Highlight focused element by path

Also force all its parents to be open, similar to forceOpen from the
previous commit (which, incidentally, this commit removes again).
This commit is contained in:
Joscha 2025-02-05 21:18:37 +01:00
parent af99414d6a
commit 37f1b0e9d1
3 changed files with 29 additions and 7 deletions

View file

@ -10,7 +10,7 @@ const ui = useUiStore();
<div class="flex h-screen touch-pan-x touch-pan-y flex-col">
<CNavbar />
<div class="h-full overflow-auto px-2 py-1">
<CNote :noteId="ui.anchor" />
<CNote :noteId="ui.anchor" :focusPath="ui.focusPath" />
</div>
</div>
</template>

View file

@ -7,13 +7,14 @@ const { notes } = useNotesStore();
const props = defineProps<{
noteId?: string;
forceOpen?: boolean;
focusPath?: number[];
}>();
const note = computed(() =>
props.noteId ? notes.get(props.noteId) : undefined,
);
// Our children and their locally unique keys.
const children = computed(() => {
if (note.value === undefined) return [];
const seen = new Map<string, number>();
@ -29,16 +30,30 @@ const children = computed(() => {
const open = ref(false);
// We want to set open to true when forced, but then it should stay true. Hence
// a computed() combining open and forceOpen would not suffice.
// We're the node pointed to by the `focusPath`.
const focused = computed(() => props.focusPath?.length === 0);
// We want to set open to true when we're on the focus path, but then it should
// stay true. Hence a computed() combining open and forceOpen would not suffice.
watchEffect(() => {
if (props.forceOpen) open.value = true;
open.value; // Ensure we stay open if `open.value = false` is attempted
if (props.focusPath && props.focusPath.length > 0) open.value = true;
});
function focusPathFor(index: number): number[] | undefined {
if (!props.focusPath) return undefined;
if (index !== props.focusPath[0]) return undefined;
return props.focusPath.slice(1);
}
</script>
<template>
<div class="flex flex-col">
<div class="flex flex-row gap-1" @click="open = !open">
<div
class="flex flex-row gap-1"
:class="focused ? ['bg-neutral-200'] : []"
@click="open = !open"
>
<!-- Fold/unfold symbol -->
<div v-if="children.length > 0 && !open" class="flex items-center">
<RiArrowRightSLine size="16px" />
@ -60,7 +75,12 @@ watchEffect(() => {
v-if="open && children.length > 0"
class="flex flex-col border-l border-neutral-300 pl-3"
>
<CNote v-for="[noteId, key] in children" :key :note-id />
<CNote
v-for="([noteId, key], index) in children"
:key
:note-id
:focusPath="focusPathFor(index)"
/>
</div>
</div>
</template>

View file

@ -3,8 +3,10 @@ import { ref } from "vue";
export const useUiStore = defineStore("ui", () => {
const anchor = ref<string>();
const focusPath = ref<number[]>([1]);
return {
anchor,
focusPath,
};
});