windows/components/StreamerFlipCard.vue

695 lines
13 KiB
Vue
Raw Permalink Normal View History

2025-09-25 17:20:06 +00:00
<template>
<div
class="flip-card"
:class="{ 'is-flipped': isFlipped }"
@mouseenter="handleCardHover"
@mouseleave="handleCardLeave"
>
<div class="flip-card-inner">
<!-- 卡片背面 (左邊的樣式) -->
<div class="flip-card-back">
<div class="back-content">
<h3 class="back-title">{{ streamer.name }}</h3>
<p class="greeting">{{ streamer.greeting }}</p>
<p class="status">{{ streamer.status }}</p>
<p class="availability">{{ streamer.availability }}</p>
<p class="personality">{{ streamer.personality }}</p>
<p class="promise">{{ streamer.promise }}</p>
<!-- 主播主頁按鈕 -->
<button
class="profile-button"
@click="handleProfileClick"
>
去這個主播主頁
</button>
</div>
</div>
<!-- 卡片正面 - 簡潔設計 -->
<div class="flip-card-front">
<div class="photo-container">
<img
:src="streamer.photo"
:alt="streamer.name"
class="streamer-photo"
/>
<!-- 簡潔的覆蓋層 -->
<div class="photo-overlay">
<!-- 右上角徽章組 -->
<div class="badges-container">
<StreamerBadge
v-for="(badgeCode, index) in streamer.badges.slice(0, 3)"
:key="`${streamer.id}-badge-${index}`"
:code="badgeCode"
size="small"
class="streamer-badge"
/>
</div>
<!-- 底部資訊條 -->
<div class="info-bar">
<div class="streamer-info">
<h3 class="streamer-name">{{ streamer.name }}</h3>
<p class="streamer-description">{{ streamer.description }}</p>
</div>
<!-- 性別和生日資訊 -->
<div class="personal-info">
<div class="gender-badge" :class="streamer.gender">
<span class="gender-icon">{{ streamer.gender === 'female' ? '♀' : '♂' }}</span>
<span class="gender-text">{{ streamer.gender === 'female' ? '女' : '男' }}</span>
</div>
<div class="birthday-info">
<span class="birthday-icon">🎂</span>
<span class="birthday-text">{{ formatBirthday(streamer.birthday) }}</span>
</div>
</div>
<div class="stats-row">
<div class="stat-item">
<span class="stat-number">{{ streamer.fans }}</span>
<span class="stat-label">粉絲</span>
</div>
<div class="stat-item">
<span class="stat-number">{{ streamer.orders }}</span>
<span class="stat-label">接單</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import StreamerBadge from './StreamerBadge.vue';
interface Streamer {
id: number;
name: string;
photo: string;
description: string;
rank: string;
fans: number;
orders: number;
badges: string[];
greeting: string;
status: string;
availability: string;
personality: string;
promise: string;
gender: 'male' | 'female';
birthday: string;
}
interface Props {
streamer: Streamer;
}
const props = defineProps<Props>();
const emit = defineEmits<{
click: [streamer: Streamer];
more: [streamer: Streamer];
profile: [streamer: Streamer];
}>();
const isFlipped = ref(false);
const handleCardHover = () => {
isFlipped.value = true;
console.log('Card hovered, showing back');
};
const handleCardLeave = () => {
isFlipped.value = false;
console.log('Card left, showing front');
};
const handleMoreClick = (event: Event) => {
event.stopPropagation();
emit('more', props.streamer);
};
const handleStreamerClick = (event: Event) => {
event.stopPropagation();
emit('click', props.streamer);
};
const handleProfileClick = (event: Event) => {
event.stopPropagation();
emit('profile', props.streamer);
};
// 格式化生日顯示
const formatBirthday = (birthday: string): string => {
const date = new Date(birthday);
return `${date.getMonth() + 1}/${date.getDate()}`;
};
</script>
<style scoped>
/* 翻轉卡片容器 */
.flip-card {
width: 100%;
height: 320px;
min-height: 320px;
max-height: 320px;
perspective: 1000px;
cursor: pointer;
position: relative;
z-index: 1;
transition: z-index 0.3s ease;
}
.flip-card:hover {
z-index: 10;
}
.flip-card.is-flipped {
z-index: 5;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.6s;
transform-style: preserve-3d;
min-height: 320px;
max-height: 320px;
box-sizing: border-box;
}
.flip-card-back,
.flip-card-front {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 1;
/* 確保正面和背面尺寸完全一致 */
min-height: 320px;
max-height: 320px;
box-sizing: border-box;
}
/* 卡片背面樣式 (左邊) */
.flip-card-back {
background: linear-gradient(135deg, rgba(255, 107, 157, 0.8) 0%, rgba(255, 167, 38, 0.8) 100%);
color: white;
display: none;
flex-direction: column;
justify-content: space-between;
padding: 20px;
position: relative;
overflow: hidden;
/* 移除框框效果 */
border: none;
box-shadow: none;
border-radius: 12px;
}
.flip-card-back::before {
content: '';
position: absolute;
top: -50%;
right: -50%;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.05) 0%, transparent 70%);
pointer-events: none;
}
.back-content {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
align-items: center;
text-align: center;
position: relative;
z-index: 1;
padding: 50px 25px;
box-sizing: border-box;
gap: 10px;
}
.back-title {
font-size: 20px;
font-weight: bold;
margin: 0 0 16px 0;
color: white;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.back-content p {
margin: 0;
font-size: 13px;
line-height: 1.4;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.greeting {
font-weight: 600;
color: #fff3e0;
font-size: 15px;
}
.status {
color: #ffe0b2;
font-size: 14px;
}
.availability {
color: #ffccbc;
font-size: 13px;
}
.personality {
color: #f8bbd9;
font-size: 13px;
}
.promise {
color: #e1bee7;
font-size: 12px;
margin: 0;
opacity: 0.9;
}
/* 主播主頁按鈕 */
.profile-button {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.4);
color: white;
padding: 10px 20px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 20px;
border-radius: 25px;
backdrop-filter: blur(8px);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
min-width: 140px;
}
.profile-button:hover {
background: rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.6);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.profile-button:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}
/* 卡片正面樣式 - 簡潔設計 */
.flip-card-front {
background: white;
display: flex;
flex-direction: column;
position: relative;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.photo-container {
width: 100%;
height: 100%;
position: relative;
border-radius: 12px;
overflow: hidden;
}
.streamer-photo {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.photo-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 16px;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.1) 0%,
transparent 30%,
transparent 70%,
rgba(0, 0, 0, 0.7) 100%
);
}
/* 徽章容器 */
.badges-container {
position: absolute;
top: 16px;
right: 16px;
display: flex;
flex-direction: column;
gap: 6px;
max-width: 120px;
align-items: flex-end;
}
.streamer-badge {
flex-shrink: 0;
}
/* 底部資訊條 */
.info-bar {
background: transparent;
backdrop-filter: none;
border-radius: 12px;
padding: 12px;
margin-top: auto;
}
.streamer-info {
margin-bottom: 8px;
}
.streamer-name {
font-size: 18px;
font-weight: 700;
color: white;
margin: 0 0 4px 0;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.8);
}
.streamer-description {
font-size: 12px;
color: white;
margin: 0;
line-height: 1.3;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}
/* 個人資訊區域 */
.personal-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
gap: 8px;
}
/* 性別徽章 */
.gender-badge {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 8px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
backdrop-filter: blur(4px);
}
.gender-badge.female {
background: rgba(255, 182, 193, 0.8);
color: #d63384;
border: 1px solid rgba(214, 51, 132, 0.3);
}
.gender-badge.male {
background: rgba(173, 216, 230, 0.8);
color: #0d6efd;
border: 1px solid rgba(13, 110, 253, 0.3);
}
.gender-icon {
font-size: 12px;
font-weight: bold;
}
.gender-text {
font-size: 10px;
}
/* 生日資訊 */
.birthday-info {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 8px;
background: rgba(255, 255, 255, 0.15);
border-radius: 12px;
font-size: 10px;
font-weight: 500;
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.birthday-icon {
font-size: 10px;
}
.birthday-text {
font-size: 10px;
opacity: 0.9;
}
/* 統計行 */
.stats-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.stat-number {
font-size: 16px;
font-weight: 700;
color: white;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.8);
line-height: 1;
}
.stat-label {
font-size: 10px;
color: white;
margin-top: 2px;
text-transform: uppercase;
letter-spacing: 0.5px;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}
/* 翻轉狀態樣式 - 懸停時顯示背面(粉橙漸變) */
.flip-card.is-flipped .flip-card-back {
display: flex;
}
.flip-card.is-flipped .flip-card-front {
display: none;
}
/* 響應式設計 */
@media (max-width: 768px) {
.flip-card {
height: 300px;
min-height: 300px;
max-height: 300px;
}
.flip-card-inner {
min-height: 300px;
max-height: 300px;
}
.flip-card-back,
.flip-card-front {
min-height: 300px;
max-height: 300px;
}
.back-content {
padding: 45px 22px;
gap: 12px;
}
.back-title {
font-size: 20px;
margin-bottom: 14px;
}
.back-content p {
font-size: 13px;
line-height: 1.4;
}
.profile-button {
padding: 8px 16px;
font-size: 13px;
margin-top: 16px;
min-width: 120px;
}
/* 正面卡片響應式 */
.streamer-name {
font-size: 16px;
}
.streamer-description {
font-size: 12px;
}
.personal-info {
margin-bottom: 8px;
gap: 6px;
}
.gender-badge {
padding: 3px 6px;
font-size: 10px;
}
.birthday-info {
padding: 3px 6px;
font-size: 9px;
}
.stat-number {
font-size: 14px;
}
.stat-label {
font-size: 10px;
}
/* 徽章響應式 */
.badges-container {
top: 12px;
right: 12px;
max-width: 100px;
gap: 4px;
}
}
@media (max-width: 480px) {
.flip-card {
height: 280px;
min-height: 280px;
max-height: 280px;
}
.flip-card-inner {
min-height: 280px;
max-height: 280px;
}
.flip-card-back,
.flip-card-front {
min-height: 280px;
max-height: 280px;
}
.back-content {
padding: 35px 18px;
gap: 10px;
}
.back-title {
font-size: 18px;
margin-bottom: 12px;
}
.back-content p {
font-size: 12px;
line-height: 1.3;
}
.profile-button {
padding: 6px 12px;
font-size: 12px;
margin-top: 14px;
min-width: 100px;
}
/* 正面卡片響應式 */
.streamer-name {
font-size: 15px;
}
.streamer-description {
font-size: 11px;
}
.personal-info {
margin-bottom: 6px;
gap: 4px;
}
.gender-badge {
padding: 2px 5px;
font-size: 9px;
}
.birthday-info {
padding: 2px 5px;
font-size: 8px;
}
.stat-number {
font-size: 13px;
}
.stat-label {
font-size: 9px;
}
/* 徽章響應式 */
.badges-container {
top: 10px;
right: 10px;
max-width: 90px;
gap: 3px;
}
}
/* 深色主題適配 */
.theme-dark .flip-card-front {
background: var(--window-background);
color: var(--content-text-color);
}
.theme-dark .streamer-name {
color: var(--content-text-color);
}
.theme-dark .streamer-description {
color: var(--content-text-color);
opacity: 0.8;
}
</style>