feat(saju): 오늘운세 컴포넌트 3개 (FortuneRing + ScoreCard + LuckyBox)
This commit is contained in:
32
src/pages/saju/components/FortuneRing.jsx
Normal file
32
src/pages/saju/components/FortuneRing.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
21
src/pages/saju/components/LuckyBox.jsx
Normal file
21
src/pages/saju/components/LuckyBox.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
38
src/pages/saju/components/ScoreCard.jsx
Normal file
38
src/pages/saju/components/ScoreCard.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user