FengShui / frontend /src /components /ScoreDial.jsx
Jaosub
Deploy to HF Space
5434776
Raw
History Blame Contribute Delete
4.89 kB
import React from 'react';
export default function ScoreDial({ score, subScores }) {
// Determine color based on score
const getScoreColorClass = (val) => {
if (val >= 80) return 'text-emerald-400';
if (val >= 60) return 'text-amber-400';
return 'text-rose-500';
};
const getScoreColorHex = (val) => {
if (val >= 80) return '#50c878'; // Jade Green
if (val >= 60) return '#d4af37'; // Gold
return '#e53e3e'; // Rose Red
};
const getScoreLabel = (val) => {
if (val >= 85) return 'Auspicious (Imperial)';
if (val >= 70) return 'Harmonious (Sheng Qi)';
if (val >= 50) return 'Moderately Balanced';
return 'Inauspicious (Sha Qi)';
};
// SVG parameters
const size = 180;
const strokeWidth = 12;
const center = size / 2;
const radius = center - strokeWidth;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (score / 100) * circumference;
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '20px' }}>
<div style={{ position: 'relative', width: size, height: size }}>
{/* Radial SVG Gauge */}
<svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
{/* Background circle */}
<circle
cx={center}
cy={center}
r={radius}
fill="transparent"
stroke="rgba(255, 255, 255, 0.05)"
strokeWidth={strokeWidth}
/>
{/* Active progress circle */}
<circle
cx={center}
cy={center}
r={radius}
fill="transparent"
stroke={getScoreColorHex(score)}
strokeWidth={strokeWidth}
strokeDasharray={circumference}
strokeDashoffset={offset}
strokeLinecap="round"
style={{ transition: 'stroke-dashoffset 1s ease-in-out' }}
/>
</svg>
{/* Core details inside the dial */}
<div style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
}}>
<span style={{ fontSize: '12px', textTransform: 'uppercase', color: 'var(--text-secondary)', letterSpacing: '0.1em' }}>
Feng Shui Score
</span>
<span style={{
fontSize: '44px',
fontFamily: 'var(--font-serif)',
fontWeight: 'bold',
color: getScoreColorHex(score),
lineHeight: 1
}}>
{score}
</span>
<span style={{ fontSize: '11px', color: 'var(--text-muted)', marginTop: '4px' }}>
out of 100
</span>
</div>
</div>
<div style={{
textAlign: 'center',
padding: '6px 16px',
borderRadius: '20px',
backgroundColor: 'rgba(255,255,255,0.03)',
border: '1px solid rgba(255,255,255,0.05)',
fontSize: '14px',
fontWeight: '500',
color: getScoreColorHex(score)
}}>
{getScoreLabel(score)}
</div>
{/* Grid of Sub-Scores */}
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: '12px',
width: '100%',
marginTop: '10px'
}}>
{[
{ key: 'terrain', label: '⛰️ Terrain', value: subScores.terrain },
{ key: 'vitality', label: '🌱 Vitality', value: subScores.vitality },
{ key: 'water', label: '💧 Water', value: subScores.water },
{ key: 'sha_qi', label: '⚡ Sha Qi', value: subScores.sha_qi }
].map((sub) => (
<div key={sub.key} style={{
padding: '10px',
borderRadius: '8px',
background: 'rgba(255,255,255,0.02)',
border: '1px solid rgba(255,255,255,0.04)',
display: 'flex',
flexDirection: 'column',
gap: '6px'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '12px' }}>
<span style={{ color: 'var(--text-secondary)' }}>{sub.label}</span>
<span style={{ fontWeight: 'bold', color: getScoreColorHex(sub.value) }}>{Math.round(sub.value)}</span>
</div>
{/* Progress bar */}
<div style={{ height: '4px', background: 'rgba(255,255,255,0.05)', borderRadius: '2px', overflow: 'hidden' }}>
<div style={{
height: '100%',
width: `${sub.value}%`,
background: getScoreColorHex(sub.value),
borderRadius: '2px',
transition: 'width 1s ease-in-out'
}} />
</div>
</div>
))}
</div>
</div>
);
}