265 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
interface TemplateCardProps {
/** 图片URL */
imageUrl: string;
/** 图片alt文本 */
imageAlt?: string;
/** 标题 */
title: string;
/** 描述文字 */
description: string;
/** 是否选中默认false */
isSelected?: boolean;
/** 卡片宽度默认150px */
width?: number;
/** 卡片高度默认200px */
height?: number;
}
/**
* 3D翻转卡片组件
* 正面显示图片,背面显示标题和描述
*/
const TemplateCard: React.FC<TemplateCardProps> = ({
imageUrl,
imageAlt = "",
title,
description,
isSelected = false,
width = 150,
height = 200,
}) => {
return (
<div
className={`card ${isSelected ? "selected" : ""}`}
style={{ width: `${width}px`, height: `${height}px` }}
data-alt="template-card"
>
<div className="card-container">
{/* 背面 - 显示图片 */}
<div className="card-back">
<div className="back-image-wrapper">
<img src={imageUrl} alt={imageAlt} className="back-image" />
</div>
</div>
{/* 正面 - 显示文字和流光效果 */}
<div className="card-front">
<div className="floating-circle floating-circle-1"></div>
<div className="floating-circle floating-circle-2"></div>
<div className="floating-circle floating-circle-3"></div>
<div className="front-content-overlay">
<div className="free-badge">Free</div>
<div className="text-content">
<h3 className="card-title">{title}</h3>
<p className="card-description">{description}</p>
</div>
</div>
</div>
</div>
<style jsx>{`
.card {
overflow: visible;
}
.card-container {
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 300ms;
box-shadow: 0px 0px 10px 1px #000000ee;
border-radius: 5px;
cursor: pointer;
}
.card-front,
.card-back {
background-color: #151515;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
border-radius: 5px;
overflow: hidden;
}
.card-back {
width: 100%;
height: 100%;
justify-content: center;
display: flex;
align-items: center;
overflow: hidden;
}
.card-back::before {
position: absolute;
content: " ";
display: block;
width: 160px;
height: 160%;
background: linear-gradient(
90deg,
transparent,
rgb(106, 244, 249),
rgb(199, 59, 255),
rgb(106, 244, 249),
rgb(199, 59, 255),
transparent
);
animation: rotation_481 5000ms infinite linear;
opacity: 0;
transition: opacity 0.3s ease;
}
.card.selected .card-back::before {
opacity: 1;
}
.back-image-wrapper {
position: absolute;
width: 99%;
height: 99%;
background-color: #151515;
border-radius: 5px;
color: white;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
padding: 0px;
box-sizing: border-box;
}
.free-badge {
background: linear-gradient(
135deg,
rgb(106, 244, 249),
rgb(199, 59, 255)
);
color: white;
padding: 3px 10px;
border-radius: 10px;
font-size: 10px;
font-weight: bold;
text-transform: uppercase;
}
.text-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 15px;
}
.card-title {
font-size: 16px;
font-weight: bold;
margin: 0;
line-height: 1.2;
}
.card-description {
font-size: 12px;
line-height: 1.4;
margin: 0;
color: #cccccc;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.card:hover .card-container {
transform: rotateY(180deg);
}
@keyframes rotation_481 {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
.card-front {
transform: rotateY(180deg);
color: white;
}
.front-content-overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(21, 21, 21, 0.6);
backdrop-filter: blur(10px);
border-radius: 5px;
color: white;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
padding: 1rem;
box-sizing: border-box;
z-index: 100;
}
.back-image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.floating-circle {
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #ffbb66;
position: absolute;
filter: blur(12px);
animation: floating 2600ms infinite linear;
}
.floating-circle-2 {
background-color: #ff8866;
left: 30px;
top: 70px;
width: 100px;
height: 100px;
animation-delay: -800ms;
}
.floating-circle-3 {
background-color: #ff2233;
left: 100px;
top: 30px;
width: 20px;
height: 20px;
animation-delay: -1800ms;
}
@keyframes floating {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(10px);
}
100% {
transform: translateY(0px);
}
}
`}</style>
</div>
);
};
export default TemplateCard;