tabSize: 4

This commit is contained in:
2023-12-09 11:29:00 +01:00
parent 10c0387eb0
commit 2880dd7a03
54 changed files with 2572 additions and 2481 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://json.schemastore.org/prettierrc", "$schema": "https://json.schemastore.org/prettierrc",
"semi": false, "semi": false,
"tabWidth": 2, "tabWidth": 4,
"singleQuote": true, "singleQuote": true,
"printWidth": 100, "printWidth": 100,
"trailingComma": "none", "trailingComma": "none",

View File

@@ -115,8 +115,8 @@ const topBarHeightWithSafeArea = computed(() => `calc(${topBarHeight}px + var(--
<template #title>Enter your passphrase</template> <template #title>Enter your passphrase</template>
<template #default="{ close }"> <template #default="{ close }">
<div> <div>
Your notes are encrypted. Please enter your encryption key passphrase to decrypt your cloud Your notes are encrypted. Please enter your encryption key passphrase to decrypt
notes. your cloud notes.
</div> </div>
<form @submit.prevent="submitPassphrase(close)"> <form @submit.prevent="submitPassphrase(close)">
<UIInputText <UIInputText

View File

@@ -124,7 +124,9 @@ export default defineComponent({
const [major] = CKEDITOR_VERSION.split('.').map(Number) const [major] = CKEDITOR_VERSION.split('.').map(Number)
if (major < 37) { if (major < 37) {
console.warn('The <CKEditor> component requires using CKEditor 5 in version 37 or higher.') console.warn(
'The <CKEditor> component requires using CKEditor 5 in version 37 or higher.'
)
} }
} else { } else {
console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.') console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')

View File

@@ -116,10 +116,16 @@ export default class ContextedLinkEditing extends Plugin {
} }
model.enqueueChange((writer) => { model.enqueueChange((writer) => {
const rangesToFormat = format.map((array) => const rangesToFormat = format.map((array) =>
model.createRange(range.start.getShiftedBy(array[0]), range.start.getShiftedBy(array[1])) model.createRange(
range.start.getShiftedBy(array[0]),
range.start.getShiftedBy(array[1])
)
) )
const validRanges = editor.model.schema.getValidRanges(rangesToFormat, 'contextedLink') const validRanges = editor.model.schema.getValidRanges(
rangesToFormat,
'contextedLink'
)
for (const range of validRanges) { for (const range of validRanges) {
for (const item of range.getItems()) { for (const item of range.getItems()) {
if ((item as any).data) { if ((item as any).data) {
@@ -145,8 +151,8 @@ export default class ContextedLinkEditing extends Plugin {
} }
const keyCodes = [...keyCodesConfirm, ...keyCodesCycle] const keyCodes = [...keyCodesConfirm, ...keyCodesCycle]
const selection = editor.model.document.selection const selection = editor.model.document.selection
const selectionInContextedLink = ['contextedLink', 'autocomplete'].some((attribute) => const selectionInContextedLink = ['contextedLink', 'autocomplete'].some(
selection.hasAttribute(attribute) (attribute) => selection.hasAttribute(attribute)
) )
if (selectionInContextedLink && keyCodes.includes(keyCode)) { if (selectionInContextedLink && keyCodes.includes(keyCode)) {
if (selection.hasAttribute('contextedLink')) { if (selection.hasAttribute('contextedLink')) {
@@ -216,7 +222,10 @@ function fireAutocompleteEvent(editor: any, show: boolean, autocompleteNode?: an
event = { event = {
position: getNodePosition( position: getNodePosition(
editor, editor,
editor.model.createPositionFromPath(autocompleteNode.root, autocompleteNode.getPath()) editor.model.createPositionFromPath(
autocompleteNode.root,
autocompleteNode.getPath()
)
), ),
autocompleteText: autocompleteNode.data, autocompleteText: autocompleteNode.data,
domElement, domElement,

View File

@@ -116,7 +116,11 @@ const signInWithEmail = () => {
<i class="fa-fw mr-2" :class="provider.icon"></i> <i class="fa-fw mr-2" :class="provider.icon"></i>
Sign in with {{ provider.name }} Sign in with {{ provider.name }}
</UIButton> </UIButton>
<UIButton class="mx-auto !block w-[225px] max-sm:w-full" size="sm" @click="signInWithEmail"> <UIButton
class="mx-auto !block w-[225px] max-sm:w-full"
size="sm"
@click="signInWithEmail"
>
<i class="fa-fw fa-regular fa-envelope mr-2"></i> <i class="fa-fw fa-regular fa-envelope mr-2"></i>
Sign in with email Sign in with email
</UIButton> </UIButton>

View File

@@ -58,7 +58,12 @@ const openModal = async (open: () => void, modal: ModalOptions) => {
<UIButtonGroup class="flex items-center" v-if="!props.note.isRoot"> <UIButtonGroup class="flex items-center" v-if="!props.note.isRoot">
<UIModal v-for="confirmModal in confirmModals" :key="confirmModal.key"> <UIModal v-for="confirmModal in confirmModals" :key="confirmModal.key">
<template #activator="{ open }"> <template #activator="{ open }">
<UIButton size="sm" @click="openModal(open, confirmModal)" @mousedown="vibrate" join> <UIButton
size="sm"
@click="openModal(open, confirmModal)"
@mousedown="vibrate"
join
>
<i :class="confirmModal.icon" /> <i :class="confirmModal.icon" />
</UIButton> </UIButton>
</template> </template>
@@ -69,7 +74,11 @@ const openModal = async (open: () => void, modal: ModalOptions) => {
<template #default>{{ confirmModal.confirmOptions.message }}</template> <template #default>{{ confirmModal.confirmOptions.message }}</template>
<template #actions="{ close }"> <template #actions="{ close }">
<UIButton size="sm" @click="close">Cancel</UIButton> <UIButton size="sm" @click="close">Cancel</UIButton>
<UIButton size="sm" color="primary" @click="emit('execute', confirmModal.key, close)"> <UIButton
size="sm"
color="primary"
@click="emit('execute', confirmModal.key, close)"
>
{{ confirmModal.confirmOptions.okButtonTitle }} {{ confirmModal.confirmOptions.okButtonTitle }}
</UIButton> </UIButton>
</template> </template>

View File

@@ -42,7 +42,8 @@ const handleKeydown = (event: KeyboardEvent) => {
if (index < 0) index = results.value.length - 1 if (index < 0) index = results.value.length - 1
activeResult.value = results.value[index] activeResult.value = results.value[index]
const element = resultsRefs.value[index].$el const element = resultsRefs.value[index].$el
if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code)) element.scrollIntoView({ block: 'nearest' }) if (['ArrowUp', 'ArrowDown', 'Tab'].includes(code))
element.scrollIntoView({ block: 'nearest' })
} else if (code === 'Enter' && activeResult.value) { } else if (code === 'Enter' && activeResult.value) {
goToNote(activeResult.value) goToNote(activeResult.value)
} else if (code === 'Escape' && queryElem.value) { } else if (code === 'Escape' && queryElem.value) {

View File

@@ -8,7 +8,11 @@ const props = withDefaults(
</script> </script>
<template> <template>
<div class="flex w-full animate-pulse flex-col"> <div class="flex w-full animate-pulse flex-col">
<div class="mt-1 h-[1.35rem] w-full rounded bg-secondary" v-for="i in props.n" :key="i"></div> <div
class="mt-1 h-[1.35rem] w-full rounded bg-secondary"
v-for="i in props.n"
:key="i"
></div>
</div> </div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -97,7 +97,12 @@ const toggleEncryption = async () => {
<div class="w-full flex-row sm:flex"> <div class="w-full flex-row sm:flex">
<div class="font-bold sm:w-4/12">Account creation date</div> <div class="font-bold sm:w-4/12">Account creation date</div>
<div> <div>
{{ format(Date.parse(user?.metadata?.creationTime || ''), 'dd/MM/yyyy') }} {{
format(
Date.parse(user?.metadata?.creationTime || ''),
'dd/MM/yyyy'
)
}}
</div> </div>
</div> </div>
</template> </template>
@@ -115,7 +120,11 @@ const toggleEncryption = async () => {
<div class="items-top w-full flex-row sm:flex sm:flex-grow"> <div class="items-top w-full flex-row sm:flex sm:flex-grow">
<div class="flex-shrink-0 font-bold sm:w-4/12">Delete account</div> <div class="flex-shrink-0 font-bold sm:w-4/12">Delete account</div>
<div> <div>
<UIButton size="sm" color="error" @click="showDeleteAccountDialog = true"> <UIButton
size="sm"
color="error"
@click="showDeleteAccountDialog = true"
>
<i class="fa-fw fa-solid fa-trash mr-2"></i> <i class="fa-fw fa-solid fa-trash mr-2"></i>
Delete account Delete account
</UIButton> </UIButton>
@@ -126,14 +135,23 @@ const toggleEncryption = async () => {
v-if="showDeleteAccountDialog" v-if="showDeleteAccountDialog"
> >
<div> <div>
Are you sure you want to delete your Contexted account? This action cannot be Are you sure you want to delete your Contexted account? This
undone! action cannot be undone!
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<UIButton size="sm" variant="outline" color="primary" @click="deleteAccount"> <UIButton
size="sm"
variant="outline"
color="primary"
@click="deleteAccount"
>
Delete account Delete account
</UIButton> </UIButton>
<UIButton size="sm" variant="outline" @click="showDeleteAccountDialog = false"> <UIButton
size="sm"
variant="outline"
@click="showDeleteAccountDialog = false"
>
Cancel Cancel
</UIButton> </UIButton>
</div> </div>
@@ -141,7 +159,9 @@ const toggleEncryption = async () => {
</div> </div>
</div> </div>
<div class="items-top w-full flex-row sm:flex"> <div class="items-top w-full flex-row sm:flex">
<div class="flex-shrink-0 font-bold sm:w-4/12">End-to-end encryption</div> <div class="flex-shrink-0 font-bold sm:w-4/12">
End-to-end encryption
</div>
<div class="w-full"> <div class="w-full">
<template v-if="!encryptionEnabled"> <template v-if="!encryptionEnabled">
<UIButton <UIButton
@@ -163,7 +183,12 @@ const toggleEncryption = async () => {
Disable end-to-end encryption Disable end-to-end encryption
</UIButton> </UIButton>
</template> </template>
<UIAlert color="info" density="compact" class="text-sm" v-if="showEncryptionDialog"> <UIAlert
color="info"
density="compact"
class="text-sm"
v-if="showEncryptionDialog"
>
<div class="w-full space-y-2"> <div class="w-full space-y-2">
<div> <div>
Enter your passphrase to Enter your passphrase to
@@ -177,7 +202,11 @@ const toggleEncryption = async () => {
v-model="passphrase" v-model="passphrase"
class="w-full !max-w-full" class="w-full !max-w-full"
/> />
<UIAlert density="compact" color="error" v-if="toggleEncryptionError"> <UIAlert
density="compact"
color="error"
v-if="toggleEncryptionError"
>
<i class="fa-solid fa-triangle-exclamation"></i> <i class="fa-solid fa-triangle-exclamation"></i>
{{ toggleEncryptionError }} {{ toggleEncryptionError }}
</UIAlert> </UIAlert>
@@ -189,9 +218,16 @@ const toggleEncryption = async () => {
color="primary" color="primary"
@click="toggleEncryption" @click="toggleEncryption"
> >
{{ encryptionEnabled ? 'Disable' : 'Enable' }} encryption {{
encryptionEnabled ? 'Disable' : 'Enable'
}}
encryption
</UIButton> </UIButton>
<UIButton size="sm" variant="outline" @click="showEncryptionDialog = false"> <UIButton
size="sm"
variant="outline"
@click="showEncryptionDialog = false"
>
Cancel Cancel
</UIButton> </UIButton>
</div> </div>

View File

@@ -34,11 +34,14 @@ const deleteSelectedNotes = (closeModal: () => void) => {
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="flex items-center"> <div class="flex items-center">
<span class="whitespace-nowrap"> <span class="whitespace-nowrap">
{{ notesWithReferences.length }} {{ notesWithReferences.length === 1 ? 'note' : 'notes' }} {{ notesWithReferences.length }}
{{ notesWithReferences.length === 1 ? 'note' : 'notes' }}
</span> </span>
<template v-if="countSelectedNotes > 0"> <template v-if="countSelectedNotes > 0">
<span class="mx-1">|</span> <span class="mx-1">|</span>
<div class="whitespace-nowrap font-semibold">{{ countSelectedNotes }} selected</div> <div class="whitespace-nowrap font-semibold">
{{ countSelectedNotes }} selected
</div>
</template> </template>
</div> </div>
<UIModal v-if="countSelectedNotes > 0"> <UIModal v-if="countSelectedNotes > 0">

View File

@@ -27,7 +27,9 @@ const renderMindmap = () => {
const elements = { const elements = {
nodes: nodes.value, nodes: nodes.value,
edges: [ edges: [
...links.value.map((link) => ({ data: { id: `${link.source}-${link.target}`, ...link } })) ...links.value.map((link) => ({
data: { id: `${link.source}-${link.target}`, ...link }
}))
] ]
} }
const cy = cytoscape({ const cy = cytoscape({
@@ -195,11 +197,13 @@ interface Mindmap {
} }
const selectedMindmap = ref<Mindmap>() const selectedMindmap = ref<Mindmap>()
const mindmaps = computed<Mindmap[]>(() => { const mindmaps = computed<Mindmap[]>(() => {
const mindmaps = Object.entries(notesRelations.value).reduce((mindmaps, [noteId, relations]) => { const mindmaps = Object.entries(notesRelations.value).reduce(
(mindmaps, [noteId, relations]) => {
const atomicMindmap = [noteId, ...relations.to, ...relations.from] const atomicMindmap = [noteId, ...relations.to, ...relations.from]
const indices = mindmaps const indices = mindmaps
.filter( .filter(
(mindmap) => [...mindmap].filter((noteId) => atomicMindmap.includes(noteId)).length > 0 (mindmap) =>
[...mindmap].filter((noteId) => atomicMindmap.includes(noteId)).length > 0
) )
.map((mindmap) => mindmaps.indexOf(mindmap)) .map((mindmap) => mindmaps.indexOf(mindmap))
if (indices.length > 0) { if (indices.length > 0) {
@@ -218,13 +222,16 @@ const mindmaps = computed<Mindmap[]>(() => {
mindmaps.push(atomicMindmap) mindmaps.push(atomicMindmap)
} }
return mindmaps return mindmaps
}, [] as string[][]) },
[] as string[][]
)
return mindmaps return mindmaps
.filter((mindmap) => mindmap.length > 1) .filter((mindmap) => mindmap.length > 1)
.sort((a, b) => b.length - a.length) .sort((a, b) => b.length - a.length)
.sort((a, b) => { .sort((a, b) => {
return ( return (
Number(b.includes(rootNote.value?.id || '')) - Number(a.includes(rootNote.value?.id || '')) Number(b.includes(rootNote.value?.id || '')) -
Number(a.includes(rootNote.value?.id || ''))
) )
}) })
.slice(0, 5) .slice(0, 5)

View File

@@ -51,7 +51,11 @@ const handleAction = async (action: 'delete' | 'setRoot', closeModal?: () => Pro
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 type="text" class="w-full bg-transparent pb-1 outline-none" v-model="noteTitle" /> <input
type="text"
class="w-full bg-transparent pb-1 outline-none"
v-model="noteTitle"
/>
</template> </template>
</NoteToolbar> </NoteToolbar>
<NoteEditor <NoteEditor

View File

@@ -97,7 +97,10 @@ const decryptNote = (note: BaseNote, key: EncryptionKey) => {
export const decryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => { export const decryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => {
const decryptedNotes = Object.fromEntries( const decryptedNotes = Object.fromEntries(
Object.entries(notes).map(([noteId, note]) => [noteId, { ...decryptNote(note, encryptionKey) }]) Object.entries(notes).map(([noteId, note]) => [
noteId,
{ ...decryptNote(note, encryptionKey) }
])
) )
return decryptedNotes return decryptedNotes
} }
@@ -112,7 +115,10 @@ const encryptNote = (note: BaseNote, key: EncryptionKey) => {
export const encryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => { export const encryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) => {
const encryptedNotes = Object.fromEntries( const encryptedNotes = Object.fromEntries(
Object.entries(notes).map(([noteId, note]) => [noteId, { ...encryptNote(note, encryptionKey) }]) Object.entries(notes).map(([noteId, note]) => [
noteId,
{ ...encryptNote(note, encryptionKey) }
])
) )
return encryptedNotes return encryptedNotes
} }

View File

@@ -151,7 +151,9 @@ 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).toLowerCase().includes(query.toLowerCase()) const matchContent = removeMdFromText(note.content)
.toLowerCase()
.includes(query.toLowerCase())
return matchTitle || matchContent return matchTitle || matchContent
}) })
} }
@@ -205,7 +207,9 @@ export const notesRelations = computed(() => {
.map((noteRelations, _, notesRelations): NoteRelations => { .map((noteRelations, _, notesRelations): NoteRelations => {
const from = [...notesRelations] const from = [...notesRelations]
.map((noteRelation) => .map((noteRelation) =>
noteRelation.to.filter((toId) => toId === noteRelations.id).map(() => noteRelation.id) noteRelation.to
.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)
@@ -262,7 +266,9 @@ export const getNotes = async () => {
} }
} else if (activeNotesSource.value === 'firebase') { } else if (activeNotesSource.value === 'firebase') {
if (encryptionKey.value === undefined || !user.value || !db.value) return if (encryptionKey.value === undefined || !user.value || !db.value) return
const firebaseNotes = (await getDoc(doc(db.value, 'pages', user.value.uid))).data() as BaseNotes const firebaseNotes = (
await getDoc(doc(db.value, 'pages', user.value.uid))
).data() as BaseNotes
notes = encryptionKey.value notes = encryptionKey.value
? decryptNotes(firebaseNotes, encryptionKey.value) ? decryptNotes(firebaseNotes, encryptionKey.value)
: firebaseNotes || {} : firebaseNotes || {}