update search results
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -22,6 +22,7 @@ declare module '@vue/runtime-core' {
|
|||||||
NoteToolbar: typeof import('./src/components/Note/NoteToolbar.vue')['default']
|
NoteToolbar: typeof import('./src/components/Note/NoteToolbar.vue')['default']
|
||||||
SearchBar: typeof import('./src/components/Search/SearchBar.vue')['default']
|
SearchBar: typeof import('./src/components/Search/SearchBar.vue')['default']
|
||||||
SearchResult: typeof import('./src/components/Search/SearchResult.vue')['default']
|
SearchResult: typeof import('./src/components/Search/SearchResult.vue')['default']
|
||||||
|
Settings: typeof import('./src/components/TopBar/Settings.vue')['default']
|
||||||
SideBar: typeof import('./src/components/SideBar.vue')['default']
|
SideBar: typeof import('./src/components/SideBar.vue')['default']
|
||||||
SideBarMenu: typeof import('./src/components/SideBar/SideBarMenu.vue')['default']
|
SideBarMenu: typeof import('./src/components/SideBar/SideBarMenu.vue')['default']
|
||||||
SideBarMenuItem: typeof import('./src/components/SideBar/SideBarMenuItem.vue')['default']
|
SideBarMenuItem: typeof import('./src/components/SideBar/SideBarMenuItem.vue')['default']
|
||||||
|
|||||||
64
package-lock.json
generated
64
package-lock.json
generated
@@ -36,7 +36,8 @@
|
|||||||
"marked": "^4.3.0",
|
"marked": "^4.3.0",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
"turndown": "^7.1.2",
|
"turndown": "^7.1.2",
|
||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4",
|
||||||
|
"vue-virtual-scroller": "^2.0.0-beta.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.2.0",
|
"@rushstack/eslint-patch": "^1.2.0",
|
||||||
@@ -8556,6 +8557,11 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
@@ -12078,6 +12084,22 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-observe-visibility": {
|
||||||
|
"version": "2.0.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vue-resize": {
|
||||||
|
"version": "2.0.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-template-compiler": {
|
"node_modules/vue-template-compiler": {
|
||||||
"version": "2.7.14",
|
"version": "2.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
||||||
@@ -12105,6 +12127,19 @@
|
|||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-virtual-scroller": {
|
||||||
|
"version": "2.0.0-beta.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.8.tgz",
|
||||||
|
"integrity": "sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"mitt": "^2.1.0",
|
||||||
|
"vue-observe-visibility": "^2.0.0-alpha.1",
|
||||||
|
"vue-resize": "^2.0.0-alpha.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/wcwidth": {
|
"node_modules/wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
@@ -18921,6 +18956,11 @@
|
|||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mitt": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
|
||||||
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
@@ -21495,6 +21535,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-observe-visibility": {
|
||||||
|
"version": "2.0.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"vue-resize": {
|
||||||
|
"version": "2.0.0-alpha.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||||
|
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"vue-template-compiler": {
|
"vue-template-compiler": {
|
||||||
"version": "2.7.14",
|
"version": "2.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
||||||
@@ -21516,6 +21568,16 @@
|
|||||||
"semver": "^7.3.8"
|
"semver": "^7.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-virtual-scroller": {
|
||||||
|
"version": "2.0.0-beta.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.8.tgz",
|
||||||
|
"integrity": "sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==",
|
||||||
|
"requires": {
|
||||||
|
"mitt": "^2.1.0",
|
||||||
|
"vue-observe-visibility": "^2.0.0-alpha.1",
|
||||||
|
"vue-resize": "^2.0.0-alpha.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"wcwidth": {
|
"wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
"marked": "^4.3.0",
|
"marked": "^4.3.0",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
"turndown": "^7.1.2",
|
"turndown": "^7.1.2",
|
||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4",
|
||||||
|
"vue-virtual-scroller": "^2.0.0-beta.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.2.0",
|
"@rushstack/eslint-patch": "^1.2.0",
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ const emit = defineEmits<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const results = computed<Note[]>(() => {
|
const results = computed<Note[]>(() => {
|
||||||
return (
|
return (props.autocompleteText ? findNotesByByTitle(props.autocompleteText) : notes.value)
|
||||||
props.autocompleteText ? findNotesByByTitle(props.autocompleteText) : notes.value
|
.filter((note) => note.id !== activeNote.value?.id)
|
||||||
).filter((note) => note.id !== activeNote.value?.id).slice(10)
|
.slice(0, 10)
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeResult = ref<Note>()
|
const activeResult = ref<Note>()
|
||||||
@@ -32,15 +32,13 @@ const handleKeypress = (event: { [key: string]: number }) => {
|
|||||||
const keyCode = event.keyCode
|
const keyCode = event.keyCode
|
||||||
const keyCodes = {
|
const keyCodes = {
|
||||||
cycle: [38, 40],
|
cycle: [38, 40],
|
||||||
confirm: [13],
|
confirm: [13]
|
||||||
}
|
}
|
||||||
if (keyCodes.cycle.includes(keyCode)) {
|
if (keyCodes.cycle.includes(keyCode)) {
|
||||||
const direction = keyCode === 38 ? -1 : 1
|
const direction = keyCode === 38 ? -1 : 1
|
||||||
changeActiveResult(direction)
|
changeActiveResult(direction)
|
||||||
} else if (keyCodes.confirm.includes(keyCode)) {
|
} else if (keyCodes.confirm.includes(keyCode)) {
|
||||||
const contextedLink = activeResult.value
|
const contextedLink = activeResult.value ? activeResult.value.title : props.autocompleteText
|
||||||
? activeResult.value.title
|
|
||||||
: props.autocompleteText
|
|
||||||
emit('createLink', contextedLink)
|
emit('createLink', contextedLink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ const createLink = (link: string) => {
|
|||||||
:autocomplete-text="autocompleteText"
|
:autocomplete-text="autocompleteText"
|
||||||
:style="autocompleteStyle"
|
:style="autocompleteStyle"
|
||||||
@create-link="createLink"
|
@create-link="createLink"
|
||||||
class="absolute w-[250px]"
|
class="absolute w-[300px]"
|
||||||
:class="autocompleteReverse && 'flex-col-reverse'"
|
:class="autocompleteReverse && 'flex-col-reverse'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { notes, findNotes, setActiveNote } from '@/composables/useNotes'
|
import { notes, findNotes, setActiveNote } from '@/composables/useNotes'
|
||||||
|
import SearchResult from '@/components/Search/SearchResult.vue'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
active: [active: boolean]
|
active: [active: boolean]
|
||||||
@@ -19,7 +20,8 @@ const results = computed<Note[]>(() => {
|
|||||||
return query.value ? findNotes(query.value) : notes.value
|
return query.value ? findNotes(query.value) : notes.value
|
||||||
})
|
})
|
||||||
|
|
||||||
const goToNote = (note: Note) => {
|
const goToNote = (note: Note, element?: HTMLElement) => {
|
||||||
|
console.log(element)
|
||||||
setActiveNote(note.id)
|
setActiveNote(note.id)
|
||||||
active.value = false
|
active.value = false
|
||||||
if (queryElem.value) queryElem.value.blur()
|
if (queryElem.value) queryElem.value.blur()
|
||||||
@@ -40,12 +42,16 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||||||
if (index + 1 > results.value.length) index = index - results.value.length
|
if (index + 1 > results.value.length) index = index - results.value.length
|
||||||
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
|
||||||
|
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) {
|
||||||
queryElem.value.blur()
|
queryElem.value.blur()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resultsRefs = ref<InstanceType<typeof SearchResult>[]>([])
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div id="search-container" class="relative h-full flex-grow">
|
<div id="search-container" class="relative h-full flex-grow">
|
||||||
@@ -62,16 +68,19 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||||||
/>
|
/>
|
||||||
<div class="z-1000 dropdown absolute left-0 right-0 top-[100%]" v-if="active">
|
<div class="z-1000 dropdown absolute left-0 right-0 top-[100%]" v-if="active">
|
||||||
<ul tabindex="0" class="menu mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow">
|
<ul tabindex="0" class="menu mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow">
|
||||||
|
<div class="max-h-[320px] w-full overflow-y-scroll">
|
||||||
<template v-if="results.length > 0">
|
<template v-if="results.length > 0">
|
||||||
<SearchResult
|
<SearchResult
|
||||||
v-for="result in results"
|
v-for="result in results"
|
||||||
:key="result.id"
|
:key="result.id"
|
||||||
:result="result"
|
:result="result"
|
||||||
:active-result="activeResult"
|
:active-result="activeResult"
|
||||||
@go-to-note="() => goToNote(result)"
|
@go-to-note="(element) => goToNote(result, element)"
|
||||||
|
ref="resultsRefs"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<li v-else><a>No notes found</a></li>
|
<li v-else><a>No notes found</a></li>
|
||||||
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,30 +8,27 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
goToNote: []
|
goToNote: [element: HTMLElement | null]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
console.log(props.activeResult)
|
const element = ref<HTMLElement | null>(null)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<li class="flex flex-row">
|
<li class="flex w-full flex-row" ref="element">
|
||||||
<a
|
<a
|
||||||
class="flex-grow items-center px-2 py-1"
|
class="items-center px-2 py-1 w-full"
|
||||||
@click.stop.prevent="() => emit('goToNote')"
|
@click.stop.prevent="() => emit('goToNote', element)"
|
||||||
@mousedown.prevent
|
@mousedown.prevent
|
||||||
:class="{
|
:class="{
|
||||||
disabled: activeNote?.id === result.id,
|
disabled: activeNote?.id === result.id,
|
||||||
active: props.activeResult?.id === result.id,
|
active: props.activeResult?.id === result.id
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span
|
<span class="badge-ghost badge badge-sm mr-0.5" v-if="activeNote?.id === result.id">
|
||||||
class="badge-ghost badge badge-sm mr-0.5"
|
|
||||||
v-if="activeNote?.id === result.id"
|
|
||||||
>
|
|
||||||
current
|
current
|
||||||
</span>
|
</span>
|
||||||
<span class="flex-grow">{{ result.title }}</span>
|
<span class="flex-grow overflow-hidden whitespace-nowrap">{{ result.title }}</span>
|
||||||
<span>{{ formatDate(result.modified) }}</span>
|
<span class="whitespace-nowrap">{{ formatDate(result.modified) }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex h-full w-full animate-pulse">
|
<div class="flex h-full w-full animate-pulse space-x-2">
|
||||||
<div class="h-full w-full rounded bg-white/10"></div>
|
<div class="h-full w-full rounded bg-white/10" />
|
||||||
|
<div class="h-full w-[44px] rounded bg-white/10" />
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="flex animate-pulse space-x-4 max-w-sm">
|
|
||||||
<div class="h-10 w-10 rounded-full bg-primary"></div>
|
|
||||||
<div class="flex-1 space-y-6 py-1">
|
|
||||||
<div class="h-2 rounded bg-primary"></div>
|
|
||||||
<div class="space-y-3">
|
|
||||||
<div class="grid grid-cols-3 gap-4">
|
|
||||||
<div class="col-span-2 h-2 rounded bg-primary"></div>
|
|
||||||
<div class="col-span-1 h-2 rounded bg-primary"></div>
|
|
||||||
</div>
|
|
||||||
<div class="h-2 rounded bg-primary"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { addNote, setActiveNote, rootNote } from '@/composables/useNotes'
|
import { addNote, setActiveNote, rootNote } from '@/composables/useNotes'
|
||||||
import { user, signOut as firebaseSignOut } from '@/composables/useFirebase'
|
import { user } from '@/composables/useFirebase'
|
||||||
import { initialized } from '@/composables/useFirebase'
|
import { initialized } from '@/composables/useFirebase'
|
||||||
|
|
||||||
const loading = inject<boolean>('loading')
|
const loading = inject<boolean>('loading')
|
||||||
@@ -15,11 +15,6 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const searchActive = ref<boolean>(false)
|
const searchActive = ref<boolean>(false)
|
||||||
|
|
||||||
const signOut = async (close: () => Promise<boolean>) => {
|
|
||||||
await firebaseSignOut()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
|
|
||||||
const authUI: any = inject('firebaseAuthUI')
|
const authUI: any = inject('firebaseAuthUI')
|
||||||
const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
||||||
</script>
|
</script>
|
||||||
@@ -69,37 +64,7 @@ const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
|||||||
<button class="btn-sm btn" @click="close">Close</button>
|
<button class="btn-sm btn" @click="close">Close</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
<template v-else-if="user">
|
<Settings v-else-if="user" />
|
||||||
<div class="search-active-hide dropdown-end dropdown">
|
|
||||||
<label tabindex="0" class="btn-outline btn-sm btn py-1 text-white">
|
|
||||||
<i class="fa-fw fa-solid fa-user-gear" />
|
|
||||||
</label>
|
|
||||||
<ul
|
|
||||||
tabindex="0"
|
|
||||||
class="dropdown-content menu rounded-box menu-compact mt-1 w-52 bg-base-100 p-2 text-base-content shadow"
|
|
||||||
>
|
|
||||||
<Modal>
|
|
||||||
<template #activator="{ open }">
|
|
||||||
<li @click="open" class="text-base">
|
|
||||||
<a>
|
|
||||||
<i class="fa-fw fa-solid fa-right-from-bracket" />
|
|
||||||
Sign out
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
<template #title>Sign out</template>
|
|
||||||
<template #default>
|
|
||||||
<p>Are you sure want to signout?</p>
|
|
||||||
<p>Your synchronized notes can't be accessed until you sign-in again.</p>
|
|
||||||
</template>
|
|
||||||
<template #actions="{ close }">
|
|
||||||
<button class="btn-sm btn" @click="close">Cancel</button>
|
|
||||||
<button class="btn-primary btn-sm btn" @click="signOut(close)">Sign out</button>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
<SkeletonTopBar v-else />
|
<SkeletonTopBar v-else />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
68
src/components/TopBar/Settings.vue
Normal file
68
src/components/TopBar/Settings.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { activeNotesSource, notesSources } from '@/composables/useNotes'
|
||||||
|
import { signOut as firebaseSignOut } from '@/composables/useFirebase'
|
||||||
|
const sourceLabels: { [source: string]: string } = {
|
||||||
|
local: 'Switch to local notes',
|
||||||
|
firebase: 'Switch to cloud notes'
|
||||||
|
}
|
||||||
|
const availableNoteSources = computed(() =>
|
||||||
|
Object.entries(notesSources.value)
|
||||||
|
.filter(([source, enabled]) => enabled && source !== activeNotesSource.value)
|
||||||
|
.map(([source]) => ({
|
||||||
|
source: source as keyof typeof notesSources.value,
|
||||||
|
label: sourceLabels[source]
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
const signOut = async (close: () => Promise<boolean>) => {
|
||||||
|
await firebaseSignOut()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (fn: (...args: any[]) => any) => {
|
||||||
|
;(document.activeElement as HTMLElement)?.blur()
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="search-active-hide dropdown-end dropdown">
|
||||||
|
<label tabindex="0" class="btn-outline btn-sm btn py-1 text-white">
|
||||||
|
<i class="fa-fw fa-solid fa-user-gear" />
|
||||||
|
</label>
|
||||||
|
<ul
|
||||||
|
tabindex="0"
|
||||||
|
class="dropdown-content menu rounded-box menu-compact mt-1 w-52 bg-base-100 p-2 text-base-content shadow"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="text-base"
|
||||||
|
v-for="{ source, label } in availableNoteSources"
|
||||||
|
:key="source"
|
||||||
|
@click="handleClick(() => (activeNotesSource = source))"
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
<i class="fa-fw fa-solid fa-database" />
|
||||||
|
{{ label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<Modal>
|
||||||
|
<template #activator="{ open }">
|
||||||
|
<li @click="open" class="text-base">
|
||||||
|
<a>
|
||||||
|
<i class="fa-fw fa-solid fa-right-from-bracket" />
|
||||||
|
Sign out
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
<template #title>Sign out</template>
|
||||||
|
<template #default>
|
||||||
|
<p>Are you sure want to signout?</p>
|
||||||
|
<p>Your synchronized notes can't be accessed until you sign-in again.</p>
|
||||||
|
</template>
|
||||||
|
<template #actions="{ close }">
|
||||||
|
<button class="btn-sm btn" @click="close">Cancel</button>
|
||||||
|
<button class="btn-primary btn-sm btn" @click="signOut(close)">Sign out</button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user