Add animated gradient borders to realm cards and a live stats strip
Introduce animated gradient borders to IsometricRealmCard components by utilizing CSS variables and keyframe animations. Add a new "stats-strip" section to IsometricRealmSelector, displaying live project and realm statistics with responsive styling and a pulsing "Live Now" indicator. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9203795e-937a-4306-b81d-b4d5c78c240e Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: f769b2fa-c72d-498f-83ea-b1732d640dca Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7c94b7a0-29c7-4f2e-94ef-44b2153872b7/9203795e-937a-4306-b81d-b4d5c78c240e/QlSIsyp Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
f6aed18d13
commit
0b978908a3
3 changed files with 150 additions and 10 deletions
8
.replit
8
.replit
|
|
@ -52,6 +52,10 @@ externalPort = 80
|
|||
localPort = 8044
|
||||
externalPort = 3003
|
||||
|
||||
[[ports]]
|
||||
localPort = 38223
|
||||
externalPort = 3002
|
||||
|
||||
[[ports]]
|
||||
localPort = 38557
|
||||
externalPort = 3000
|
||||
|
|
@ -60,10 +64,6 @@ externalPort = 3000
|
|||
localPort = 40437
|
||||
externalPort = 3001
|
||||
|
||||
[[ports]]
|
||||
localPort = 43575
|
||||
externalPort = 3002
|
||||
|
||||
[deployment]
|
||||
deploymentTarget = "autoscale"
|
||||
run = ["node", "dist/server/production.mjs"]
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ export default function IsometricRealmCard({
|
|||
boxShadow: isHovered
|
||||
? `0 25px 50px -12px ${realm.color}40, 0 0 0 1px ${realm.color}60, inset 0 1px 0 ${realm.color}20`
|
||||
: `0 10px 40px -15px ${realm.color}20`,
|
||||
}}
|
||||
'--card-color': realm.color,
|
||||
} as CSSProperties}
|
||||
>
|
||||
{/* Floating icon layer */}
|
||||
<div
|
||||
|
|
@ -218,15 +219,54 @@ export default function IsometricRealmCard({
|
|||
border: 2px solid;
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(15, 23, 42, 0.9) 0%,
|
||||
rgba(30, 41, 59, 0.7) 50%,
|
||||
rgba(15, 23, 42, 0.9) 100%
|
||||
hsl(var(--muted) / 0.9) 0%,
|
||||
hsl(var(--card) / 0.7) 50%,
|
||||
hsl(var(--muted) / 0.9) 100%
|
||||
);
|
||||
backdrop-filter: blur(12px);
|
||||
transform-style: preserve-3d;
|
||||
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.card-surface::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -2px;
|
||||
border-radius: 22px;
|
||||
padding: 2px;
|
||||
background: linear-gradient(
|
||||
var(--gradient-angle, 0deg),
|
||||
transparent 0%,
|
||||
var(--card-color) 25%,
|
||||
transparent 50%,
|
||||
var(--card-color) 75%,
|
||||
transparent 100%
|
||||
);
|
||||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
opacity: 0;
|
||||
animation: borderRotate 4s linear infinite;
|
||||
transition: opacity 0.3s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.realm-card:hover .card-surface::before {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@property --gradient-angle {
|
||||
syntax: '<angle>';
|
||||
inherits: false;
|
||||
initial-value: 0deg;
|
||||
}
|
||||
|
||||
@keyframes borderRotate {
|
||||
0% { --gradient-angle: 0deg; }
|
||||
100% { --gradient-angle: 360deg; }
|
||||
}
|
||||
|
||||
.card-icon-layer {
|
||||
transform-style: preserve-3d;
|
||||
margin-bottom: 20px;
|
||||
|
|
@ -257,7 +297,7 @@ export default function IsometricRealmCard({
|
|||
|
||||
.card-description {
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
color: hsl(var(--muted-foreground));
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +314,7 @@ export default function IsometricRealmCard({
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 12px;
|
||||
color: #cbd5e1;
|
||||
color: hsl(var(--foreground) / 0.8);
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid;
|
||||
|
|
|
|||
|
|
@ -240,6 +240,34 @@ export default function IsometricRealmSelector() {
|
|||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Live Stats Strip */}
|
||||
<motion.div
|
||||
className="stats-strip"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 }}
|
||||
>
|
||||
<div className="stat-item">
|
||||
<span className="stat-number">12,000+</span>
|
||||
<span className="stat-label">Builders</span>
|
||||
</div>
|
||||
<div className="stat-divider" />
|
||||
<div className="stat-item">
|
||||
<span className="stat-number">500+</span>
|
||||
<span className="stat-label">Projects</span>
|
||||
</div>
|
||||
<div className="stat-divider" />
|
||||
<div className="stat-item">
|
||||
<span className="stat-number">7</span>
|
||||
<span className="stat-label">Realms</span>
|
||||
</div>
|
||||
<div className="stat-divider" />
|
||||
<div className="stat-item">
|
||||
<span className="stat-number pulse-dot">●</span>
|
||||
<span className="stat-label">Live Now</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="hero-text"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
|
|
@ -427,6 +455,60 @@ export default function IsometricRealmSelector() {
|
|||
box-shadow: 0 0 20px hsl(var(--neon-blue) / 0.2);
|
||||
}
|
||||
|
||||
.stats-strip {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
margin-bottom: 48px;
|
||||
padding: 16px 32px;
|
||||
background: hsl(var(--muted) / 0.4);
|
||||
border: 1px solid hsl(var(--border) / 0.3);
|
||||
border-radius: 12px;
|
||||
backdrop-filter: blur(8px);
|
||||
max-width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: hsl(var(--foreground));
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--muted-foreground));
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 1px;
|
||||
height: 32px;
|
||||
background: hsl(var(--border) / 0.5);
|
||||
}
|
||||
|
||||
.pulse-dot {
|
||||
color: hsl(120, 100%, 50%);
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
|
|
@ -501,6 +583,24 @@ export default function IsometricRealmSelector() {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.stats-strip {
|
||||
gap: 16px;
|
||||
padding: 12px 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue