Skip to content

Commit faea534

Browse files
feat(my): dashboard page (#262)
Co-authored-by: Dropheart <[email protected]>
1 parent f462760 commit faea534

15 files changed

+488
-62
lines changed

app/components/Dashboard/Button.vue

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
type Props = {
3+
background: string;
4+
};
5+
defineProps<Props>();
6+
7+
const opened = defineModel<boolean>();
8+
</script>
9+
10+
<template>
11+
<div
12+
class="blue-ic flex cursor-pointer items-center justify-between px-4 py-3"
13+
:class="opened ? 'border border-white bg-transparent' : background"
14+
@click="opened = !opened">
15+
<p class="max-w-min text-3xl font-bold"><slot></slot></p>
16+
<p
17+
class="font-ichack text-3xl transition-transform"
18+
:class="{ 'rotate-90': opened }">
19+
>
20+
</p>
21+
</div>
22+
</template>
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<script setup lang="ts">
2+
const hackspacePoints = ref({
3+
jcr: 0,
4+
scr: 0,
5+
qtr: 0
6+
});
7+
8+
const scaledNormalisation = computed(() => {
9+
const average =
10+
(hackspacePoints.value.jcr +
11+
hackspacePoints.value.scr +
12+
hackspacePoints.value.qtr) /
13+
3;
14+
15+
if (average === 0) {
16+
return {
17+
jcr: 0.5,
18+
scr: 0.5,
19+
qtr: 0.5
20+
};
21+
}
22+
23+
const normalised = {
24+
jcr: 0.5 + (hackspacePoints.value.jcr - average) / average,
25+
scr: 0.5 + (hackspacePoints.value.scr - average) / average,
26+
qtr: 0.5 + (hackspacePoints.value.qtr - average) / average
27+
};
28+
29+
const adjusted = {
30+
jcr: Math.max(0.1, Math.min(0.9, normalised.jcr)),
31+
scr: Math.max(0.1, Math.min(0.9, normalised.scr)),
32+
qtr: Math.max(0.1, Math.min(0.9, normalised.qtr))
33+
};
34+
return adjusted;
35+
});
36+
37+
onMounted(() => {
38+
// TODO actually make the request
39+
setTimeout(() => {
40+
hackspacePoints.value = {
41+
jcr: 0,
42+
scr: 0,
43+
qtr: 0
44+
};
45+
}, 200);
46+
});
47+
</script>
48+
49+
<template>
50+
<div class="flex gap-x-10 max-lg:flex-col lg:max-h-[512px]">
51+
<div
52+
class="flex gap-12 max-lg:aspect-[3/4] max-lg:max-h-[256px] lg:min-h-[256px] lg:w-2/3">
53+
<div
54+
class="bar bg-red-ic"
55+
:style="`transform: scaleY(${scaledNormalisation.jcr});`">
56+
<img
57+
src="@ui25/assets/jcr_white.svg"
58+
:style="`transform: scaleY(${1 / scaledNormalisation.jcr}) translateX(-50%)`" />
59+
60+
<div class="relative flex h-full w-full flex-col overflow-hidden">
61+
<p
62+
class="z-10 self-center font-semibold"
63+
:style="`transform: scaleY(${1 / scaledNormalisation.jcr})`">
64+
{{ hackspacePoints.jcr }} Pts
65+
</p>
66+
</div>
67+
</div>
68+
<div
69+
class="bar bg-yellow-ic"
70+
:style="`transform: scaleY(${scaledNormalisation.scr});`">
71+
<img
72+
src="@ui25/assets/scr_white.svg"
73+
:style="`transform: scaleY(${1 / scaledNormalisation.scr}) translateX(-50%)`" />
74+
75+
<div class="relative flex h-full w-full flex-col overflow-hidden">
76+
<p
77+
class="z-10 self-center font-semibold"
78+
:style="`transform: scaleY(${1 / scaledNormalisation.scr})`">
79+
{{ hackspacePoints.scr }} Pts
80+
</p>
81+
</div>
82+
</div>
83+
<div
84+
class="bar bg-blue-ic"
85+
:style="`transform: scaleY(${scaledNormalisation.qtr});`">
86+
<img
87+
src="@ui25/assets/qtr_white.svg"
88+
:style="`transform: scaleY(${1 / scaledNormalisation.qtr}) translateX(-50%)`" />
89+
90+
<div class="relative flex h-full w-full flex-col overflow-hidden">
91+
<p
92+
class="z-10 self-center font-semibold"
93+
:style="`transform: scaleY(${1 / scaledNormalisation.qtr})`">
94+
{{ hackspacePoints.qtr }} Pts
95+
</p>
96+
</div>
97+
</div>
98+
</div>
99+
100+
<div class="mt-8 w-full border border-white px-4 py-3 lg:max-w-[25vw]">
101+
<div class="flex justify-between">
102+
<h3 class="text-2xl font-bold">Challenges</h3>
103+
<img src="@ui25/assets/crown.svg" alt="Hackspace Scores" />
104+
</div>
105+
106+
<div class="mt-5 flex flex-col gap-2">
107+
<!-- Make v-for from challenges!! -->
108+
<div
109+
class="flex items-center justify-between border border-white px-3 py-2">
110+
<p class="text-xl font-semibold">
111+
Stay tuned to see challenge winners!
112+
</p>
113+
<!-- <img src="@ui25/assets/qtr_white.svg" alt="" class="size-10" /> -->
114+
</div>
115+
</div>
116+
</div>
117+
</div>
118+
</template>
119+
120+
<style scoped>
121+
.bar {
122+
@apply relative w-full origin-bottom transition-transform duration-500;
123+
}
124+
125+
.bar img {
126+
@apply absolute -top-12 left-1/2 size-8 origin-bottom transition-transform duration-500;
127+
}
128+
129+
.bar p {
130+
@apply origin-top transition-transform duration-500;
131+
}
132+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<div
3+
class="flex cursor-pointer items-center justify-center gap-8 bg-white p-4">
4+
<img :src="logo" :alt="room" class="h-8" />
5+
<p class="font-bold text-black">{{ room }}</p>
6+
</div>
7+
</template>
8+
9+
<script setup lang="ts">
10+
type Props = {
11+
room: string;
12+
logo: string;
13+
};
14+
defineProps<Props>();
15+
</script>

app/components/Dashboard/Schedule.vue

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script setup lang="ts">
2+
import { format } from 'date-fns';
3+
import type { Event as ICEvent } from '#shared/types';
4+
5+
type Prop = {
6+
events: ICEvent[];
7+
};
8+
defineProps<Prop>();
9+
</script>
10+
11+
<template>
12+
<div class="inline-flex gap-4 lg:flex-col-reverse lg:overflow-x-hidden">
13+
<div class="bg-white max-lg:w-2 lg:h-2"></div>
14+
<div
15+
class="no-scrollbar flex flex-initial gap-2 overflow-x-scroll max-lg:flex-col">
16+
<!-- <div
17+
v-for="event in events"
18+
:key="event.id"
19+
class="flex justify-between gap-4 border border-white px-3 py-2">
20+
<p class="flex-1 text-ellipsis text-xl">{{ event.title }}</p>
21+
<div class="flex items-center gap-2">
22+
<img src="@ui25/assets/clock.svg" alt="" />
23+
<p>{{ format(event.startsAt, 'HH:mm') }}</p>
24+
</div>
25+
</div> -->
26+
<div
27+
v-for="event in events"
28+
:key="event.id"
29+
class="border border-white px-3 py-2">
30+
<p
31+
class="min-w-[100px] overflow-x-hidden text-ellipsis whitespace-nowrap">
32+
{{ event.title }}
33+
</p>
34+
<div class="flex items-center gap-2">
35+
<img
36+
src="@ui25/assets/clock.svg"
37+
:alt="format(event.startsAt, 'HH:mm')" />
38+
<span>{{ format(event.startsAt, 'HH:mm') }}</span>
39+
</div>
40+
</div>
41+
</div>
42+
</div>
43+
</template>
44+
45+
<style scoped>
46+
.no-scrollbar::-webkit-scrollbar {
47+
display: none;
48+
}
49+
.no-scrollbar {
50+
-ms-overflow-style: none;
51+
scrollbar-width: none;
52+
}
53+
</style>

app/middleware/requireLink.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
55
const { getOwnQr } = useQR();
66
const result = await getOwnQr();
77

8-
if (result.isError()) return navigateTo('/ticket'); // TODO where to go to?
8+
if (result.isError()) return navigateTo('/onboarding');
99
});

0 commit comments

Comments
 (0)