@lichta/core 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants/heavenly-stems.ts","../src/constants/earthly-branches.ts","../src/core/lunar.ts","../src/constants/five-elements.ts","../src/core/feng-shui.ts","../src/utils/format.ts","../src/constants/i18n.ts"],"sourcesContent":["/**\n * Heavenly Stems (Thiên Can)\n * Giáp (Dương) | Wood\n * Ất (Âm) | Wood\n * Bính (Dương) | Fire\n * Đinh (Âm) | Fire\n * Mậu (Dương) | Earth\n * Kỷ (Âm) | Earth\n * Canh (Dương) | Metal\n * Tân (Âm) | Metal\n * Nhâm (Dương) | Water\n * Quý (Âm) | Water\n */\nexport const HEAVENLY_STEMS = [\n 'Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu',\n 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'\n] as const;\n\n/**\n * Tính trọng số của Thiên Can (dùng để tính Ngũ Hành)\n * Index: 0, 1 -> 1 | 2, 3 -> 2 | ... | 8, 9 -> 5\n */\nexport function getStemWeight(index: number): number {\n return Math.floor(index / 2) + 1;\n}","/**\n * Earthly Branches (Địa Chi - 12 con giáp)\n * Tý | Rat (Chuột)\n * Sửu | Ox (Trâu)\n * Dần | Tiger (Cọp)\n * Mão | Rabbit (Thỏ)\n * Thìn | Dragon (Rồng)\n * Tỵ | Snake (Rắn)\n * Ngọ | Horse (Ngựa)\n * Mùi | Goat (Dê)\n * Thân | Monkey (Khỉ)\n * Dậu | Rooster (Gà)\n * Tuất | Dog (Chó)\n * Hợi | Pig (Heo)\n */\nexport const EARTHLY_BRANCHES = [\n 'Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ',\n 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'\n] as const;\n\n/**\n * Tính trọng số của Địa Chi (dùng để tính Ngũ Hành)\n * Chu kỳ lặp lại sau mỗi 6 Chi (index % 6)\n */\nexport function getBranchWeight(index: number): number {\n const normalizedIndex = index % 6;\n return Math.floor(normalizedIndex / 2);\n}\n\n/**\n * Tính Dương - Âm (Yin - Yang) cho Địa Chi\n * Index: 0 -> 1 (Dương) | 1 -> 0 (Âm) | ...\n */\nexport function getBranchYinYang(index: number): 1 | 0 {\n return (index % 2 === 0) ? 1 : 0;\n}\n\n/**\n * Tính Ngũ Hành cho Địa Chi\n * Tý: 1 (Thủy Dương), Sửu: 12 (Thổ Âm), Dần: 3 (Mộc Dương), ...\n */\nexport function getBranchElement(index: number): number {\n const weight = Math.floor(index / 2) + 1;\n return weight === 5 ? 1 : weight;\n}","import type { LunarDate, SolarDate } from './types.js';\nimport { HEAVENLY_STEMS } from '../constants/heavenly-stems.js';\nimport { EARTHLY_BRANCHES } from '../constants/earthly-branches.js';\n\n/**\n * Thuật toán chuyển đổi Dương lịch ↔ Âm lịch Việt Nam\n * Dựa trên công trình của Hồ Ngọc Đức (Đại học Leipzig)\n * Tham khảo: Jean Meeus, \"Astronomical Algorithms\" (1998)\n *\n * Copyright (c) 2006 Ho Ngoc Duc. All Rights Reserved.\n * TypeScript adaptation for Lichta library.\n */\n\nconst PI = Math.PI;\n\nfunction INT(d: number): number {\n return Math.floor(d);\n}\n\n// ============================================================\n// Julian Day Number\n// ============================================================\n\n/**\n * Chuyển ngày Gregorian sang Julian Day Number.\n *\n * @param dd - Ngày (1-31)\n * @param mm - Tháng (1-12)\n * @param yy - Năm\n */\nexport function jdFromDate(dd: number, mm: number, yy: number): number {\n const a = INT((14 - mm) / 12);\n const y = yy + 4800 - a;\n const m = mm + 12 * a - 3;\n let jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - INT(y / 100) + INT(y / 400) - 32045;\n if (jd < 2299161) {\n jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - 32083;\n }\n return jd;\n}\n\n/**\n * Chuyển Julian Day Number sang ngày Gregorian.\n *\n * @param jd - Julian Day Number\n * @returns Tuple [day, month, year]\n */\nexport function jdToDate(jd: number): [number, number, number] {\n let a: number, b: number, c: number;\n if (jd > 2299160) {\n a = jd + 32044;\n b = INT((4 * a + 3) / 146097);\n c = a - INT((b * 146097) / 4);\n } else {\n b = 0;\n c = jd + 32082;\n }\n const d = INT((4 * c + 3) / 1461);\n const e = c - INT((1461 * d) / 4);\n const m = INT((5 * e + 2) / 153);\n const day = e - INT((153 * m + 2) / 5) + 1;\n const month = m + 3 - 12 * INT(m / 10);\n const year = b * 100 + d - 4800 + INT(m / 10);\n return [day, month, year];\n}\n\n// ============================================================\n// Điểm Sóc (New Moon) — Thuật toán Hồ Ngọc Đức / Jean Meeus\n// ============================================================\n\n/**\n * Tính thời điểm điểm Sóc (New Moon) thứ k\n * (đo bằng số ngày Julian kể từ 1/1/4713 BC trưa UTC).\n *\n * k=0 tương ứng New Moon ngày 1/1/1900 13:52 UTC.\n *\n * @param k - Số thứ tự New Moon\n */\nfunction NewMoon(k: number): number {\n const T = k / 1236.85;\n const T2 = T * T;\n const T3 = T2 * T;\n const dr = PI / 180;\n\n let Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;\n Jd1 = Jd1 + 0.00033 * Math.sin((166.56 + 132.87 * T - 0.009173 * T2) * dr);\n\n // Mean anomaly của Mặt Trời\n const M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3;\n // Mean anomaly của Mặt Trăng\n const Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3;\n // Argument of latitude của Mặt Trăng\n const F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3;\n\n // Hiệu chỉnh\n let C1 = (0.1734 - 0.000393 * T) * Math.sin(M * dr) + 0.0021 * Math.sin(2 * dr * M);\n C1 = C1 - 0.4068 * Math.sin(Mpr * dr) + 0.0161 * Math.sin(dr * 2 * Mpr);\n C1 = C1 - 0.0004 * Math.sin(dr * 3 * Mpr);\n C1 = C1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (M + Mpr));\n C1 = C1 - 0.0074 * Math.sin(dr * (M - Mpr)) + 0.0004 * Math.sin(dr * (2 * F + M));\n C1 = C1 - 0.0004 * Math.sin(dr * (2 * F - M)) - 0.0006 * Math.sin(dr * (2 * F + Mpr));\n C1 = C1 + 0.001 * Math.sin(dr * (2 * F - Mpr)) + 0.0005 * Math.sin(dr * (2 * Mpr + M));\n\n const JdNew = Jd1 + C1;\n return JdNew;\n}\n\n/**\n * Tính ngày Julian (integer) của điểm Sóc thứ k theo múi giờ.\n *\n * @param k - Số thứ tự New Moon\n * @param timeZone - Múi giờ (7 = GMT+7)\n */\nexport function getNewMoonDay(k: number, timeZone: number): number {\n return INT(NewMoon(k) + 0.5 + timeZone / 24);\n}\n\n// ============================================================\n// Kinh độ Mặt Trời (Sun Longitude)\n// ============================================================\n\n/**\n * Tính kinh độ Mặt Trời tại ngày Julian cho trước.\n * Trả về index 0-11 (mỗi 30°), dùng để xác định Trung khí.\n *\n * Index 9 = Đông Chí (270°-300°)\n *\n * @param jdn - Julian Day Number\n * @param timeZone - Múi giờ\n */\nexport function getSunLongitude(jdn: number, timeZone: number): number {\n const T = (jdn - 2451545.5 - timeZone / 24) / 36525;\n const T2 = T * T;\n const dr = PI / 180;\n\n // Mean longitude\n const M = 357.5291 + 35999.0503 * T - 0.0001559 * T2 - 0.00000048 * T * T2;\n\n // Mean longitude\n const L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2;\n\n let DL = (1.9146 - 0.004817 * T - 0.000014 * T2) * Math.sin(dr * M);\n DL = DL + (0.019993 - 0.000101 * T) * Math.sin(dr * 2 * M) + 0.00029 * Math.sin(dr * 3 * M);\n\n let L = L0 + DL;\n // Chuẩn hóa\n L = L - 360 * INT(L / 360);\n return INT(L / 30);\n}\n\n// ============================================================\n// Tháng 11 âm lịch & Tháng nhuận\n// ============================================================\n\n/**\n * Tìm JDN của mùng 1 tháng 11 âm lịch (tháng chứa Đông Chí).\n */\nfunction getLunarMonth11(yy: number, timeZone: number): number {\n const off = jdFromDate(31, 12, yy) - 2415021.076998695;\n const k = INT(off / 29.530588853);\n let nm = getNewMoonDay(k, timeZone);\n const sunLong = getSunLongitude(nm, timeZone);\n if (sunLong >= 9) {\n nm = getNewMoonDay(k - 1, timeZone);\n }\n return nm;\n}\n\n/**\n * Tìm offset tháng nhuận (tháng đầu tiên không chứa Trung khí\n * giữa 2 tháng 11 âm lịch liên tiếp).\n */\nfunction getLeapMonthOffset(a11: number, timeZone: number): number {\n const k = INT((a11 - 2415021.076998695) / 29.530588853 + 0.5);\n let last: number;\n let i = 1;\n let arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);\n last = arc;\n while (i < 14) {\n i++;\n arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);\n if (arc !== last) {\n last = arc;\n } else {\n // 2 tháng liên tiếp cùng Trung khí → tháng trước đó là tháng nhuận\n break;\n }\n }\n return i - 1;\n}\n\n// ============================================================\n// Can Chi helpers\n// ============================================================\n\nfunction getYearCanChi(lunarYear: number): string {\n const stemIndex = (lunarYear + 6) % 10;\n const branchIndex = (lunarYear + 8) % 12;\n return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;\n}\n\nfunction getMonthCanChiInternal(lunarMonth: number, lunarYear: number): string {\n const yearStemIndex = (lunarYear + 6) % 10;\n const monthStemOffset = (yearStemIndex % 5) * 2 + 2;\n const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;\n const monthBranchIndex = (lunarMonth + 1) % 12;\n return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;\n}\n\nfunction getDayCanChiInternal(jd: number): string {\n const stemIndex = (jd + 9) % 10;\n const branchIndex = (jd + 1) % 12;\n return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;\n}\n\n// ============================================================\n// LichTa — Public API\n// ============================================================\n\nexport class LichTa {\n /**\n * Chuyển đổi ngày Dương lịch sang Âm lịch.\n *\n * Sử dụng thuật toán Hồ Ngọc Đức để tìm Điểm Sóc và Tiết Khí,\n * từ đó xác định ngày, tháng, năm âm lịch tương ứng.\n *\n * @param day - Ngày dương lịch (1-31)\n * @param month - Tháng dương lịch (1-12)\n * @param year - Năm dương lịch (1800-2199)\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @returns Đối tượng LunarDate chứa thông tin ngày âm lịch\n * @throws {RangeError} Khi input ngoài phạm vi hợp lệ\n *\n * @example\n * ```typescript\n * const lunar = LichTa.toLunar(10, 2, 2024);\n * // → { day: 1, month: 1, year: 2024, isLeap: false, yearCanChi: 'Giáp Thìn' }\n * ```\n */\n static toLunar(day: number, month: number, year: number, timeZone: number = 7): LunarDate {\n if (year < 1800 || year > 2199) {\n throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${year}`);\n }\n if (month < 1 || month > 12) {\n throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);\n }\n if (day < 1 || day > 31) {\n throw new RangeError(`Lichta: Day must be between 1 and 31, got ${day}`);\n }\n\n const dayNumber = jdFromDate(day, month, year);\n const k = INT((dayNumber - 2415021.076998695) / 29.530588853);\n\n let monthStart = getNewMoonDay(k + 1, timeZone);\n if (monthStart > dayNumber) {\n monthStart = getNewMoonDay(k, timeZone);\n }\n\n let a11 = getLunarMonth11(year, timeZone);\n let b11 = a11;\n let lunarYear: number;\n if (a11 >= monthStart) {\n lunarYear = year;\n a11 = getLunarMonth11(year - 1, timeZone);\n } else {\n lunarYear = year + 1;\n b11 = getLunarMonth11(year + 1, timeZone);\n }\n\n const lunarDay = dayNumber - monthStart + 1;\n const diff = INT((monthStart - a11) / 29);\n\n // Kiểm tra tháng nhuận: một năm âm lịch nhuận có 13 tháng (~384 ngày)\n // thay vì 12 tháng (~354 ngày) giữa 2 mốc tháng 11.\n let lunarLeap = false;\n let lunarMonth = diff + 11;\n if (b11 - a11 > 365) {\n const leapMonthDiff = getLeapMonthOffset(a11, timeZone);\n if (diff >= leapMonthDiff) {\n lunarMonth = diff + 10;\n if (diff === leapMonthDiff) {\n lunarLeap = true;\n }\n }\n }\n if (lunarMonth > 12) {\n lunarMonth -= 12;\n }\n if (lunarMonth >= 11 && diff < 4) {\n lunarYear -= 1;\n }\n\n const yearCanChi = getYearCanChi(lunarYear);\n const monthCanChi = getMonthCanChiInternal(lunarMonth, lunarYear);\n const dayCanChi = getDayCanChiInternal(dayNumber);\n\n return {\n day: lunarDay,\n month: lunarMonth,\n year: lunarYear,\n isLeap: lunarLeap,\n jd: dayNumber,\n dayCanChi,\n monthCanChi,\n yearCanChi,\n };\n }\n\n /**\n * Chuyển đổi ngày Âm lịch sang Dương lịch.\n *\n * @param lunarDay - Ngày âm lịch\n * @param lunarMonth - Tháng âm lịch\n * @param lunarYear - Năm âm lịch\n * @param isLeap - Có phải tháng nhuận không\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @returns Đối tượng SolarDate\n * @throws {RangeError} Khi năm ngoài phạm vi 1800-2199\n *\n * @example\n * ```typescript\n * const solar = LichTa.toSolar(1, 1, 2024, false);\n * // → { day: 10, month: 2, year: 2024 }\n * ```\n */\n static toSolar(\n lunarDay: number,\n lunarMonth: number,\n lunarYear: number,\n isLeap: boolean = false,\n timeZone: number = 7\n ): SolarDate {\n if (lunarYear < 1800 || lunarYear > 2199) {\n throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${lunarYear}`);\n }\n\n let a11: number, b11: number;\n\n if (lunarMonth < 11) {\n a11 = getLunarMonth11(lunarYear - 1, timeZone);\n b11 = getLunarMonth11(lunarYear, timeZone);\n } else {\n a11 = getLunarMonth11(lunarYear, timeZone);\n b11 = getLunarMonth11(lunarYear + 1, timeZone);\n }\n\n const k = INT(0.5 + (a11 - 2415021.076998695) / 29.530588853);\n let off = lunarMonth - 11;\n if (off < 0) {\n off += 12;\n }\n\n // Xử lý tháng nhuận: nếu năm có tháng nhuận (13 tháng, ~384 ngày giữa\n // 2 mốc tháng 11), cần dịch offset thêm 1 cho tháng nhuận và các tháng\n // sau nó, để phân biệt với tháng thường cùng số.\n if (b11 - a11 > 365) {\n const leapOff = getLeapMonthOffset(a11, timeZone);\n let leapMonth = leapOff - 2;\n if (leapMonth < 0) leapMonth += 12;\n\n if (isLeap && lunarMonth !== leapMonth) {\n throw new RangeError(\n `Lichta: Month ${lunarMonth} is not a leap month in lunar year ${lunarYear}`\n );\n } else if (isLeap || off >= leapOff) {\n off += 1;\n }\n }\n\n const nm = getNewMoonDay(k + off, timeZone);\n const jd = nm + lunarDay - 1;\n const [day, month, year] = jdToDate(jd);\n\n return { day, month, year };\n }\n}","/**\n * Five Elements (Ngũ Hành)\n * Kim | Metal\n * Mộc | Wood\n * Thủy | Water\n * Hỏa | Fire\n * Thổ | Earth\n */\nexport const FIVE_ELEMENTS = ['Kim', 'Mộc', 'Thủy', 'Hỏa', 'Thổ'];","import { HEAVENLY_STEMS, getStemWeight } from '../constants/heavenly-stems.js';\nimport { EARTHLY_BRANCHES, getBranchWeight } from '../constants/earthly-branches.js';\nimport { FIVE_ELEMENTS } from '../constants/five-elements.js';\n\n/**\n * Lấy ra chuỗi mô tả toàn bộ Can, Chi và Mệnh dựa vào số năm (Ví dụ: 2024)\n * Theo quy ước: Năm 4 (sau CN) là năm Giáp Tý (Can index 0, Chi index 0)\n */\nexport function getYearDetails(year: number) {\n // Tính index của Can và Chi dựa trên mốc năm gốc\n // Năm 1984, 2044 là Giáp Tý -> Offset để tính toán dễ nhất là lấy (year - 4) % hệ cơ số\n const stemIndex = (year - 4) % 10;\n const branchIndex = (year - 4) % 12;\n\n // Công thức vàng tính Ngũ Hành\n const stemWeight = getStemWeight(stemIndex);\n const branchWeight = getBranchWeight(branchIndex);\n \n let elementValue = stemWeight + branchWeight;\n if (elementValue > 5) {\n elementValue -= 5;\n }\n\n // Value ra từ 1-5, nên trừ 1 để lấy index của mảng FIVE_ELEMENTS (0-4)\n const elementIndex = elementValue - 1;\n\n return {\n can: HEAVENLY_STEMS[stemIndex],\n chi: EARTHLY_BRANCHES[branchIndex],\n menh: FIVE_ELEMENTS[elementIndex],\n fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - Mệnh ${FIVE_ELEMENTS[elementIndex]}`\n };\n}\n\n// ============================================================\n// Can Chi cho Ngày, Tháng, Giờ\n// ============================================================\n\n/**\n * Tính Can Chi ngày từ Julian Day Number.\n *\n * @param jd - Julian Day Number\n * @returns Chuỗi Can Chi (ví dụ: \"Giáp Tý\")\n */\nexport function getDayCanChi(jd: number): string {\n const stemIndex = (jd + 9) % 10;\n const branchIndex = (jd + 1) % 12;\n return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;\n}\n\n/**\n * Tính Can Chi tháng từ tháng và năm âm lịch.\n * Can tháng phụ thuộc vào Can của năm (quy tắc Ngũ Hổ Độn):\n * - Năm Giáp/Kỷ → Tháng Giêng bắt đầu bằng Bính (index 2)\n * - Năm Ất/Canh → Tháng Giêng bắt đầu bằng Mậu (index 4)\n * - Năm Bính/Tân → Tháng Giêng bắt đầu bằng Canh (index 6)\n * - Năm Đinh/Nhâm → Tháng Giêng bắt đầu bằng Nhâm (index 8)\n * - Năm Mậu/Quý → Tháng Giêng bắt đầu bằng Giáp (index 0)\n *\n * @param lunarMonth - Tháng âm lịch (1-12)\n * @param lunarYear - Năm âm lịch\n */\nexport function getMonthCanChi(lunarMonth: number, lunarYear: number): string {\n const yearStemIndex = (lunarYear + 6) % 10;\n const monthStemOffset = (yearStemIndex % 5) * 2 + 2;\n const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;\n const monthBranchIndex = (lunarMonth + 1) % 12;\n return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;\n}\n\n/**\n * Tính Can Chi giờ từ giờ (0-23) và Julian Day Number của ngày.\n *\n * 12 canh giờ (mỗi canh = 2 tiếng):\n * Tý: 23h-01h, Sửu: 01h-03h, Dần: 03h-05h, ...\n *\n * Can giờ Tý phụ thuộc Can ngày (quy tắc Ngũ Thử Độn):\n * - Ngày Giáp/Kỷ → Giờ Tý bắt đầu bằng Giáp\n * - Ngày Ất/Canh → Giờ Tý bắt đầu bằng Bính\n * - Ngày Bính/Tân → Giờ Tý bắt đầu bằng Mậu\n * - Ngày Đinh/Nhâm → Giờ Tý bắt đầu bằng Canh\n * - Ngày Mậu/Quý → Giờ Tý bắt đầu bằng Nhâm\n *\n * @param hour - Giờ (0-23)\n * @param dayJd - Julian Day Number của ngày\n */\nexport function getHourCanChi(hour: number, dayJd: number): string {\n // Tính Địa Chi của giờ: Tý từ 23h, mỗi canh 2 tiếng\n const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;\n\n // Tính Thiên Can của giờ dựa vào Can ngày\n const dayStemIndex = (dayJd + 9) % 10;\n const hourStemOffset = (dayStemIndex % 5) * 2;\n const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;\n\n return `${HEAVENLY_STEMS[hourStemIndex]} ${EARTHLY_BRANCHES[hourBranchIndex]}`;\n}\n\n// ============================================================\n// Giờ Hoàng Đạo\n// ============================================================\n\n/**\n * Bảng giờ Hoàng Đạo theo Chi của ngày.\n * Mỗi hàng tương ứng với 2 Chi (Tý-Ngọ, Sửu-Mùi, ...) → 6 nhóm.\n * Giá trị là index các Địa Chi tốt (6 giờ tốt trong 12 canh).\n */\nconst AUSPICIOUS_HOURS_TABLE: readonly (readonly number[])[] = [\n [0, 1, 3, 6, 7, 9], // Ngày Tý (0) / Ngọ (6)\n [2, 3, 5, 8, 9, 11], // Ngày Sửu (1) / Mùi (7)\n [0, 1, 4, 5, 7, 10], // Ngày Dần (2) / Thân (8)\n [1, 2, 4, 7, 8, 10], // Ngày Mão (3) / Dậu (9)\n [0, 3, 4, 6, 9, 10], // Ngày Thìn (4) / Tuất (10)\n [2, 5, 6, 8, 11, 0], // Ngày Tỵ (5) / Hợi (11)\n] as const;\n\n/**\n * Lấy danh sách 6 giờ Hoàng Đạo trong ngày.\n * Giờ Hoàng Đạo phụ thuộc vào Địa Chi của ngày.\n *\n * @param dayJd - Julian Day Number của ngày\n * @returns Mảng 6 chuỗi tên Địa Chi (ví dụ: [\"Tý\", \"Sửu\", \"Mão\", \"Ngọ\", \"Mùi\", \"Dậu\"])\n */\nexport function getAuspiciousHours(dayJd: number): string[] {\n const branchIndex = (dayJd + 1) % 12;\n // Nhóm theo 2 Chi (Tý-Ngọ, Sửu-Mùi, ...)\n const groupIndex = branchIndex % 6;\n const hourIndices = AUSPICIOUS_HOURS_TABLE[groupIndex];\n return hourIndices.map((i) => EARTHLY_BRANCHES[i] as string);\n}","import type { LunarDate } from '../core/types.js';\n\n// ============================================================\n// Tên tháng & ngày truyền thống\n// ============================================================\n\n/** Tên tháng âm lịch truyền thống */\nconst MONTH_NAMES = [\n 'Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu',\n 'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp',\n] as const;\n\n/** Tên số đếm truyền thống */\nconst DAY_UNITS = [\n '', 'Một', 'Hai', 'Ba', 'Bốn', 'Năm',\n 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười',\n] as const;\n\n/**\n * Lấy tên tháng âm lịch dạng chữ truyền thống.\n *\n * @param month - Tháng âm lịch (1-12)\n * @returns Tên tháng (ví dụ: 1 → \"Giêng\", 12 → \"Chạp\")\n *\n * @example\n * ```typescript\n * getMonthName(1); // \"Giêng\"\n * getMonthName(12); // \"Chạp\"\n * ```\n */\nexport function getMonthName(month: number): string {\n if (month < 1 || month > 12) {\n throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);\n }\n return MONTH_NAMES[month - 1];\n}\n\n/**\n * Lấy tên ngày âm lịch theo cách gọi truyền thống Việt Nam.\n *\n * - 1-10: \"Mùng Một\", \"Mùng Hai\", ..., \"Mùng Mười\"\n * - 11-20: \"Mười Một\", ..., \"Hai Mươi\"\n * - 21-30: \"Hăm Mốt\", \"Hăm Hai\", ..., \"Ba Mươi\"\n *\n * @param day - Ngày âm lịch (1-30)\n *\n * @example\n * ```typescript\n * getDayName(1); // \"Mùng Một\"\n * getDayName(15); // \"Rằm\"\n * getDayName(30); // \"Ba Mươi\"\n * ```\n */\nexport function getDayName(day: number): string {\n if (day < 1 || day > 30) {\n throw new RangeError(`Lichta: Day must be between 1 and 30, got ${day}`);\n }\n\n // Ngày Rằm\n if (day === 15) return 'Rằm';\n\n // Mùng 1-10\n if (day <= 10) {\n return `Mùng ${DAY_UNITS[day]}`;\n }\n\n // 11-19\n if (day < 20) {\n if (day === 11) return 'Mười Một';\n if (day === 14) return 'Mười Bốn';\n return `Mười ${DAY_UNITS[day - 10]}`;\n }\n\n // 20\n if (day === 20) return 'Hai Mươi';\n\n // 21-29\n if (day < 30) {\n if (day === 21) return 'Hăm Mốt';\n if (day === 24) return 'Hăm Tư';\n if (day === 25) return 'Hăm Lăm';\n return `Hăm ${DAY_UNITS[day - 20]}`;\n }\n\n // 30\n return 'Ba Mươi';\n}\n\n// ============================================================\n// Format functions\n// ============================================================\n\n/**\n * Format ngày âm lịch theo pattern.\n *\n * **Patterns hỗ trợ:**\n * | Token | Mô tả | Ví dụ |\n * |-------|------------------------------------------|----------------|\n * | `dd` | Ngày 2 chữ số | 01, 15, 30 |\n * | `d` | Ngày | 1, 15, 30 |\n * | `MM` | Tháng 2 chữ số | 01, 12 |\n * | `M` | Tháng | 1, 12 |\n * | `yyyy`| Năm 4 chữ số | 2024 |\n * | `yy` | Năm 2 chữ số cuối | 24 |\n * | `L` | \"Nhuận\" nếu tháng nhuận, \"\" nếu không | Nhuận |\n * | `CC` | Can Chi năm | Giáp Thìn |\n * | `DC` | Can Chi ngày | Giáp Tý |\n * | `MC` | Can Chi tháng | Bính Dần |\n *\n * @param lunar - Đối tượng LunarDate\n * @param pattern - Chuỗi pattern\n *\n * @example\n * ```typescript\n * formatLunarDate(lunar, 'dd/MM/yyyy');\n * // → \"01/01/2024\"\n *\n * formatLunarDate(lunar, 'Ngày d tháng M năm CC');\n * // → \"Ngày 1 tháng 1 năm Giáp Thìn\"\n * ```\n */\nexport function formatLunarDate(lunar: LunarDate, pattern: string): string {\n let result = pattern;\n\n // Thay thế theo thứ tự dài → ngắn để tránh xung đột (yyyy trước yy, dd trước d, MM trước M)\n result = result.replace(/yyyy/g, String(lunar.year));\n result = result.replace(/yy/g, String(lunar.year).slice(-2));\n result = result.replace(/dd/g, String(lunar.day).padStart(2, '0'));\n result = result.replace(/MM/g, String(lunar.month).padStart(2, '0'));\n result = result.replace(/CC/g, lunar.yearCanChi ?? '');\n result = result.replace(/DC/g, lunar.dayCanChi ?? '');\n result = result.replace(/MC/g, lunar.monthCanChi ?? '');\n result = result.replace(/L/g, lunar.isLeap ? 'Nhuận' : '');\n\n // Thay d và M cuối cùng (sau khi dd, MM đã được xử lý, tránh double-replace)\n // Dùng regex negative lookbehind để không match các token đã được thay\n result = result.replace(/(?<![0-9])d(?![0-9d])/g, String(lunar.day));\n result = result.replace(/(?<![0-9])M(?![0-9MC])/g, String(lunar.month));\n\n return result.trim();\n}\n\n/**\n * Format ngày âm lịch theo kiểu truyền thống Việt Nam.\n *\n * @param lunar - Đối tượng LunarDate\n * @returns Chuỗi truyền thống (ví dụ: \"Mùng Một tháng Giêng năm Giáp Thìn\")\n *\n * @example\n * ```typescript\n * formatTraditional(lunar);\n * // → \"Mùng Một tháng Giêng năm Giáp Thìn\"\n * ```\n */\nexport function formatTraditional(lunar: LunarDate): string {\n const dayName = getDayName(lunar.day);\n const monthName = getMonthName(lunar.month);\n const leapSuffix = lunar.isLeap ? ' Nhuận' : '';\n const yearCanChi = lunar.yearCanChi ?? '';\n\n return `${dayName} tháng ${monthName}${leapSuffix} năm ${yearCanChi}`.trim();\n}\n","/**\n * Internationalization — Hỗ trợ song ngữ Việt-Anh\n */\nexport type Locale = 'vi' | 'en' | 'ja' | 'ko';\n\nconst translations = {\n vi: {\n heavenlyStems: ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'],\n earthlyBranches: ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'],\n fiveElements: ['Kim', 'Mộc', 'Thủy', 'Hỏa', 'Thổ'],\n zodiacAnimals: ['Chuột', 'Trâu', 'Cọp', 'Thỏ', 'Rồng', 'Rắn', 'Ngựa', 'Dê', 'Khỉ', 'Gà', 'Chó', 'Heo'],\n monthNames: ['Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp'],\n weekDays: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'],\n leapLabel: 'Nhuận',\n yearLabel: 'Năm',\n monthLabel: 'Tháng',\n destiny: 'Mệnh',\n },\n en: {\n heavenlyStems: ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'],\n earthlyBranches: ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'],\n fiveElements: ['Metal', 'Wood', 'Water', 'Fire', 'Earth'],\n zodiacAnimals: ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'],\n monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n weekDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n leapLabel: 'Leap',\n yearLabel: 'Year',\n monthLabel: 'Month',\n destiny: 'Destiny',\n },\n ja: {\n heavenlyStems: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'],\n earthlyBranches: ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'],\n fiveElements: ['金', '木', '水', '火', '土'],\n zodiacAnimals: ['鼠', '牛', '虎', '兎', '竜', '蛇', '馬', '羊', '猿', '鶏', '犬', '猪'],\n monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n weekDays: ['日', '月', '火', '水', '木', '金', '土'],\n leapLabel: '閏',\n yearLabel: '年',\n monthLabel: '月',\n destiny: '命',\n },\n ko: {\n heavenlyStems: ['갑', '을', '병', '정', '무', '기', '경', '신', '임', '계'],\n earthlyBranches: ['자', '축', '인', '묘', '진', '사', '오', '미', '신', '유', '술', '해'],\n fiveElements: ['금', '목', '수', '화', '토'],\n zodiacAnimals: ['쥐', '소', '호랑이', '토끼', '용', '뱀', '말', '양', '원숭이', '닭', '개', '돼지'],\n monthNames: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],\n weekDays: ['일', '월', '화', '수', '목', '금', '토'],\n leapLabel: '윤',\n yearLabel: '년',\n monthLabel: '월',\n destiny: '명',\n },\n} as const;\n\n/**\n * Lấy bộ dịch theo locale\n * @param locale - Ngôn ngữ ('vi' | 'en' | 'ja' | 'ko')\n */\nexport function t(locale: Locale) {\n return translations[locale];\n}\n\n/**\n * Lấy tên con giáp theo locale\n * @param branchIndex - Index Địa Chi (0-11)\n * @param locale - Ngôn ngữ\n */\nexport function getZodiacAnimal(branchIndex: number, locale: Locale = 'vi'): string {\n return translations[locale].zodiacAnimals[branchIndex % 12];\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/constants/heavenly-stems.ts","../src/constants/earthly-branches.ts","../src/core/astronomical.ts","../src/core/calendar-engine.ts","../src/constants/i18n.ts","../src/core/can-chi.ts","../src/utils/math.ts","../src/core/ngu-hanh.ts","../src/core/tiet-khi.ts","../src/core/truc-zodiac.ts","../src/constants/five-elements.ts","../src/core/almanac.ts","../src/utils/format.ts","../src/utils/calendar-grid.ts"],"sourcesContent":["/**\n * Heavenly Stems (Thiên Can)\n * Giáp (Dương) | Wood\n * Ất (Âm) | Wood\n * Bính (Dương) | Fire\n * Đinh (Âm) | Fire\n * Mậu (Dương) | Earth\n * Kỷ (Âm) | Earth\n * Canh (Dương) | Metal\n * Tân (Âm) | Metal\n * Nhâm (Dương) | Water\n * Quý (Âm) | Water\n */\nexport const HEAVENLY_STEMS = [\n 'Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu',\n 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'\n] as const;","/**\n * Earthly Branches (Địa Chi - 12 con giáp)\n * Tý | Rat (Chuột)\n * Sửu | Ox (Trâu)\n * Dần | Tiger (Cọp)\n * Mão | Rabbit (Thỏ)\n * Thìn | Dragon (Rồng)\n * Tỵ | Snake (Rắn)\n * Ngọ | Horse (Ngựa)\n * Mùi | Goat (Dê)\n * Thân | Monkey (Khỉ)\n * Dậu | Rooster (Gà)\n * Tuất | Dog (Chó)\n * Hợi | Pig (Heo)\n */\nexport const EARTHLY_BRANCHES = [\n 'Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ',\n 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'\n] as const;\n\n/**\n * Tính Dương - Âm (Yin - Yang) cho Địa Chi\n * Index: 0 -> 1 (Dương) | 1 -> 0 (Âm) | ...\n */\nexport function getBranchYinYang(index: number): 1 | 0 {\n return (index % 2 === 0) ? 1 : 0;\n}\n\n/**\n * Tính Ngũ Hành cho Địa Chi\n * Tý: 1 (Thủy Dương), Sửu: 12 (Thổ Âm), Dần: 3 (Mộc Dương), ...\n */\nexport function getBranchElement(index: number): number {\n const weight = Math.floor(index / 2) + 1;\n return weight === 5 ? 1 : weight;\n}","/**\n * Thuật toán thiên văn nền tảng cho chuyển đổi Dương lịch ↔ Âm lịch Việt Nam\n * Dựa trên công trình của Hồ Ngọc Đức (Đại học Leipzig)\n * Tham khảo: Jean Meeus, \"Astronomical Algorithms\" (1998)\n *\n * Copyright (c) 2006 Ho Ngoc Duc. All Rights Reserved.\n * TypeScript adaptation for Lichta library.\n */\n\nconst PI = Math.PI;\n\nfunction INT(d: number): number {\n return Math.floor(d);\n}\n\n// ============================================================\n// Julian Day Number\n// ============================================================\n\n/**\n * Chuyển ngày Gregorian sang Julian Day Number.\n *\n * @param dd - Ngày (1-31)\n * @param mm - Tháng (1-12)\n * @param yy - Năm\n */\nexport function jdFromDate(dd: number, mm: number, yy: number): number {\n const a = INT((14 - mm) / 12);\n const y = yy + 4800 - a;\n const m = mm + 12 * a - 3;\n let jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - INT(y / 100) + INT(y / 400) - 32045;\n if (jd < 2299161) {\n jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - 32083;\n }\n return jd;\n}\n\n/**\n * Chuyển Julian Day Number sang ngày Gregorian.\n *\n * @param jd - Julian Day Number\n * @returns Tuple [day, month, year]\n */\nexport function jdToDate(jd: number): [number, number, number] {\n let a: number, b: number, c: number;\n if (jd > 2299160) {\n a = jd + 32044;\n b = INT((4 * a + 3) / 146097);\n c = a - INT((b * 146097) / 4);\n } else {\n b = 0;\n c = jd + 32082;\n }\n const d = INT((4 * c + 3) / 1461);\n const e = c - INT((1461 * d) / 4);\n const m = INT((5 * e + 2) / 153);\n const day = e - INT((153 * m + 2) / 5) + 1;\n const month = m + 3 - 12 * INT(m / 10);\n const year = b * 100 + d - 4800 + INT(m / 10);\n return [day, month, year];\n}\n\n// ============================================================\n// Điểm Sóc (New Moon) — Thuật toán Hồ Ngọc Đức / Jean Meeus\n// ============================================================\n\n/**\n * Tính thời điểm điểm Sóc (New Moon) thứ k\n * (đo bằng số ngày Julian kể từ 1/1/4713 BC trưa UTC).\n *\n * k=0 tương ứng New Moon ngày 1/1/1900 13:52 UTC.\n *\n * @param k - Số thứ tự New Moon\n */\nfunction NewMoon(k: number): number {\n const T = k / 1236.85;\n const T2 = T * T;\n const T3 = T2 * T;\n const dr = PI / 180;\n\n let Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;\n Jd1 = Jd1 + 0.00033 * Math.sin((166.56 + 132.87 * T - 0.009173 * T2) * dr);\n\n // Mean anomaly của Mặt Trời\n const M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3;\n // Mean anomaly của Mặt Trăng\n const Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3;\n // Argument of latitude của Mặt Trăng\n const F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3;\n\n // Hiệu chỉnh\n let C1 = (0.1734 - 0.000393 * T) * Math.sin(M * dr) + 0.0021 * Math.sin(2 * dr * M);\n C1 = C1 - 0.4068 * Math.sin(Mpr * dr) + 0.0161 * Math.sin(dr * 2 * Mpr);\n C1 = C1 - 0.0004 * Math.sin(dr * 3 * Mpr);\n C1 = C1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (M + Mpr));\n C1 = C1 - 0.0074 * Math.sin(dr * (M - Mpr)) + 0.0004 * Math.sin(dr * (2 * F + M));\n C1 = C1 - 0.0004 * Math.sin(dr * (2 * F - M)) - 0.0006 * Math.sin(dr * (2 * F + Mpr));\n C1 = C1 + 0.001 * Math.sin(dr * (2 * F - Mpr)) + 0.0005 * Math.sin(dr * (2 * Mpr + M));\n\n const JdNew = Jd1 + C1;\n return JdNew;\n}\n\n/**\n * Tính ngày Julian (integer) của điểm Sóc thứ k theo múi giờ.\n *\n * @param k - Số thứ tự New Moon\n * @param timeZone - Múi giờ (7 = GMT+7)\n */\nexport function getNewMoonDay(k: number, timeZone: number): number {\n return INT(NewMoon(k) + 0.5 + timeZone / 24);\n}\n\n// ============================================================\n// Kinh độ Mặt Trời (Sun Longitude)\n// ============================================================\n\n/**\n * Tính kinh độ Mặt Trời biểu kiến (0°-360°) tại ngày Julian cho trước.\n * Dùng làm cơ sở chung cho cả Trung Khí ({@link getSunLongitude}, bước 30°)\n * và Tiết Khí ({@link getSolarTermIndex}, bước 15°).\n *\n * @param jdn - Julian Day Number\n * @param timeZone - Múi giờ\n */\nfunction sunLongitudeDegrees(jdn: number, timeZone: number): number {\n const T = (jdn - 2451545.5 - timeZone / 24) / 36525;\n const T2 = T * T;\n const dr = PI / 180;\n\n // Mean longitude\n const M = 357.5291 + 35999.0503 * T - 0.0001559 * T2 - 0.00000048 * T * T2;\n\n // Mean longitude\n const L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2;\n\n let DL = (1.9146 - 0.004817 * T - 0.000014 * T2) * Math.sin(dr * M);\n DL = DL + (0.019993 - 0.000101 * T) * Math.sin(dr * 2 * M) + 0.00029 * Math.sin(dr * 3 * M);\n\n let L = L0 + DL;\n // Chuẩn hóa\n L = L - 360 * INT(L / 360);\n return L;\n}\n\n/**\n * Tính kinh độ Mặt Trời tại ngày Julian cho trước.\n * Trả về index 0-11 (mỗi 30°), dùng để xác định Trung khí.\n *\n * Index 9 = Đông Chí (270°-300°)\n *\n * @param jdn - Julian Day Number\n * @param timeZone - Múi giờ\n */\nexport function getSunLongitude(jdn: number, timeZone: number): number {\n return INT(sunLongitudeDegrees(jdn, timeZone) / 30);\n}\n\n/**\n * Tính index Tiết Khí (0-23, mỗi tiết cách nhau 15°) tại ngày Julian cho trước.\n *\n * Index 0 = Xuân Phân (kinh độ 0°), Index 18 = Đông Chí (270°),\n * tăng dần theo chiều quỹ đạo — xem thứ tự đầy đủ trong\n * `SOLAR_TERM_NAMES` (`tiet-khi.ts`).\n *\n * @param jdn - Julian Day Number\n * @param timeZone - Múi giờ\n */\nexport function getSolarTermIndex(jdn: number, timeZone: number): number {\n return INT(sunLongitudeDegrees(jdn, timeZone) / 15);\n}\n","import type { LunarDate, SolarDate } from './types.js';\nimport { HEAVENLY_STEMS } from '../constants/heavenly-stems.js';\nimport { EARTHLY_BRANCHES } from '../constants/earthly-branches.js';\nimport { jdFromDate, jdToDate, getNewMoonDay, getSunLongitude } from './astronomical.js';\n\n/**\n * `LichTa.toLunar`/`toSolar` — chuyển đổi Dương lịch ↔ Âm lịch Việt Nam.\n * Xây dựng trên các hàm thiên văn thuần túy ở `astronomical.ts` (Điểm Sóc, Tiết Khí)\n * để xác định ranh giới tháng âm lịch, bao gồm tháng nhuận.\n */\n\nfunction INT(d: number): number {\n return Math.floor(d);\n}\n\n// ============================================================\n// Tháng 11 âm lịch & Tháng nhuận\n// ============================================================\n\n/**\n * Tìm JDN của mùng 1 tháng 11 âm lịch (tháng chứa Đông Chí).\n */\nfunction getLunarMonth11(yy: number, timeZone: number): number {\n const off = jdFromDate(31, 12, yy) - 2415021.076998695;\n const k = INT(off / 29.530588853);\n let nm = getNewMoonDay(k, timeZone);\n const sunLong = getSunLongitude(nm, timeZone);\n if (sunLong >= 9) {\n nm = getNewMoonDay(k - 1, timeZone);\n }\n return nm;\n}\n\n/**\n * Tìm offset tháng nhuận (tháng đầu tiên không chứa Trung khí\n * giữa 2 tháng 11 âm lịch liên tiếp).\n */\nfunction getLeapMonthOffset(a11: number, timeZone: number): number {\n const k = INT((a11 - 2415021.076998695) / 29.530588853 + 0.5);\n let last: number;\n let i = 1;\n let arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);\n last = arc;\n while (i < 14) {\n i++;\n arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);\n if (arc !== last) {\n last = arc;\n } else {\n // 2 tháng liên tiếp cùng Trung khí → tháng trước đó là tháng nhuận\n break;\n }\n }\n return i - 1;\n}\n\n// ============================================================\n// Can Chi helpers\n// ============================================================\n\nfunction getYearCanChi(lunarYear: number): string {\n const stemIndex = (lunarYear + 6) % 10;\n const branchIndex = (lunarYear + 8) % 12;\n return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;\n}\n\nfunction getMonthCanChiInternal(lunarMonth: number, lunarYear: number): string {\n const yearStemIndex = (lunarYear + 6) % 10;\n const monthStemOffset = (yearStemIndex % 5) * 2 + 2;\n const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;\n const monthBranchIndex = (lunarMonth + 1) % 12;\n return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;\n}\n\nfunction getDayCanChiInternal(jd: number): string {\n const stemIndex = (jd + 9) % 10;\n const branchIndex = (jd + 1) % 12;\n return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;\n}\n\n// ============================================================\n// LichTa — Public API\n// ============================================================\n\nexport class LichTa {\n /**\n * Chuyển đổi ngày Dương lịch sang Âm lịch.\n *\n * Sử dụng thuật toán Hồ Ngọc Đức để tìm Điểm Sóc và Tiết Khí,\n * từ đó xác định ngày, tháng, năm âm lịch tương ứng.\n *\n * @param day - Ngày dương lịch (1-31)\n * @param month - Tháng dương lịch (1-12)\n * @param year - Năm dương lịch (1800-2199)\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @returns Đối tượng LunarDate chứa thông tin ngày âm lịch\n * @throws {RangeError} Khi input ngoài phạm vi hợp lệ\n *\n * @example\n * ```typescript\n * const lunar = LichTa.toLunar(10, 2, 2024);\n * // → { day: 1, month: 1, year: 2024, isLeap: false, yearCanChi: 'Giáp Thìn' }\n * ```\n */\n static toLunar(day: number, month: number, year: number, timeZone: number = 7): LunarDate {\n if (year < 1800 || year > 2199) {\n throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${year}`);\n }\n if (month < 1 || month > 12) {\n throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);\n }\n if (day < 1 || day > 31) {\n throw new RangeError(`Lichta: Day must be between 1 and 31, got ${day}`);\n }\n\n const dayNumber = jdFromDate(day, month, year);\n const k = INT((dayNumber - 2415021.076998695) / 29.530588853);\n\n let monthStart = getNewMoonDay(k + 1, timeZone);\n if (monthStart > dayNumber) {\n monthStart = getNewMoonDay(k, timeZone);\n }\n\n let a11 = getLunarMonth11(year, timeZone);\n let b11 = a11;\n let lunarYear: number;\n if (a11 >= monthStart) {\n lunarYear = year;\n a11 = getLunarMonth11(year - 1, timeZone);\n } else {\n lunarYear = year + 1;\n b11 = getLunarMonth11(year + 1, timeZone);\n }\n\n const lunarDay = dayNumber - monthStart + 1;\n const diff = INT((monthStart - a11) / 29);\n\n // Kiểm tra tháng nhuận: một năm âm lịch nhuận có 13 tháng (~384 ngày)\n // thay vì 12 tháng (~354 ngày) giữa 2 mốc tháng 11.\n let lunarLeap = false;\n let lunarMonth = diff + 11;\n if (b11 - a11 > 365) {\n const leapMonthDiff = getLeapMonthOffset(a11, timeZone);\n if (diff >= leapMonthDiff) {\n lunarMonth = diff + 10;\n if (diff === leapMonthDiff) {\n lunarLeap = true;\n }\n }\n }\n if (lunarMonth > 12) {\n lunarMonth -= 12;\n }\n if (lunarMonth >= 11 && diff < 4) {\n lunarYear -= 1;\n }\n\n const yearCanChi = getYearCanChi(lunarYear);\n const monthCanChi = getMonthCanChiInternal(lunarMonth, lunarYear);\n const dayCanChi = getDayCanChiInternal(dayNumber);\n\n return {\n day: lunarDay,\n month: lunarMonth,\n year: lunarYear,\n isLeap: lunarLeap,\n jd: dayNumber,\n dayCanChi,\n monthCanChi,\n yearCanChi,\n };\n }\n\n /**\n * Chuyển đổi ngày Âm lịch sang Dương lịch.\n *\n * @param lunarDay - Ngày âm lịch\n * @param lunarMonth - Tháng âm lịch\n * @param lunarYear - Năm âm lịch\n * @param isLeap - Có phải tháng nhuận không\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @returns Đối tượng SolarDate\n * @throws {RangeError} Khi năm ngoài phạm vi 1800-2199\n *\n * @example\n * ```typescript\n * const solar = LichTa.toSolar(1, 1, 2024, false);\n * // → { day: 10, month: 2, year: 2024 }\n * ```\n */\n static toSolar(\n lunarDay: number,\n lunarMonth: number,\n lunarYear: number,\n isLeap: boolean = false,\n timeZone: number = 7\n ): SolarDate {\n if (lunarYear < 1800 || lunarYear > 2199) {\n throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${lunarYear}`);\n }\n\n let a11: number, b11: number;\n\n if (lunarMonth < 11) {\n a11 = getLunarMonth11(lunarYear - 1, timeZone);\n b11 = getLunarMonth11(lunarYear, timeZone);\n } else {\n a11 = getLunarMonth11(lunarYear, timeZone);\n b11 = getLunarMonth11(lunarYear + 1, timeZone);\n }\n\n const k = INT(0.5 + (a11 - 2415021.076998695) / 29.530588853);\n let off = lunarMonth - 11;\n if (off < 0) {\n off += 12;\n }\n\n // Xử lý tháng nhuận: nếu năm có tháng nhuận (13 tháng, ~384 ngày giữa\n // 2 mốc tháng 11), cần dịch offset thêm 1 cho tháng nhuận và các tháng\n // sau nó, để phân biệt với tháng thường cùng số.\n if (b11 - a11 > 365) {\n const leapOff = getLeapMonthOffset(a11, timeZone);\n let leapMonth = leapOff - 2;\n if (leapMonth < 0) leapMonth += 12;\n\n if (isLeap && lunarMonth !== leapMonth) {\n throw new RangeError(\n `Lichta: Month ${lunarMonth} is not a leap month in lunar year ${lunarYear}`\n );\n } else if (isLeap || off >= leapOff) {\n off += 1;\n }\n }\n\n const nm = getNewMoonDay(k + off, timeZone);\n const jd = nm + lunarDay - 1;\n const [day, month, year] = jdToDate(jd);\n\n return { day, month, year };\n }\n}\n","import type { FirstDayOfWeek } from '../utils/calendar-grid.js';\n\n/**\n * Internationalization — Hỗ trợ song ngữ Việt-Anh\n */\nexport type Locale = 'vi' | 'en' | 'ja' | 'ko';\n\nconst translations = {\n vi: {\n heavenlyStems: ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'],\n earthlyBranches: ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'],\n fiveElements: ['Kim', 'Mộc', 'Thủy', 'Hỏa', 'Thổ'],\n zodiacAnimals: ['Chuột', 'Trâu', 'Cọp', 'Thỏ', 'Rồng', 'Rắn', 'Ngựa', 'Dê', 'Khỉ', 'Gà', 'Chó', 'Heo'],\n // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).\n monthNames: ['Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp'],\n lunarMonthNames: ['Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp'],\n solarMonthNames: ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'],\n weekDays: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'],\n leapLabel: 'Nhuận',\n yearLabel: 'Năm',\n monthLabel: 'Tháng',\n destiny: 'Mệnh',\n // Thứ tự bắt đầu từ Xuân Phân (kinh độ Mặt Trời 0°), xem getSolarTermIndex trong lunar.ts\n solarTermNames: [\n 'Xuân Phân', 'Thanh Minh', 'Cốc Vũ', 'Lập Hạ', 'Tiểu Mãn', 'Mang Chủng',\n 'Hạ Chí', 'Tiểu Thử', 'Đại Thử', 'Lập Thu', 'Xử Thử', 'Bạch Lộ',\n 'Thu Phân', 'Hàn Lộ', 'Sương Giáng', 'Lập Đông', 'Tiểu Tuyết', 'Đại Tuyết',\n 'Đông Chí', 'Tiểu Hàn', 'Đại Hàn', 'Lập Xuân', 'Vũ Thủy', 'Kinh Trập',\n ],\n // Thứ tự bắt đầu từ Kiến (0), xem getTrucIndex trong feng-shui.ts\n trucNames: ['Kiến', 'Trừ', 'Mãn', 'Bình', 'Định', 'Chấp', 'Phá', 'Nguy', 'Thành', 'Thu', 'Khai', 'Bế'],\n // Thứ tự: sinh, được sinh, khắc, bị khắc, hòa — xem getElementRelationIndex trong feng-shui.ts\n elementRelationNames: ['Tương sinh', 'Được sinh', 'Tương khắc', 'Bị khắc', 'Tương hòa'],\n // Thứ tự: xấu, trung bình, tốt — xem getTrucQualityIndex trong feng-shui.ts\n trucQualityNames: ['Xấu', 'Trung bình', 'Tốt'],\n },\n en: {\n heavenlyStems: ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'],\n earthlyBranches: ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'],\n fiveElements: ['Metal', 'Wood', 'Water', 'Fire', 'Earth'],\n zodiacAnimals: ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'],\n // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).\n monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n lunarMonthNames: ['Month 1', 'Month 2', 'Month 3', 'Month 4', 'Month 5', 'Month 6', 'Month 7', 'Month 8', 'Month 9', 'Month 10', 'Month 11', 'Month 12'],\n solarMonthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n weekDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n leapLabel: 'Leap',\n yearLabel: 'Year',\n monthLabel: 'Month',\n destiny: 'Destiny',\n solarTermNames: [\n 'Spring Equinox', 'Clear and Bright', 'Grain Rain', 'Start of Summer', 'Grain Full', 'Grain in Ear',\n 'Summer Solstice', 'Minor Heat', 'Major Heat', 'Start of Autumn', 'End of Heat', 'White Dew',\n 'Autumn Equinox', 'Cold Dew', \"Frost's Descent\", 'Start of Winter', 'Minor Snow', 'Major Snow',\n 'Winter Solstice', 'Minor Cold', 'Major Cold', 'Start of Spring', 'Rain Water', 'Awakening of Insects',\n ],\n trucNames: ['Kiến', 'Trừ', 'Mãn', 'Bình', 'Định', 'Chấp', 'Phá', 'Nguy', 'Thành', 'Thu', 'Khai', 'Bế'],\n elementRelationNames: ['Generates', 'Generated By', 'Overcomes', 'Overcome By', 'Same Element'],\n trucQualityNames: ['Bad', 'Neutral', 'Good'],\n },\n ja: {\n heavenlyStems: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'],\n earthlyBranches: ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'],\n fiveElements: ['金', '木', '水', '火', '土'],\n zodiacAnimals: ['鼠', '牛', '虎', '兎', '竜', '蛇', '馬', '羊', '猿', '鶏', '犬', '猪'],\n // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).\n monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n lunarMonthNames: ['旧暦1月', '旧暦2月', '旧暦3月', '旧暦4月', '旧暦5月', '旧暦6月', '旧暦7月', '旧暦8月', '旧暦9月', '旧暦10月', '旧暦11月', '旧暦12月'],\n solarMonthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n weekDays: ['日', '月', '火', '水', '木', '金', '土'],\n leapLabel: '閏',\n yearLabel: '年',\n monthLabel: '月',\n destiny: '命',\n solarTermNames: [\n '春分', '清明', '穀雨', '立夏', '小満', '芒種',\n '夏至', '小暑', '大暑', '立秋', '処暑', '白露',\n '秋分', '寒露', '霜降', '立冬', '小雪', '大雪',\n '冬至', '小寒', '大寒', '立春', '雨水', '啓蟄',\n ],\n trucNames: ['建', '除', '満', '平', '定', '執', '破', '危', '成', '収', '開', '閉'],\n elementRelationNames: ['相生', '被生', '相克', '被克', '比和'],\n trucQualityNames: ['凶', '普通', '吉'],\n },\n ko: {\n heavenlyStems: ['갑', '을', '병', '정', '무', '기', '경', '신', '임', '계'],\n earthlyBranches: ['자', '축', '인', '묘', '진', '사', '오', '미', '신', '유', '술', '해'],\n fiveElements: ['금', '목', '수', '화', '토'],\n zodiacAnimals: ['쥐', '소', '호랑이', '토끼', '용', '뱀', '말', '양', '원숭이', '닭', '개', '돼지'],\n // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).\n monthNames: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],\n lunarMonthNames: ['음력 1월', '음력 2월', '음력 3월', '음력 4월', '음력 5월', '음력 6월', '음력 7월', '음력 8월', '음력 9월', '음력 10월', '음력 11월', '음력 12월'],\n solarMonthNames: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],\n weekDays: ['일', '월', '화', '수', '목', '금', '토'],\n leapLabel: '윤',\n yearLabel: '년',\n monthLabel: '월',\n destiny: '명',\n solarTermNames: [\n '춘분', '청명', '곡우', '입하', '소만', '망종',\n '하지', '소서', '대서', '입추', '처서', '백로',\n '추분', '한로', '상강', '입동', '소설', '대설',\n '동지', '소한', '대한', '입춘', '우수', '경칩',\n ],\n trucNames: ['건', '제', '만', '평', '정', '집', '파', '위', '성', '수', '개', '폐'],\n elementRelationNames: ['상생', '피생', '상극', '피극', '비화'],\n trucQualityNames: ['흉', '보통', '길'],\n },\n} as const;\n\n/**\n * Lấy bộ dịch theo locale\n * @param locale - Ngôn ngữ ('vi' | 'en' | 'ja' | 'ko')\n */\nexport function t(locale: Locale) {\n return translations[locale];\n}\n\n/**\n * Lấy tên con giáp theo locale\n * @param branchIndex - Index Địa Chi (0-11)\n * @param locale - Ngôn ngữ\n */\nexport function getZodiacAnimal(branchIndex: number, locale: Locale = 'vi'): string {\n return translations[locale].zodiacAnimals[branchIndex % 12];\n}\n\n/**\n * Lấy nhãn thứ trong tuần theo locale, xoay vòng theo ngày bắt đầu tuần.\n * @param locale - Ngôn ngữ\n * @param firstDayOfWeek - Ngày bắt đầu tuần: 0 = Chủ Nhật (mặc định), 1 = Thứ Hai\n */\nexport function getWeekDayLabels(locale: Locale, firstDayOfWeek: FirstDayOfWeek = 0): string[] {\n const { weekDays } = translations[locale];\n return firstDayOfWeek === 0 ? [...weekDays] : [...weekDays.slice(1), weekDays[0]];\n}\n","import { t, type Locale } from '../constants/i18n.js';\n\n// ============================================================\n// Can Chi cho Ngày, Tháng, Giờ\n// ============================================================\n\n/**\n * Tính Can Chi ngày từ Julian Day Number.\n *\n * @param jd - Julian Day Number\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)\n * @returns Chuỗi Can Chi (ví dụ: \"Giáp Tý\")\n */\nexport function getDayCanChi(jd: number, locale: Locale = 'vi'): string {\n const stemIndex = (jd + 9) % 10;\n const branchIndex = (jd + 1) % 12;\n const { heavenlyStems, earthlyBranches } = t(locale);\n return `${heavenlyStems[stemIndex]} ${earthlyBranches[branchIndex]}`;\n}\n\n/**\n * Tính Can Chi tháng từ tháng và năm âm lịch.\n * Can tháng phụ thuộc vào Can của năm (quy tắc Ngũ Hổ Độn):\n * - Năm Giáp/Kỷ → Tháng Giêng bắt đầu bằng Bính (index 2)\n * - Năm Ất/Canh → Tháng Giêng bắt đầu bằng Mậu (index 4)\n * - Năm Bính/Tân → Tháng Giêng bắt đầu bằng Canh (index 6)\n * - Năm Đinh/Nhâm → Tháng Giêng bắt đầu bằng Nhâm (index 8)\n * - Năm Mậu/Quý → Tháng Giêng bắt đầu bằng Giáp (index 0)\n *\n * @param lunarMonth - Tháng âm lịch (1-12)\n * @param lunarYear - Năm âm lịch\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)\n */\nexport function getMonthCanChi(lunarMonth: number, lunarYear: number, locale: Locale = 'vi'): string {\n const yearStemIndex = (lunarYear + 6) % 10;\n const monthStemOffset = (yearStemIndex % 5) * 2 + 2;\n const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;\n const monthBranchIndex = (lunarMonth + 1) % 12;\n const { heavenlyStems, earthlyBranches } = t(locale);\n return `${heavenlyStems[monthStemIndex]} ${earthlyBranches[monthBranchIndex]}`;\n}\n\n/**\n * Tính Can Chi giờ từ giờ (0-23) và Julian Day Number của ngày.\n *\n * 12 canh giờ (mỗi canh = 2 tiếng):\n * Tý: 23h-01h, Sửu: 01h-03h, Dần: 03h-05h, ...\n *\n * Can giờ Tý phụ thuộc Can ngày (quy tắc Ngũ Thử Độn):\n * - Ngày Giáp/Kỷ → Giờ Tý bắt đầu bằng Giáp\n * - Ngày Ất/Canh → Giờ Tý bắt đầu bằng Bính\n * - Ngày Bính/Tân → Giờ Tý bắt đầu bằng Mậu\n * - Ngày Đinh/Nhâm → Giờ Tý bắt đầu bằng Canh\n * - Ngày Mậu/Quý → Giờ Tý bắt đầu bằng Nhâm\n *\n * @param hour - Giờ (0-23)\n * @param dayJd - Julian Day Number của ngày\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)\n */\nexport function getHourCanChi(hour: number, dayJd: number, locale: Locale = 'vi'): string {\n // Tính Địa Chi của giờ: Tý từ 23h, mỗi canh 2 tiếng\n const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;\n\n // Tính Thiên Can của giờ dựa vào Can ngày\n const dayStemIndex = (dayJd + 9) % 10;\n const hourStemOffset = (dayStemIndex % 5) * 2;\n const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;\n\n const { heavenlyStems, earthlyBranches } = t(locale);\n return `${heavenlyStems[hourStemIndex]} ${earthlyBranches[hourBranchIndex]}`;\n}\n","/**\n * Modulo luôn trả về số không âm (khác toán tử `%` gốc của JS, vốn trả về số âm\n * khi vế trái âm — ví dụ `-1 % 10 === -1`, trong khi `mod(-1, 10) === 9`).\n *\n * Dùng chung cho các module can-chi/ngũ-hành/trực (không phải public API).\n */\nexport function mod(n: number, m: number): number {\n return ((n % m) + m) % m;\n}\n","import { t, type Locale } from '../constants/i18n.js';\nimport { mod } from '../utils/math.js';\n\n// ============================================================\n// Ngũ Hành Nạp Âm (Mệnh) — dùng chung cho Năm, Tháng, Ngày, Giờ\n// ============================================================\n\n/**\n * Bảng Nạp Âm Ngũ Hành của 60 Hoa Giáp, gộp theo 30 nhóm (2 tổ hợp Can Chi liền kề\n * trong chu kỳ 60 dùng chung 1 hành — ví dụ Giáp Tý & Ất Sửu đều là Kim/Hải Trung\n * Kim). Bảng Nạp Âm KHÔNG có công thức đóng (closed-form): đây là bảng tra cứu\n * chuẩn theo quy ước truyền thống, không suy ra được từ Can/Chi bằng phép cộng đơn\n * giản. (Bản trước của repo dùng công thức cộng trọng số Can+Chi, sai lệch 48/60\n * tổ hợp — tức 80% — so với bảng chuẩn khi đối chiếu; đã thay bằng bảng tra cứu này.)\n *\n * Giá trị là index vào `FIVE_ELEMENTS` ['Kim', 'Mộc', 'Thủy', 'Hỏa', 'Thổ'].\n * Nhóm 0 = Giáp Tý/Ất Sửu (Hải Trung Kim), nhóm 1 = Bính Dần/Đinh Mão (Lư Trung\n * Hỏa), ..., nhóm 29 = Nhâm Tuất/Quý Hợi (Đại Hải Thủy).\n */\nconst NAP_AM_ELEMENT_INDEX: readonly number[] = [\n 0, 3, 1, 4, 0, 3, 2, 4, 0, 1, 2, 4, 3, 1, 2,\n 0, 3, 1, 4, 0, 3, 2, 4, 0, 1, 2, 4, 3, 1, 2,\n];\n\n/**\n * Tính vị trí (0-59) của một tổ hợp Can Chi trong chu kỳ 60 Hoa Giáp, từ index\n * Thiên Can (0-9) và Địa Chi (0-11). Dò tuyến tính 60 giá trị — hàm này không nằm\n * trên đường găng hiệu năng (chỉ gọi khi cần tra Nạp Âm), nên ưu tiên đơn giản/khó\n * sai hơn là tự suy công thức CRT đóng.\n */\nfunction getSexagenaryIndex(stemIndex: number, branchIndex: number): number {\n for (let i = 0; i < 60; i++) {\n if (i % 10 === stemIndex && i % 12 === branchIndex) {\n return i;\n }\n }\n // Không xảy ra với Can Chi hợp lệ — Can/Chi hợp lệ luôn cùng tính chẵn/lẻ\n // (Can Dương luôn đi với Chi Dương, Can Âm luôn đi với Chi Âm).\n throw new RangeError(`Lichta: Invalid Can Chi combination (stem=${stemIndex}, chi=${branchIndex})`);\n}\n\n/**\n * Tính index Ngũ Hành Nạp Âm (0-4, vào FIVE_ELEMENTS) từ index Can + Chi.\n * Export nội bộ — dùng bởi `almanac.ts` ({@link getYearDetails}), không thuộc public API.\n */\nexport function getNapAmElementIndex(stemIndex: number, branchIndex: number): number {\n const sexagenaryIndex = getSexagenaryIndex(stemIndex, branchIndex);\n return NAP_AM_ELEMENT_INDEX[Math.floor(sexagenaryIndex / 2)] as number;\n}\n\n/**\n * Lấy tên Ngũ Hành theo index và locale.\n *\n * @param index - Index Ngũ Hành (0-4, vào FIVE_ELEMENTS: Kim, Mộc, Thủy, Hỏa, Thổ)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getElementName(index: number, locale: Locale = 'vi'): string {\n return t(locale).fiveElements[mod(index, 5)] as string;\n}\n\n/**\n * Tính index Ngũ Hành Nạp Âm (0-4, vào FIVE_ELEMENTS) của ngày, dùng chung bảng\n * Nạp Âm 60 Hoa Giáp với `getYearDetails` (almanac.ts). Chỉ số Can/Chi tính giống hệt\n * {@link import('./can-chi.js').getDayCanChi}.\n *\n * @param jd - Julian Day Number\n */\nexport function getDayElementIndex(jd: number): number {\n const stemIndex = (jd + 9) % 10;\n const branchIndex = (jd + 1) % 12;\n return getNapAmElementIndex(stemIndex, branchIndex);\n}\n\n/**\n * Tính Mệnh (Ngũ Hành Nạp Âm) của ngày theo locale (xem {@link getDayElementIndex}).\n *\n * @param jd - Julian Day Number\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getDayElement(jd: number, locale: Locale = 'vi'): string {\n return getElementName(getDayElementIndex(jd), locale);\n}\n\n/**\n * Tính index Ngũ Hành Nạp Âm (0-4, vào FIVE_ELEMENTS) của tháng âm lịch. Chỉ số\n * Can/Chi tính giống hệt {@link import('./can-chi.js').getMonthCanChi}.\n *\n * @param lunarMonth - Tháng âm lịch (1-12)\n * @param lunarYear - Năm âm lịch\n */\nexport function getMonthElementIndex(lunarMonth: number, lunarYear: number): number {\n const yearStemIndex = (lunarYear + 6) % 10;\n const monthStemOffset = (yearStemIndex % 5) * 2 + 2;\n const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;\n const monthBranchIndex = (lunarMonth + 1) % 12;\n return getNapAmElementIndex(monthStemIndex, monthBranchIndex);\n}\n\n/**\n * Tính Mệnh (Ngũ Hành Nạp Âm) của tháng âm lịch theo locale (xem {@link getMonthElementIndex}).\n *\n * @param lunarMonth - Tháng âm lịch (1-12)\n * @param lunarYear - Năm âm lịch\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getMonthElement(lunarMonth: number, lunarYear: number, locale: Locale = 'vi'): string {\n return getElementName(getMonthElementIndex(lunarMonth, lunarYear), locale);\n}\n\n/**\n * Tính index Ngũ Hành Nạp Âm (0-4, vào FIVE_ELEMENTS) của giờ. Chỉ số Can/Chi tính\n * giống hệt {@link import('./can-chi.js').getHourCanChi}.\n *\n * @param hour - Giờ (0-23)\n * @param dayJd - Julian Day Number của ngày\n */\nexport function getHourElementIndex(hour: number, dayJd: number): number {\n const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;\n const dayStemIndex = (dayJd + 9) % 10;\n const hourStemOffset = (dayStemIndex % 5) * 2;\n const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;\n return getNapAmElementIndex(hourStemIndex, hourBranchIndex);\n}\n\n/**\n * Tính Mệnh (Ngũ Hành Nạp Âm) của giờ theo locale (xem {@link getHourElementIndex}).\n *\n * @param hour - Giờ (0-23)\n * @param dayJd - Julian Day Number của ngày\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getHourElement(hour: number, dayJd: number, locale: Locale = 'vi'): string {\n return getElementName(getHourElementIndex(hour, dayJd), locale);\n}\n\n// ============================================================\n// Tương Sinh — Tương Khắc\n// ============================================================\n\n/** Ngũ Hành mà mỗi hành (theo index FIVE_ELEMENTS) SINH ra: Kim→Thủy, Mộc→Hỏa, Thủy→Mộc, Hỏa→Thổ, Thổ→Kim. */\nconst ELEMENT_SINH_TARGET: readonly number[] = [2, 3, 1, 4, 0];\n\n/** Ngũ Hành mà mỗi hành (theo index FIVE_ELEMENTS) KHẮC: Kim→Mộc, Mộc→Thổ, Thủy→Hỏa, Hỏa→Kim, Thổ→Thủy. */\nconst ELEMENT_KHAC_TARGET: readonly number[] = [1, 4, 3, 0, 2];\n\n/**\n * Tính quan hệ Ngũ Hành từ `fromIndex` tới `toIndex`, trả về index 0-4:\n * 0 = sinh (from sinh to) 2 = khắc (from khắc to) 4 = hòa (cùng hành)\n * 1 = được sinh (to sinh from) 3 = bị khắc (to khắc from)\n *\n * Với 5 hành, 2 hành khác nhau bất kỳ luôn rơi vào đúng 1 trong 4 quan hệ trên\n * (mỗi hành có đúng 1 hành sinh nó, 1 hành nó sinh, 1 hành khắc nó, 1 hành nó khắc)\n * — không có trường hợp mơ hồ.\n *\n * @param fromIndex - Index Ngũ Hành thứ nhất (0-4, vào FIVE_ELEMENTS)\n * @param toIndex - Index Ngũ Hành thứ hai (0-4, vào FIVE_ELEMENTS)\n */\nexport function getElementRelationIndex(fromIndex: number, toIndex: number): number {\n const a = mod(fromIndex, 5);\n const b = mod(toIndex, 5);\n if (a === b) return 4;\n if (ELEMENT_SINH_TARGET[a] === b) return 0;\n if (ELEMENT_SINH_TARGET[b] === a) return 1;\n if (ELEMENT_KHAC_TARGET[a] === b) return 2;\n return 3; // Trường hợp còn lại duy nhất: ELEMENT_KHAC_TARGET[b] === a\n}\n\n/**\n * Lấy tên quan hệ Ngũ Hành giữa 2 hành theo locale (xem {@link getElementRelationIndex}).\n *\n * @param fromIndex - Index Ngũ Hành thứ nhất (0-4, vào FIVE_ELEMENTS)\n * @param toIndex - Index Ngũ Hành thứ hai (0-4, vào FIVE_ELEMENTS)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n *\n * @example\n * ```typescript\n * // Mộc (1) và Hỏa (3): Mộc sinh Hỏa\n * getElementRelation(1, 3); // → 'Tương sinh'\n * getElementRelation(3, 1); // → 'Được sinh' (từ góc nhìn của Hỏa: được Mộc sinh)\n * ```\n */\nexport function getElementRelation(fromIndex: number, toIndex: number, locale: Locale = 'vi'): string {\n const { elementRelationNames } = t(locale);\n return elementRelationNames[getElementRelationIndex(fromIndex, toIndex)] as string;\n}\n","import { jdFromDate, jdToDate, getSolarTermIndex } from './astronomical.js';\nimport { t, type Locale } from '../constants/i18n.js';\nimport type { SolarTerm } from './types.js';\n\n/**\n * Lấy tên Tiết Khí theo index và locale.\n *\n * @param index - Index Tiết Khí (0-23, xem {@link getSolarTermIndex} trong astronomical.ts;\n * 0 = Xuân Phân, 18 = Đông Chí, 21 = Lập Xuân, ...)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getSolarTermName(index: number, locale: Locale = 'vi'): string {\n const { solarTermNames } = t(locale);\n return solarTermNames[((index % 24) + 24) % 24] as string;\n}\n\n/**\n * Lấy Tiết Khí đang hiệu lực tại một ngày dương lịch cho trước.\n *\n * `getSolarTermIndex` (astronomical.ts) trả về kinh độ Mặt Trời tại thời điểm 00:00 (đầu\n * ngày) của `jdn`. Theo quy ước almanac truyền thống, một ngày được tính là \"ngày\n * Tiết Khí X\" nếu thời điểm chuyển Tiết Khí rơi vào bất kỳ lúc nào trong ngày đó —\n * tức là dùng giá trị tại 00:00 của ngày **kế tiếp** mới phản ánh đúng Tiết Khí đã\n * \"chốt\" cho ngày hiện tại. Vì vậy hàm này tra cứu tại `jd + 1`, không phải `jd`.\n *\n * @param day - Ngày dương lịch (1-31)\n * @param month - Tháng dương lịch (1-12)\n * @param year - Năm dương lịch\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n *\n * @example\n * ```typescript\n * getSolarTerm(21, 6, 2024);\n * // → { index: 6, name: 'Hạ Chí', date: { day: 21, month: 6, year: 2024 }, jd: ... }\n * ```\n */\nexport function getSolarTerm(\n day: number,\n month: number,\n year: number,\n timeZone: number = 7,\n locale: Locale = 'vi'\n): SolarTerm {\n const jd = jdFromDate(day, month, year);\n const index = getSolarTermIndex(jd + 1, timeZone);\n return { index, name: getSolarTermName(index, locale), date: { day, month, year }, jd };\n}\n\n/** Một lần xuất hiện Tiết Khí, chưa gắn tên/locale — dữ liệu thô dùng để cache. */\nexport interface SolarTermOccurrence {\n index: number;\n jd: number;\n}\n\n/**\n * Cache kết quả quét theo `năm:timeZone` — phần quét (dưới đây) tốn ~370 lần tính\n * lượng giác mỗi năm, trong khi kết quả không đổi giữa các lần gọi cùng năm/timeZone\n * (chỉ locale khác nhau, mà locale không ảnh hưởng tới ngày/index tính được). Không\n * cần giới hạn kích thước cache: thực tế chỉ vài chục năm được truy vấn trong vòng\n * đời một ứng dụng lịch, chi phí bộ nhớ không đáng kể.\n */\nconst occurrencesCache = new Map<string, SolarTermOccurrence[]>();\n\n/**\n * Quét kinh độ Mặt Trời để tìm toàn bộ Tiết Khí bắt đầu trong một năm dương lịch,\n * trả về dữ liệu thô (index + jd, chưa gắn tên/locale). Dùng nội bộ, chia sẻ giữa\n * {@link getSolarTermsInYear} (gắn tên theo locale) và `getTrucIndex` (truc-zodiac.ts,\n * chỉ cần jd/index để tìm mốc Tiết gần nhất, không cần tên).\n *\n * Quét trực tiếp trên kinh độ Mặt Trời (cùng công thức Hồ Ngọc Đức/Meeus dùng cho\n * Điểm Sóc và Trung Khí) thay vì suy ra ngày trung bình, nên chính xác đến từng ngày\n * kể cả ở các năm nhuận Dương lịch hoặc gần ranh giới năm.\n *\n * `getSolarTermIndex(jd)` phản ánh Tiết Khí tại 00:00 đầu ngày `jd`. Khi chỉ số này\n * đổi từ ngày `jd - 1` sang ngày `jd`, thời điểm chuyển Tiết Khí thực tế rơi vào\n * trong ngày `jd - 1` (xem giải thích chi tiết ở {@link getSolarTerm}) — nên ngày\n * được ghi nhận là `jd - 1`, không phải `jd`.\n */\nexport function getSolarTermOccurrencesInYear(year: number, timeZone: number): SolarTermOccurrence[] {\n const cacheKey = `${year}:${timeZone}`;\n const cached = occurrencesCache.get(cacheKey);\n if (cached) return cached;\n\n const startJd = jdFromDate(1, 1, year) - 5;\n const endJd = jdFromDate(31, 12, year) + 5;\n\n const occurrences: SolarTermOccurrence[] = [];\n let prevIndex = getSolarTermIndex(startJd, timeZone);\n for (let jd = startJd + 1; jd <= endJd; jd++) {\n const index = getSolarTermIndex(jd, timeZone);\n if (index !== prevIndex) {\n const termJd = jd - 1;\n const [, , jdYear] = jdToDate(termJd);\n if (jdYear === year) {\n occurrences.push({ index, jd: termJd });\n }\n prevIndex = index;\n }\n }\n\n occurrencesCache.set(cacheKey, occurrences);\n return occurrences;\n}\n\n/**\n * Liệt kê toàn bộ Tiết Khí bắt đầu trong một năm dương lịch (thường 24 hoặc 25 lần\n * xuất hiện tùy năm, do các Tiết Khí không rơi đúng vào ranh giới năm).\n *\n * @param year - Năm dương lịch\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n * @returns Mảng {@link SolarTerm} theo thứ tự thời gian tăng dần\n */\nexport function getSolarTermsInYear(\n year: number,\n timeZone: number = 7,\n locale: Locale = 'vi'\n): SolarTerm[] {\n return getSolarTermOccurrencesInYear(year, timeZone).map(({ index, jd }) => {\n const [day, month, jdYear] = jdToDate(jd);\n return { index, name: getSolarTermName(index, locale), date: { day, month, year: jdYear }, jd };\n });\n}\n","import { t, type Locale } from '../constants/i18n.js';\nimport { mod } from '../utils/math.js';\nimport { jdToDate } from './astronomical.js';\nimport { getSolarTermOccurrencesInYear } from './tiet-khi.js';\n\n// ============================================================\n// Trực (12 Kiến Trừ)\n// ============================================================\n\nconst TRUC_COUNT = 12;\n\n/**\n * Tính index Trực (0-11: Kiến, Trừ, Mãn, Bình, Định, Chấp, Phá, Nguy, Thành, Thu, Khai, Bế)\n * tại một ngày dương lịch (Julian Day Number).\n *\n * Trực được neo theo 12 Tiết (Lập Xuân, Kinh Trập, Thanh Minh, ...) — tức các index\n * lẻ trong 24 Tiết Khí ({@link import('./tiet-khi.js').getSolarTermsInYear}, `tiet-khi.ts`) —\n * KHÔNG theo số tháng âm lịch, vì tháng nhuận âm lịch không tương ứng với một Tiết mới\n * (dùng số tháng âm lịch sẽ cho kết quả sai trong các tháng nhuận).\n *\n * Ngày Tiết bắt đầu luôn là \"Kiến\" (index 0), Trực tăng dần 1 mỗi ngày sau đó và\n * quay lại \"Kiến\" vào Tiết kế tiếp. Vì mỗi Tiết dài ~15 ngày (không chia hết cho\n * chu kỳ 12 ngày của Trực), một số Trực sẽ bị lặp lại hoặc rút ngắn giữa 2 Tiết\n * liên tiếp — đây là đặc tính vốn có của hệ Kiến Trừ truyền thống, không phải lỗi.\n *\n * Dùng `getSolarTermOccurrencesInYear` (dữ liệu thô, có cache theo năm+timeZone)\n * thay vì `getSolarTermsInYear` công khai — tránh tính tên/locale không cần dùng\n * tới, và tránh quét lại kinh độ Mặt Trời mỗi lần gọi khi hàm này được gọi lặp lại\n * cho nhiều ngày cùng năm (vd. dựng lịch Trực cho cả tháng/năm).\n *\n * @param jd - Julian Day Number của ngày cần tra\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n */\nexport function getTrucIndex(jd: number, timeZone: number = 7): number {\n const [, , year] = jdToDate(jd);\n // Quét cả năm trước/sau để không bỏ sót Tiết gần ranh giới năm dương lịch\n // (vd. đầu tháng 1 vẫn thuộc Tiết Đại Tuyết bắt đầu từ đầu tháng 12 năm trước).\n const tietTerms = [year - 1, year, year + 1]\n .flatMap((y) => getSolarTermOccurrencesInYear(y, timeZone))\n .filter((term) => term.index % 2 === 1); // 12 Tiết = index lẻ, bỏ 12 Khí (index chẵn)\n\n let governingTietJd = -Infinity;\n for (const term of tietTerms) {\n if (term.jd <= jd && term.jd > governingTietJd) {\n governingTietJd = term.jd;\n }\n }\n\n return mod(jd - governingTietJd, TRUC_COUNT);\n}\n\n/**\n * Lấy tên Trực theo index và locale.\n *\n * @param index - Index Trực (0-11, xem {@link getTrucIndex})\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getTrucName(index: number, locale: Locale = 'vi'): string {\n const { trucNames } = t(locale);\n return trucNames[mod(index, TRUC_COUNT)] as string;\n}\n\n/**\n * Lấy tên Trực tại một ngày dương lịch (Julian Day Number).\n *\n * @param jd - Julian Day Number của ngày cần tra\n * @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getTruc(jd: number, timeZone: number = 7, locale: Locale = 'vi'): string {\n return getTrucName(getTrucIndex(jd, timeZone), locale);\n}\n\n/**\n * Mức tốt/xấu tổng quát của mỗi Trực (0 = Xấu, 1 = Trung bình, 2 = Tốt).\n *\n * Chỉ phân loại dứt khoát 4/12 Trực có sự đồng thuận rất cao giữa các nguồn:\n * Phá và Nguy luôn được xem là 2 Trực xấu nhất; Thành và Khai luôn được xem là 2\n * Trực tốt nhất. 8 Trực còn lại (Kiến, Trừ, Mãn, Bình, Định, Chấp, Thu, Bế) được\n * xếp \"Trung bình\" — KHÔNG phải vì chúng thực sự trung tính, mà vì mức tốt/xấu\n * chi tiết của chúng phụ thuộc vào từng việc cụ thể (nên/kỵ làm gì) và có dị bản\n * giữa các nguồn, nên repo này không tự khẳng định dứt khoát khi chưa đối chiếu\n * được một nguồn cụ thể. Nếu cần phân loại chi tiết hơn, nên tự bổ sung dựa trên\n * nguồn tham khảo bạn tin cậy thay vì dùng bảng này làm chỗ dựa duy nhất.\n */\nconst TRUC_QUALITY_INDEX: readonly number[] = [1, 1, 1, 1, 1, 1, 0, 0, 2, 1, 2, 1];\n\n/**\n * Lấy index mức tốt/xấu (0-2) của một Trực — xem giải thích độ tin cậy ở\n * {@link TRUC_QUALITY_INDEX}.\n *\n * @param trucIndex - Index Trực (0-11, xem {@link getTrucIndex})\n */\nexport function getTrucQualityIndex(trucIndex: number): number {\n return TRUC_QUALITY_INDEX[mod(trucIndex, TRUC_COUNT)] as number;\n}\n\n/**\n * Lấy tên mức tốt/xấu của một Trực theo locale (xem {@link getTrucQualityIndex}).\n *\n * @param trucIndex - Index Trực (0-11, xem {@link getTrucIndex})\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n */\nexport function getTrucQuality(trucIndex: number, locale: Locale = 'vi'): string {\n const { trucQualityNames } = t(locale);\n return trucQualityNames[getTrucQualityIndex(trucIndex)] as string;\n}\n\n// ============================================================\n// Tuổi Xung Khắc (Lục Xung — Lục Hại — Tứ Hành Xung)\n// ============================================================\n\n/**\n * Lấy Chi đối xung (Lục Xung) với một Chi cho trước — 2 Chi cách nhau đúng 6 vị\n * trí trong vòng tròn 12 Chi: Tý-Ngọ, Sửu-Mùi, Dần-Thân, Mão-Dậu, Thìn-Tuất, Tỵ-Hợi.\n *\n * @param branchIndex - Index Địa Chi (0-11, vào EARTHLY_BRANCHES)\n * @returns Index Địa Chi đối xung\n */\nexport function getXungBranchIndex(branchIndex: number): number {\n return mod(branchIndex + 6, 12);\n}\n\n/**\n * Kiểm tra 2 Chi (tuổi) có phạm Lục Xung với nhau không.\n *\n * @param branchIndexA - Index Địa Chi thứ nhất (0-11)\n * @param branchIndexB - Index Địa Chi thứ hai (0-11)\n */\nexport function isXung(branchIndexA: number, branchIndexB: number): boolean {\n return getXungBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);\n}\n\n/**\n * Bảng Lục Hại: Tý-Mùi, Sửu-Ngọ, Dần-Tỵ, Mão-Thìn, Thân-Hợi, Dậu-Tuất.\n * Giá trị tại index i là Chi bị hại với Chi i (quan hệ đối xứng).\n */\nconst HAI_BRANCH_TARGET: readonly number[] = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8];\n\n/**\n * Lấy Chi bị Lục Hại với một Chi cho trước (xem {@link HAI_BRANCH_TARGET}).\n *\n * @param branchIndex - Index Địa Chi (0-11, vào EARTHLY_BRANCHES)\n * @returns Index Địa Chi bị hại\n */\nexport function getHaiBranchIndex(branchIndex: number): number {\n return HAI_BRANCH_TARGET[mod(branchIndex, 12)] as number;\n}\n\n/**\n * Kiểm tra 2 Chi (tuổi) có phạm Lục Hại với nhau không.\n *\n * @param branchIndexA - Index Địa Chi thứ nhất (0-11)\n * @param branchIndexB - Index Địa Chi thứ hai (0-11)\n */\nexport function isHai(branchIndexA: number, branchIndexB: number): boolean {\n return getHaiBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);\n}\n\n/**\n * Bảng Tứ Hành Xung: 3 nhóm, mỗi nhóm 4 Chi được xem là xung khắc lẫn nhau —\n * Nhóm 0: Tý, Mão, Ngọ, Dậu (Tứ Chính)\n * Nhóm 1: Dần, Tỵ, Thân, Hợi (Tứ Sinh)\n * Nhóm 2: Sửu, Thìn, Mùi, Tuất (Tứ Mộ)\n * Giá trị tại index i là nhóm (0-2) chứa Chi i.\n */\nconst TU_HANH_XUNG_GROUP: readonly number[] = [0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1];\n\n/** 3 nhóm Tứ Hành Xung, mỗi nhóm là mảng 4 index Địa Chi (xem {@link TU_HANH_XUNG_GROUP}). */\nconst TU_HANH_XUNG_MEMBERS: readonly (readonly number[])[] = [\n [0, 3, 6, 9], // Tý, Mão, Ngọ, Dậu\n [2, 5, 8, 11], // Dần, Tỵ, Thân, Hợi\n [1, 4, 7, 10], // Sửu, Thìn, Mùi, Tuất\n];\n\n/**\n * Lấy nhóm Tứ Hành Xung (0-2) chứa một Chi cho trước.\n *\n * @param branchIndex - Index Địa Chi (0-11, vào EARTHLY_BRANCHES)\n * @returns Index nhóm (0-2, xem {@link getTuHanhXungGroupMembers})\n */\nexport function getTuHanhXungGroupIndex(branchIndex: number): number {\n return TU_HANH_XUNG_GROUP[mod(branchIndex, 12)] as number;\n}\n\n/**\n * Lấy 4 Chi thuộc cùng nhóm Tứ Hành Xung với một Chi cho trước (bao gồm cả chính nó).\n *\n * @param branchIndex - Index Địa Chi (0-11, vào EARTHLY_BRANCHES)\n * @returns Mảng 4 index Địa Chi cùng nhóm\n */\nexport function getTuHanhXungGroupMembers(branchIndex: number): number[] {\n return [...TU_HANH_XUNG_MEMBERS[getTuHanhXungGroupIndex(branchIndex)]];\n}\n\n/**\n * Kiểm tra 2 Chi (tuổi) khác nhau có cùng nhóm Tứ Hành Xung không.\n *\n * @param branchIndexA - Index Địa Chi thứ nhất (0-11)\n * @param branchIndexB - Index Địa Chi thứ hai (0-11)\n */\nexport function isTuHanhXung(branchIndexA: number, branchIndexB: number): boolean {\n const a = mod(branchIndexA, 12);\n const b = mod(branchIndexB, 12);\n return a !== b && getTuHanhXungGroupIndex(a) === getTuHanhXungGroupIndex(b);\n}\n\n/** Kết quả trả về của {@link getZodiacConflicts}. */\nexport interface ZodiacConflicts {\n xung: boolean;\n hai: boolean;\n tuHanhXung: boolean;\n}\n\n/**\n * Kiểm tra toàn bộ quan hệ \"kỵ tuổi\" (Lục Xung, Lục Hại, Tứ Hành Xung) giữa 2 tuổi\n * (Chi năm sinh). Không loại trừ lẫn nhau — 1 cặp Chi có thể vừa Lục Xung vừa cùng\n * nhóm Tứ Hành Xung (vd. Tý-Ngọ là cả 2).\n *\n * @param branchIndexA - Index Địa Chi (con giáp) thứ nhất (0-11)\n * @param branchIndexB - Index Địa Chi (con giáp) thứ hai (0-11)\n *\n * @example\n * ```typescript\n * getZodiacConflicts(0, 6); // Tý (0) và Ngọ (6)\n * // → { xung: true, hai: false, tuHanhXung: true }\n * ```\n */\nexport function getZodiacConflicts(branchIndexA: number, branchIndexB: number): ZodiacConflicts {\n return {\n xung: isXung(branchIndexA, branchIndexB),\n hai: isHai(branchIndexA, branchIndexB),\n tuHanhXung: isTuHanhXung(branchIndexA, branchIndexB),\n };\n}\n","/**\n * Five Elements (Ngũ Hành)\n * Kim | Metal\n * Mộc | Wood\n * Thủy | Water\n * Hỏa | Fire\n * Thổ | Earth\n */\nexport const FIVE_ELEMENTS = ['Kim', 'Mộc', 'Thủy', 'Hỏa', 'Thổ'];","import { HEAVENLY_STEMS } from '../constants/heavenly-stems.js';\nimport { EARTHLY_BRANCHES } from '../constants/earthly-branches.js';\nimport { FIVE_ELEMENTS } from '../constants/five-elements.js';\nimport { t, type Locale } from '../constants/i18n.js';\nimport { mod } from '../utils/math.js';\nimport { getNapAmElementIndex } from './ngu-hanh.js';\n\n/** Kết quả trả về của {@link getYearDetails}. */\nexport interface YearDetails {\n can: string;\n chi: string;\n menh: string;\n /** Index Ngũ Hành của `menh` (0-4, vào FIVE_ELEMENTS) — dùng cho `getElementRelation` (ngu-hanh.ts). */\n menhIndex: number;\n fullString: string;\n}\n\n/**\n * Lấy ra chuỗi mô tả toàn bộ Can, Chi và Mệnh dựa vào số năm (Ví dụ: 2024)\n * Theo quy ước: Năm 4 (sau CN) là năm Giáp Tý (Can index 0, Chi index 0)\n *\n * Công thức Can Chi là chu kỳ 60 năm lặp lại vô hạn nên nhận mọi số năm nguyên,\n * kể cả năm 0 hoặc âm (trước Công Nguyên) — không giới hạn phạm vi như\n * `LichTa.toLunar` (phạm vi đó là do thuật toán tìm Điểm Sóc, không áp\n * dụng cho công thức Can Chi thuần).\n *\n * @param year - Năm (số nguyên bất kỳ, kể cả 0 hoặc âm)\n *\n * @example\n * ```typescript\n * getYearDetails(2024);\n * // → { can: 'Giáp', chi: 'Thìn', menh: 'Hỏa', menhIndex: 3, fullString: 'Giáp Thìn - Mệnh Hỏa' }\n * ```\n */\nexport function getYearDetails(year: number): YearDetails {\n // Tính index của Can và Chi dựa trên mốc năm gốc\n // Năm 1984, 2044 là Giáp Tý -> Offset để tính toán dễ nhất là lấy (year - 4) % hệ cơ số\n const stemIndex = mod(year - 4, 10);\n const branchIndex = mod(year - 4, 12);\n const elementIndex = getNapAmElementIndex(stemIndex, branchIndex);\n\n return {\n can: HEAVENLY_STEMS[stemIndex],\n chi: EARTHLY_BRANCHES[branchIndex],\n menh: FIVE_ELEMENTS[elementIndex],\n menhIndex: elementIndex,\n fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - Mệnh ${FIVE_ELEMENTS[elementIndex]}`\n };\n}\n\n// ============================================================\n// Giờ Hoàng Đạo\n// ============================================================\n\n/**\n * Bảng giờ Hoàng Đạo theo Chi của ngày.\n * Mỗi hàng tương ứng với 2 Chi (Tý-Ngọ, Sửu-Mùi, ...) → 6 nhóm.\n * Giá trị là index các Địa Chi tốt (6 giờ tốt trong 12 canh).\n */\nconst AUSPICIOUS_HOURS_TABLE: readonly (readonly number[])[] = [\n [0, 1, 3, 6, 7, 9], // Ngày Tý (0) / Ngọ (6)\n [2, 3, 5, 8, 9, 11], // Ngày Sửu (1) / Mùi (7)\n [0, 1, 4, 5, 7, 10], // Ngày Dần (2) / Thân (8)\n [1, 2, 4, 7, 8, 10], // Ngày Mão (3) / Dậu (9)\n [0, 3, 4, 6, 9, 10], // Ngày Thìn (4) / Tuất (10)\n [2, 5, 6, 8, 11, 0], // Ngày Tỵ (5) / Hợi (11)\n] as const;\n\n/**\n * Lấy danh sách 6 giờ Hoàng Đạo trong ngày.\n * Giờ Hoàng Đạo phụ thuộc vào Địa Chi của ngày.\n *\n * @param dayJd - Julian Day Number của ngày\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi', giữ nguyên hành vi cũ)\n * @returns Mảng 6 chuỗi tên Địa Chi (ví dụ: [\"Tý\", \"Sửu\", \"Mão\", \"Ngọ\", \"Mùi\", \"Dậu\"])\n */\nexport function getAuspiciousHours(dayJd: number, locale: Locale = 'vi'): string[] {\n const branchIndex = (dayJd + 1) % 12;\n // Nhóm theo 2 Chi (Tý-Ngọ, Sửu-Mùi, ...)\n const groupIndex = branchIndex % 6;\n const hourIndices = AUSPICIOUS_HOURS_TABLE[groupIndex];\n const { earthlyBranches } = t(locale);\n return hourIndices.map((i) => earthlyBranches[i] as string);\n}\n\n/**\n * Lấy index (0-11, theo thứ tự Địa Chi Tý→Hợi) của 6 giờ Hoàng Đạo trong ngày.\n *\n * Dùng khi cần một khoá ổn định, không phụ thuộc ngôn ngữ — ví dụ để map sang\n * icon riêng, hoặc tự tra bảng dịch của bạn thay vì dùng chuỗi tên có sẵn từ\n * {@link getAuspiciousHours}. Cả hai hàm dùng chung thứ tự dữ liệu nên\n * `getAuspiciousHourIndices(jd)[i]` luôn tương ứng với `getAuspiciousHours(jd)[i]`.\n *\n * @param dayJd - Julian Day Number của ngày\n * @returns Mảng 6 index Địa Chi (ví dụ: [0, 1, 3, 6, 7, 9])\n */\nexport function getAuspiciousHourIndices(dayJd: number): number[] {\n const branchIndex = (dayJd + 1) % 12;\n const groupIndex = branchIndex % 6;\n return [...AUSPICIOUS_HOURS_TABLE[groupIndex]];\n}\n\n/**\n * Lấy index (0-11, theo thứ tự Địa Chi Tý→Hợi) của 6 giờ Hắc Đạo (giờ xấu) trong\n * ngày — phần bù của {@link getAuspiciousHourIndices} trong 12 canh giờ (6 giờ\n * Hoàng Đạo + 6 giờ Hắc Đạo = đủ 12 canh).\n *\n * @param dayJd - Julian Day Number của ngày\n * @returns Mảng 6 index Địa Chi, tăng dần\n */\nexport function getInauspiciousHourIndices(dayJd: number): number[] {\n const auspicious = new Set(getAuspiciousHourIndices(dayJd));\n const inauspicious: number[] = [];\n for (let i = 0; i < 12; i++) {\n if (!auspicious.has(i)) inauspicious.push(i);\n }\n return inauspicious;\n}\n\n/**\n * Lấy danh sách 6 giờ Hắc Đạo (giờ xấu) trong ngày theo locale (xem\n * {@link getInauspiciousHourIndices}).\n *\n * @param dayJd - Julian Day Number của ngày\n * @param locale - Ngôn ngữ hiển thị (mặc định: 'vi')\n * @returns Mảng 6 chuỗi tên Địa Chi\n */\nexport function getInauspiciousHours(dayJd: number, locale: Locale = 'vi'): string[] {\n const { earthlyBranches } = t(locale);\n return getInauspiciousHourIndices(dayJd).map((i) => earthlyBranches[i] as string);\n}\n","import type { LunarDate } from '../core/types.js';\nimport { t, type Locale } from '../constants/i18n.js';\n\n// ============================================================\n// Tên tháng & ngày truyền thống\n// ============================================================\n\n/** Tên tháng âm lịch truyền thống */\nconst MONTH_NAMES = [\n 'Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu',\n 'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp',\n] as const;\n\n/** Tên số đếm truyền thống */\nconst DAY_UNITS = [\n '', 'Một', 'Hai', 'Ba', 'Bốn', 'Năm',\n 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười',\n] as const;\n\n/**\n * Lấy tên tháng âm lịch dạng chữ truyền thống.\n *\n * @param month - Tháng âm lịch (1-12)\n * @returns Tên tháng (ví dụ: 1 → \"Giêng\", 12 → \"Chạp\")\n *\n * @example\n * ```typescript\n * getMonthName(1); // \"Giêng\"\n * getMonthName(12); // \"Chạp\"\n * ```\n */\nexport function getMonthName(month: number): string {\n if (month < 1 || month > 12) {\n throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);\n }\n return MONTH_NAMES[month - 1];\n}\n\n/**\n * Lấy tên ngày âm lịch theo cách gọi truyền thống Việt Nam.\n *\n * - 1-10: \"Mùng Một\", \"Mùng Hai\", ..., \"Mùng Mười\"\n * - 11-20: \"Mười Một\", ..., \"Hai Mươi\"\n * - 21-30: \"Hăm Mốt\", \"Hăm Hai\", ..., \"Ba Mươi\"\n *\n * @param day - Ngày âm lịch (1-30)\n *\n * @example\n * ```typescript\n * getDayName(1); // \"Mùng Một\"\n * getDayName(15); // \"Rằm\"\n * getDayName(30); // \"Ba Mươi\"\n * ```\n */\nexport function getDayName(day: number): string {\n if (day < 1 || day > 30) {\n throw new RangeError(`Lichta: Day must be between 1 and 30, got ${day}`);\n }\n\n // Ngày Rằm\n if (day === 15) return 'Rằm';\n\n // Mùng 1-10\n if (day <= 10) {\n return `Mùng ${DAY_UNITS[day]}`;\n }\n\n // 11-19\n if (day < 20) {\n if (day === 11) return 'Mười Một';\n if (day === 14) return 'Mười Bốn';\n return `Mười ${DAY_UNITS[day - 10]}`;\n }\n\n // 20\n if (day === 20) return 'Hai Mươi';\n\n // 21-29\n if (day < 30) {\n if (day === 21) return 'Hăm Mốt';\n if (day === 24) return 'Hăm Tư';\n if (day === 25) return 'Hăm Lăm';\n return `Hăm ${DAY_UNITS[day - 20]}`;\n }\n\n // 30\n return 'Ba Mươi';\n}\n\n// ============================================================\n// Format functions\n// ============================================================\n\n/**\n * Format ngày âm lịch theo pattern.\n *\n * **Patterns hỗ trợ:**\n * | Token | Mô tả | Ví dụ |\n * |-------|------------------------------------------|----------------|\n * | `dd` | Ngày 2 chữ số | 01, 15, 30 |\n * | `d` | Ngày | 1, 15, 30 |\n * | `MM` | Tháng 2 chữ số | 01, 12 |\n * | `M` | Tháng | 1, 12 |\n * | `yyyy`| Năm 4 chữ số | 2024 |\n * | `yy` | Năm 2 chữ số cuối | 24 |\n * | `L` | Nhãn tháng nhuận theo `locale` (xem tham số `locale`), \"\" nếu không phải tháng nhuận | Nhuận |\n * | `CC` | Can Chi năm | Giáp Thìn |\n * | `DC` | Can Chi ngày | Giáp Tý |\n * | `MC` | Can Chi tháng | Bính Dần |\n *\n * @param lunar - Đối tượng LunarDate\n * @param pattern - Chuỗi pattern\n * @param locale - Ngôn ngữ cho token `L` (mặc định: 'vi', giữ nguyên hành vi cũ — \"Nhuận\")\n *\n * @example\n * ```typescript\n * formatLunarDate(lunar, 'dd/MM/yyyy');\n * // → \"01/01/2024\"\n *\n * formatLunarDate(lunar, 'Ngày d tháng M năm CC');\n * // → \"Ngày 1 tháng 1 năm Giáp Thìn\"\n * ```\n */\nexport function formatLunarDate(lunar: LunarDate, pattern: string, locale: Locale = 'vi'): string {\n let result = pattern;\n\n // Thay thế theo thứ tự dài → ngắn để tránh xung đột (yyyy trước yy, dd trước d, MM trước M)\n result = result.replace(/yyyy/g, String(lunar.year));\n result = result.replace(/yy/g, String(lunar.year).slice(-2));\n result = result.replace(/dd/g, String(lunar.day).padStart(2, '0'));\n result = result.replace(/MM/g, String(lunar.month).padStart(2, '0'));\n result = result.replace(/CC/g, lunar.yearCanChi ?? '');\n result = result.replace(/DC/g, lunar.dayCanChi ?? '');\n result = result.replace(/MC/g, lunar.monthCanChi ?? '');\n result = result.replace(/L/g, lunar.isLeap ? t(locale).leapLabel : '');\n\n // Thay d và M cuối cùng (sau khi dd, MM đã được xử lý, tránh double-replace)\n // Dùng regex negative lookbehind để không match các token đã được thay\n result = result.replace(/(?<![0-9])d(?![0-9d])/g, String(lunar.day));\n result = result.replace(/(?<![0-9])M(?![0-9MC])/g, String(lunar.month));\n\n return result.trim();\n}\n\n/**\n * Format ngày âm lịch theo kiểu truyền thống Việt Nam.\n *\n * @param lunar - Đối tượng LunarDate\n * @returns Chuỗi truyền thống (ví dụ: \"Mùng Một tháng Giêng năm Giáp Thìn\")\n *\n * @example\n * ```typescript\n * formatTraditional(lunar);\n * // → \"Mùng Một tháng Giêng năm Giáp Thìn\"\n * ```\n */\nexport function formatTraditional(lunar: LunarDate): string {\n const dayName = getDayName(lunar.day);\n const monthName = getMonthName(lunar.month);\n const leapSuffix = lunar.isLeap ? ' Nhuận' : '';\n const yearCanChi = lunar.yearCanChi ?? '';\n\n return `${dayName} tháng ${monthName}${leapSuffix} năm ${yearCanChi}`.trim();\n}\n","import { LichTa } from '../core/calendar-engine.js';\nimport type { LunarDate } from '../core/types.js';\n\n/** Một ô ngày trong lưới lịch tháng. */\nexport interface CalendarDayCell {\n solar: Date;\n lunar: LunarDate;\n isToday: boolean;\n isSelected: boolean;\n isCurrentMonth: boolean;\n /** Số tuần trong năm (ISO-8601) của hàng chứa ô này — giống nhau cho cả 7 ô trong hàng. */\n weekNumber: number;\n}\n\n/** Ngày bắt đầu tuần: 0 = Chủ Nhật (mặc định, giống `Date.getDay()`), 1 = Thứ Hai. */\nexport type FirstDayOfWeek = 0 | 1;\n\nfunction dateKey(date: Date): string {\n return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;\n}\n\n/**\n * Tính số tuần theo chuẩn ISO-8601: tuần bắt đầu Thứ Hai, tuần 1 của năm là\n * tuần chứa Thứ Năm đầu tiên (tương đương: tuần chứa ngày 4/1).\n */\nexport function getISOWeekNumber(date: Date): number {\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n const dayNum = (d.getUTCDay() + 6) % 7; // 0 = Thứ Hai .. 6 = Chủ Nhật\n d.setUTCDate(d.getUTCDate() - dayNum + 3); // Nhích về Thứ Năm cùng tuần ISO\n\n const firstThursday = new Date(Date.UTC(d.getUTCFullYear(), 0, 4));\n const firstThursdayDayNum = (firstThursday.getUTCDay() + 6) % 7;\n firstThursday.setUTCDate(firstThursday.getUTCDate() - firstThursdayDayNum + 3);\n\n return 1 + Math.round((d.getTime() - firstThursday.getTime()) / 604800000);\n}\n\n/**\n * Dựng lưới 42 ô (6 tuần x 7 ngày) cho 1 tháng dương lịch, gồm ngày tràn từ\n * tháng trước/sau để lấp đầy tuần đầu/cuối, mỗi ô kèm ngày âm tương ứng.\n *\n * Logic này trước đây bị lặp lại độc lập ở Calendar.tsx/vue/svelte — tách ra\n * đây để có 1 nguồn tính toán duy nhất (tránh 3 bản có thể lệch nhau khi sửa\n * riêng lẻ), dùng chung cho cả Calendar và DatePicker ở mọi framework.\n *\n * @param month - Tháng dương lịch (1-12)\n * @param year - Năm dương lịch\n * @param selectedDate - Ngày đang được chọn (nếu có), dùng để đánh dấu `isSelected`\n * @param firstDayOfWeek - Ngày bắt đầu tuần: 0 = Chủ Nhật (mặc định), 1 = Thứ Hai\n */\nexport function getCalendarGrid(\n month: number,\n year: number,\n selectedDate?: Date | null,\n firstDayOfWeek: FirstDayOfWeek = 0\n): CalendarDayCell[] {\n const grid: CalendarDayCell[] = [];\n const firstDay = new Date(year, month - 1, 1);\n const lastDay = new Date(year, month, 0);\n const startingDayOfWeek = (firstDay.getDay() - firstDayOfWeek + 7) % 7;\n const daysInMonth = lastDay.getDate();\n const todayKey = dateKey(new Date());\n const selectedKey = selectedDate ? dateKey(selectedDate) : '';\n const prevMonthLastDay = new Date(year, month - 1, 0).getDate();\n\n const pushCell = (solar: Date, d: number, m: number, y: number, isCurrentMonth: boolean) => {\n grid.push({\n solar,\n lunar: LichTa.toLunar(d, m, y),\n isToday: dateKey(solar) === todayKey,\n isSelected: dateKey(solar) === selectedKey,\n isCurrentMonth,\n weekNumber: 0, // gán lại theo từng hàng ở bước cuối, xem vòng lặp bên dưới\n });\n };\n\n for (let i = startingDayOfWeek - 1; i >= 0; i--) {\n const d = prevMonthLastDay - i;\n const m = month - 1 < 1 ? 12 : month - 1;\n const y = month - 1 < 1 ? year - 1 : year;\n pushCell(new Date(y, m - 1, d), d, m, y, false);\n }\n\n for (let d = 1; d <= daysInMonth; d++) {\n pushCell(new Date(year, month - 1, d), d, month, year, true);\n }\n\n const remaining = 42 - grid.length;\n for (let d = 1; d <= remaining; d++) {\n const m = month + 1 > 12 ? 1 : month + 1;\n const y = month + 1 > 12 ? year + 1 : year;\n pushCell(new Date(y, m - 1, d), d, m, y, false);\n }\n\n // Số tuần của cả hàng lấy theo Thứ Năm trong hàng đó — đây là ngày ISO-8601\n // dùng để định danh tuần, nên đúng chuẩn dù hàng bắt đầu Chủ Nhật hay Thứ Hai.\n const thursdayOffset = (4 - firstDayOfWeek + 7) % 7;\n for (let row = 0; row < grid.length; row += 7) {\n const weekNumber = getISOWeekNumber(grid[row + thursdayOffset].solar);\n for (let i = row; i < row + 7; i++) {\n grid[i].weekNumber = weekNumber;\n }\n }\n\n return grid;\n}\n"],"mappings":"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","names":["INT"]}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@lichta/core",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "Thư viện lõi tính toán Dương lịch ↔ Âm lịch Việt Nam",
5
5
  "author": "Zeforc Labs | Stridev",
6
6
  "license": "MIT",
7
+ "sideEffects": false,
7
8
  "main": "./dist/index.js",
8
9
  "module": "./dist/index.mjs",
9
10
  "types": "./dist/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  --lichta-text-dim: #c4b5a0;
9
9
  --lichta-border: #e8ddd0;
10
10
  --lichta-today-bg: #d4a373;
11
- --lichta-today-text: #ffffff;
11
+ --lichta-today-text: #a0522d;
12
12
  --lichta-selected-bg: #a0522d;
13
13
  --lichta-selected-text: #ffffff;
14
14
  --lichta-hover-bg: #f5e6d3;
@@ -16,13 +16,14 @@
16
16
  --lichta-first-lunar: #c2185b;
17
17
  --lichta-radius: 8px;
18
18
  --lichta-font: inherit;
19
+ --lichta-max-width: 420px;
19
20
 
20
21
  font-family: var(--lichta-font);
21
22
  background: var(--lichta-bg);
22
23
  border: 1px solid var(--lichta-border);
23
24
  border-radius: calc(var(--lichta-radius) * 2);
24
25
  padding: 16px;
25
- max-width: 420px;
26
+ max-width: var(--lichta-max-width);
26
27
  width: 100%;
27
28
  box-sizing: border-box;
28
29
  user-select: none;
@@ -91,17 +92,32 @@
91
92
 
92
93
  .lich-ta-calendar-grid {
93
94
  display: grid;
94
- grid-template-columns: repeat(7, 1fr);
95
+ grid-template-columns: repeat(7, minmax(0, 1fr));
95
96
  gap: 2px;
96
97
  }
97
98
 
99
+ .lich-ta-calendar--with-week-number .lich-ta-calendar-weekdays,
100
+ .lich-ta-calendar--with-week-number .lich-ta-calendar-grid {
101
+ grid-template-columns: minmax(24px, auto) repeat(7, minmax(0, 1fr));
102
+ }
103
+
104
+ .lich-ta-calendar-week-number {
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ font-size: 0.7rem;
109
+ font-weight: 500;
110
+ color: var(--lichta-text-dim);
111
+ }
112
+
98
113
  .lich-ta-calendar-day {
99
114
  display: flex;
100
115
  flex-direction: column;
101
116
  align-items: center;
102
117
  justify-content: center;
103
118
  padding: 6px 2px;
104
- min-height: 48px;
119
+ aspect-ratio: 1;
120
+ overflow: hidden;
105
121
  border: none;
106
122
  border-radius: var(--lichta-radius);
107
123
  background: transparent;
@@ -112,6 +128,7 @@
112
128
 
113
129
  .lich-ta-calendar-day:hover {
114
130
  background: var(--lichta-hover-bg);
131
+ color: var(--lichta-text-muted) !important;
115
132
  }
116
133
 
117
134
  .lich-ta-calendar-day:focus-visible {
@@ -163,12 +180,10 @@
163
180
 
164
181
  .is-selected .solar-day {
165
182
  color: var(--lichta-selected-text);
166
- font-weight: 700;
167
183
  }
168
184
 
169
185
  .is-selected .lunar-day {
170
186
  color: var(--lichta-selected-text);
171
- opacity: 0.85;
172
187
  }
173
188
 
174
189
  .is-first-lunar .lunar-day {
@@ -17,10 +17,10 @@
17
17
  --lichta-first-lunar: #FBBF24 !important;
18
18
  --lichta-radius: 12px !important;
19
19
  --lichta-font: 'Outfit', sans-serif !important;
20
-
20
+
21
21
  border: none !important;
22
22
  padding: 0 !important;
23
- max-width: 100% !important;
23
+ max-width: var(--lichta-max-width) !important;
24
24
  }
25
25
 
26
26
  .lich-ta-calendar.lichta-theme-glass .lich-ta-calendar-nav {
@@ -33,13 +33,3 @@
33
33
  border-color: rgba(251, 191, 36, 0.3) !important;
34
34
  color: #FBBF24 !important;
35
35
  }
36
-
37
- .lich-ta-calendar.lichta-theme-glass .is-today .solar-day {
38
- background: rgba(251, 191, 36, 0.2) !important;
39
- border-radius: 50% !important;
40
- width: 28px !important;
41
- height: 28px !important;
42
- display: flex !important;
43
- align-items: center !important;
44
- justify-content: center !important;
45
- }