feat(saju-ui-v2): match.mobile.jsx — 두 사람 입력 폼 (PersonForm + IconHeart)
This commit is contained in:
108
src/pages/saju/views/match.mobile.jsx
Normal file
108
src/pages/saju/views/match.mobile.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React from 'react';
|
||||
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 PrimaryButton from '../_shell/PrimaryButton';
|
||||
import InputRow from '../_shell/InputRow';
|
||||
import { IconHeart, IconSparkle } from '../_shell/Icons';
|
||||
|
||||
const inputStyle = {
|
||||
flex: 1, padding: '8px 10px', border: '1px solid rgba(31,42,68,0.12)',
|
||||
borderRadius: 8, background: '#FBF7EF', fontSize: 13, color: '#1F2A44',
|
||||
fontFamily: 'inherit',
|
||||
};
|
||||
|
||||
function pad(n) { return String(n).padStart(2, '0'); }
|
||||
function dateValue(p) {
|
||||
if (!p.year || !p.month || !p.day) return '';
|
||||
return `${p.year}-${pad(p.month)}-${pad(p.day)}`;
|
||||
}
|
||||
function timeValue(p) {
|
||||
if (p.hour === '' || p.hour == null) return '';
|
||||
return `${pad(p.hour)}:00`;
|
||||
}
|
||||
function onDate(p, set, e) {
|
||||
const v = e.target.value;
|
||||
if (!v) return set({ ...p, year: '', month: '', day: '' });
|
||||
const [y, m, d] = v.split('-');
|
||||
set({ ...p, year: parseInt(y, 10), month: parseInt(m, 10), day: parseInt(d, 10) });
|
||||
}
|
||||
function onTime(p, set, e) {
|
||||
const v = e.target.value;
|
||||
if (!v) return set({ ...p, hour: null });
|
||||
const [h] = v.split(':');
|
||||
set({ ...p, hour: parseInt(h, 10) });
|
||||
}
|
||||
|
||||
function PersonForm({ label, person, onChange }) {
|
||||
return (
|
||||
<OrnateFrame color="#4E6B5C" bg="#FBF7EF" radius={14} padding="14px 16px">
|
||||
<div className="font-title" style={{
|
||||
fontSize: 14, color: '#4E6B5C', textAlign: 'center', marginBottom: 8,
|
||||
}}>{label}</div>
|
||||
<InputRow label="이름">
|
||||
<input value={person.name || ''}
|
||||
onChange={(e) => onChange({ ...person, name: e.target.value })}
|
||||
placeholder="홍길동" style={inputStyle} />
|
||||
</InputRow>
|
||||
<InputRow label="생년월일">
|
||||
<input type="date" value={dateValue(person)}
|
||||
onChange={(e) => onDate(person, onChange, e)} style={inputStyle} />
|
||||
</InputRow>
|
||||
<InputRow label="시간">
|
||||
<input type="time" value={timeValue(person)}
|
||||
onChange={(e) => onTime(person, onChange, e)} style={inputStyle} />
|
||||
</InputRow>
|
||||
<InputRow label="성별">
|
||||
<select value={person.gender}
|
||||
onChange={(e) => onChange({ ...person, gender: e.target.value })}
|
||||
style={inputStyle}>
|
||||
<option value="male">남</option>
|
||||
<option value="female">여</option>
|
||||
</select>
|
||||
</InputRow>
|
||||
<InputRow label="달력">
|
||||
<select value={person.calendar_type}
|
||||
onChange={(e) => onChange({ ...person, calendar_type: e.target.value })}
|
||||
style={inputStyle}>
|
||||
<option value="solar">양력</option>
|
||||
<option value="lunar">음력</option>
|
||||
</select>
|
||||
</InputRow>
|
||||
</OrnateFrame>
|
||||
);
|
||||
}
|
||||
|
||||
export default function MatchMobile({ personA, personB, onChangeA, onChangeB, onSubmit, loading, error }) {
|
||||
return (
|
||||
<main className="page paper-bg screen-in">
|
||||
<TopRibbon color="#4E6B5C" opacity={0.6} />
|
||||
<div style={{ padding: '8px 24px 0', textAlign: 'center' }}>
|
||||
<TitleBlock title="궁합 보기" gold="#4E6B5C"
|
||||
subtitle="두 사람의 사주를 입력하면 만남의 흐름을 알려드려요." />
|
||||
</div>
|
||||
<div style={{ padding: '14px 20px 0', display: 'flex', gap: 8, alignItems: 'flex-end' }}>
|
||||
<MascotBubble tone="green"
|
||||
text={'두 사주를 비교해\n어울리는 결을\n읽어드릴게요.'}
|
||||
style={{ flex: 1, marginBottom: 8 }} />
|
||||
<Mascot variant="upper" size={120} style={{ marginRight: -8 }} />
|
||||
</div>
|
||||
<form onSubmit={onSubmit} style={{ padding: '24px 20px 40px', display: 'grid', gap: 14 }}>
|
||||
<PersonForm label="사람 A" person={personA} onChange={onChangeA} />
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<IconHeart size={28} stroke="#4E6B5C" strokeWidth={2} />
|
||||
</div>
|
||||
<PersonForm label="사람 B" person={personB} onChange={onChangeB} />
|
||||
{error && (
|
||||
<div style={{ color: '#C04A4A', fontSize: 12, textAlign: 'center' }}>{error}</div>
|
||||
)}
|
||||
<PrimaryButton color="#4E6B5C" type="submit">
|
||||
{loading ? '호령이 두 사주를 비교 중...' : '궁합 보기'}
|
||||
{!loading && <IconSparkle size={12} color="#E8C76B" />}
|
||||
</PrimaryButton>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user