Skip to content

Commit cdf0603

Browse files
authored
Merge pull request #213 from vuejs-jp/feat/namecard
Feat/add Namecard Component
2 parents c154a09 + 387f30e commit cdf0603

File tree

12 files changed

+346
-9
lines changed

12 files changed

+346
-9
lines changed

packages/composable/lib/useUserRole.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { match } from 'ts-pattern'
44
export function useUserRole() {
55
const backgroundColor = (role: Role) =>
66
match(role)
7-
.with('staff', () => '#233445')
8-
.with('speaker', () => '#90B44B')
9-
.with('sponsor', () => '#FFC408')
10-
.with('attendee', () => '#F17C67')
11-
.with('attendee + party', () => '#33A6B8')
7+
.with('staff', () => 'color-mix(in srgb, var(--color-vue-blue), #000 20%)')
8+
.with('speaker', () => 'var(--color-hiwamoegi200)')
9+
.with('sponsor', () => 'var(--color-tohoh200)')
10+
.with('attendee', () => 'var(--color-sangosyo200)')
11+
.with('attendee + party', () => 'var(--color-asagi200)')
1212
.exhaustive()
1313

1414
const textColor = (role: Role) =>

packages/model/lib/attendee.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type Attendee = {
2424
id?: string
2525
provider: string
2626
receipt_id: string
27-
role?: string
27+
role?: Role
2828
updated_at: string
2929
user_id: string
3030
}
83.8 KB
Loading
Lines changed: 24 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

packages/ui/components/namecard/Namecard23.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import NamecardAvatar from './NamecardAvatar.vue'
2+
import NamecardAvatar from './NamecardAvatar23.vue'
33
import type { NamecardUser } from '@vuejs-jp/model'
44
import { defineAsyncComponent } from 'vue'
55

packages/ui/components/namecard/Namecard24.stories.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import Namecard24 from './Namecard24.vue'
44
export default {
55
title: 'namecard/Namecard24',
66
component: Namecard24,
7+
args: {
8+
user: {
9+
display_name: 'jiyuujin',
10+
avatar_url: 'https://i.imgur.com/X0CcoU9.jpg',
11+
role: 'attendee',
12+
},
13+
},
714
}
815

916
const Template: StoryFn<unknown> = (args, { argTypes }) => ({
@@ -16,3 +23,49 @@ const Template: StoryFn<unknown> = (args, { argTypes }) => ({
1623
})
1724

1825
export const Default = Template.bind({})
26+
27+
export const WithParty = Template.bind({})
28+
WithParty.args = {
29+
user: {
30+
display_name: 'jiyuujin',
31+
avatar_url: 'https://i.imgur.com/X0CcoU9.jpg',
32+
role: 'attendee + party',
33+
},
34+
}
35+
36+
export const Speaker = Template.bind({})
37+
Speaker.args = {
38+
user: {
39+
display_name: 'jiyuujin',
40+
avatar_url: 'https://i.imgur.com/X0CcoU9.jpg',
41+
role: 'speaker',
42+
},
43+
}
44+
45+
export const Sponsor = Template.bind({})
46+
Sponsor.args = {
47+
user: {
48+
display_name: 'jiyuujin',
49+
avatar_url: 'https://i.imgur.com/X0CcoU9.jpg',
50+
role: 'sponsor',
51+
},
52+
}
53+
54+
export const Staff = Template.bind({})
55+
Staff.args = {
56+
user: {
57+
display_name: 'jiyuujin',
58+
avatar_url: 'https://i.imgur.com/X0CcoU9.jpg',
59+
role: 'staff',
60+
},
61+
}
62+
63+
export const NoAvatar = Template.bind({})
64+
NoAvatar.args = {
65+
user: {
66+
display_name: '山田 太郎',
67+
avatar_url: '',
68+
role: 'attendee',
69+
},
70+
isPlaceholder: true,
71+
}
Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,79 @@
1+
<script setup lang="ts">
2+
import NamecardAvatar from './NamecardAvatar24.vue'
3+
import type { NamecardUser } from '@vuejs-jp/model'
4+
import { useUserRole } from '@vuejs-jp/composable'
5+
import { onMounted, ref } from 'vue'
6+
7+
type NamecardProps = {
8+
user: NamecardUser
9+
isPlaceholder?: boolean
10+
}
11+
12+
defineProps<NamecardProps>()
13+
14+
const { backgroundColor } = useUserRole()
15+
const sponsorImagePath = ref('')
16+
onMounted(() => {
17+
sponsorImagePath.value = new URL('../../assets/namecard/support.svg', import.meta.url).href
18+
})
19+
</script>
20+
121
<template>
2-
Namecard 2024
22+
<div class="namecard-root">
23+
<NamecardAvatar :user="user" :is-placeholder="isPlaceholder" />
24+
<div
25+
class="namecard-role"
26+
:style="{ '--background-color-role': backgroundColor(user.role ?? 'staff') }"
27+
>
28+
{{ user.role }}
29+
</div>
30+
<div class="namecard-sponsor">
31+
<img :src="sponsorImagePath" alt="Supported by Stockmark" />
32+
</div>
33+
</div>
334
</template>
35+
36+
<style scoped>
37+
.namecard-root {
38+
width: 23.5rem;
39+
background-color: var(--color-white);
40+
border-radius: calc(var(--unit) * 1.25);
41+
overflow: hidden;
42+
box-shadow: 0px 8px 24px 0px #0000003d;
43+
border: 1px solid #000;
44+
@media (width <= 480px) {
45+
width: 18rem;
46+
}
47+
}
48+
49+
.namecard-role {
50+
--background-color-role: color-mix(in srgb, var(--color-vue-blue), #000 20%);
51+
font-size: 1.6875rem;
52+
height: 2.625rem;
53+
display: grid;
54+
place-items: center;
55+
font-weight: 700;
56+
text-transform: uppercase;
57+
color: var(--color-white);
58+
background-color: var(--background-color-role);
59+
@media (width <= 480px) {
60+
font-size: 1.3125rem;
61+
height: 2.0625rem;
62+
}
63+
}
64+
65+
.namecard-sponsor {
66+
display: grid;
67+
place-items: center;
68+
height: 3.75rem;
69+
img {
70+
width: 16.25rem;
71+
}
72+
@media (width <= 480px) {
73+
height: 2.8125rem;
74+
img {
75+
width: 12.5rem;
76+
}
77+
}
78+
}
79+
</style>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<script setup lang="ts">
2+
import NamecardAvatarLogo from './NamecardAvatarLogo24.vue'
3+
import type { NamecardUser } from '@vuejs-jp/model'
4+
import { onMounted, ref } from 'vue'
5+
6+
type NamecardAvatarProps = {
7+
user: NamecardUser
8+
isPlaceholder?: boolean
9+
}
10+
defineProps<NamecardAvatarProps>()
11+
12+
const COLOR_AVATAR_NAME = {
13+
DEFAULT: 'color-mix(in srgb, var(--color-vue-blue), #000 20%)',
14+
PLACEHOLDER: 'var(--color-gray100)',
15+
}
16+
const vuefesLogoImagePath = ref('')
17+
onMounted(() => {
18+
vuefesLogoImagePath.value = new URL('../../assets/namecard/vuefes_logo.svg', import.meta.url).href
19+
})
20+
</script>
21+
22+
<template>
23+
<div class="avatar">
24+
<span class="avatar-hook" aria-hidden="true" />
25+
<div class="vuefes-logo-wrapper">
26+
<img :src="vuefesLogoImagePath" alt="vuefes logo" />
27+
</div>
28+
<div class="avatar-logo-wrapper">
29+
<NamecardAvatarLogo :user="user" />
30+
</div>
31+
<div class="avatar-name-area">
32+
<div
33+
class="avatar-name"
34+
:style="{
35+
'--color-avatar-name': isPlaceholder
36+
? COLOR_AVATAR_NAME.PLACEHOLDER
37+
: COLOR_AVATAR_NAME.DEFAULT,
38+
}"
39+
>
40+
{{ user.display_name }}
41+
</div>
42+
</div>
43+
<small class="avatar-footer">Vue Fes Japan 2024</small>
44+
</div>
45+
</template>
46+
47+
<style scoped>
48+
.avatar {
49+
display: grid;
50+
place-items: center;
51+
background: color-mix(in srgb, var(--color-vue-blue), #000 20%)
52+
url('../../assets/namecard/bg_texture.png') no-repeat;
53+
background-size: cover;
54+
container: avatar / inline-size;
55+
}
56+
57+
.avatar-hook {
58+
margin-top: 1.25rem;
59+
width: 25px;
60+
aspect-ratio: 1;
61+
background-color: var(--color-white);
62+
border-radius: 50%;
63+
@media (width <= 480px) {
64+
margin-top: 0.9375rem;
65+
width: 20px;
66+
}
67+
}
68+
69+
.vuefes-logo-wrapper {
70+
position: absolute;
71+
top: 17.98px;
72+
right: 14.07px;
73+
width: 29.72px;
74+
img {
75+
width: 100%;
76+
}
77+
@media (width <= 480px) {
78+
top: 13.77px;
79+
right: 10.77px;
80+
width: 22.76px;
81+
}
82+
}
83+
84+
.avatar-logo-wrapper {
85+
width: 36.17cqi;
86+
aspect-ratio: 1;
87+
border-radius: 50%;
88+
margin-top: 2.5rem;
89+
background: var(--color-vue-green-gradation);
90+
display: grid;
91+
place-items: center;
92+
border: 4px solid var(--color-white);
93+
container: avatar-logo / inline-size;
94+
@media (width <= 480px) {
95+
border-width: 3px;
96+
margin-top: 1.875rem;
97+
}
98+
}
99+
100+
.avatar-name-area {
101+
width: 85cqi;
102+
height: 8rem;
103+
background-color: var(--color-white);
104+
margin-top: 0.8125rem;
105+
display: grid;
106+
place-items: center;
107+
border-radius: calc(var(--unit) * 1.25);
108+
padding-inline: 1rem;
109+
overflow-wrap: anywhere;
110+
word-break: break-all;
111+
overflow-y: hidden;
112+
@media (width <= 480px) {
113+
margin-top: 0.625rem;
114+
height: 6.125rem;
115+
}
116+
}
117+
118+
.avatar-name {
119+
--color-avatar-name: color-mix(in srgb, var(--color-vue-blue), #000 20%);
120+
121+
font-size: 2.25rem;
122+
font-weight: 700;
123+
line-height: 1.1;
124+
color: var(--color-avatar-name);
125+
@media (width <= 480px) {
126+
font-size: 1.6875rem;
127+
}
128+
}
129+
130+
.avatar-footer {
131+
font-size: 1.0625rem;
132+
font-weight: 700;
133+
color: var(--color-white);
134+
margin-top: 2.875rem;
135+
margin-bottom: 0.75rem;
136+
line-height: 1;
137+
height: 0.75rem;
138+
@media (width <= 480px) {
139+
font-size: 0.8125rem;
140+
margin-top: 2.125rem;
141+
margin-bottom: 0.4rem;
142+
}
143+
}
144+
</style>

0 commit comments

Comments
 (0)