<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rau Muong</title><link>https://www.raumuong.com/</link><description>Recent content on Rau Muong</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 29 Sep 2026 12:00:00 +0000</lastBuildDate><atom:link href="https://www.raumuong.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Lunisolar Calendar</title><link>https://www.raumuong.com/lunarcalendar/</link><pubDate>Tue, 29 Sep 2026 12:00:00 +0000</pubDate><guid>https://www.raumuong.com/lunarcalendar/</guid><description>&lt;p&gt;Dates below show the standard solar day on top, with the &lt;strong&gt;lunar day (âm lịch)&lt;/strong&gt; highlighted in red underneath.&lt;/p&gt;
&lt;div class="lunisolar-app-root" id="lunisolar-app-root"&gt;
&lt;div class="app-container"&gt;
&lt;header class="cal-top-header"&gt;
&lt;div class="brand"&gt;
&lt;h3&gt;🌓 Lịch Âm Dương&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="controls-top"&gt;
&lt;select id="langSelect" aria-label="Language selection"&gt;
&lt;option value="vi" selected&gt;Tiếng Việt (Âm Lịch)&lt;/option&gt;
&lt;option value="en"&gt;English (Lunisolar)&lt;/option&gt;
&lt;option value="zh"&gt;中文 (农历)&lt;/option&gt;
&lt;/select&gt;
&lt;button type="button" id="btnToday"&gt;🎯 Hôm nay&lt;/button&gt;
&lt;/div&gt;
&lt;/header&gt;
&lt;section class="nav-bar"&gt;
&lt;div class="breadcrumbs" id="breadcrumbs"&gt;
&lt;span class="breadcrumb-item" id="crumbYear"&gt;Năm&lt;/span&gt;
&lt;span class="nav-arrow"&gt;&amp;rsaquo;&lt;/span&gt;
&lt;span class="breadcrumb-item" id="crumbMonth"&gt;Tháng&lt;/span&gt;
&lt;span class="nav-arrow" id="arrowWeek" style="display: none;"&gt;&amp;rsaquo;&lt;/span&gt;
&lt;span class="breadcrumb-item" id="crumbWeek" style="display: none;"&gt;Tuần&lt;/span&gt;
&lt;/div&gt;
&lt;div class="zoom-buttons"&gt;
&lt;button type="button" id="btnPrev" title="Trước"&gt;&amp;lt;&lt;/button&gt;
&lt;button type="button" id="btnNext" title="Sau"&gt;&amp;gt;&lt;/button&gt;
&lt;button type="button" id="btnZoomOut" title="Zoom Out"&gt;🔍 Thu nhỏ&lt;/button&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;main class="calendar-stage" id="calendarStage"&gt;&lt;/main&gt;
&lt;/div&gt;
&lt;div class="modal-backdrop" id="dayDetailModal"&gt;
&lt;div class="modal-card"&gt;
&lt;button type="button" class="modal-close-btn" id="modalCloseBtn"&gt;&amp;times;&lt;/button&gt;
&lt;div class="gregorian-hero"&gt;
&lt;div class="gregorian-hero-label"&gt;📅 Dương Lịch (Gregorian)&lt;/div&gt;
&lt;div class="gregorian-hero-date" id="mdlGregorianDate"&gt;--&lt;/div&gt;
&lt;/div&gt;
&lt;div class="details-table"&gt;
&lt;div class="detail-item"&gt;
&lt;span class="detail-label"&gt;🌓 Âm Lịch (Lunisolar)&lt;/span&gt;
&lt;span class="detail-value accent" id="mdlLunarDate"&gt;--&lt;/span&gt;
&lt;/div&gt;
&lt;div class="detail-item"&gt;
&lt;span class="detail-label"&gt;🐉 Can Chi Năm&lt;/span&gt;
&lt;span class="detail-value" id="mdlYearCanChi"&gt;--&lt;/span&gt;
&lt;/div&gt;
&lt;div class="detail-item"&gt;
&lt;span class="detail-label"&gt;☀️ Can Chi Ngày&lt;/span&gt;
&lt;span class="detail-value" id="mdlDayCanChi"&gt;--&lt;/span&gt;
&lt;/div&gt;
&lt;div class="detail-item"&gt;
&lt;span class="detail-label"&gt;🌕 Tuần Trăng&lt;/span&gt;
&lt;span class="detail-value" id="mdlMoonPhase"&gt;--&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="mdlHolidayBox" style="display: none;"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;style&gt;
.lunisolar-app-root {
--cal-bg-surface: var(--entry, #ffffff);
--cal-bg-card: var(--tertiary, #f8fafc);
--cal-bg-card-hover: var(--border, #f1f5f9);
--cal-border: var(--border, #e2e8f0);
--cal-text: var(--primary, #0f172a);
--cal-text-muted: var(--secondary, #64748b);
--cal-accent: #dc2626;
--cal-highlight: #0284c7;
--badge-tet-bg: #fee2e2;
--badge-tet-text: #991b1b;
--badge-trungthu-bg: #fef3c7;
--badge-trungthu-text: #92400e;
--badge-hungvuong-bg: #e0e7ff;
--badge-hungvuong-text: #3730a3;
--badge-vulan-bg: #ffedd5;
--badge-vulan-text: #9a3412;
--badge-phatdan-bg: #d1fae5;
--badge-phatdan-text: #065f46;
--badge-nguyentieu-bg: #ffe4e6;
--badge-nguyentieu-text: #9f1239;
margin: 1.5rem 0;
width: 100%;
}
.dark .lunisolar-app-root {
--cal-bg-surface: var(--entry, #1e293b);
--cal-bg-card: #151e32;
--cal-bg-card-hover: #293548;
--cal-border: var(--border, #334155);
--cal-text: var(--primary, #f8fafc);
--cal-text-muted: var(--secondary, #94a3b8);
--cal-highlight: #38bdf8;
--badge-tet-bg: #dc2626;
--badge-tet-text: #ffffff;
--badge-trungthu-bg: #f59e0b;
--badge-trungthu-text: #78350f;
--badge-hungvuong-bg: #4f46e5;
--badge-hungvuong-text: #ffffff;
--badge-vulan-bg: #ea580c;
--badge-vulan-text: #ffffff;
--badge-phatdan-bg: #059669;
--badge-phatdan-text: #ffffff;
--badge-nguyentieu-bg: #e11d48;
--badge-nguyentieu-text: #ffffff;
}
.lunisolar-app-root * { box-sizing: border-box; }
.lunisolar-app-root .app-container {
display: flex;
flex-direction: column;
gap: 1rem;
}
.lunisolar-app-root .cal-top-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.75rem;
background-color: var(--cal-bg-surface);
padding: 0.75rem 1rem;
border-radius: 10px;
border: 1px solid var(--cal-border);
}
.lunisolar-app-root .brand h3 {
margin: 0;
font-size: 1.15rem;
font-weight: 700;
color: var(--cal-text);
}
.lunisolar-app-root .controls-top {
display: flex;
align-items: center;
gap: 0.5rem;
}
.lunisolar-app-root button,
.lunisolar-app-root select {
background-color: var(--cal-bg-card);
color: var(--cal-text);
border: 1px solid var(--cal-border);
padding: 0.35rem 0.65rem;
border-radius: 6px;
font-size: 0.825rem;
font-family: inherit;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 0.3rem;
transition: all 0.2s ease;
}
.lunisolar-app-root button:hover,
.lunisolar-app-root select:hover {
background-color: var(--cal-bg-card-hover);
}
.lunisolar-app-root .nav-bar {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.75rem;
background-color: var(--cal-bg-surface);
padding: 0.65rem 1rem;
border-radius: 10px;
border: 1px solid var(--cal-border);
}
.lunisolar-app-root .breadcrumbs {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.9rem;
font-weight: 600;
}
.lunisolar-app-root .breadcrumb-item {
cursor: pointer;
padding: 0.2rem 0.45rem;
border-radius: 4px;
color: var(--cal-text-muted);
}
.lunisolar-app-root .breadcrumb-item:hover {
color: var(--cal-text);
background-color: var(--cal-bg-card-hover);
}
.lunisolar-app-root .breadcrumb-item.active {
color: var(--cal-highlight);
background-color: rgba(56, 189, 248, 0.12);
}
.lunisolar-app-root .nav-arrow { color: var(--cal-text-muted); }
.lunisolar-app-root .zoom-buttons {
display: flex;
align-items: center;
gap: 0.4rem;
}
.lunisolar-app-root .calendar-stage {
background-color: var(--cal-bg-surface);
border: 1px solid var(--cal-border);
border-radius: 10px;
overflow: hidden;
min-height: 480px;
}
.lunisolar-app-root .year-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
gap: 0.85rem;
padding: 1rem;
}
.lunisolar-app-root .month-card {
background-color: var(--cal-bg-card);
border: 1px solid var(--cal-border);
border-radius: 8px;
padding: 0.75rem;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 0.4rem;
transition: all 0.2s ease;
}
.lunisolar-app-root .month-card:hover {
border-color: var(--cal-highlight);
transform: translateY(-2px);
}
.lunisolar-app-root .month-card-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--cal-border);
padding-bottom: 0.35rem;
}
.lunisolar-app-root .month-card-title {
font-weight: 700;
font-size: 0.9rem;
}
.lunisolar-app-root .month-badge-row {
display: flex;
gap: 0.2rem;
flex-wrap: wrap;
justify-content: flex-end;
}
.lunisolar-app-root .month-mini-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 2px;
font-size: 0.65rem;
text-align: center;
color: var(--cal-text-muted);
}
.lunisolar-app-root .mini-day { padding: 2px 0; border-radius: 2px; }
.lunisolar-app-root .mini-day.has-holiday { color: #ffffff; font-weight: bold; }
.lunisolar-app-root .mini-day.holiday-tet { background-color: var(--badge-tet-bg); }
.lunisolar-app-root .mini-day.holiday-trungthu { background-color: var(--badge-trungthu-bg); color: #78350f; }
.lunisolar-app-root .mini-day.holiday-hungvuong { background-color: var(--badge-hungvuong-bg); }
.lunisolar-app-root .mini-day.holiday-vulan { background-color: var(--badge-vulan-bg); }
.lunisolar-app-root .mini-day.holiday-phatdan { background-color: var(--badge-phatdan-bg); }
.lunisolar-app-root .mini-day.holiday-nguyentieu { background-color: var(--badge-nguyentieu-bg); }
.lunisolar-app-root .month-view-container { display: flex; flex-direction: column; }
.lunisolar-app-root .weekdays-header {
display: grid;
grid-template-columns: 44px repeat(7, 1fr);
background-color: var(--cal-bg-card);
border-bottom: 1px solid var(--cal-border);
text-align: center;
font-weight: 700;
font-size: 0.8rem;
padding: 0.5rem 0;
}
.lunisolar-app-root .weekdays-header div:nth-child(2),
.lunisolar-app-root .weekdays-header div:last-child {
color: var(--cal-accent);
}
.lunisolar-app-root .week-row {
display: grid;
grid-template-columns: 44px repeat(7, 1fr);
border-bottom: 1px solid var(--cal-border);
}
.lunisolar-app-root .week-zoom-btn {
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid var(--cal-border);
background-color: var(--cal-bg-card);
color: var(--cal-text-muted);
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
user-select: none;
}
.lunisolar-app-root .week-zoom-btn:hover {
background-color: var(--cal-highlight);
color: #ffffff;
}
.lunisolar-app-root .day-cell {
min-height: 80px;
padding: 0.35rem;
border-right: 1px solid var(--cal-border);
display: flex;
flex-direction: column;
justify-content: space-between;
cursor: pointer;
position: relative;
transition: background-color 0.15s ease;
}
.lunisolar-app-root .day-cell:last-child { border-right: none; }
.lunisolar-app-root .day-cell:hover { background-color: var(--cal-bg-card-hover); }
.lunisolar-app-root .day-cell.inactive { opacity: 0.35; }
.lunisolar-app-root .day-cell.is-today { box-shadow: inset 0 0 0 2px var(--cal-highlight); }
.lunisolar-app-root .day-header-top {
display: flex;
justify-content: space-between;
align-items: center;
}
.lunisolar-app-root .solar-num { font-size: 0.95rem; font-weight: 700; }
.lunisolar-app-root .day-cell.weekend .solar-num { color: var(--cal-accent); }
.lunisolar-app-root .lunar-info-box {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.15rem;
}
.lunisolar-app-root .lunar-num { font-size: 0.75rem; font-weight: 600; color: var(--cal-text-muted); }
.lunisolar-app-root .lunar-num.new-month { color: var(--cal-accent); font-weight: 800; }
.lunisolar-app-root .holiday-badge {
font-size: 0.6rem;
font-weight: 700;
padding: 0.1rem 0.3rem;
border-radius: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.lunisolar-app-root .badge-tet { background-color: var(--badge-tet-bg); color: var(--badge-tet-text); }
.lunisolar-app-root .badge-trungthu { background-color: var(--badge-trungthu-bg); color: var(--badge-trungthu-text); }
.lunisolar-app-root .badge-hungvuong { background-color: var(--badge-hungvuong-bg); color: var(--badge-hungvuong-text); }
.lunisolar-app-root .badge-vulan { background-color: var(--badge-vulan-bg); color: var(--badge-vulan-text); }
.lunisolar-app-root .badge-phatdan { background-color: var(--badge-phatdan-bg); color: var(--badge-phatdan-text); }
.lunisolar-app-root .badge-nguyentieu { background-color: var(--badge-nguyentieu-bg); color: var(--badge-nguyentieu-text); }
.lunisolar-app-root .week-view-container {
display: flex;
flex-direction: column;
padding: 1rem;
}
.lunisolar-app-root .week-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
gap: 0.65rem;
}
.lunisolar-app-root .week-day-card {
background-color: var(--cal-bg-card);
border: 1px solid var(--cal-border);
border-radius: 8px;
padding: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
cursor: pointer;
transition: all 0.2s;
}
.lunisolar-app-root .week-day-card:hover {
border-color: var(--cal-highlight);
transform: translateY(-2px);
}
.lunisolar-app-root .week-day-card.is-today {
border-color: var(--cal-highlight);
box-shadow: 0 0 0 1px var(--cal-highlight);
}
.lunisolar-app-root .week-day-title {
font-size: 0.8rem;
font-weight: 700;
color: var(--cal-text-muted);
border-bottom: 1px solid var(--cal-border);
padding-bottom: 0.25rem;
}
.lunisolar-app-root .week-day-solar { font-size: 1.5rem; font-weight: 800; }
.lunisolar-app-root .week-day-lunar { display: flex; flex-direction: column; gap: 0.2rem; }
.lunisolar-app-root .week-day-lunar-date { font-size: 0.85rem; font-weight: 700; color: var(--cal-accent); }
.lunisolar-app-root .week-day-canchi { font-size: 0.75rem; color: var(--cal-text-muted); }
.lunisolar-app-root .modal-backdrop {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(3px);
display: none;
justify-content: center;
align-items: center;
z-index: 9999;
padding: 1rem;
}
.lunisolar-app-root .modal-backdrop.open { display: flex; }
.lunisolar-app-root .modal-card {
background-color: var(--cal-bg-surface);
border: 1px solid var(--cal-border);
border-radius: 12px;
width: 100%;
max-width: 480px;
padding: 1.5rem;
position: relative;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
}
.lunisolar-app-root .modal-close-btn {
position: absolute;
top: 1rem;
right: 1rem;
background: transparent;
border: none;
font-size: 1.4rem;
color: var(--cal-text-muted);
cursor: pointer;
}
.lunisolar-app-root .gregorian-hero {
background: rgba(56, 189, 248, 0.08);
border: 1px solid var(--cal-border);
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
}
.lunisolar-app-root .gregorian-hero-label {
font-size: 0.75rem;
text-transform: uppercase;
color: var(--cal-text-muted);
margin-bottom: 0.2rem;
}
.lunisolar-app-root .gregorian-hero-date {
font-size: 1.25rem;
font-weight: 800;
color: var(--cal-text);
}
.lunisolar-app-root .details-table { display: flex; flex-direction: column; gap: 0.5rem; }
.lunisolar-app-root .detail-item {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 0.4rem;
border-bottom: 1px solid var(--cal-border);
font-size: 0.85rem;
}
.lunisolar-app-root .detail-label { color: var(--cal-text-muted); }
.lunisolar-app-root .detail-value { font-weight: 600; color: var(--cal-text); }
.lunisolar-app-root .detail-value.accent { color: var(--cal-accent); }
.lunisolar-app-root .holiday-callout {
margin-top: 1rem;
padding: 0.75rem;
border-radius: 8px;
display: flex;
flex-direction: column;
gap: 0.25rem;
border: 1px solid;
}
.lunisolar-app-root .holiday-callout-title { font-size: 0.9rem; font-weight: 800; }
.lunisolar-app-root .holiday-callout-desc { font-size: 0.8rem; line-height: 1.4; opacity: 0.9; }
.lunisolar-app-root .holiday-callout.tet { background-color: rgba(220, 38, 38, 0.1); border-color: var(--badge-tet-bg); }
.lunisolar-app-root .holiday-callout.trungthu { background-color: rgba(245, 158, 11, 0.1); border-color: var(--badge-trungthu-bg); }
.lunisolar-app-root .holiday-callout.hungvuong { background-color: rgba(79, 70, 229, 0.1); border-color: var(--badge-hungvuong-bg); }
.lunisolar-app-root .holiday-callout.vulan { background-color: rgba(234, 88, 12, 0.1); border-color: var(--badge-vulan-bg); }
.lunisolar-app-root .holiday-callout.phatdan { background-color: rgba(5, 150, 105, 0.1); border-color: var(--badge-phatdan-bg); }
.lunisolar-app-root .holiday-callout.nguyentieu { background-color: rgba(225, 29, 72, 0.1); border-color: var(--badge-nguyentieu-bg); }
@media (max-width: 640px) {
.lunisolar-app-root .weekdays-header,
.lunisolar-app-root .week-row {
grid-template-columns: 32px repeat(7, 1fr);
}
.lunisolar-app-root .day-cell { min-height: 60px; padding: 0.2rem; }
.lunisolar-app-root .solar-num { font-size: 0.8rem; }
.lunisolar-app-root .lunar-num { font-size: 0.65rem; }
}
&lt;/style&gt;
&lt;script&gt;
(function() {
const root = document.getElementById("lunisolar-app-root");
if (!root) return;
const I18N = {
vi: {
year: "Năm",
month: "Tháng",
week: "Tuần",
zoomOut: "Thu nhỏ",
weekdays: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"],
months: ["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"],
stems: ["Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"],
branches: ["Tý (Chuột)", "Sửu (Trâu)", "Dần (Hổ)", "Mão (Mèo)", "Thìn (Rồng)", "Tỵ (Rắn)", "Ngọ (Ngựa)", "Mùi (Dê)", "Thân (Khỉ)", "Dậu (Gà)", "Tuất (Chó)", "Hợi (Lợn)"],
elements: ["Mộc", "Mộc", "Hỏa", "Hỏa", "Thổ", "Thổ", "Kim", "Kim", "Thủy", "Thủy"],
holidays: {
"12-29": { name: "Tất Niên", type: "tet", desc: "Tất Niên / Đêm Giao Thừa năm cũ" },
"12-30": { name: "Giao Thừa", type: "tet", desc: "Tất Niên / Đêm Giao Thừa năm cũ" },
"1-1": { name: "Mùng 1 Tết", type: "tet", desc: "Tết Nguyên Đán (Năm mới Âm lịch)" },
"1-2": { name: "Mùng 2 Tết", type: "tet", desc: "Tết Nguyên Đán ngày thứ hai" },
"1-3": { name: "Mùng 3 Tết", type: "tet", desc: "Tết Nguyên Đán ngày thứ ba" },
"1-15": { name: "Tết Nguyên Tiêu", type: "nguyentieu", desc: "Tết Nguyên Tiêu (Rằm tháng Giêng)" },
"3-10": { name: "Giỗ Tổ Hùng Vương", type: "hungvuong", desc: "Giỗ Tổ Hùng Vương (10/3 Âm lịch)" },
"4-8": { name: "Lễ Phật Đản", type: "phatdan", desc: "Lễ Phật Đản (8/4 Âm lịch)" },
"7-15": { name: "Lễ Vu Lan", type: "vulan", desc: "Lễ Vu Lan / Báo hiếu (15/7 Âm lịch)" },
"8-14": { name: "Tiền Trung Thu", type: "trungthu", desc: "Đêm trước Rằm Trung Thu" },
"8-15": { name: "Tết Trung Thu", type: "trungthu", desc: "Tết Trung Thu (Rằm tháng 8)" }
}
},
en: {
year: "Year",
month: "Month",
week: "Week",
zoomOut: "Zoom Out",
weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
stems: ["Jia", "Yi", "Bing", "Ding", "Wu", "Ji", "Geng", "Xin", "Ren", "Gui"],
branches: ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
elements: ["Wood", "Wood", "Fire", "Fire", "Earth", "Earth", "Metal", "Metal", "Water", "Water"],
holidays: {
"12-29": { name: "Lunar NY Eve", type: "tet", desc: "Lunar New Year's Eve (Tet Eve)" },
"12-30": { name: "Lunar NY Eve", type: "tet", desc: "Lunar New Year's Eve (Tet Eve)" },
"1-1": { name: "Tet (Day 1)", type: "tet", desc: "Tet Holiday - First day of Lunar New Year" },
"1-2": { name: "Tet (Day 2)", type: "tet", desc: "Tet Holiday - Second day of Lunar New Year" },
"1-3": { name: "Tet (Day 3)", type: "tet", desc: "Tet Holiday - Third day of Lunar New Year" },
"1-15": { name: "Lantern Festival", type: "nguyentieu", desc: "Lantern Festival (15th of 1st Lunar Month)" },
"3-10": { name: "Hung Kings Day", type: "hungvuong", desc: "Hung Kings Commemoration Day" },
"4-8": { name: "Buddha's Birthday", type: "phatdan", desc: "Buddha's Birthday (Vesak)" },
"7-15": { name: "Ghost Festival / Vu Lan", type: "vulan", desc: "Vu Lan Festival (15th of 7th Lunar Month)" },
"8-14": { name: "Mid-Autumn Eve", type: "trungthu", desc: "Eve of Mid-Autumn Festival" },
"8-15": { name: "Mid-Autumn (Trung Thu)", type: "trungthu", desc: "Mid-Autumn Moon Festival" }
}
},
zh: {
year: "年",
month: "月",
week: "周",
zoomOut: "缩小",
weekdays: ["日", "一", "二", "三", "四", "五", "六"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
stems: ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"],
branches: ["子 (鼠)", "丑 (牛)", "寅 (虎)", "卯 (兔)", "辰 (龙)", "巳 (蛇)", "午 (马)", "未 (羊)", "申 (猴)", "酉 (鸡)", "戌 (狗)", "亥 (猪)"],
elements: ["木", "木", "火", "火", "土", "土", "金", "金", "水", "水"],
holidays: {
"12-29": { name: "除夕", type: "tet", desc: "农历除夕" },
"12-30": { name: "除夕", type: "tet", desc: "农历除夕 (大年三十)" },
"1-1": { name: "春节 (大年初一)", type: "tet", desc: "农历新年，大年初一" },
"1-2": { name: "大年初二", type: "tet", desc: "农历大年初二" },
"1-3": { name: "大年初三", type: "tet", desc: "农历大年初三" },
"1-15": { name: "元宵节", type: "nguyentieu", desc: "元宵节 (农历正月十五)" },
"3-10": { name: "雄王节", type: "hungvuong", desc: "雄王节 (农历三月初十)" },
"4-8": { name: "佛诞节", type: "phatdan", desc: "佛诞节 (农历四月初八)" },
"7-15": { name: "中元节 / 盂兰盆节", type: "vulan", desc: "中元节 (农历七月十五)" },
"8-14": { name: "迎中秋", type: "trungthu", desc: "中秋前夕" },
"8-15": { name: "中秋节", type: "trungthu", desc: "中秋节 (农历八月十五)" }
}
}
};
function getJulianDayNumber(y, m, d) {
const a = Math.floor((14 - m) / 12);
const yr = y + 4800 - a;
const mo = m + 12 * a - 3;
return d + Math.floor((153 * mo + 2) / 5) + 365 * yr + Math.floor(yr / 4) - Math.floor(yr / 100) + Math.floor(yr / 400) - 32045;
}
function getLunisolarInfo(date) {
const formatter = new Intl.DateTimeFormat("en-US-u-ca-chinese", {
year: "numeric",
month: "numeric",
day: "numeric"
});
const parts = formatter.formatToParts(date);
let lunarYear = date.getFullYear();
let lunarMonthStr = "1";
let lunarDay = 1;
let isLeap = false;
parts.forEach(p =&gt; {
if (p.type === "relatedYear") lunarYear = parseInt(p.value, 10);
if (p.type === "month") {
lunarMonthStr = p.value;
if (lunarMonthStr.includes("bis") || lunarMonthStr.includes("leap") || lunarMonthStr.endsWith("b")) {
isLeap = true;
}
}
if (p.type === "day") lunarDay = parseInt(p.value, 10);
});
const lunarMonth = parseInt(lunarMonthStr, 10) || 1;
const jdn = getJulianDayNumber(date.getFullYear(), date.getMonth() + 1, date.getDate());
const yearStemIdx = (lunarYear - 4) % 10;
const yearBranchIdx = (lunarYear - 4) % 12;
const dayStemIdx = (jdn + 9) % 10;
const dayBranchIdx = (jdn + 1) % 12;
const holidayKey = `${lunarMonth}-${lunarDay}`;
const langData = I18N[currentLang];
let holidayObj = null;
if (!isLeap &amp;&amp; langData.holidays[holidayKey]) {
holidayObj = langData.holidays[holidayKey];
}
return {
lunarYear,
lunarMonth,
lunarDay,
isLeap,
yearStemIdx,
yearBranchIdx,
dayStemIdx,
dayBranchIdx,
holidayObj
};
}
let currentLang = "vi";
let zoomLevel = "month";
let selectedYear = new Date().getFullYear();
let selectedMonth = new Date().getMonth();
let selectedWeekStart = null;
const calendarStage = root.querySelector("#calendarStage");
const crumbYear = root.querySelector("#crumbYear");
const crumbMonth = root.querySelector("#crumbMonth");
const crumbWeek = root.querySelector("#crumbWeek");
const arrowWeek = root.querySelector("#arrowWeek");
const btnPrev = root.querySelector("#btnPrev");
const btnNext = root.querySelector("#btnNext");
const btnToday = root.querySelector("#btnToday");
const btnZoomOut = root.querySelector("#btnZoomOut");
const langSelect = root.querySelector("#langSelect");
const dayDetailModal = root.querySelector("#dayDetailModal");
const modalCloseBtn = root.querySelector("#modalCloseBtn");
const mdlGregorianDate = root.querySelector("#mdlGregorianDate");
const mdlLunarDate = root.querySelector("#mdlLunarDate");
const mdlYearCanChi = root.querySelector("#mdlYearCanChi");
const mdlDayCanChi = root.querySelector("#mdlDayCanChi");
const mdlMoonPhase = root.querySelector("#mdlMoonPhase");
const mdlHolidayBox = root.querySelector("#mdlHolidayBox");
function updateBreadcrumbs() {
const t = I18N[currentLang];
crumbYear.textContent = `${t.year} ${selectedYear}`;
crumbMonth.textContent = t.months[selectedMonth];
crumbYear.className = `breadcrumb-item ${zoomLevel === 'year' ? 'active' : ''}`;
crumbMonth.className = `breadcrumb-item ${zoomLevel === 'month' ? 'active' : ''}`;
if (zoomLevel === "week" &amp;&amp; selectedWeekStart) {
const weekEnd = new Date(selectedWeekStart);
weekEnd.setDate(weekEnd.getDate() + 6);
crumbWeek.style.display = "inline-block";
arrowWeek.style.display = "inline-block";
crumbWeek.className = "breadcrumb-item active";
crumbWeek.textContent = `${t.week} (${selectedWeekStart.getDate()}/${selectedWeekStart.getMonth()+1} - ${weekEnd.getDate()}/${weekEnd.getMonth()+1})`;
} else {
crumbWeek.style.display = "none";
arrowWeek.style.display = "none";
}
btnZoomOut.style.visibility = zoomLevel === "year" ? "hidden" : "visible";
btnZoomOut.textContent = `🔍 ${t.zoomOut}`;
}
function renderYearView() {
zoomLevel = "year";
updateBreadcrumbs();
calendarStage.innerHTML = "";
const yearGrid = document.createElement("div");
yearGrid.className = "year-grid";
const t = I18N[currentLang];
for (let m = 0; m &lt; 12; m++) {
const monthCard = document.createElement("div");
monthCard.className = "month-card";
const header = document.createElement("div");
header.className = "month-card-header";
const title = document.createElement("span");
title.className = "month-card-title";
title.textContent = t.months[m];
header.appendChild(title);
const badgeArea = document.createElement("div");
badgeArea.className = "month-badge-row";
const holidaysFound = new Map();
const daysInMonth = new Date(selectedYear, m + 1, 0).getDate();
for (let d = 1; d &lt;= daysInMonth; d++) {
const checkDate = new Date(selectedYear, m, d);
const info = getLunisolarInfo(checkDate);
if (info.holidayObj &amp;&amp; !holidaysFound.has(info.holidayObj.type)) {
holidaysFound.set(info.holidayObj.type, info.holidayObj);
}
}
holidaysFound.forEach((hObj) =&gt; {
const badge = document.createElement("span");
badge.className = `holiday-badge badge-${hObj.type}`;
badge.textContent = hObj.name;
badgeArea.appendChild(badge);
});
header.appendChild(badgeArea);
monthCard.appendChild(header);
const miniGrid = document.createElement("div");
miniGrid.className = "month-mini-grid";
t.weekdays.forEach(wd =&gt; {
const wHead = document.createElement("div");
wHead.textContent = wd[0];
wHead.style.fontWeight = "bold";
miniGrid.appendChild(wHead);
});
const firstDay = new Date(selectedYear, m, 1).getDay();
for (let i = 0; i &lt; firstDay; i++) {
miniGrid.appendChild(document.createElement("div"));
}
for (let d = 1; d &lt;= daysInMonth; d++) {
const dayDiv = document.createElement("div");
dayDiv.className = "mini-day";
dayDiv.textContent = d;
const checkDate = new Date(selectedYear, m, d);
const info = getLunisolarInfo(checkDate);
if (info.holidayObj) {
dayDiv.classList.add("has-holiday", `holiday-${info.holidayObj.type}`);
}
miniGrid.appendChild(dayDiv);
}
monthCard.appendChild(miniGrid);
monthCard.addEventListener("click", () =&gt; {
selectedMonth = m;
renderMonthView();
});
yearGrid.appendChild(monthCard);
}
calendarStage.appendChild(yearGrid);
}
function renderMonthView() {
zoomLevel = "month";
updateBreadcrumbs();
calendarStage.innerHTML = "";
const t = I18N[currentLang];
const container = document.createElement("div");
container.className = "month-view-container";
const wHeader = document.createElement("div");
wHeader.className = "weekdays-header";
const wLabel = document.createElement("div");
wLabel.textContent = "🔍";
wLabel.title = "Bấm W để xem tuần";
wHeader.appendChild(wLabel);
t.weekdays.forEach(wd =&gt; {
const col = document.createElement("div");
col.textContent = wd;
wHeader.appendChild(col);
});
container.appendChild(wHeader);
const firstDayIdx = new Date(selectedYear, selectedMonth, 1).getDay();
const totalDays = new Date(selectedYear, selectedMonth + 1, 0).getDate();
const prevMonthDays = new Date(selectedYear, selectedMonth, 0).getDate();
let currentDayCount = 1;
let nextMonthDayCount = 1;
for (let week = 0; week &lt; 6; week++) {
if (currentDayCount &gt; totalDays &amp;&amp; week &gt; 0) break;
const weekRow = document.createElement("div");
weekRow.className = "week-row";
let weekStartDate = null;
const zoomWeekCol = document.createElement("div");
zoomWeekCol.className = "week-zoom-btn";
zoomWeekCol.textContent = `W${week + 1}`;
weekRow.appendChild(zoomWeekCol);
for (let col = 0; col &lt; 7; col++) {
let cellDate = null;
let isInactive = false;
if (week === 0 &amp;&amp; col &lt; firstDayIdx) {
const dNum = prevMonthDays - (firstDayIdx - 1 - col);
cellDate = new Date(selectedYear, selectedMonth - 1, dNum);
isInactive = true;
} else if (currentDayCount &lt;= totalDays) {
cellDate = new Date(selectedYear, selectedMonth, currentDayCount);
currentDayCount++;
} else {
cellDate = new Date(selectedYear, selectedMonth + 1, nextMonthDayCount);
nextMonthDayCount++;
isInactive = true;
}
if (col === 0) weekStartDate = new Date(cellDate);
const dayCell = createDayCell(cellDate, isInactive);
weekRow.appendChild(dayCell);
}
zoomWeekCol.addEventListener("click", (e) =&gt; {
e.stopPropagation();
selectedWeekStart = weekStartDate;
renderWeekView();
});
container.appendChild(weekRow);
}
calendarStage.appendChild(container);
}
function renderWeekView() {
zoomLevel = "week";
updateBreadcrumbs();
calendarStage.innerHTML = "";
const t = I18N[currentLang];
const container = document.createElement("div");
container.className = "week-view-container";
const weekGrid = document.createElement("div");
weekGrid.className = "week-grid";
for (let i = 0; i &lt; 7; i++) {
const date = new Date(selectedWeekStart);
date.setDate(date.getDate() + i);
const info = getLunisolarInfo(date);
const card = document.createElement("div");
card.className = "week-day-card";
const isToday = date.toDateString() === new Date().toDateString();
if (isToday) card.classList.add("is-today");
const dayTitle = document.createElement("div");
dayTitle.className = "week-day-title";
dayTitle.textContent = `${t.weekdays[date.getDay()]} - ${date.toLocaleDateString(currentLang === 'vi' ? 'vi-VN' : 'en-US', { month: 'numeric', day: 'numeric' })}`;
card.appendChild(dayTitle);
const solarNum = document.createElement("div");
solarNum.className = "week-day-solar";
solarNum.textContent = date.getDate();
card.appendChild(solarNum);
const lunarDiv = document.createElement("div");
lunarDiv.className = "week-day-lunar";
const lunarDate = document.createElement("div");
lunarDate.className = "week-day-lunar-date";
lunarDate.textContent = `Âm: ${info.lunarDay}/${info.lunarMonth}`;
lunarDiv.appendChild(lunarDate);
const canchi = document.createElement("div");
canchi.className = "week-day-canchi";
canchi.textContent = `${t.stems[info.dayStemIdx]} ${t.branches[info.dayBranchIdx]}`;
lunarDiv.appendChild(canchi);
if (info.holidayObj) {
const badge = document.createElement("div");
badge.className = `holiday-badge badge-${info.holidayObj.type}`;
badge.textContent = info.holidayObj.name;
lunarDiv.appendChild(badge);
}
card.appendChild(lunarDiv);
card.addEventListener("click", () =&gt; showDayDetail(date, info));
weekGrid.appendChild(card);
}
container.appendChild(weekGrid);
calendarStage.appendChild(container);
}
function createDayCell(date, isInactive) {
const info = getLunisolarInfo(date);
const isToday = date.toDateString() === new Date().toDateString();
const cell = document.createElement("div");
cell.className = `day-cell ${isInactive ? 'inactive' : ''} ${isToday ? 'is-today' : ''}`;
if (date.getDay() === 0 || date.getDay() === 6) cell.classList.add("weekend");
const top = document.createElement("div");
top.className = "day-header-top";
const solarSpan = document.createElement("span");
solarSpan.className = "solar-num";
solarSpan.textContent = date.getDate();
top.appendChild(solarSpan);
if (info.lunarDay === 1) {
const moon = document.createElement("span");
moon.textContent = "🌑";
top.appendChild(moon);
} else if (info.lunarDay === 15) {
const moon = document.createElement("span");
moon.textContent = "🌕";
top.appendChild(moon);
}
cell.appendChild(top);
const bottom = document.createElement("div");
bottom.className = "lunar-info-box";
const lunarSpan = document.createElement("span");
lunarSpan.className = `lunar-num ${info.lunarDay === 1 ? 'new-month' : ''}`;
lunarSpan.textContent = info.lunarDay === 1 ? `${info.lunarDay}/${info.lunarMonth}` : info.lunarDay;
bottom.appendChild(lunarSpan);
if (info.holidayObj) {
const badge = document.createElement("span");
badge.className = `holiday-badge badge-${info.holidayObj.type}`;
badge.textContent = info.holidayObj.name;
bottom.appendChild(badge);
}
cell.appendChild(bottom);
cell.addEventListener("click", () =&gt; showDayDetail(date, info));
return cell;
}
function showDayDetail(date, info) {
const t = I18N[currentLang];
const gregorianFull = date.toLocaleDateString(
currentLang === 'vi' ? 'vi-VN' : (currentLang === 'zh' ? 'zh-CN' : 'en-US'),
{ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
);
mdlGregorianDate.textContent = gregorianFull;
const leapStr = info.isLeap ? " (Nhuận)" : "";
mdlLunarDate.textContent = `Ngày ${info.lunarDay} tháng ${info.lunarMonth}${leapStr}, Năm ${info.lunarYear}`;
mdlYearCanChi.textContent = `${t.stems[info.yearStemIdx]} ${t.branches[info.yearBranchIdx]} (${t.elements[info.yearStemIdx]})`;
mdlDayCanChi.textContent = `${t.stems[info.dayStemIdx]} ${t.branches[info.dayBranchIdx]}`;
let moonDesc = "Trăng khuyết";
if (info.lunarDay === 1) moonDesc = "🌑 Mùng 1 - Trăng non (New Moon)";
else if (info.lunarDay === 15) moonDesc = "🌕 Rằm - Trăng tròn (Full Moon)";
else if (info.lunarDay &lt; 15) moonDesc = `🌒 Trăng thượng huyền (Ngày ${info.lunarDay})`;
else moonDesc = `🌘 Trăng hạ huyền (Ngày ${info.lunarDay})`;
mdlMoonPhase.textContent = moonDesc;
if (info.holidayObj) {
mdlHolidayBox.style.display = "flex";
mdlHolidayBox.className = `holiday-callout ${info.holidayObj.type}`;
mdlHolidayBox.innerHTML = `
&lt;div class="holiday-callout-title"&gt;${info.holidayObj.name}&lt;/div&gt;
&lt;div class="holiday-callout-desc"&gt;${info.holidayObj.desc}&lt;/div&gt;
`;
} else {
mdlHolidayBox.style.display = "none";
}
dayDetailModal.classList.add("open");
}
function navigate(direction) {
if (zoomLevel === "year") {
selectedYear += direction;
renderYearView();
} else if (zoomLevel === "month") {
selectedMonth += direction;
if (selectedMonth &lt; 0) {
selectedMonth = 11;
selectedYear--;
} else if (selectedMonth &gt; 11) {
selectedMonth = 0;
selectedYear++;
}
renderMonthView();
} else if (zoomLevel === "week") {
if (!selectedWeekStart) selectedWeekStart = new Date(selectedYear, selectedMonth, 1);
selectedWeekStart.setDate(selectedWeekStart.getDate() + (direction * 7));
selectedYear = selectedWeekStart.getFullYear();
selectedMonth = selectedWeekStart.getMonth();
renderWeekView();
}
}
function zoomOut() {
if (zoomLevel === "week") renderMonthView();
else if (zoomLevel === "month") renderYearView();
}
btnPrev.addEventListener("click", () =&gt; navigate(-1));
btnNext.addEventListener("click", () =&gt; navigate(1));
btnZoomOut.addEventListener("click", zoomOut);
btnToday.addEventListener("click", () =&gt; {
const now = new Date();
selectedYear = now.getFullYear();
selectedMonth = now.getMonth();
selectedWeekStart = new Date(now);
selectedWeekStart.setDate(now.getDate() - now.getDay());
if (zoomLevel === "year") renderYearView();
else if (zoomLevel === "week") renderWeekView();
else renderMonthView();
});
crumbYear.addEventListener("click", () =&gt; renderYearView());
crumbMonth.addEventListener("click", () =&gt; renderMonthView());
langSelect.addEventListener("change", (e) =&gt; {
currentLang = e.target.value;
if (zoomLevel === "year") renderYearView();
else if (zoomLevel === "week") renderWeekView();
else renderMonthView();
});
modalCloseBtn.addEventListener("click", () =&gt; dayDetailModal.classList.remove("open"));
dayDetailModal.addEventListener("click", (e) =&gt; {
if (e.target === dayDetailModal) dayDetailModal.classList.remove("open");
});
renderMonthView();
})();
&lt;/script&gt;</description></item><item><title>Schedule &amp; Calendar</title><link>https://www.raumuong.com/calendar/</link><pubDate>Tue, 29 Sep 2026 12:00:00 +0000</pubDate><guid>https://www.raumuong.com/calendar/</guid><description>&lt;p&gt;Here is the upcoming schedule:&lt;/p&gt;
&lt;div class="calendar-container"&gt;
&lt;iframe
src="https://calendar.google.com/calendar/embed?src=your_calendar_id%40group.calendar.google.com&amp;amp;ctz=America%2FNew_York&amp;amp;mode=AGENDA"
style="border: 0;"
width="100%"
height="650"
frameborder="0"
scrolling="no"&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;style&gt;
.calendar-container {
position: relative;
width: 100%;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
margin: 1.5rem 0;
}
.calendar-container iframe {
width: 100%;
min-height: 500px;
}
@media (max-width: 640px) {
.calendar-container iframe {
min-height: 400px;
}
}
&lt;/style&gt;</description></item></channel></rss>