Add nonfunctional text box to create new notes
This commit is contained in:
parent
6c785ce566
commit
8453f6ee53
4 changed files with 96 additions and 7 deletions
|
|
@ -10,7 +10,12 @@ const ui = useUiStore();
|
||||||
<div class="flex h-screen touch-pan-x touch-pan-y flex-col">
|
<div class="flex h-screen touch-pan-x touch-pan-y flex-col">
|
||||||
<CNavbar />
|
<CNavbar />
|
||||||
<div class="h-full overflow-auto p-1">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,25 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useNotesStore } from "@/stores/notes";
|
import { useNotesStore } from "@/stores/notes";
|
||||||
import { useUiStore } from "@/stores/ui";
|
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 { computed, ref, watchEffect } from "vue";
|
||||||
|
import CNoteButton from "./CNoteButton.vue";
|
||||||
|
import CNoteCreator from "./CNoteCreator.vue";
|
||||||
|
|
||||||
const notes = useNotesStore();
|
const notes = useNotesStore();
|
||||||
const ui = useUiStore();
|
const ui = useUiStore();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
noteId?: string;
|
noteId: string;
|
||||||
path: number[]; // From root to here
|
path: number[]; // From root to here
|
||||||
focusPath?: number[]; // From here to focus
|
focusPath?: number[]; // From here to focus
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const note = computed(() =>
|
const note = computed(() => notes.notes.get(props.noteId));
|
||||||
props.noteId ? notes.notes.get(props.noteId) : undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Our children and their locally unique keys.
|
// Our children and their locally unique keys.
|
||||||
const children = computed(() => {
|
const children = computed(() => {
|
||||||
|
|
@ -35,6 +39,8 @@ const open = ref(false);
|
||||||
|
|
||||||
const focused = computed(() => props.focusPath?.length === 0);
|
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
|
// 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.
|
// stay true. Hence a computed() combining open and forceOpen would not suffice.
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
|
|
@ -42,6 +48,16 @@ watchEffect(() => {
|
||||||
if (props.focusPath && props.focusPath.length > 0) open.value = true;
|
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 {
|
function focusPathFor(index: number): number[] | undefined {
|
||||||
if (!props.focusPath) return undefined;
|
if (!props.focusPath) return undefined;
|
||||||
if (index !== props.focusPath[0]) return undefined;
|
if (index !== props.focusPath[0]) return undefined;
|
||||||
|
|
@ -79,7 +95,7 @@ function onClick() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col">
|
<div class="relative flex flex-col">
|
||||||
<div
|
<div
|
||||||
class="flex flex-row gap-1 pl-1"
|
class="flex flex-row gap-1 pl-1"
|
||||||
:class="focused ? ['bg-neutral-200'] : ['hover:bg-neutral-100']"
|
:class="focused ? ['bg-neutral-200'] : ['hover:bg-neutral-100']"
|
||||||
|
|
@ -113,5 +129,23 @@ function onClick() {
|
||||||
:focusPath="focusPathFor(index)"
|
:focusPath="focusPathFor(index)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
7
gdn-app/src/components/CNoteButton.vue
Normal file
7
gdn-app/src/components/CNoteButton.vue
Normal 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>
|
||||||
43
gdn-app/src/components/CNoteCreator.vue
Normal file
43
gdn-app/src/components/CNoteCreator.vue
Normal 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>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue