98 lines
4.0 KiB
Vue
98 lines
4.0 KiB
Vue
<script lang="ts" setup>
|
|
import { computed } from 'vue'
|
|
import logoUrl from '@/assets/images/logo-original.svg'
|
|
import { displayCardValue } from '../utils/member-digital-card.utils'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
memberNumber?: string | number | null
|
|
memberName?: string | null
|
|
memberType?: string | null
|
|
companyName?: string | null
|
|
imageUrl?: string | null
|
|
expanded?: boolean
|
|
}>(),
|
|
{ expanded: false },
|
|
)
|
|
|
|
const avatarFallback = computed(() => {
|
|
const name = props.memberName?.trim()
|
|
if (!name) return '--'
|
|
return name.slice(0, 2).toUpperCase()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="[
|
|
'relative h-full w-full overflow-hidden rounded-2xl bg-linear-to-br from-primary via-primary/95 to-primary/75 text-primary-foreground shadow-lg ring-1 ring-white/20',
|
|
expanded ? 'p-6 sm:p-8' : 'p-4 sm:p-5',
|
|
]">
|
|
<div class="pointer-events-none absolute inset-0 bg-noise opacity-30" />
|
|
<div class="pointer-events-none absolute -right-10 -top-10 rounded-full bg-white/10"
|
|
:class="expanded ? 'size-48' : 'size-36'" />
|
|
<div class="pointer-events-none absolute -bottom-12 -left-8 rounded-full bg-white/5"
|
|
:class="expanded ? 'size-52' : 'size-40'" />
|
|
<div
|
|
class="pointer-events-none absolute top-1/2 -translate-y-1/2 overflow-hidden rounded-md border border-white/25 bg-white/10 shadow-sm"
|
|
:class="expanded ? 'right-6 size-20 sm:size-24' : 'right-4 size-14'">
|
|
<img v-if="imageUrl" :src="imageUrl" :alt="memberName ?? 'Profil anggota'" class="size-full object-cover" />
|
|
<div v-else class="flex size-full items-center justify-center bg-white/15 font-semibold uppercase tracking-wide"
|
|
:class="expanded ? 'text-base' : 'text-[11px]'">
|
|
{{ avatarFallback }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="relative flex h-full min-h-0 flex-col">
|
|
<div class="flex shrink-0 items-start justify-between gap-3">
|
|
<img :src="logoUrl" alt="" class="w-auto brightness-0 invert"
|
|
:class="expanded ? 'h-8 sm:h-10' : 'h-6 sm:h-7'" />
|
|
<div class="text-right font-semibold uppercase opacity-80"
|
|
:class="expanded ? 'text-sm tracking-[0.2em]' : 'text-[10px] tracking-[0.2em]'">
|
|
Kad Digital
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex min-h-0 flex-1 flex-col justify-center py-2" :class="expanded ? 'gap-4' : 'gap-2'">
|
|
<div>
|
|
<div class="font-medium uppercase tracking-widest opacity-70" :class="expanded ? 'text-sm' : 'text-[10px]'">
|
|
No. Anggota
|
|
</div>
|
|
<div class="mt-0.5 font-mono font-semibold"
|
|
:class="expanded ? 'text-4xl tracking-[0.15em] sm:text-5xl' : 'text-xl tracking-[0.15em] sm:text-2xl'">
|
|
{{ displayCardValue(memberNumber) }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="min-w-0" :class="expanded ? 'pr-28 sm:pr-32' : 'pr-16'">
|
|
<div class="font-medium uppercase tracking-widest opacity-70" :class="expanded ? 'text-sm' : 'text-[10px]'">
|
|
Unit
|
|
</div>
|
|
<div class="truncate font-medium" :class="expanded ? 'text-lg sm:text-xl' : 'text-xs'">
|
|
{{ displayCardValue(companyName) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex shrink-0 items-end justify-between gap-3 border-t border-white/15"
|
|
:class="expanded ? 'pt-4' : 'pt-2'">
|
|
<div class="min-w-0 flex-1">
|
|
<div class="truncate font-medium" :class="expanded ? 'text-xl sm:text-2xl' : 'text-sm'">
|
|
{{ memberName || '-' }}
|
|
</div>
|
|
<div class="mt-0.5 uppercase tracking-wide opacity-60" :class="expanded ? 'text-sm' : 'text-[10px]'">
|
|
Nama
|
|
</div>
|
|
</div>
|
|
<div class="shrink-0 text-right">
|
|
<div class="font-semibold" :class="expanded ? 'text-xl sm:text-2xl' : 'text-sm'">
|
|
{{ displayCardValue(memberType) }}
|
|
</div>
|
|
<div class="mt-0.5 uppercase tracking-wide opacity-60" :class="expanded ? 'text-sm' : 'text-[10px]'">
|
|
Jenis Anggota
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|