feat(saju-ui-v2): saju.mobile.jsx — 4탭 (Basic/Chart/Flow/Traits) + 실 schema 매핑
This commit is contained in:
424
src/pages/saju/views/saju.mobile.jsx
Normal file
424
src/pages/saju/views/saju.mobile.jsx
Normal file
@@ -0,0 +1,424 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import TopRibbon from '../_shell/TopRibbon';
|
||||
import TitleBlock from '../_shell/TitleBlock';
|
||||
import Mascot from '../_shell/Mascot';
|
||||
import MascotBubble from '../_shell/MascotBubble';
|
||||
import OrnateFrame from '../_shell/OrnateFrame';
|
||||
import OrnamentBloom from '../_shell/OrnamentBloom';
|
||||
import PrimaryButton from '../_shell/PrimaryButton';
|
||||
import { IconChevron, IconSparkle } from '../_shell/Icons';
|
||||
import deriveTraits from '../_shell/helpers/deriveTraits';
|
||||
import daeunLabel from '../_shell/helpers/daeunLabel';
|
||||
import hexA from '../_shell/helpers/hexA';
|
||||
|
||||
// 한자 element key → english id (deriveTraits 입력 표준화)
|
||||
const HANJA_TO_ID = { '木': 'wood', '火': 'fire', '土': 'earth', '金': 'metal', '水': 'water' };
|
||||
const ID_TO_KO = { wood: '목', fire: '화', earth: '토', metal: '금', water: '수' };
|
||||
const ID_TO_CH = { wood: '木', fire: '火', earth: '土', metal: '金', water: '水' };
|
||||
const ID_TO_COLOR = {
|
||||
wood: '#4E6B5C', fire: '#C04A4A', earth: '#A67B3F',
|
||||
metal: '#D4AF37', water: '#3A5A8C',
|
||||
};
|
||||
|
||||
function elementsByEngId(scores) {
|
||||
if (!scores) return {};
|
||||
const out = {};
|
||||
for (const [hanja, val] of Object.entries(scores)) {
|
||||
const id = HANJA_TO_ID[hanja];
|
||||
if (id) out[id] = val;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function pillarStemColor(saju, pillarKey) {
|
||||
const stem = saju?.[pillarKey]?.stem;
|
||||
// 천간 → 오행 매핑 (간략 — 핵심 색만)
|
||||
const STEM_EL = { '甲':'wood','乙':'wood','丙':'fire','丁':'fire','戊':'earth','己':'earth','庚':'metal','辛':'metal','壬':'water','癸':'water' };
|
||||
return ID_TO_COLOR[STEM_EL[stem]] || '#1F2A44';
|
||||
}
|
||||
|
||||
function pillarBranchColor(saju, pillarKey) {
|
||||
const branch = saju?.[pillarKey]?.branch;
|
||||
const BRANCH_EL = { '子':'water','丑':'earth','寅':'wood','卯':'wood','辰':'earth','巳':'fire','午':'fire','未':'earth','申':'metal','酉':'metal','戌':'earth','亥':'water' };
|
||||
return ID_TO_COLOR[BRANCH_EL[branch]] || '#1F2A44';
|
||||
}
|
||||
|
||||
const TABS = [
|
||||
['basic', '기본정보'],
|
||||
['chart', '사주명식'],
|
||||
['flow', '운세흐름'],
|
||||
['traits', '성향분석'],
|
||||
];
|
||||
|
||||
export default function SajuMobile({ reading }) {
|
||||
const [tab, setTab] = useState('basic');
|
||||
const navigate = useNavigate();
|
||||
const elementsObj = elementsByEngId(reading?.analysis_data?.element_scores);
|
||||
const traits = deriveTraits(elementsObj, []);
|
||||
|
||||
return (
|
||||
<main className="page paper-bg screen-in">
|
||||
<TopRibbon color="#6A4C7C" opacity={0.6} />
|
||||
<div style={{ padding: '8px 24px 0', textAlign: 'center' }}>
|
||||
<TitleBlock gold="#6A4C7C" title="사주풀이"
|
||||
subtitle="당신의 사주를 자세히 풀이해드립니다." />
|
||||
</div>
|
||||
<div style={{ padding: '14px 20px 0', display: 'flex', gap: 8, alignItems: 'flex-end' }}>
|
||||
<MascotBubble tone="purple"
|
||||
text={'당신이 가진 타고난\n기운과 운명의 흐름을\n알려드릴게요.'}
|
||||
style={{ flex: 1, marginBottom: 8 }} />
|
||||
<Mascot variant="full" size={130} style={{ marginRight: -8 }} />
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '14px 16px 0' }}>
|
||||
<div className="no-scrollbar" style={{
|
||||
display: 'flex', gap: 6, overflowX: 'auto',
|
||||
background: 'rgba(247,242,232,0.7)', borderRadius: 999,
|
||||
padding: 4, border: '1px solid rgba(31,42,68,0.08)',
|
||||
}}>
|
||||
{TABS.map(([id, label]) => {
|
||||
const active = tab === id;
|
||||
return (
|
||||
<button key={id} onClick={() => setTab(id)} style={{
|
||||
flex: 1, padding: '10px 8px', borderRadius: 999, border: 'none',
|
||||
background: active ? '#1F2A44' : 'transparent',
|
||||
color: active ? '#F7F2E8' : '#6B6B6B',
|
||||
fontSize: 12, fontWeight: 700, letterSpacing: '-0.02em', whiteSpace: 'nowrap',
|
||||
boxShadow: active ? '0 2px 8px rgba(31,42,68,0.25), inset 0 1px 0 rgba(212,175,55,0.3)' : 'none',
|
||||
transition: 'all .2s',
|
||||
}}>{label}</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '14px 20px 0' }}>
|
||||
{tab === 'basic' && <BasicTab reading={reading} traits={traits} onResult={() => setTab('chart')} />}
|
||||
{tab === 'chart' && <ChartTab reading={reading} elementsObj={elementsObj} />}
|
||||
{tab === 'flow' && <FlowTab reading={reading} />}
|
||||
{tab === 'traits' && <TraitsTab traits={traits} onToday={() => navigate(`/saju/today?rid=${reading?.id || ''}`)} />}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function BasicTab({ reading, traits, onResult }) {
|
||||
const r = reading || {};
|
||||
const rows = [
|
||||
['생년월일', `${r.birth_year}년 ${r.birth_month}월 ${r.birth_day}일 (${r.calendar_type === 'lunar' ? '음력' : '양력'})`],
|
||||
['시간', r.birth_hour != null ? `${r.birth_hour}시` : '시간 미상'],
|
||||
['성별', r.gender === 'female' ? '여' : '남'],
|
||||
['사주', [r.saju_data?.year, r.saju_data?.month, r.saju_data?.day, r.saju_data?.hour].filter(Boolean).map((p) => `${p.stem}${p.branch}`).join(' ') || '-'],
|
||||
];
|
||||
const summary = reading?.interpretation_json?.summary || '풀이 결과를 준비 중입니다.';
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)',
|
||||
boxShadow: 'var(--shadow-card)', overflow: 'hidden',
|
||||
}}>
|
||||
{rows.map(([label, value], idx) => (
|
||||
<div key={label} style={{
|
||||
display: 'flex', alignItems: 'center', padding: '13px 16px',
|
||||
borderBottom: idx === rows.length - 1 ? 'none' : '1px solid rgba(31,42,68,0.06)',
|
||||
}}>
|
||||
<div style={{ width: 80, fontSize: 12, color: '#6B6B6B', fontWeight: 700 }}>{label}</div>
|
||||
<div style={{ flex: 1, fontSize: 13, color: '#1F2A44' }}>{value || '-'}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<OrnateFrame color="#6A4C7C" bg="#FBF7EF" radius={14} padding="20px 18px 16px" style={{ marginTop: 14 }}>
|
||||
<div className="font-title" style={{
|
||||
fontSize: 13, color: '#6A4C7C', textAlign: 'center', marginBottom: 6,
|
||||
}}>사주 요약</div>
|
||||
<div style={{
|
||||
fontSize: 13, color: '#1F2A44', lineHeight: 1.75, textAlign: 'center', whiteSpace: 'pre-line',
|
||||
}}>{summary}</div>
|
||||
</OrnateFrame>
|
||||
|
||||
<div style={{
|
||||
marginTop: 14, background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)', padding: '16px 12px',
|
||||
boxShadow: 'var(--shadow-card)',
|
||||
}}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 6 }}>
|
||||
{traits.slice(0, 5).map((t) => (<TraitChip key={t.id} {...t} />))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<PrimaryButton color="#6A4C7C" onClick={onResult}>
|
||||
상세 풀이 보러가기
|
||||
<IconChevron dir="right" size={14} color="#E8C76B" />
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TraitChip({ ko, color }) {
|
||||
// color는 'var(--el-fire)' 같은 CSS var. swatch에 직접 사용.
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, padding: '10px 4px 8px',
|
||||
}}>
|
||||
<div style={{
|
||||
width: 42, height: 42, borderRadius: '50%',
|
||||
background: 'rgba(106,76,124,0.06)',
|
||||
border: `1px solid ${color}`,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
color, fontSize: 18, fontWeight: 800,
|
||||
}}>●</div>
|
||||
<span style={{ fontSize: 11, color: '#1F2A44', fontWeight: 700, letterSpacing: '-0.02em' }}>{ko}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ChartTab({ reading, elementsObj }) {
|
||||
const saju = reading?.saju_data || {};
|
||||
const ohaengArr = ['wood', 'fire', 'earth', 'metal', 'water'].map((id) => ({
|
||||
id, ko: ID_TO_KO[id], ch: ID_TO_CH[id],
|
||||
value: Math.round(elementsObj?.[id] || 0),
|
||||
color: ID_TO_COLOR[id],
|
||||
}));
|
||||
const strongest = ohaengArr.reduce((a, b) => (a.value > b.value ? a : b), { value: 0 });
|
||||
const dms = reading?.analysis_data?.day_master_strength;
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)', boxShadow: 'var(--shadow-card)',
|
||||
padding: '14px 12px 12px',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 10, padding: '0 6px' }}>
|
||||
<OrnamentBloom size={14} color="#6A4C7C" />
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: '#1F2A44' }}>사주 명식</span>
|
||||
<span style={{ fontSize: 10, color: '#9A968D', marginLeft: 'auto' }}>일간 중심 해석</span>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
|
||||
{['year', 'month', 'day', 'hour'].map((pk) => (
|
||||
<PillarColumn key={pk} pillarKey={pk}
|
||||
pillar={saju[pk]}
|
||||
stemColor={pillarStemColor(saju, pk)}
|
||||
branchColor={pillarBranchColor(saju, pk)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
marginTop: 14, background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)', boxShadow: 'var(--shadow-card)',
|
||||
padding: '16px 16px 14px',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 12 }}>
|
||||
<OrnamentBloom size={14} color="#6A4C7C" />
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: '#1F2A44' }}>오행 분석</span>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
|
||||
height: 110, gap: 4,
|
||||
}}>
|
||||
{ohaengArr.map((o) => (<OhaengBar key={o.id} {...o} />))}
|
||||
</div>
|
||||
{strongest.value > 0 && (
|
||||
<div style={{
|
||||
marginTop: 12, padding: '10px 12px',
|
||||
background: hexA('#C04A4A', 0.06), borderRadius: 8,
|
||||
border: `1px solid ${hexA(strongest.color, 0.25)}`,
|
||||
}}>
|
||||
<div style={{ fontSize: 12, fontWeight: 700, color: strongest.color, marginBottom: 4 }}>
|
||||
{strongest.ko}({strongest.ch})의 기운이 강한 사주입니다.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{dms && (
|
||||
<div style={{
|
||||
marginTop: 10, padding: '10px 12px',
|
||||
background: 'rgba(106,76,124,0.06)', borderRadius: 8,
|
||||
border: '1px dashed rgba(106,76,124,0.25)',
|
||||
}}>
|
||||
<div style={{ fontSize: 12, fontWeight: 700, color: '#6A4C7C', marginBottom: 4 }}>
|
||||
일간 강도: {dms.result} · {dms.score}점
|
||||
</div>
|
||||
{dms.reasons && dms.reasons.length > 0 && (
|
||||
<div style={{ fontSize: 11, color: '#6B6B6B', lineHeight: 1.55 }}>
|
||||
{dms.reasons.join(' · ')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const PILLAR_LABELS = { year: '년주', month: '월주', day: '일주', hour: '시주' };
|
||||
|
||||
function PillarColumn({ pillarKey, pillar, stemColor, branchColor }) {
|
||||
const isDay = pillarKey === 'day';
|
||||
if (!pillar) {
|
||||
return (
|
||||
<div style={{ padding: '8px 4px 10px', textAlign: 'center', color: '#9A968D', fontSize: 11 }}>
|
||||
{PILLAR_LABELS[pillarKey]}<br />-
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div style={{
|
||||
borderRadius: 10, padding: '8px 4px 10px',
|
||||
background: isDay ? '#FBF7EF' : 'transparent',
|
||||
border: isDay ? '1.5px solid #6A4C7C' : '1px solid rgba(31,42,68,0.06)',
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, position: 'relative',
|
||||
}}>
|
||||
{isDay && (
|
||||
<div style={{
|
||||
position: 'absolute', top: -10, left: '50%', transform: 'translateX(-50%)',
|
||||
background: '#6A4C7C', color: '#F7F2E8',
|
||||
fontSize: 10, fontWeight: 700, padding: '2px 10px', borderRadius: 99,
|
||||
}}>일간</div>
|
||||
)}
|
||||
<div style={{ fontSize: 10, color: '#6B6B6B', fontWeight: 700, marginTop: 2 }}>{PILLAR_LABELS[pillarKey]}</div>
|
||||
<CharBox char={pillar.stem} sub={pillar.stem_kr} color={stemColor} />
|
||||
<CharBox char={pillar.branch} sub={pillar.branch_kr} color={branchColor} />
|
||||
<div style={{ width: '100%', height: 1, background: 'rgba(31,42,68,0.08)' }} />
|
||||
<div style={{ fontSize: 10, color: '#6B6B6B' }}>{pillar.ten_god || '-'}</div>
|
||||
<div style={{ fontSize: 10, color: '#9A968D' }}>{pillar.fortune || ''}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CharBox({ char, sub, color }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
|
||||
<div className="font-title" style={{ fontSize: 24, color, lineHeight: 1, fontWeight: 800 }}>{char || '?'}</div>
|
||||
<div style={{ fontSize: 8.5, color, opacity: 0.85, fontWeight: 700 }}>{sub || ''}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function OhaengBar({ ko, ch, value, color }) {
|
||||
return (
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%' }}>
|
||||
<div style={{ flex: 1, width: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
|
||||
<div style={{ fontSize: 10, color, fontWeight: 700, textAlign: 'center', marginBottom: 2 }}>{value}%</div>
|
||||
<div style={{
|
||||
width: '70%', margin: '0 auto', height: `${value}%`, minHeight: 4,
|
||||
background: color, borderRadius: '6px 6px 2px 2px',
|
||||
boxShadow: `0 -2px 6px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.3)`,
|
||||
}} />
|
||||
</div>
|
||||
<div style={{ marginTop: 6, fontSize: 11, color: '#1F2A44', fontWeight: 700 }}>
|
||||
{ko}<span style={{ fontSize: 9, color: '#9A968D', marginLeft: 2 }}>({ch})</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FlowTab({ reading }) {
|
||||
const daeun = reading?.daeun_data || [];
|
||||
const currentYear = new Date().getFullYear();
|
||||
const enriched = daeun.map((d) => ({
|
||||
...d,
|
||||
label: daeunLabel(d.age),
|
||||
current: d.start_year <= currentYear && currentYear <= d.end_year,
|
||||
}));
|
||||
const current = enriched.find((x) => x.current);
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)', boxShadow: 'var(--shadow-card)',
|
||||
padding: '16px 14px',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
|
||||
<OrnamentBloom size={14} color="#6A4C7C" />
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: '#1F2A44' }}>대운 흐름</span>
|
||||
<span style={{ marginLeft: 'auto', fontSize: 10, color: '#9A968D' }}>10년 단위</span>
|
||||
</div>
|
||||
<div style={{ fontSize: 11, color: '#6B6B6B', marginBottom: 12 }}>
|
||||
10년 주기로 변화하는 운의 흐름을 확인하세요.
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8 }}>
|
||||
{enriched.map((du, i) => (<DaeunNode key={i} {...du} />))}
|
||||
</div>
|
||||
</div>
|
||||
{current && (
|
||||
<div style={{
|
||||
marginTop: 14, background: '#1F2A44', borderRadius: 14,
|
||||
border: '1px solid rgba(212,175,55,0.4)',
|
||||
padding: '16px 16px 18px', color: '#F7F2E8',
|
||||
boxShadow: '0 8px 24px rgba(31,42,68,0.2)', position: 'relative',
|
||||
}}>
|
||||
<div style={{
|
||||
position: 'absolute', top: -10, left: 16,
|
||||
background: '#6A4C7C', color: '#F7F2E8',
|
||||
fontSize: 10, fontWeight: 700, padding: '3px 10px',
|
||||
borderRadius: 99, border: '1px solid rgba(212,175,55,0.5)',
|
||||
}}>현재 대운 · {current.age}~{current.age + 9}세</div>
|
||||
<div className="font-title" style={{ marginTop: 8, fontSize: 18, color: '#E8C76B' }}>
|
||||
{current.stem}{current.branch} · {current.label}
|
||||
</div>
|
||||
<div style={{ marginTop: 10, fontSize: 12.5, color: '#D9D2C0', lineHeight: 1.7 }}>
|
||||
{current.start_year}년 ~ {current.end_year}년 — 이 시기는 {current.label} 단계로,
|
||||
10년 간의 운기 흐름을 차분히 살펴보세요.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DaeunNode({ age, stem, label, current }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, position: 'relative' }}>
|
||||
{current && (
|
||||
<div style={{
|
||||
position: 'absolute', top: -6, left: '50%', transform: 'translateX(-50%)',
|
||||
fontSize: 8, fontWeight: 700, color: '#F7F2E8', background: '#6A4C7C',
|
||||
padding: '1px 6px', borderRadius: 99, zIndex: 1,
|
||||
}}>현재</div>
|
||||
)}
|
||||
<div style={{ fontSize: 9.5, color: '#9A968D', marginTop: current ? 8 : 0, fontWeight: 700 }}>{age}세</div>
|
||||
<div style={{
|
||||
width: 42, height: 50, borderRadius: '50% 50% 40% 40%',
|
||||
background: current ? '#6A4C7C' : '#FBF7EF',
|
||||
border: current ? '1.5px solid #D4AF37' : '1px solid rgba(31,42,68,0.12)',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
boxShadow: current ? '0 4px 12px rgba(106,76,124,0.4)' : 'none',
|
||||
}}>
|
||||
<span className="font-title" style={{ fontSize: 20, color: current ? '#E8C76B' : '#1F2A44' }}>{stem}</span>
|
||||
</div>
|
||||
<div style={{ fontSize: 10, color: current ? '#6A4C7C' : '#6B6B6B', fontWeight: current ? 700 : 500 }}>{label}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TraitsTab({ traits, onToday }) {
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
background: '#FBF7EF', borderRadius: 14,
|
||||
border: '1px solid rgba(31,42,68,0.10)', boxShadow: 'var(--shadow-card)',
|
||||
padding: '16px 12px',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 12, padding: '0 6px' }}>
|
||||
<OrnamentBloom size={14} color="#6A4C7C" />
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: '#1F2A44' }}>타고난 성향</span>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
|
||||
{traits.map((t) => (<TraitChip key={t.id} {...t} />))}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<PrimaryButton color="#6A4C7C" onClick={onToday}>
|
||||
오늘의 운세 확인하기
|
||||
<IconSparkle size={12} color="#E8C76B" />
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user