Files
sb-front/src/components/UserAvatar.vue
T
ByungCheol ca66c1d53e
CI / build (push) Failing after 13m27s
feat: 게시판 추천/비추천·작성자 아바타·추천자·포인트 (프론트)
- UserAvatar 컴포넌트(커스텀>구글>이니셜, 로드 실패 시 이니셜 폴백)
- 목록: 작성자 아바타 + 추천 수 표기
- 상세: 작성자 아바타, 추천/비추천 토글 버튼(내 투표 강조),
  추천자 본문 하단 아바타 10개 + 초과 시 (+N명이 추천했습니다), 클릭 시 전체 목록 모달
- 댓글: 작성자 아바타 + 추천/비추천 버튼
- 계정정보: 포인트 표기(GET /auth/points 최신값)
- boardApi.votePost/voteComment/recommenders, authApi.points 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 12:28:20 +09:00

63 lines
1.5 KiB
Vue

<script setup>
import { computed, ref, watch } from 'vue'
// 작성자/추천자 아바타. 우선순위: 커스텀(profileImage) > 구글(googlePicture) > 이니셜.
const props = defineProps({
name: { type: String, default: '' },
googlePicture: { type: String, default: '' },
profileImage: { type: String, default: '' },
size: { type: Number, default: 28 },
})
const broken = ref(false)
const src = computed(() => props.profileImage || props.googlePicture || '')
const initial = computed(() => {
const s = (props.name || '').trim()
return s ? s[0].toUpperCase() : '?'
})
// src 가 바뀌면 깨짐 상태 리셋
watch(src, () => { broken.value = false })
</script>
<template>
<span class="user-avatar" :style="{ width: size + 'px', height: size + 'px' }" :title="name">
<img
v-if="src && !broken"
:src="src"
:alt="name"
referrerpolicy="no-referrer"
@error="broken = true"
/>
<span v-else class="ua-initial" :style="{ fontSize: Math.round(size * 0.45) + 'px' }">{{ initial }}</span>
</span>
</template>
<style scoped>
.user-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
overflow: hidden;
flex: none;
vertical-align: middle;
background: var(--color-background-mute);
}
.user-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.ua-initial {
font-weight: 700;
color: #fff;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: hsla(160, 100%, 37%, 1);
}
</style>