feat: 음력 변환, 대운 계산, 소셜 공유 기능 추가

- 음력 변환 기능 구현
  - lunar-calendar 라이브러리 추가
  - 음력-양력 변환 유틸리티 생성
  - 모든 입력 폼에 양력/음력 선택 및 윤달 옵션 추가
  - SajuForm, CompatibilityForm에 음력 지원

- 대운(大運) 계산 기능 구현
  - 10년 단위 대운 계산 알고리즘
  - 현재 대운 표시 및 해석
  - 사주팔자 결과 페이지에 대운 섹션 추가
  - 8개 대운 (80년치) 표시

- 소셜 공유 기능 구현
  - ShareButtons 컴포넌트 생성
  - 카카오톡, 페이스북, 트위터 공유
  - 네이티브 공유 API 지원
  - 링크 복사 기능
  - 모든 결과 페이지에 공유 버튼 추가

- 메타데이터 개선
  - 사이트 제목 및 설명 최적화
  - 한국어(ko) 설정
  - 카카오 SDK 추가

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 23:57:53 +09:00
parent f85e857bea
commit affbdf1a44
11 changed files with 695 additions and 16 deletions

135
lib/daeun-calculator.ts Normal file
View File

@@ -0,0 +1,135 @@
import { HEAVENLY_STEMS, EARTHLY_BRANCHES, HEAVENLY_STEMS_KR, EARTHLY_BRANCHES_KR } from './saju-calculator';
/**
* 대운 (大運) 정보
*/
export interface DaeunPillar {
age: number; // 시작 나이
startYear: number; // 시작 년도
endYear: number; // 끝 년도
stem: string; // 천간
branch: string; // 지지
stemKr: string; // 천간 한글
branchKr: string; // 지지 한글
}
/**
* 대운 계산
* @param birthYear 생년
* @param birthMonth 생월
* @param birthDay 생일
* @param gender 성별
* @param monthStem 월주 천간 인덱스
* @param monthBranch 월주 지지 인덱스
* @returns 대운 배열 (10년 단위)
*/
export function calculateDaeun(
birthYear: number,
birthMonth: number,
birthDay: number,
gender: 'male' | 'female',
monthStem: string,
monthBranch: string
): DaeunPillar[] {
const monthStemIndex = HEAVENLY_STEMS.indexOf(monthStem as any);
const monthBranchIndex = EARTHLY_BRANCHES.indexOf(monthBranch as any);
if (monthStemIndex === -1 || monthBranchIndex === -1) {
return [];
}
// 양남음녀(陽男陰女)는 순행, 음남양녀(陰男陽女)는 역행
const yearStemIndex = (birthYear - 1900 + 6) % 10;
const isYangYear = yearStemIndex % 2 === 0; // 양년
let isForward: boolean;
if (gender === 'male') {
isForward = isYangYear; // 양남: 순행, 음남: 역행
} else {
isForward = !isYangYear; // 양녀: 역행, 음녀: 순행
}
// 대운 시작 나이 계산 (간단화: 평균 8세로 설정)
// 실제로는 절입일부터 생일까지의 일수를 계산해야 하지만 복잡하므로 단순화
const startAge = 8;
const daeunList: DaeunPillar[] = [];
for (let i = 0; i < 8; i++) {
const age = startAge + (i * 10);
const startYear = birthYear + age;
const endYear = startYear + 9;
let stemIndex: number;
let branchIndex: number;
if (isForward) {
// 순행: 월주에서 증가
stemIndex = (monthStemIndex + i + 1) % 10;
branchIndex = (monthBranchIndex + i + 1) % 12;
} else {
// 역행: 월주에서 감소
stemIndex = (monthStemIndex - i - 1 + 100) % 10;
branchIndex = (monthBranchIndex - i - 1 + 120) % 12;
}
daeunList.push({
age,
startYear,
endYear,
stem: HEAVENLY_STEMS[stemIndex],
branch: EARTHLY_BRANCHES[branchIndex],
stemKr: HEAVENLY_STEMS_KR[stemIndex],
branchKr: EARTHLY_BRANCHES_KR[branchIndex]
});
}
return daeunList;
}
/**
* 현재 대운 찾기
* @param daeunList 대운 목록
* @param currentYear 현재 년도
*/
export function getCurrentDaeun(daeunList: DaeunPillar[], currentYear: number): DaeunPillar | null {
for (const daeun of daeunList) {
if (currentYear >= daeun.startYear && currentYear <= daeun.endYear) {
return daeun;
}
}
return null;
}
/**
* 대운 해석
* @param daeun 대운 정보
* @param dayStem 일간
*/
export function getDaeunDescription(daeun: DaeunPillar, dayStem: string): string {
const age = daeun.age;
const ganzi = `${daeun.stem}${daeun.branch}`;
let description = `${age}세부터 ${age + 9}세까지의 10년은 ${daeun.stemKr}${daeun.branchKr}(${ganzi}) 대운입니다. `;
// 대운 천간과 일간의 관계에 따른 기본 해석
const stemIndex = HEAVENLY_STEMS.indexOf(daeun.stem as any);
if (age < 20) {
description += '청소년기로 학업과 기초를 다지는 시기입니다. ';
} else if (age < 40) {
description += '성장과 발전의 시기로 사회활동이 왕성한 때입니다. ';
} else if (age < 60) {
description += '안정과 성숙의 시기로 경험이 쌓이는 때입니다. ';
} else {
description += '원숙한 시기로 인생의 지혜를 나누는 때입니다. ';
}
if (stemIndex % 2 === 0) {
description += '적극적이고 외향적인 활동이 유리합니다.';
} else {
description += '차분하고 내실을 다지는 것이 좋습니다.';
}
return description;
}

97
lib/lunar-utils.ts Normal file
View File

@@ -0,0 +1,97 @@
/**
* 음력-양력 변환 유틸리티
*/
interface LunarDate {
year: number;
month: number;
day: number;
isLeap: boolean;
}
interface SolarDate {
year: number;
month: number;
day: number;
}
/**
* 음력을 양력으로 변환
* @param lunarYear 음력 년
* @param lunarMonth 음력 월
* @param lunarDay 음력 일
* @param isLeapMonth 윤달 여부
*/
export function lunarToSolar(
lunarYear: number,
lunarMonth: number,
lunarDay: number,
isLeapMonth: boolean = false
): SolarDate {
try {
const lunar = require('lunar-calendar');
const result = lunar.lunarToSolar(lunarYear, lunarMonth, lunarDay, isLeapMonth);
return {
year: result.year,
month: result.month,
day: result.day
};
} catch (error) {
console.error('음력 변환 오류:', error);
// 변환 실패시 입력값 그대로 반환
return {
year: lunarYear,
month: lunarMonth,
day: lunarDay
};
}
}
/**
* 양력을 음력으로 변환
* @param solarYear 양력 년
* @param solarMonth 양력 월
* @param solarDay 양력 일
*/
export function solarToLunar(
solarYear: number,
solarMonth: number,
solarDay: number
): LunarDate {
try {
const lunar = require('lunar-calendar');
const result = lunar.solarToLunar(solarYear, solarMonth, solarDay);
return {
year: result.year,
month: result.month,
day: result.day,
isLeap: result.isLeap || false
};
} catch (error) {
console.error('양력 변환 오류:', error);
// 변환 실패시 입력값 그대로 반환
return {
year: solarYear,
month: solarMonth,
day: solarDay,
isLeap: false
};
}
}
/**
* 음력 날짜를 문자열로 변환
*/
export function formatLunarDate(lunar: LunarDate): string {
const leapText = lunar.isLeap ? '윤' : '';
return `음력 ${lunar.year}${leapText}${lunar.month}${lunar.day}`;
}
/**
* 양력 날짜를 문자열로 변환
*/
export function formatSolarDate(solar: SolarDate): string {
return `양력 ${solar.year}${solar.month}${solar.day}`;
}