import { defaultNotes } from '@/utils/defaultNotes' import { viewModes, activeViewMode } from '@/composables/useViewMode' import { useTitle } from '@vueuse/core' import { mdToHtml } from '@/utils/markdown' import { getAllMatches } from '@/utils/helpers' import { initialized, user } from '@/composables/useFirebase' import shortid from 'shortid' const notesSources = computed(() => ({ local: true, firebase: initialized.value && user.value })) type notesSourceValues = keyof typeof notesSources.value | null const activeNotesSource = ref(null) watchEffect(() => { const getSource = (): notesSourceValues => { if (!initialized.value) return null return user.value ? 'firebase' : 'local' } activeNotesSource.value = getSource() }) const baseNotes = ref<{ [noteId: string]: BaseNote }>({}) watch( baseNotes, () => { console.log(`Sync base notes with ${activeNotesSource.value}`, baseNotes.value) if (!activeNotesSource.value) return if (activeNotesSource.value === 'local') { console.log('sync with local') localStorage.setItem('notes', JSON.stringify(baseNotes.value)) } else if (activeNotesSource.value === 'firebase') { console.log('sync with firebase') } }, { deep: true } ) export const notes = computed(() => { return Object.entries(baseNotes.value) .map(([, note]) => ({ ...note, wordCount: note.content.split(' ').filter((word) => word.length > 0).length })) .sort((a, b) => b.modified - a.modified) as Note[] }) watch(notes, () => { if (notes.value.length > 0 && !activeNote.value && activeViewMode.value.name === 'Note') setActiveNote(rootNote.value?.id) }) const activeNoteId = ref() export const activeNote = computed(() => notes.value.find((note) => note.id === activeNoteId.value)) watch(activeNote, () => { if (activeNote.value) { useTitle(`${activeNote.value.title} | Contexted`) } }) export const setActiveNote = (noteId: string | undefined) => { if (noteId) { activeNoteId.value = noteId activeViewMode.value = viewModes.find((mode) => mode.name === 'Note') || viewModes[0] } } export const rootNote = computed(() => { const rootNote = notes.value.find((note: Note) => note.isRoot) return rootNote }) export const setRootNote = (noteId: string) => { if (rootNote.value) { const updatedRootNote = { ...baseNotes.value[rootNote.value.id], isRoot: false } updateNote(updatedRootNote.id, updatedRootNote) } const note = { ...baseNotes.value[noteId], isRoot: true } updateNote(noteId, note) setActiveNote(noteId) } export const setDefaultNotes = (defaultNotes: BaseNote[]) => { defaultNotes.forEach((defaultNote) => { baseNotes.value[defaultNote.id] = defaultNote }) } export const getNoteById = (noteId: string) => { return notes.value.find((note) => note.id === noteId) } export const getNoteByTitle = (title: string) => { return notes.value.find((note) => note.title === title) } export const findNotesByByTitle = (title: string) => { const titleLowerCase = title.toLowerCase() return notes.value.filter((note) => note.title.toLowerCase().includes(titleLowerCase)) } export const findNotes = (query: string): Note[] => { const removeMdFromText = (mdText: string): string => { const div = document.createElement('div') div.innerHTML = mdToHtml(mdText) const textWithoutMd = div.textContent || div.innerText || '' return textWithoutMd } return notes.value.filter((note) => { const matchTitle = note.title.toLowerCase().includes(query.toLowerCase()) const matchContent = removeMdFromText(note.content).toLowerCase().includes(query.toLowerCase()) return matchTitle || matchContent }) } export const updateNote = (noteId: string, note: BaseNote) => { const updatedNote: BaseNote = { ...note, modified: new Date().getTime() } baseNotes.value[noteId] = updatedNote } export const addNote = (title: string, content: string, goToNote: boolean = false) => { const id = shortid.generate() const newNote: BaseNote = { id, title, content, created: new Date().getTime(), modified: new Date().getTime() } baseNotes.value[id] = newNote if (goToNote) setActiveNote(id) return newNote } export const deleteNote = (noteId: string) => { delete baseNotes.value[noteId] } const getNoteLinksByNoteId = (noteId: string): string[] => { const note = baseNotes.value[noteId] const regex = /\[\[(.*?)\]\]/g const links = getAllMatches(regex, note.content || '') .map((to) => notes.value.find((note) => note.title === to[1])?.id || '') .filter((noteId) => Object.keys(baseNotes.value).includes(noteId)) return [...links] } export const notesRelations = computed(() => { const noteIds = Object.keys(baseNotes.value) const relations = noteIds .filter((id) => id !== undefined) .map((id) => { const to = getNoteLinksByNoteId(id) return { id, to } }) .map((noteRelations, _, notesRelations): NoteRelations => { const from = [...notesRelations] .map((noteRelation) => noteRelation.to.filter((toId) => toId === noteRelations.id).map(() => noteRelation.id) ) .reduce((arr, elem) => arr.concat(elem), []) .filter((value, index, self) => self.indexOf(value) === index) return { id: noteRelations.id, to: noteRelations.to, from } }) .reduce((notes, { id, to, from }) => { notes[id] = { to, from } return notes }, {} as NotesRelations) 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) : [] } watch( activeNotesSource, () => { if (!activeNotesSource.value) return baseNotes.value = {} if (activeNotesSource.value === 'local') { try { const localNotes = JSON.parse(localStorage.getItem('notes') || '{}') baseNotes.value = localNotes } catch (error) { console.log(error) } } else if (activeNotesSource.value === 'firebase') { console.log('get notes from firebase') } if (Object.entries(baseNotes.value).length === 0) { setDefaultNotes(defaultNotes) } setActiveNote(rootNote.value?.id) }, { immediate: true } )