feat(saju): 오늘운세 컴포넌트 3개 (FortuneRing + ScoreCard + LuckyBox)

This commit is contained in:
2026-05-26 08:33:52 +09:00
parent 2d2895c9a4
commit 435e6fb1bc
3 changed files with 91 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
import React from 'react';
export default function FortuneRing({ score, max = 100 }) {
const radius = 80;
const circumference = 2 * Math.PI * radius;
const safe = Math.max(0, Math.min(score || 0, max));
const dashOffset = circumference - (safe / max) * circumference;
return (
<div className="saju-fortune-ring">
<svg viewBox="0 0 200 200">
<circle
cx="100" cy="100" r={radius}
stroke="var(--saju-paper)" strokeWidth="14" fill="none"
/>
<circle
cx="100" cy="100" r={radius}
stroke="var(--saju-gold)" strokeWidth="14" fill="none"
strokeDasharray={circumference}
strokeDashoffset={dashOffset}
strokeLinecap="round"
transform="rotate(-90 100 100)"
style={{ transition: 'stroke-dashoffset 0.6s ease' }}
/>
</svg>
<div style={{ position: 'absolute', textAlign: 'center' }}>
<div className="saju-fortune-ring__score">{safe}</div>
<div className="saju-fortune-ring__total">/ {max}</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,21 @@
import React from 'react';
export default function LuckyBox({ lucky }) {
if (!lucky) return null;
return (
<div className="saju-lucky-box">
<div className="saju-lucky-box__item">
<div className="saju-lucky-box__label">럭키 컬러</div>
<div className="saju-lucky-box__value">{(lucky.color || []).join(' · ')}</div>
</div>
<div className="saju-lucky-box__item">
<div className="saju-lucky-box__label">럭키 숫자</div>
<div className="saju-lucky-box__value">{lucky.number}</div>
</div>
<div className="saju-lucky-box__item">
<div className="saju-lucky-box__label">럭키 방향</div>
<div className="saju-lucky-box__value">{lucky.direction}</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,38 @@
import React from 'react';
const ICON_BY_CATEGORY = {
wealth: '💰',
romance: '💖',
social: '🤝',
career: '💼',
};
const COLOR_VAR_BY_CATEGORY = {
wealth: 'var(--saju-wealth)',
romance: 'var(--saju-romance)',
social: 'var(--saju-social)',
career: 'var(--saju-career)',
};
const TITLE_BY_CATEGORY = {
wealth: '재물운',
romance: '연애운',
social: '인간관계',
career: '직장운',
};
export default function ScoreCard({ category, score }) {
const safe = Math.max(0, Math.min(score || 0, 100));
return (
<div className="saju-score-card">
<div className="saju-score-card__head">
<span className="saju-score-card__icon">{ICON_BY_CATEGORY[category]}</span>
<span className="saju-score-card__title">{TITLE_BY_CATEGORY[category]}</span>
</div>
<div className="saju-score-card__value">{safe}<small style={{ fontSize: '1rem', opacity: 0.5 }}>/100</small></div>
<div className="saju-score-card__bar">
<div style={{ width: `${safe}%`, background: COLOR_VAR_BY_CATEGORY[category] }} />
</div>
</div>
);
}