diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index a70ef48..6e1038c 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -30,5 +30,6 @@ export const api = { get: (path: string) => request("GET", path), post: (path: string, body?: unknown) => request("POST", path, body), patch: (path: string, body?: unknown) => request("PATCH", path, body), + put: (path: string, body?: unknown) => request("PUT", path, body), del: (path: string) => request("DELETE", path), }; diff --git a/frontend/src/components/AppShell.vue b/frontend/src/components/AppShell.vue new file mode 100644 index 0000000..2abd2a1 --- /dev/null +++ b/frontend/src/components/AppShell.vue @@ -0,0 +1,106 @@ + + + diff --git a/frontend/src/components/Icon.vue b/frontend/src/components/Icon.vue index ca8718d..321df71 100644 --- a/frontend/src/components/Icon.vue +++ b/frontend/src/components/Icon.vue @@ -9,6 +9,11 @@ const paths: Record = { restore: '', logout: '', settings: '', + note: '', + tag: '', + pencil: '', + plus: '', + check: '', }; diff --git a/frontend/src/components/LabelPicker.vue b/frontend/src/components/LabelPicker.vue new file mode 100644 index 0000000..07f4d9e --- /dev/null +++ b/frontend/src/components/LabelPicker.vue @@ -0,0 +1,101 @@ + + + diff --git a/frontend/src/components/LabelsModal.vue b/frontend/src/components/LabelsModal.vue new file mode 100644 index 0000000..4433f4b --- /dev/null +++ b/frontend/src/components/LabelsModal.vue @@ -0,0 +1,73 @@ + + + diff --git a/frontend/src/components/NoteCard.vue b/frontend/src/components/NoteCard.vue index 5766a0c..8253861 100644 --- a/frontend/src/components/NoteCard.vue +++ b/frontend/src/components/NoteCard.vue @@ -32,6 +32,15 @@ function cardClass(color: NoteColor): string {

Empty note

+
+ {{ lb.name }} +
+
diff --git a/frontend/src/components/NoteEditor.vue b/frontend/src/components/NoteEditor.vue index 2b11e17..471943f 100644 --- a/frontend/src/components/NoteEditor.vue +++ b/frontend/src/components/NoteEditor.vue @@ -3,7 +3,8 @@ import { nextTick, onMounted, ref, watch } from "vue"; import { useNotesStore } from "../stores/notes"; import ColorPicker from "./ColorPicker.vue"; import Icon from "./Icon.vue"; -import type { Note } from "../stores/notes"; +import LabelPicker from "./LabelPicker.vue"; +import type { Note, NoteLabel } from "../stores/notes"; import type { NoteColor } from "../notes/colors"; const props = defineProps<{ note: Note }>(); @@ -13,6 +14,7 @@ const notes = useNotesStore(); const title = ref(props.note.title ?? ""); const body = ref(props.note.body); const color = ref(props.note.color); +const labelList = ref([...props.note.labels]); const bodyInput = ref(null); watch( @@ -21,6 +23,7 @@ watch( title.value = n.title ?? ""; body.value = n.body; color.value = n.color; + labelList.value = [...n.labels]; }, ); @@ -29,6 +32,18 @@ onMounted(async () => { bodyInput.value?.focus(); }); +async function onLabelsChange(next: NoteLabel[]) { + labelList.value = next; + await notes.setLabels( + props.note.id, + next.map((lb) => lb.id), + ); +} + +async function removeLabel(id: string) { + await onLabelsChange(labelList.value.filter((lb) => lb.id !== id)); +} + async function close() { const changed = (title.value.trim() || null) !== (props.note.title ?? null) || @@ -71,10 +86,28 @@ async function act(fn: () => Promise) { placeholder="Take a note…" class="w-full resize-none bg-transparent text-sm leading-relaxed outline-none placeholder:text-neutral-400" /> +
+ + {{ lb.name }} + + +
+