Skip to content

Commit 06f3b2b

Browse files
committed
feat: added skeleton loading
1 parent bf3b930 commit 06f3b2b

File tree

7 files changed

+94
-21
lines changed

7 files changed

+94
-21
lines changed

src/pages/index.vue

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
<script>
2-
</script >
2+
</script>
33

44
<template>
5-
<div>
6-
<h1>Homepage</h1>
5+
<div class="text-center bg-white rounded-lg p-8 shadow-lg grid gap-8">
6+
<h1 class="text-3xl font-bold">WANT TO TAKE A QUIZ?</h1>
7+
<div>
8+
<p>This is an app for quiz enthusiasts, where you can:</p>
9+
<ul>
10+
<li>View a list of quizzes</li>
11+
<li>View a quiz</li>
12+
<li>Take a quiz</li>
13+
<li>View the results of a quiz</li>
14+
<li>Create your own quiz</li>
15+
</ul>
16+
<p>You can also check your standing in the leaderboards!!</p>
17+
</div>
718
</div>
819
</template>

src/pages/leaderboard/index.vue

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,33 @@ const loading = ref(true);
99
1010
onMounted(async () => {
1111
await userStore.fetchUsers();
12+
await delay(500);
1213
loading.value = false;
1314
});
15+
16+
function delay(ms: number) {
17+
return new Promise(resolve => setTimeout(resolve, ms));
18+
}
1419
</script>
1520

1621
<template>
1722
<section class="flex flex-col gap-8 text-center w-full">
1823
<div class="flex items-center gap-2 mx-auto">
1924
<span>----</span>
20-
<FontAwesomeIcon :icon="faStar"/>
25+
<FontAwesomeIcon :icon="faStar" />
2126
<h1 class="font-bold text-3xl">LEADERBOARDS</h1>
22-
<FontAwesomeIcon :icon="faStar"/>
27+
<FontAwesomeIcon :icon="faStar" />
2328
<span>----</span>
2429
</div>
25-
<div v-if="loading">
26-
<p>Loading...</p>
30+
<div v-if="loading" class="w-[30%] mx-auto">
31+
<div class="bg-white rounded-lg shadow-md p-4 animate-pulse">
32+
<!-- Header -->
33+
<div class="w-2/3 h-4 bg-gray-300 rounded mb-2"></div>
34+
<!-- Body -->
35+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
36+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
37+
<div class="w-1/2 h-8 bg-gray-300 rounded"></div>
38+
</div>
2739
</div>
2840
<div v-else>
2941
<ul class="flex flex-col w-[30%] mx-auto">

src/pages/profile/[username].vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,34 @@ import { useIndividualUserStore } from '@/stores/individualUserStore';
33
import { onMounted, ref } from 'vue';
44
const individualUserStore = useIndividualUserStore();
55
const loading = ref(true);
6-
onMounted(() => {
6+
onMounted(async () => {
77
individualUserStore.fetchIndividualUser();
8+
await delay(700)
89
loading.value = false;
10+
function delay(ms: number) {
11+
return new Promise(resolve => setTimeout(resolve, ms));
12+
}
913
})
1014
</script>
1115

1216
<template>
13-
<div class="text-center grid gap-8">
17+
<div class="text-center grid gap-8 w-full">
1418
<h1 class="text-3xl">WELCOME!</h1>
15-
<p v-if="individualUserStore.loading">Loading...</p>
16-
<div v-else>
19+
<div v-if="individualUserStore.loading" class="w-[30%] mx-auto">
20+
<div class="bg-white rounded-lg shadow-md p-4 animate-pulse">
21+
<!-- Header -->
22+
<div class="w-2/3 h-4 bg-gray-300 rounded mb-2"></div>
23+
<!-- Body -->
24+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
25+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
26+
<div class="w-1/2 h-8 bg-gray-300 rounded"></div>
27+
</div>
28+
</div>
29+
<div v-else class="w-[30%] mx-auto">
1730
<p>Username: <strong>{{ individualUserStore.user?.username }}</strong></p>
1831
<p>Email Address: {{ individualUserStore.user?.email_address }}</p>
1932
</div>
20-
<div v-if="individualUserStore.quizzes.length" class="grid gap-2">
33+
<div v-if="individualUserStore.quizzes.length" class="grid gap-2 w-[30%] mx-auto">
2134
<h2>Quizzes Created:</h2>
2235
<ul>
2336
<li v-for="quiz in individualUserStore.quizzes" :key="quiz.quiz_id" class="border py-2 px-8">

src/pages/quiz/index.vue

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ const scrollToTop = () => window.scrollTo(0, 0);
88
99
onMounted(async () => {
1010
await quizStore.fetchQuiz();
11+
await delay(500)
1112
loading.value = false;
1213
scrollToTop();
14+
15+
function delay(ms: number) {
16+
return new Promise(resolve => setTimeout(resolve, ms));
17+
}
1318
});
1419
</script>
1520

@@ -23,8 +28,15 @@ onMounted(async () => {
2328
<div>
2429
<h1 class="font-bold text-3xl">QUIZZES</h1>
2530
</div>
26-
<div v-if="loading">
27-
<p>Loading...</p>
31+
<div v-if="loading" class="w-[30%] mx-auto">
32+
<div class="bg-white rounded-lg shadow-md p-4 animate-pulse">
33+
<!-- Header -->
34+
<div class="w-2/3 h-4 bg-gray-300 rounded mb-2"></div>
35+
<!-- Body -->
36+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
37+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
38+
<div class="w-1/2 h-8 bg-gray-300 rounded"></div>
39+
</div>
2840
</div>
2941
<div v-else>
3042
<ul class="flex flex-col w-[30%] mx-auto">

src/pages/user/create/index.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const email = ref("");
1010
const user = useAuthStore();
1111
1212
const createUser = async () => {
13+
1314
if (!username.value || !email.value) {
1415
window.alert('Username and email are required');
1516
return;

src/pages/user/index.vue

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import { supabase } from '@/lib/supabaseClient';
33
import { useRouter } from 'vue-router';
44
import { useLoggedInUserStore } from '@/stores/loggedInUserStore';
5-
import { onMounted} from 'vue';
5+
import { onMounted, ref } from 'vue';
66
77
const router = useRouter();
88
const loggedInUserStore = useLoggedInUserStore();
9+
const loading = ref(true);
910
1011
const signOut = async () => {
1112
console.log('Signing out');
@@ -19,19 +20,42 @@ const signOut = async () => {
1920
2021
onMounted(async () => {
2122
await loggedInUserStore.fetchLoggedInUser();
23+
await delay(500)
2224
if (!loggedInUserStore.user) {
2325
router.push('/user/create');
2426
}
27+
loading.value = false;
2528
})
2629
30+
31+
function delay(ms: number) {
32+
return new Promise(resolve => setTimeout(resolve, ms));
33+
}
2734
</script>
2835

2936
<template>
30-
<section>
31-
<div class="grid gap-4">
32-
<h1>Welcome, {{ loggedInUserStore.user?.username }}</h1>
37+
<section class="w-full">
38+
39+
<div v-if="loading" class="w-[30%] mx-auto">
40+
<div class="bg-white rounded-lg shadow-md p-8 animate-pulse grid gap-4">
41+
<!-- Header -->
42+
<div class="flex gap-4 items-center">
43+
<div class="w-[10%] h-10 bg-gray-300 rounded mb-2 rounded-full"></div>
44+
<div class="w-2/3 h-4 bg-gray-300 rounded mb-2"></div>
45+
</div>
46+
<!-- Body -->
47+
<div>
48+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
49+
<div class="w-full h-8 bg-gray-300 rounded mb-2"></div>
50+
<div class="w-1/2 h-8 bg-gray-300 rounded"></div>
51+
</div>
52+
</div>
53+
</div>
54+
55+
<div v-if="!loading" class="grid gap-6 w-[25%] mx-auto text-center">
56+
<h1 class="text-2xl">Welcome, <strong>{{ loggedInUserStore.user?.username }}</strong></h1>
3357
<button type="button" @click="signOut"
34-
class="w-full bg-black text-white py-[9px] border-[1px] rounded-lg hover:bg-white hover:text-black border-white hover:border-black cursor-pointer transition-all duration-200 text-sm">Log
58+
class="w-[50%] bg-black text-white py-[9px] border-[1px] rounded-lg hover:bg-white hover:text-black border-white hover:border-black cursor-pointer transition-all duration-200 text-sm mx-auto">Log
3559
out</button>
3660
</div>
3761
</section>

src/router/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { supabase } from '@/lib/supabaseClient'
77
const guestRoutes = ['/auth/signIn', '/auth/signUp']
88

99
// Define routes that require authentication (use regex for dynamic paths)
10-
const protectedRoutes = ['/quiz/take/:id', '/user', '/edit']
10+
const protectedRoutes = ['/quiz/take/:id', '/user', '/edit', '/user/create']
1111

1212
const router = createRouter({
1313
history: createWebHistory(import.meta.env.BASE_URL),
@@ -26,7 +26,7 @@ router.beforeEach(async (to, from, next) => {
2626
next('/') // Redirect logged-in users away from auth pages
2727
}
2828
// Check if the route requires authentication
29-
else if (to.matched.some(route => protectedRoutes.some(p => to.path.startsWith(p.replace(':id', '')))) && !authStore.user) {
29+
else if (to.matched.some(() => protectedRoutes.some(p => to.path.startsWith(p.replace(':id', '')))) && !authStore.user) {
3030
next('/auth/signIn') // Redirect guests to sign-in
3131
}
3232
else {

0 commit comments

Comments
 (0)