Skip to content
Merged
76 changes: 76 additions & 0 deletions apps/web/app/components/namecard/Namecard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script setup lang="ts">
import NamecardAvatar from './NamecardAvatar.vue'
import type { NamecardUser } from '@vuejs-jp/model'
import { useUserRole } from '@vuejs-jp/composable'

type NamecardProps = {
user: NamecardUser
isPlaceholder?: boolean
}

defineProps<NamecardProps>()

const { backgroundColor } = useUserRole()
</script>

<template>
<div class="namecard-root">
<NamecardAvatar :user="user" :is-placeholder="isPlaceholder" />
<div
class="namecard-role"
:style="{ '--background-color-role': backgroundColor(user.role ?? 'staff') }"
>
{{ user.role }}
</div>
<div class="namecard-sponsor">
<img src="/namecard/support.svg" alt="Supported by Stockmark" />
</div>
</div>
</template>

<style scoped>
@import url('~/assets/media.css');

.namecard-root {
width: 23.5rem;
background-color: var(--color-white);
border-radius: calc(var(--unit) * 1.25);
overflow: hidden;
box-shadow: 0px 8px 24px 0px hsla(0, 0%, 0%, 0.239);
border: 1px solid #000;
@media (--mobile) {
width: 18rem;
}
}

.namecard-role {
--background-color-role: color-mix(in srgb, var(--color-vue-blue), #000 20%);
font-size: 1.6875rem;
height: 2.625rem;
display: grid;
place-items: center;
font-weight: 700;
text-transform: uppercase;
color: var(--color-white);
background-color: var(--background-color-role);
@media (--mobile) {
font-size: 1.3125rem;
height: 2.0625rem;
}
}

.namecard-sponsor {
display: grid;
place-items: center;
height: 3.75rem;
img {
width: 16.25rem;
}
@media (--mobile) {
height: 2.8125rem;
img {
width: 12.5rem;
}
}
}
</style>
144 changes: 144 additions & 0 deletions apps/web/app/components/namecard/NamecardAvatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<script setup lang="ts">
import type { NamecardUser } from '@vuejs-jp/model'

type NamecardAvatarProps = {
user: NamecardUser
isPlaceholder?: boolean
}
defineProps<NamecardAvatarProps>()

const COLOR_AVATAR_NAME = {
DEFAULT: 'color-mix(in srgb, var(--color-vue-blue), #000 20%)',
PLACEHOLDER: 'var(--color-gray100)',
}
</script>

<template>
<div class="avatar">
<span class="avatar-hook" aria-hidden="true" />
<div class="vuefes-logo-wrapper">
<img src="/namecard/vuefes_logo.svg" alt="vuefes logo" />
</div>
<div class="avatar-logo-wrapper">
<img :alt="user.display_name" :src="user.avatar_url" class="avatar-logo" decoding="async" />
</div>
<div class="avatar-name-area">
<div
class="avatar-name"
:style="{
'--color-avatar-name': isPlaceholder
? COLOR_AVATAR_NAME.PLACEHOLDER
: COLOR_AVATAR_NAME.DEFAULT,
}"
>
{{ user.display_name }}
</div>
</div>
<small class="avatar-footer">Vue Fes Japan 2024</small>
</div>
</template>

<style scoped>
@import url('~/assets/media.css');

.avatar {
display: grid;

place-items: center;
background: color-mix(in srgb, var(--color-vue-blue), #000 20%) url('/namecard/bg_texture.png')
no-repeat;
background-size: cover;
container: avatar / inline-size;
box-shadow: var(--shadow-1);
}

.avatar-hook {
margin-top: 1.25rem;
width: 25px;
aspect-ratio: 1;
background-color: #fff;
border-radius: 50%;
@media (--mobile) {
margin-top: 0.9375rem;
width: 20px;
}
}

.vuefes-logo-wrapper {
position: absolute;
top: 17.98px;
right: 14.07px;
width: 29.72px;
img {
width: 100%;
}
@media (--mobile) {
top: 13.77px;
right: 10.77px;
width: 22.76px;
}
}

.avatar-logo-wrapper {
width: 36.17cqi;
aspect-ratio: 1;
border-radius: 50%;
margin-top: 2.5rem;
@media (--mobile) {
margin-top: 1.875rem;
}
}

.avatar-logo {
width: 100%;
height: 100%;
border-radius: 50%;
border: 4px solid var(--color-white);
box-sizing: border-box;
vertical-align: top;
}

.avatar-name-area {
width: 85cqi;
height: 8rem;
background-color: var(--color-white);
margin-top: 0.8125rem;
display: grid;
place-items: center;
border-radius: calc(var(--unit) * 1.25);
padding-inline: 1rem;
overflow-wrap: anywhere;
word-break: break-all;
@media (--mobile) {
margin-top: 0.625rem;
height: 6.125rem;
}
}

.avatar-name {
--color-avatar-name: color-mix(in srgb, var(--color-vue-blue), #000 20%);

font-size: 2.25rem;
font-weight: 700;
line-height: 1.1;
color: var(--color-avatar-name);
@media (--mobile) {
font-size: 1.6875rem;
}
}

.avatar-footer {
font-size: 1.0625rem;
font-weight: 700;
color: var(--color-white);
margin-top: 2.875rem;
margin-bottom: 0.75rem;
line-height: 1;
height: 0.75rem;
@media (--mobile) {
font-size: 0.8125rem;
margin-top: 2.125rem;
margin-bottom: 0.4rem;
}
}
</style>
Binary file added apps/web/app/public/namecard/bg_texture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions apps/web/app/public/namecard/support.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions apps/web/app/public/namecard/vuefes_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions packages/composable/lib/useUserRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { match } from 'ts-pattern'
export function useUserRole() {
const backgroundColor = (role: Role) =>
match(role)
.with('staff', () => '#233445')
.with('speaker', () => '#90B44B')
.with('sponsor', () => '#FFC408')
.with('attendee', () => '#F17C67')
.with('attendee + party', () => '#33A6B8')
.with('staff', () => 'color-mix(in srgb, var(--color-vue-blue), #000 20%)')
.with('speaker', () => 'var(--color-hiwamoegi200)')
.with('sponsor', () => 'var(--color-tohoh200)')
.with('attendee', () => 'var(--color-sangosyo200)')
.with('attendee + party', () => 'var(--color-asagi200)')
.exhaustive()

const textColor = (role: Role) =>
Expand Down
2 changes: 1 addition & 1 deletion packages/model/lib/attendee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type Attendee = {
id?: string
provider: string
receipt_id: string
role?: string
role?: Role
updated_at: string
user_id: string
}
Expand Down