Skip to content

Commit d5774d5

Browse files
committed
feat: sheet design
1 parent d16054a commit d5774d5

File tree

23 files changed

+981
-342
lines changed

23 files changed

+981
-342
lines changed

frontend/app/api/generated.ts

Lines changed: 524 additions & 23 deletions
Large diffs are not rendered by default.

frontend/app/assets/styles/main.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
--radius-navigation: calc(32px * var(--radius-multiplier));
3131
--radius-navigation-inset: calc(28px * var(--radius-multiplier));
3232
--radius-card: calc(48px * var(--radius-multiplier));
33+
--radius-modal: calc(40px * var(--radius-multiplier));
3334
--radius-button-large: calc(26px * var(--radius-multiplier));
3435
--radius-button-medium: calc(22px * var(--radius-multiplier));
3536
--radius-button-small: calc(18px * var(--radius-multiplier));
@@ -91,7 +92,7 @@
9192
--color-accent: #ffaedf;
9293
--color-accent-contrast: #ffaedf;
9394
--color-on-accent: #5d0045;
94-
--color-accent-positive: #c6ff62;
95+
--color-accent-positive: #a5d357;
9596
--color-accent-negative: #e86a4a;
9697
--color-background-default: #222222;
9798
--color-background-raised: #343434;

frontend/app/components/LocaleSelector.vue

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,8 @@ const selectedLocale = computed({
1212
</script>
1313

1414
<template>
15-
<DesignDrawer>
15+
<DesignDrawer :title="$t('settings.language')">
1616
<slot :selected-locale="locales.find((l) => l.code === selectedLocale)" />
17-
<template #content="{ close }">
18-
<PageLayout :title="$t('settings.language')">
19-
<template #action>
20-
<DesignIconButton icon="lucide:x" @click="close" />
21-
</template>
22-
</PageLayout>
23-
</template>
17+
<template #content="{ close }"></template>
2418
</DesignDrawer>
2519
</template>

frontend/app/components/PageLayout.vue

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,24 @@ withDefaults(
44
title?: string
55
bottomPadding?: boolean
66
shadow?: boolean
7+
blurred?: boolean
78
}>(),
89
{
910
bottomPadding: true,
1011
shadow: true,
12+
blurred: true,
1113
},
1214
)
13-
14-
const { y } = useWindowScroll()
15-
const hasScrolled = computed(() => y.value > 25)
1615
</script>
1716

1817
<template>
1918
<div class="flex min-h-full flex-col">
2019
<div class="sticky top-0 z-10">
21-
<ProgressiveBlur
22-
direction="up"
23-
:class="[
24-
shadow && 'from-shadow-blank/0 to-shadow-default bg-linear-to-t',
25-
]"
26-
>
27-
<header
28-
:class="[
29-
'relative flex items-center justify-between gap-4 px-6 pt-12 pb-3',
30-
{ 'min-h-20': hasScrolled, 'min-h-24': !hasScrolled },
31-
]"
32-
>
33-
<h1
34-
v-if="title"
35-
:class="[
36-
'text-text-default absolute transition-all duration-300 ease-out',
37-
{
38-
'text-heading bottom-3 left-6 translate-x-0 translate-y-0':
39-
!hasScrolled,
40-
'text-label top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2':
41-
hasScrolled,
42-
},
43-
]"
44-
>
45-
{{ title }}
46-
</h1>
47-
<div
48-
:class="[
49-
'absolute right-6 bottom-3 size-11 transition-all duration-300 ease-out',
50-
{
51-
'bottom-3': !hasScrolled,
52-
'top-1/2 -translate-y-1/2': hasScrolled,
53-
},
54-
]"
55-
>
56-
<slot name="action" />
57-
</div>
58-
</header>
59-
</ProgressiveBlur>
20+
<TitleBar :title="title" :blurred :shadow>
21+
<template #action>
22+
<slot name="action" />
23+
</template>
24+
</TitleBar>
6025
</div>
6126
<div
6227
:class="['p-list-outside flex grow flex-col', { 'pb-28': bottomPadding }]"

frontend/app/components/ProgressiveBlur.vue

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ interface Props {
33
maxBlur?: number // Maximum blur amount in pixels
44
layers?: number // Number of blur layers for smoothness
55
direction?: 'up' | 'down'
6+
enabled?: boolean
67
}
78
89
const props = withDefaults(defineProps<Props>(), {
910
maxBlur: 8,
1011
layers: 4,
1112
direction: 'down',
13+
enabled: true,
1214
})
1315
1416
// Determine gradient direction based on prop
@@ -35,17 +37,19 @@ const blurLayers = computed(() => {
3537

3638
<template>
3739
<div class="progressive-blur">
38-
<div
39-
v-for="(layer, index) in blurLayers"
40-
:key="index"
41-
class="blur-layer"
42-
:style="{
43-
backdropFilter: `blur(${layer.blur}px)`,
44-
WebkitBackdropFilter: `blur(${layer.blur}px)`,
45-
maskImage: `linear-gradient(${gradientDirection}, transparent 0%, black ${layer.maskMid}%, black 100%)`,
46-
WebkitMaskImage: `linear-gradient(${gradientDirection}, transparent 0%, black ${layer.maskMid}%, black 100%)`,
47-
}"
48-
/>
40+
<template v-if="enabled">
41+
<div
42+
v-for="(layer, index) in blurLayers"
43+
:key="index"
44+
class="blur-layer"
45+
:style="{
46+
backdropFilter: `blur(${layer.blur}px)`,
47+
WebkitBackdropFilter: `blur(${layer.blur}px)`,
48+
maskImage: `linear-gradient(${gradientDirection}, transparent 0%, black ${layer.maskMid}%, black 100%)`,
49+
WebkitMaskImage: `linear-gradient(${gradientDirection}, transparent 0%, black ${layer.maskMid}%, black 100%)`,
50+
}"
51+
/>
52+
</template>
4953
<slot />
5054
</div>
5155
</template>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<script setup lang="ts">
2+
import { cva } from 'cva'
3+
4+
withDefaults(
5+
defineProps<{
6+
title?: string
7+
shadow?: boolean
8+
blurred?: boolean
9+
size?: 'large' | 'small'
10+
}>(),
11+
{
12+
size: 'large',
13+
},
14+
)
15+
16+
const { y } = useWindowScroll()
17+
const hasScrolled = computed(() => y.value > 25)
18+
19+
const classes = cva(
20+
'relative flex items-center justify-between gap-4 px-6 pb-3',
21+
{
22+
variants: {
23+
size: {
24+
large: '',
25+
small: '',
26+
},
27+
hasScrolled: {
28+
true: '',
29+
false: '',
30+
},
31+
},
32+
compoundVariants: [
33+
{ size: 'small', hasScrolled: true, class: 'pt-6 min-h-20' },
34+
{ size: 'large', hasScrolled: true, class: 'pt-12 min-h-20' },
35+
{ size: 'small', hasScrolled: false, class: 'pt-6 min-h-20' },
36+
{ size: 'large', hasScrolled: false, class: 'pt-12 min-h-24' },
37+
],
38+
defaultVariants: {
39+
size: 'large',
40+
hasScrolled: false,
41+
},
42+
},
43+
)
44+
</script>
45+
46+
<template>
47+
<ProgressiveBlur
48+
direction="up"
49+
:class="[shadow && 'from-shadow-blank/0 to-shadow-default bg-linear-to-t']"
50+
:enabled="blurred"
51+
>
52+
<header :class="classes({ hasScrolled, size })">
53+
<h1
54+
v-if="title"
55+
:class="[
56+
'text-text-default absolute transition-all duration-300 ease-out',
57+
{
58+
'text-heading bottom-3 left-6 translate-x-0 translate-y-0':
59+
!hasScrolled,
60+
'text-label top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2':
61+
hasScrolled,
62+
},
63+
]"
64+
>
65+
{{ title }}
66+
</h1>
67+
<div
68+
:class="[
69+
'absolute right-6 bottom-3 size-11 transition-all duration-300 ease-out',
70+
{
71+
'bottom-3': !hasScrolled,
72+
'top-1/2 -translate-y-1/2': hasScrolled,
73+
},
74+
]"
75+
>
76+
<slot name="action" />
77+
</div>
78+
</header>
79+
</ProgressiveBlur>
80+
</template>

frontend/app/components/achievements/AchievementBadge.vue

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ watch(open, (isOpen) => {
2020

2121
<template>
2222
<div>
23-
<DesignDrawer v-model:open="open">
23+
<DesignDrawer
24+
v-model:open="open"
25+
:title="
26+
achievement.achievedAt
27+
? $t('achievement.unlocked')
28+
: $t('achievement.title')
29+
"
30+
>
2431
<button
2532
class="grid aspect-square place-items-center overflow-hidden rounded-full"
2633
>
@@ -35,57 +42,48 @@ watch(open, (isOpen) => {
3542
class="size-full object-cover"
3643
/>
3744
</button>
38-
<template #content="{ close }">
39-
<PageLayout
40-
:title="achievement.achievedAt ? 'Unlocked!' : 'Achievement'"
41-
:shadow="false"
42-
>
43-
<template #action>
44-
<DesignIconButton icon="lucide:x" @click="close" />
45-
</template>
46-
47-
<div class="flex h-full flex-col items-center justify-center gap-6">
48-
<div
49-
:class="[
50-
'grid aspect-square size-55 place-items-center overflow-hidden rounded-full',
51-
{ 'shadow-large': achievement.achievedAt },
52-
]"
53-
>
54-
<NuxtImg
55-
v-if="achievement.image && achievement.achievedAt != null"
56-
:src="achievement.image"
57-
class="size-full object-cover"
58-
/>
59-
<NuxtImg
60-
v-else
61-
src="/images/achievement-placeholder.png"
62-
class="size-full object-cover"
63-
/>
64-
</div>
65-
<div
66-
class="flex flex-col items-center gap-1 text-center text-balance"
67-
>
68-
<h3 class="text-heading">
69-
{{ achievement.name }}
70-
</h3>
71-
<p class="text-label">
72-
{{ achievement.description }}
73-
</p>
74-
</div>
75-
<div
76-
v-if="achievement.achievedAt"
77-
class="rounded-full bg-background-indent py-2 px-3 text-label text-accent-contrast"
78-
>
79-
+{{ achievement.points }} {{ $t('points') }}
80-
</div>
81-
<div
82-
v-else-if="achievement.points"
83-
class="rounded-full bg-background-indent py-2 px-3 text-label text-text-muted"
84-
>
85-
{{ $t('givesYouXPoints', { points: achievement.points }) }}
86-
</div>
45+
<template #content>
46+
<div class="flex h-full flex-col items-center justify-center gap-6">
47+
<div
48+
:class="[
49+
'grid aspect-square size-55 place-items-center overflow-hidden rounded-full',
50+
{ 'shadow-large': achievement.achievedAt },
51+
]"
52+
>
53+
<NuxtImg
54+
v-if="achievement.image && achievement.achievedAt != null"
55+
:src="achievement.image"
56+
class="size-full object-cover"
57+
/>
58+
<NuxtImg
59+
v-else
60+
src="/images/achievement-placeholder.png"
61+
class="size-full object-cover"
62+
/>
63+
</div>
64+
<div
65+
class="flex flex-col items-center gap-1 text-center text-balance"
66+
>
67+
<h3 class="text-heading">
68+
{{ achievement.name }}
69+
</h3>
70+
<p class="text-label">
71+
{{ achievement.description }}
72+
</p>
73+
</div>
74+
<div
75+
v-if="achievement.achievedAt"
76+
class="rounded-full bg-background-indent py-2 px-3 text-label text-accent-contrast"
77+
>
78+
+{{ achievement.points }} {{ $t('points') }}
79+
</div>
80+
<div
81+
v-else-if="achievement.points"
82+
class="rounded-full bg-background-indent py-2 px-3 text-label text-text-muted"
83+
>
84+
{{ $t('givesYouXPoints', { points: achievement.points }) }}
8785
</div>
88-
</PageLayout>
86+
</div>
8987
</template>
9088
</DesignDrawer>
9189
</div>

frontend/app/components/consent/ConsentBanner.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ defineEmits<{
55
</script>
66

77
<template>
8-
<DesignBanner :title="$t('consent.bannerTitle')" @close="$emit('close')">
8+
<DesignBanner
9+
:title="$t('consent.bannerTitle')"
10+
:dismissable="false"
11+
@close="$emit('close')"
12+
>
913
<template #action>
1014
<NuxtLink :to="{ name: 'settings-consent' }">
1115
<DesignButton size="large" class="w-full">
1216
{{ $t('consent.bannerButton') }}
17+
<Icon name="lucide:arrow-right" />
1318
</DesignButton>
1419
</NuxtLink>
1520
</template>

0 commit comments

Comments
 (0)