listview
This commit is contained in:
@@ -23,9 +23,7 @@ const emit = defineEmits<{
|
|||||||
</template>
|
</template>
|
||||||
<template #default>Are you sure you want to delete this note?</template>
|
<template #default>Are you sure you want to delete this note?</template>
|
||||||
<template #actions="{ close }">
|
<template #actions="{ close }">
|
||||||
<button class="btn-primary btn-sm btn mr-1" @click="emit('delete', close)">
|
<button class="btn-primary btn-sm btn" @click="emit('delete', close)">Delete note</button>
|
||||||
Delete note
|
|
||||||
</button>
|
|
||||||
<button class="btn-sm btn" @click="close">Close</button>
|
<button class="btn-sm btn" @click="close">Close</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
@@ -35,12 +33,10 @@ const emit = defineEmits<{
|
|||||||
<i class="fas fa-fw fa-sitemap" />
|
<i class="fas fa-fw fa-sitemap" />
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>Are you sure you want to set this note as root note?</template>
|
||||||
Are you sure you want to set this note as root note?
|
|
||||||
</template>
|
|
||||||
<template #actions="{ close }">
|
<template #actions="{ close }">
|
||||||
<button class="btn-sm btn" @click="close">Close</button>
|
<button class="btn-sm btn" @click="close">Close</button>
|
||||||
<button class="btn-primary btn-sm btn mr-1" @click="emit('setRoot', close)">
|
<button class="btn-primary btn-sm btn" @click="emit('setRoot', close)">
|
||||||
Set current note as root
|
Set current note as root
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,70 +1,102 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const rows = [
|
import { getNoteReferences, setActiveNote, findNotes, deleteNote } from '@/composables/useNotes'
|
||||||
{
|
import { formatDate } from '@/utils/helpers'
|
||||||
noteTitle: 'Cy Ganderton',
|
|
||||||
references: 'Quality Control Specialist',
|
const notesWithReferences = computed(() => {
|
||||||
modified: 'Blue'
|
return findNotes(filter.value).map((note) => ({
|
||||||
},
|
...note,
|
||||||
{
|
references: getNoteReferences(note)
|
||||||
noteTitle: 'Hart Hagerty',
|
|
||||||
references: 'Desktop Support Technician',
|
|
||||||
modified: 'Purple',
|
|
||||||
rootNote: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
noteTitle: 'Brice Swyre',
|
|
||||||
references: 'Tax Accountant',
|
|
||||||
modified: 'Red'
|
|
||||||
}
|
|
||||||
].map((row) => ({
|
|
||||||
...row,
|
|
||||||
selected: false
|
|
||||||
}))
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
const checkedRows = ref<{ [key: string]: Boolean }>({})
|
const selectedNotes = ref<{ [key: string]: Boolean }>({})
|
||||||
|
const countSelectedNotes = computed(
|
||||||
|
() => Object.entries(selectedNotes.value).filter(([, selected]) => Boolean(selected)).length
|
||||||
|
)
|
||||||
|
|
||||||
const toggleRow = (row: any) => {
|
const toggleRow = (note: Note) => {
|
||||||
if (!row.rootNote) checkedRows.value[row.noteTitle] = !checkedRows.value[row.noteTitle]
|
if (!note.isRoot) selectedNotes.value[note.id] = !selectedNotes.value[note.id]
|
||||||
|
}
|
||||||
|
|
||||||
|
const filter = ref('')
|
||||||
|
|
||||||
|
const deleteSelectedNotes = (closeModal: () => void) => {
|
||||||
|
closeModal()
|
||||||
|
const notesToDelete = Object.entries(selectedNotes.value)
|
||||||
|
.filter(([, selected]) => Boolean(selected))
|
||||||
|
.map(([id]) => id)
|
||||||
|
notesToDelete.forEach((noteId) => deleteNote(noteId))
|
||||||
|
selectedNotes.value = {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-x-auto">
|
<div class="flex flex-col gap-2 overflow-x-auto">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span class="whitespace-nowrap">
|
||||||
|
{{ notesWithReferences.length }} {{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
|
||||||
|
</span>
|
||||||
|
<template v-if="countSelectedNotes > 0">
|
||||||
|
<span class="mx-1">|</span>
|
||||||
|
<div class="whitespace-nowrap font-semibold">{{ countSelectedNotes }} selected</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<Modal v-if="countSelectedNotes > 0">
|
||||||
|
<template #activator="{ open }">
|
||||||
|
<button class="btn-toolbar btn-sm btn" @click="open">Delete</button>
|
||||||
|
</template>
|
||||||
|
<template #default>Are you sure you want to delete the selected notes?</template>
|
||||||
|
<template #actions="{ close }">
|
||||||
|
<button class="btn-primary btn-sm btn" @click="deleteSelectedNotes(close)">
|
||||||
|
Delete selected notes
|
||||||
|
</button>
|
||||||
|
<button class="btn-sm btn" @click="close">Close</button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Start typing to filter"
|
||||||
|
class="input-bordered input input-sm my-1 ml-auto mr-1 max-w-xs flex-grow"
|
||||||
|
v-model="filter"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<table class="table-compact table w-full">
|
<table class="table-compact table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th class="w-[48px]"></th>
|
||||||
<!-- <label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
class="checkbox-primary checkbox checkbox-sm border-secondary"
|
|
||||||
/>
|
|
||||||
</label> -->
|
|
||||||
</th>
|
|
||||||
<th>Note title</th>
|
<th>Note title</th>
|
||||||
<th>References</th>
|
<th class="w-[100px]">References</th>
|
||||||
<th>Modified</th>
|
<th class="w-[150px]">Modified</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="row in rows"
|
v-for="note in notesWithReferences"
|
||||||
:key="row.noteTitle"
|
:key="note.id"
|
||||||
class="hover hover:cursor-pointer"
|
class="hover hover:cursor-pointer"
|
||||||
@click="toggleRow(row)"
|
@click="setActiveNote(note.id)"
|
||||||
>
|
>
|
||||||
<th>
|
<th @click.stop="toggleRow(note)" class="text-center">
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="checkbox-primary checkbox checkbox-sm border-secondary"
|
class="checkbox-primary checkbox checkbox-sm border-secondary"
|
||||||
v-model="checkedRows[row.noteTitle]"
|
:checked="Boolean(selectedNotes[note.id])"
|
||||||
:disabled="row.rootNote"
|
:disabled="note.isRoot"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</th>
|
</th>
|
||||||
<td>{{ row.noteTitle }}</td>
|
<td>
|
||||||
<td>{{ row.references }}</td>
|
<i class="fas fa-fw fa-home mr-1 text-secondary" v-if="note.isRoot" />
|
||||||
<td>{{ row.modified }}</td>
|
{{ note.title }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="badge" v-if="note.references.length > 0">
|
||||||
|
<i data-v-41bbc26f="" class="fas fa-fw fa-sign-out-alt mr-1"></i>
|
||||||
|
{{ note.references.length }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ formatDate(note.modified) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatDate } from '@/utils/helpers'
|
import { formatDate } from '@/utils/helpers'
|
||||||
import {
|
import {
|
||||||
notes,
|
|
||||||
activeNote,
|
activeNote,
|
||||||
notesRelations,
|
|
||||||
deleteNote,
|
deleteNote,
|
||||||
rootNote,
|
rootNote,
|
||||||
setRootNote,
|
setRootNote,
|
||||||
setActiveNote,
|
setActiveNote,
|
||||||
|
getNoteReferences
|
||||||
} from '@/composables/useNotes'
|
} from '@/composables/useNotes'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -29,16 +28,7 @@ const updateNoteContent = (content: string) => {
|
|||||||
emit('update', updatedNote)
|
emit('update', updatedNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
const references = computed<Note[]>(() => {
|
const references = computed<Note[]>(() => getNoteReferences(props.note))
|
||||||
const relations = notesRelations.value[props.note.id]
|
|
||||||
return relations
|
|
||||||
? (relations.from || [])
|
|
||||||
.map((noteId) => {
|
|
||||||
return notes.value.find((note) => note.id === noteId)
|
|
||||||
})
|
|
||||||
.filter((note): note is Note => note !== undefined)
|
|
||||||
: []
|
|
||||||
})
|
|
||||||
|
|
||||||
const del = async (closeModal: () => Promise<Boolean>) => {
|
const del = async (closeModal: () => Promise<Boolean>) => {
|
||||||
await closeModal()
|
await closeModal()
|
||||||
@@ -52,18 +42,14 @@ const setRoot = async (closeModal: () => Promise<Boolean>) => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex h-full flex-col">
|
||||||
<NoteToolbar :note="props.note" @delete="del" @set-root="setRoot">
|
<NoteToolbar :note="props.note" @delete="del" @set-root="setRoot">
|
||||||
<template #title>
|
<template #title>
|
||||||
<i
|
<i
|
||||||
class="fas fa-fw fa-home mr-2 text-base text-secondary opacity-40"
|
class="fas fa-fw fa-home mr-2 text-base text-secondary opacity-40"
|
||||||
v-if="props.note.isRoot"
|
v-if="props.note.isRoot"
|
||||||
></i>
|
></i>
|
||||||
<input
|
<input type="text" class="flex-grow bg-transparent py-1 outline-none" v-model="noteTitle" />
|
||||||
type="text"
|
|
||||||
class="flex-grow bg-transparent py-1 outline-none"
|
|
||||||
v-model="noteTitle"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</NoteToolbar>
|
</NoteToolbar>
|
||||||
<NoteEditor
|
<NoteEditor
|
||||||
|
|||||||
@@ -10,18 +10,17 @@ export const notes = computed<Note[]>(() => {
|
|||||||
return Object.entries(baseNotes)
|
return Object.entries(baseNotes)
|
||||||
.map(([, note]) => ({
|
.map(([, note]) => ({
|
||||||
...note,
|
...note,
|
||||||
wordCount: note.content.split(' ').filter((word) => word.length > 0).length,
|
wordCount: note.content.split(' ').filter((word) => word.length > 0).length
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.modified - a.modified) as Note[]
|
.sort((a, b) => b.modified - a.modified) as Note[]
|
||||||
})
|
})
|
||||||
watch(notes, () => {
|
watch(notes, () => {
|
||||||
if (notes.value.length > 0 && !activeNote.value) setActiveNote(rootNote.value?.id)
|
if (notes.value.length > 0 && !activeNote.value && activeViewMode.value.name === 'Note')
|
||||||
|
setActiveNote(rootNote.value?.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeNoteId = ref<string>()
|
const activeNoteId = ref<string>()
|
||||||
export const activeNote = computed(() =>
|
export const activeNote = computed(() => notes.value.find((note) => note.id === activeNoteId.value))
|
||||||
notes.value.find((note) => note.id === activeNoteId.value)
|
|
||||||
)
|
|
||||||
watch(activeNote, () => {
|
watch(activeNote, () => {
|
||||||
if (activeNote.value) {
|
if (activeNote.value) {
|
||||||
useTitle(`${activeNote.value.title} | Contexted`)
|
useTitle(`${activeNote.value.title} | Contexted`)
|
||||||
@@ -30,8 +29,7 @@ watch(activeNote, () => {
|
|||||||
export const setActiveNote = (noteId: string | undefined) => {
|
export const setActiveNote = (noteId: string | undefined) => {
|
||||||
if (noteId) {
|
if (noteId) {
|
||||||
activeNoteId.value = noteId
|
activeNoteId.value = noteId
|
||||||
activeViewMode.value =
|
activeViewMode.value = viewModes.find((mode) => mode.name === 'Note') || viewModes[0]
|
||||||
viewModes.find((mode) => mode.name === 'Note') || viewModes[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,9 +76,7 @@ export const findNotes = (query: string): Note[] => {
|
|||||||
}
|
}
|
||||||
return notes.value.filter((note) => {
|
return notes.value.filter((note) => {
|
||||||
const matchTitle = note.title.toLowerCase().includes(query.toLowerCase())
|
const matchTitle = note.title.toLowerCase().includes(query.toLowerCase())
|
||||||
const matchContent = removeMdFromText(note.content)
|
const matchContent = removeMdFromText(note.content).toLowerCase().includes(query.toLowerCase())
|
||||||
.toLowerCase()
|
|
||||||
.includes(query.toLowerCase())
|
|
||||||
return matchTitle || matchContent
|
return matchTitle || matchContent
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -88,7 +84,7 @@ export const findNotes = (query: string): Note[] => {
|
|||||||
export const updateNote = (noteId: string, note: BaseNote) => {
|
export const updateNote = (noteId: string, note: BaseNote) => {
|
||||||
const updatedNote: BaseNote = {
|
const updatedNote: BaseNote = {
|
||||||
...note,
|
...note,
|
||||||
modified: new Date().getTime(),
|
modified: new Date().getTime()
|
||||||
}
|
}
|
||||||
baseNotes[noteId] = updatedNote
|
baseNotes[noteId] = updatedNote
|
||||||
}
|
}
|
||||||
@@ -100,7 +96,7 @@ export const addNote = (title: string, content: string, goToNote: boolean = fals
|
|||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
created: new Date().getTime(),
|
created: new Date().getTime(),
|
||||||
modified: new Date().getTime(),
|
modified: new Date().getTime()
|
||||||
}
|
}
|
||||||
baseNotes[id] = newNote
|
baseNotes[id] = newNote
|
||||||
if (goToNote) setActiveNote(id)
|
if (goToNote) setActiveNote(id)
|
||||||
@@ -143,16 +139,14 @@ export const notesRelations = computed(() => {
|
|||||||
.map((noteRelations, _, notesRelations): NoteRelations => {
|
.map((noteRelations, _, notesRelations): NoteRelations => {
|
||||||
const from = [...notesRelations]
|
const from = [...notesRelations]
|
||||||
.map((noteRelation) =>
|
.map((noteRelation) =>
|
||||||
noteRelation.to
|
noteRelation.to.filter((toId) => toId === noteRelations.id).map(() => noteRelation.id)
|
||||||
.filter((toId) => toId === noteRelations.id)
|
|
||||||
.map(() => noteRelation.id)
|
|
||||||
)
|
)
|
||||||
.reduce((arr, elem) => arr.concat(elem), [])
|
.reduce((arr, elem) => arr.concat(elem), [])
|
||||||
.filter((value, index, self) => self.indexOf(value) === index)
|
.filter((value, index, self) => self.indexOf(value) === index)
|
||||||
return {
|
return {
|
||||||
id: noteRelations.id,
|
id: noteRelations.id,
|
||||||
to: noteRelations.to,
|
to: noteRelations.to,
|
||||||
from,
|
from
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.reduce((notes, { id, to, from }) => {
|
.reduce((notes, { id, to, from }) => {
|
||||||
@@ -161,3 +155,14 @@ export const notesRelations = computed(() => {
|
|||||||
}, {} as NotesRelations)
|
}, {} as NotesRelations)
|
||||||
return relations
|
return relations
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export function getNoteReferences(note: Note) {
|
||||||
|
const relations = notesRelations.value[note.id]
|
||||||
|
return relations
|
||||||
|
? (relations.from || [])
|
||||||
|
.map((noteId) => {
|
||||||
|
return notes.value.find((note) => note.id === noteId)
|
||||||
|
})
|
||||||
|
.filter((note): note is Note => note !== undefined)
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user