Add nonfunctional text box to create new notes

This commit is contained in:
Joscha 2025-02-06 02:55:33 +01:00
parent 6c785ce566
commit 8453f6ee53
4 changed files with 96 additions and 7 deletions

View file

@ -10,7 +10,12 @@ const ui = useUiStore();
<div class="flex h-screen touch-pan-x touch-pan-y flex-col">
<CNavbar />
<div class="h-full overflow-auto p-1">
<CNote :noteId="ui.anchor" :path="[]" :focusPath="ui.focusPath" />
<CNote
v-if="ui.anchor"
:noteId="ui.anchor"
:path="[]"
:focusPath="ui.focusPath"
/>
</div>
</div>
</template>

View file

@ -1,21 +1,25 @@
<script setup lang="ts">
import { useNotesStore } from "@/stores/notes";
import { useUiStore } from "@/stores/ui";
import { RiArrowDownSLine, RiArrowRightSLine } from "@remixicon/vue";
import {
RiArrowDownSLine,
RiArrowRightSLine,
RiStickyNoteAddLine,
} from "@remixicon/vue";
import { computed, ref, watchEffect } from "vue";
import CNoteButton from "./CNoteButton.vue";
import CNoteCreator from "./CNoteCreator.vue";
const notes = useNotesStore();
const ui = useUiStore();
const props = defineProps<{
noteId?: string;
noteId: string;
path: number[]; // From root to here
focusPath?: number[]; // From here to focus
}>();
const note = computed(() =>
props.noteId ? notes.notes.get(props.noteId) : undefined,
);
const note = computed(() => notes.notes.get(props.noteId));
// Our children and their locally unique keys.
const children = computed(() => {
@ -35,6 +39,8 @@ const open = ref(false);
const focused = computed(() => props.focusPath?.length === 0);
const creating = ref(false);
// 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(() => {
@ -42,6 +48,16 @@ watchEffect(() => {
if (props.focusPath && props.focusPath.length > 0) open.value = true;
});
// Abort creating a child node whenever we stop being focused.
watchEffect(() => {
if (!focused.value) creating.value = false;
});
// Ensure the creator component is visible.
watchEffect(() => {
if (creating.value) open.value = true;
});
function focusPathFor(index: number): number[] | undefined {
if (!props.focusPath) return undefined;
if (index !== props.focusPath[0]) return undefined;
@ -79,7 +95,7 @@ function onClick() {
</script>
<template>
<div class="flex flex-col">
<div class="relative flex flex-col">
<div
class="flex flex-row gap-1 pl-1"
:class="focused ? ['bg-neutral-200'] : ['hover:bg-neutral-100']"
@ -113,5 +129,23 @@ function onClick() {
:focusPath="focusPathFor(index)"
/>
</div>
<div v-if="creating" class="pl-2">
<CNoteCreator
:parent-id="props.noteId"
@close="creating = false"
@finish="creating = false"
/>
</div>
<!-- Controls -->
<div
v-if="focused"
class="absolute right-0.5 flex h-6 items-center gap-0.5"
>
<CNoteButton @click="creating = true">
<RiStickyNoteAddLine size="16px" />
</CNoteButton>
</div>
</div>
</template>

View file

@ -0,0 +1,7 @@
<template>
<div
class="flex select-none items-center rounded-sm border bg-white p-0.5 transition hover:scale-110 active:scale-95"
>
<slot></slot>
</div>
</template>

View file

@ -0,0 +1,43 @@
<script setup lang="ts">
import { RiAddLine, RiCheckLine, RiCloseLine } from "@remixicon/vue";
import CNoteButton from "./CNoteButton.vue";
import { onMounted, ref, useTemplateRef } from "vue";
const emit = defineEmits<{
(e: "close"): void;
(e: "finish", text: string): void;
}>();
const input = useTemplateRef<HTMLInputElement>("input");
const text = ref("");
onMounted(() => input.value?.focus());
</script>
<template>
<div class="flex flex-row items-center gap-1 pl-1 pr-0.5">
<!-- Fold/unfold symbol -->
<div class="flex items-center">
<div class="rounded">
<RiAddLine size="16px" />
</div>
</div>
<!-- Text -->
<input
ref="input"
v-model="text"
type="text"
class="z-1 flex-1 bg-neutral-100"
autofocus
/>
<CNoteButton @click="emit('finish', text)">
<RiCheckLine size="16px" />
</CNoteButton>
<CNoteButton @click="emit('close')">
<RiCloseLine size="16px" />
</CNoteButton>
</div>
</template>