skeleton loader
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -25,6 +25,9 @@ declare module '@vue/runtime-core' {
|
||||
SideBar: typeof import('./src/components/SideBar.vue')['default']
|
||||
SideBarMenu: typeof import('./src/components/SideBar/SideBarMenu.vue')['default']
|
||||
SideBarMenuItem: typeof import('./src/components/SideBar/SideBarMenuItem.vue')['default']
|
||||
SkeletonNote: typeof import('./src/components/Skeleton/SkeletonNote.vue')['default']
|
||||
SkeletonSidebarItem: typeof import('./src/components/Skeleton/SkeletonSidebarItem.vue')['default']
|
||||
SkeletonTopBar: typeof import('./src/components/Skeleton/SkeletonTopBar.vue')['default']
|
||||
TopBar: typeof import('./src/components/TopBar.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
22
src/App.vue
22
src/App.vue
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { activeNote, updateNote } from '@/composables/useNotes'
|
||||
import { viewModes, activeViewMode } from '@/composables/useViewMode'
|
||||
import { initialized } from '@/composables/useFirebase'
|
||||
const sideBarCollapsed = ref(false)
|
||||
</script>
|
||||
|
||||
@@ -20,15 +21,18 @@ const sideBarCollapsed = ref(false)
|
||||
class="transition[margin-left] z-10 mt-[50px] w-full border-x-[1px] bg-white px-10 py-6 duration-200 ease-out"
|
||||
:class="sideBarCollapsed ? 'ml-0' : 'ml-sidebar'"
|
||||
>
|
||||
<Note
|
||||
v-if="activeViewMode.name === 'Note' && activeNote"
|
||||
:key="activeNote.id"
|
||||
:note="activeNote"
|
||||
class=""
|
||||
@update="(note) => updateNote(note.id, note)"
|
||||
/>
|
||||
<ListView v-else-if="activeViewMode.name === 'List'" />
|
||||
<Mindmap v-else-if="activeViewMode.name === 'Mindmap'" />
|
||||
<template v-if="initialized">
|
||||
<Note
|
||||
v-if="activeViewMode.name === 'Note' && activeNote"
|
||||
:key="activeNote.id"
|
||||
:note="activeNote"
|
||||
class=""
|
||||
@update="(note) => updateNote(note.id, note)"
|
||||
/>
|
||||
<ListView v-else-if="activeViewMode.name === 'List'" />
|
||||
<Mindmap v-else-if="activeViewMode.name === 'Mindmap'" />
|
||||
</template>
|
||||
<SkeletonNote v-else />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -47,7 +47,7 @@ const handleKeydown = (event: KeyboardEvent) => {
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search for notes"
|
||||
class="h-full w-full rounded border-0 bg-[#355fd3] px-2 text-white outline-none placeholder:text-white focus:bg-white focus:text-black"
|
||||
class="h-full w-full rounded border-0 bg-white/10 px-2 text-white outline-none placeholder:text-white focus:bg-white focus:text-black"
|
||||
@focus="active = true"
|
||||
@mousedown="active = true"
|
||||
@blur="active = false"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { rootNote, notes, setActiveNote } from '@/composables/useNotes'
|
||||
import { initialized } from '@/composables/useFirebase'
|
||||
|
||||
const props = defineProps<{
|
||||
viewModes: ViewMode[]
|
||||
@@ -22,23 +23,28 @@ const emit = defineEmits<{
|
||||
icon="fas fa-fw fa-home"
|
||||
@click="setActiveNote(rootNote?.id)"
|
||||
:title="rootNote?.title"
|
||||
v-if="initialized"
|
||||
>
|
||||
{{ rootNote?.title }}
|
||||
</SideBarMenuItem>
|
||||
<SkeletonSidebarItem v-else />
|
||||
</template>
|
||||
</SideBarMenu>
|
||||
<SideBarMenu>
|
||||
<template #header>View mode</template>
|
||||
<template #items>
|
||||
<SideBarMenuItem
|
||||
v-for="viewMode in props.viewModes"
|
||||
:key="viewMode.name"
|
||||
:icon="viewMode.icon"
|
||||
:active="viewMode.name === activeViewMode.name"
|
||||
@click="emit('setViewMode', viewMode)"
|
||||
>
|
||||
{{ viewMode.name }}
|
||||
</SideBarMenuItem>
|
||||
<template v-if="initialized">
|
||||
<SideBarMenuItem
|
||||
v-for="viewMode in props.viewModes"
|
||||
:key="viewMode.name"
|
||||
:icon="viewMode.icon"
|
||||
:active="viewMode.name === activeViewMode.name"
|
||||
@click="emit('setViewMode', viewMode)"
|
||||
>
|
||||
{{ viewMode.name }}
|
||||
</SideBarMenuItem>
|
||||
</template>
|
||||
<SkeletonSidebarItem :n="3" v-else />
|
||||
</template>
|
||||
</SideBarMenu>
|
||||
<SideBarMenu>
|
||||
@@ -47,15 +53,18 @@ const emit = defineEmits<{
|
||||
Recent notes
|
||||
</template>
|
||||
<template #items>
|
||||
<SideBarMenuItem
|
||||
v-for="note in notes.slice(-10)"
|
||||
:key="note.id"
|
||||
icon="far fa-file-alt fa-fw"
|
||||
@click="setActiveNote(note.id)"
|
||||
:title="rootNote?.title"
|
||||
>
|
||||
{{ note.title }}
|
||||
</SideBarMenuItem>
|
||||
<template v-if="initialized">
|
||||
<SideBarMenuItem
|
||||
v-for="note in notes.slice(-10)"
|
||||
:key="note.id"
|
||||
icon="far fa-file-alt fa-fw"
|
||||
@click="setActiveNote(note.id)"
|
||||
:title="rootNote?.title"
|
||||
>
|
||||
{{ note.title }}
|
||||
</SideBarMenuItem>
|
||||
</template>
|
||||
<SkeletonSidebarItem v-else :n="5" />
|
||||
</template>
|
||||
</SideBarMenu>
|
||||
</div>
|
||||
|
||||
30
src/components/Skeleton/SkeletonNote.vue
Normal file
30
src/components/Skeleton/SkeletonNote.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="flex h-full w-full animate-pulse flex-col">
|
||||
<div class="mb-2 flex items-center space-x-4 py-1">
|
||||
<div class="h-[2.25rem] w-[40px] rounded bg-secondary"></div>
|
||||
<div class="h-[2.25rem] flex-grow rounded bg-secondary"></div>
|
||||
</div>
|
||||
<div class="flex flex-grow flex-col gap-2">
|
||||
<div class="h-[1.25rem] my-1 w-full rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] my-1 w-full rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] my-1 w-5/12 rounded bg-secondary"></div>
|
||||
<div class="mt-2 h-[2rem] w-full rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] my-1 w-full rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] my-1 w-4/6 rounded bg-secondary"></div>
|
||||
<div class="ml-8 h-[1.25rem] my-1 w-5/12 rounded bg-secondary"></div>
|
||||
<div class="ml-8 h-[1.25rem] my-1 w-7/12 rounded bg-secondary"></div>
|
||||
<div class="ml-8 h-[1.25rem] my-1 w-6/12 rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] my-1 w-full rounded bg-secondary"></div>
|
||||
</div>
|
||||
<hr class="my-3" />
|
||||
<div class="flex gap-2">
|
||||
<div class="h-[1.25rem] w-2/12 rounded bg-secondary"></div>
|
||||
<div class="h-[1.25rem] w-4/12 rounded bg-secondary ml-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.bg-secondary {
|
||||
@apply bg-secondary/25;
|
||||
}
|
||||
</style>
|
||||
18
src/components/Skeleton/SkeletonSidebarItem.vue
Normal file
18
src/components/Skeleton/SkeletonSidebarItem.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
n?: number
|
||||
}>(),
|
||||
{ n: 1 }
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex w-full animate-pulse flex-col">
|
||||
<div class="h-[1.35rem] w-full rounded bg-secondary mt-1" v-for="i in props.n" :key="i"></div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.bg-secondary {
|
||||
@apply bg-secondary/25;
|
||||
}
|
||||
</style>
|
||||
18
src/components/Skeleton/SkeletonTopBar.vue
Normal file
18
src/components/Skeleton/SkeletonTopBar.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div class="flex h-full w-full animate-pulse">
|
||||
<div class="h-full w-full 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>
|
||||
@@ -39,37 +39,39 @@ const authModalInitialStateOpen = ref(
|
||||
/>
|
||||
</div>
|
||||
<div class="flex h-full flex-grow flex-row items-center gap-2 pl-5 pr-3">
|
||||
<SearchBar />
|
||||
<button
|
||||
class="btn-outline btn-sm btn py-1 text-white"
|
||||
@click="addNote('Untitled new note', '', true)"
|
||||
>
|
||||
<i class="fas fa-plus-circle text-[1.1rem]" />
|
||||
</button>
|
||||
<Modal v-if="initialized && !user" :open="authModalInitialStateOpen">
|
||||
<template #activator="{ open }">
|
||||
<button class="btn-outline btn-sm btn py-1 text-white" @click="open">Sign in</button>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<Auth @signedIn="close" />
|
||||
</template>
|
||||
<template #actions="{ close }">
|
||||
<button class="btn-sm btn" @click="close">Close</button>
|
||||
</template>
|
||||
</Modal>
|
||||
<Modal v-else-if="user">
|
||||
<template #activator="{ open }">
|
||||
<button class="btn-outline btn-sm btn py-1 text-white" @click="open">
|
||||
{{ user.displayName || user.email }}
|
||||
</button>
|
||||
</template>
|
||||
<template #default>Are you sure want to signout?</template>
|
||||
<template #actions="{ close }">
|
||||
<button class="btn-sm btn" @click="close">Close</button>
|
||||
<button class="btn-primary btn-sm btn" @click="signOut(close)">Sign out</button>
|
||||
</template>
|
||||
</Modal>
|
||||
<template v-else>Loading...</template>
|
||||
<template v-if="initialized">
|
||||
<SearchBar />
|
||||
<button
|
||||
class="btn-outline btn-sm btn py-1 text-white"
|
||||
@click="addNote('Untitled new note', '', true)"
|
||||
>
|
||||
<i class="fas fa-plus-circle text-[1.1rem]" />
|
||||
</button>
|
||||
<Modal v-if="initialized && !user" :open="authModalInitialStateOpen">
|
||||
<template #activator="{ open }">
|
||||
<button class="btn-outline btn-sm btn py-1 text-white" @click="open">Sign in</button>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<Auth @signedIn="close" />
|
||||
</template>
|
||||
<template #actions="{ close }">
|
||||
<button class="btn-sm btn" @click="close">Close</button>
|
||||
</template>
|
||||
</Modal>
|
||||
<Modal v-else-if="user">
|
||||
<template #activator="{ open }">
|
||||
<button class="btn-outline btn-sm btn py-1 text-white" @click="open">
|
||||
{{ user.displayName || user.email }}
|
||||
</button>
|
||||
</template>
|
||||
<template #default>Are you sure want to signout?</template>
|
||||
<template #actions="{ close }">
|
||||
<button class="btn-sm btn" @click="close">Close</button>
|
||||
<button class="btn-primary btn-sm btn" @click="signOut(close)">Sign out</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
<SkeletonTopBar v-else />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user