diff options
author | Ngô Ngọc Đức Huy <huyngo@disroot.org> | 2025-02-12 22:55:23 +0700 |
---|---|---|
committer | Ngô Ngọc Đức Huy <huyngo@disroot.org> | 2025-02-12 22:55:23 +0700 |
commit | 4a46ae3bbaf3a4281bdaf39b8a4386ce8f812333 (patch) | |
tree | b6aea457b4eb7f63df3dc13b8041d96fff6c1d4f /content | |
parent | 633c82187b754637218f2a9087e11b3e85b09e19 (diff) | |
download | blog-4a46ae3bbaf3a4281bdaf39b8a4386ce8f812333.tar.gz |
Restyle the calendar to look more calendary
Diffstat (limited to 'content')
-rw-r--r-- | content/cal/_index.html | 59 | ||||
-rw-r--r-- | content/cal/lunar.js | 280 |
2 files changed, 313 insertions, 26 deletions
diff --git a/content/cal/_index.html b/content/cal/_index.html index 876897d..a32beca 100644 --- a/content/cal/_index.html +++ b/content/cal/_index.html @@ -3,39 +3,64 @@ title: Calendar disable_feed: true --- +<noscript> + This calendar works locally in your browser and requires JavaScript to remain serverless +</noscript> +<div> + <label> + Solar date: + <input id="solar-date" type="date" /> + </label> +</div> <div id="lunar-solar-cal"> - <noscript> - This calendar works locally in your browser and requires JavaScript to remain serverless - </noscript> - <div> - <label> - Solar date: - <input id="solar-date" type="date" /> - </label> - </div> <div id="solar-cal"> <div id="month-year-row"> - <div id="solar-month-vi"></div> + <div id="solar-month-vi" lang=vi></div> <div id="solar-year"></div> <div id="solar-month-en"></div> </div> - <div id="solar-day"></div> + <hr> + <div id="day-area" lang=vi> + <button id="nav-day-before"> + <span class="sr-only">Ngày trước</span> + </button> + <div> + <div id="solar-day"></div> + <div id="special-day-vi"></div> + </div> + <button id="nav-day-after"> + <span class="sr-only">Ngày tiếp theo</span> + </button> + </div> + <hr> <div id="weekday-row"> - <div id="solar-weekday-vi"></div> <div id="solar-weekday-en"></div> + <div id="solar-weekday-vi" lang=vi></div> + <div id="solar-weekday-zh" lang=zh></div> </div> </div> + <hr> <div id="lunar-cal"> - <div id=lunar-cal-vi> + <div id=lunar-cal-vi lang="vi"> <div id="lunar-year-vi"></div> <div id="lunar-month-vi"></div> - <div id="lunar-day-vi"></div> + <div id="lunar-month-zodiac-vi"></div> + <div id="lunar-day-zodiac-vi"></div> + <div id="solar-term-vi"></div> </div> - <div id=lunar-cal-zh> + <div id="lunar-day"></div> + <div id=lunar-cal-zh lang="zh"> <div id="lunar-year-zh"></div> - <div id="lunar-month-zh"></div> + <div> + <span id="lunar-month-zh"></span> · + <span id="lunar-month-zodiac-zh"></span> + </div> <div id="lunar-day-zh"></div> - <div id="solar-weekday-zh"></div> + <div id="lunar-day-zodiac-zh"></div> + <div> + <span id="solar-term-zh"></span> + <span id="special-day-zh"></span> + </div> </div> </div> </div> diff --git a/content/cal/lunar.js b/content/cal/lunar.js index cfd15a6..b5b0bd1 100644 --- a/content/cal/lunar.js +++ b/content/cal/lunar.js @@ -167,10 +167,62 @@ function convertSolarToLunar(date, tzOffset) { } } -CAN_VI = ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'] -CAN_ZH = [] -CHI_VI = ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'] -CHI_ZH = [] +const CAN_VI = ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'] +const CAN_ZH = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'] +const CHI_VI = ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'] +const CHI_ZH = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'] +const TERM_VI = [ + 'Xuân phân', + 'Thanh minh', + 'Cốc vũ', + 'Lập hạ', + 'Tiểu mãn', + 'Mang chủng', + 'Hạ chí', + 'Tiểu thử', + 'Đại thử', + 'Lập thu', + 'Xử thử', + 'Bạch lộ', + 'Thu phân', + 'Hàn lộ', + 'Sương giáng', + 'Lập đông', + 'Tiểu tuyết', + 'Đại tuyết', + 'Đông chí', + 'Tiểu hàn', + 'Đại hàn', + 'Lập xuân', + 'Vũ thuỷ', + 'Kinh trập', +] +const TERM_ZH = [ + '春分', + '清明', + '穀雨', + '立夏', + '小滿', + '芒種', + '夏至', + '小暑', + '大暑', + '立秋', + '處暑', + '白露', + '秋分', + '寒露', + '霜降', + '立冬', + '小雪', + '大雪', + '冬至', + '小寒', + '大寒', + '立春', + '雨水', + '驚蟄' +] // Get can/chi of a lunar date function getZodiac({year, month, day, jd}) { @@ -204,19 +256,36 @@ function getZodiacText(zodiac, lang) { // DOM const dateInput = document.querySelector('#solar-date') +const calendar = document.querySelector('#lunar-solar-cal') const solarYearOutput = document.querySelector('#solar-year') const solarMonthOutputEN = document.querySelector('#solar-month-en') const solarMonthOutputVI = document.querySelector('#solar-month-vi') + const solarDayOutput = document.querySelector('#solar-day') +const specialDayOutputVI = document.querySelector('#special-day-vi') +const specialDayOutputZH = document.querySelector('#special-day-zh') + const solarWeekdayOutputEN = document.querySelector('#solar-weekday-en') const solarWeekdayOutputVI = document.querySelector('#solar-weekday-vi') const solarWeekdayOutputZH = document.querySelector('#solar-weekday-zh') + const lunarYearOutputVI = document.querySelector('#lunar-year-vi') const lunarMonthOutputVI = document.querySelector('#lunar-month-vi') -const lunarDayOutputVI = document.querySelector('#lunar-day-vi') +const lunarMonthZodiacOutputVI = document.querySelector('#lunar-month-zodiac-vi') +const lunarDayZodiacOutputVI = document.querySelector('#lunar-day-zodiac-vi') +const solarTermVI = document.querySelector('#solar-term-vi') + +const lunarDayOutput = document.querySelector('#lunar-day') + const lunarYearOutputZH = document.querySelector('#lunar-year-zh') const lunarMonthOutputZH = document.querySelector('#lunar-month-zh') +const lunarMonthZodiacOutputZH = document.querySelector('#lunar-month-zodiac-zh') const lunarDayOutputZH = document.querySelector('#lunar-day-zh') +const lunarDayZodiacOutputZH = document.querySelector('#lunar-day-zodiac-zh') +const solarTermZH = document.querySelector('#solar-term-zh') + +const dayBeforeBtn = document.querySelector('#nav-day-before') +const dayAfterBtn = document.querySelector('#nav-day-after') const monthFormatEN = new Intl.DateTimeFormat("en-US", {month: "long"}) const monthFormatVI = new Intl.DateTimeFormat("vi-VN", {month: "long"}) @@ -224,14 +293,156 @@ const weekdayFormatEN = new Intl.DateTimeFormat("en-US", {weekday: "long"}) const weekdayFormatVI = new Intl.DateTimeFormat("vi-VN", {weekday: "long"}) const weekdayFormatZH = new Intl.DateTimeFormat("zh-CN", {weekday: "long"}) -const LUNAR_MONTH_VI = ["một", "hai", "ba", "tư", "năm", "sáu", "bảy", "tám", "chín", "mười", "mười một", "chạp"] +const SOLAR_MONTH_VI = ["Một", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Mười Một", "Mười Hai"] +const LUNAR_MONTH_VI = ["Giêng", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Mười Một", "Chạp"] +const LUNAR_MONTH_ZH = ["元", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "臘", ] +const tzOffset = 7 + +const CHINESE_NUMBERS = "一二三四五六七八九十" + +function getChineseDay(day) { + if (day <= 10) { + return "初" + CHINESE_NUMBERS[day - 1] + } else if (day < 20) { + return "十" + CHINESE_NUMBERS[(day - 1) % 10] + } else if (day == 20) { + return "二十" + } else if (day < 30) { + return "廿" + CHINESE_NUMBERS[(day - 1) % 10] + } else { + return "三十" + } +} + +function isFullMonth(date, lunarDate) { + const daysTill30 = 30 - lunarDate.day + date.setDate(date.getDate() + daysTill30) + let day30 = convertSolarToLunar(date, tzOffset) + return day30.month === lunarDate.month +} + +const specialDaysSolar = { + "01-01": { + vi: "Tết Dương Lịch", + zh: "元旦", + isHoliday: true + }, + "02-03": { + vi: "Ngày thành lập Đảng Cộng Sản Việt Nam", + isHoliday: false + }, + "02-14": { + vi: "Lễ tình nhân (Valentine)", + isHoliday: false + }, + "03-08": { + vi: "Ngày Quốc tế Phụ nữ", + isHoliday: false + }, + "04-30": { + vi: "Ngày Thống nhất", + isHoliday: true + }, + "05-01": { + vi: "Ngày Quốc tế Lao động", + zh: "劳动节", + isHoliday: true + }, + "06-01": { + vi: "Ngày Quốc tế thiếu nhi", + isHoliday: false + }, + "08-19": { + vi: "Ngày kỷ niệm Cách mạng Tháng 8 thành công", + isHoliday: false + }, + "09-02": { + vi: "Ngày Quốc Khánh", + isHoliday: true + }, + "10-01": { + vi: "Ngày quốc tế người cao tuổi", + isHoliday: false + }, + "10-20": { + vi: "Ngày Phụ nữ Việt Nam", + isHoliday: false + }, + "10-31": { + vi: "Halloween", + isHoliday: false + }, + "11-19": { + vi: "Ngày Quốc tế Nam giới", + isHoliday: false + }, + "11-20": { + vi: "Ngày Nhà giáo Việt Nam", + isHoliday: false + }, + "12-24": { + vi: "Đêm Giáng sinh", + isHoliday: false + }, + "12-25": { + vi: "Giáng sinh", + isHoliday: false + } +} +const specialDaysLunar = { + "1-1": { + vi: "Tết Nguyên Đán", + zh: "春节", + isHoliday: true + }, + "1-15": { + vi: "Tết Nguyên Tiêu", + zh: "元宵节", + isHoliday: false + }, + "3-3": { + vi: "Tết Hàn thực", + isHoliday: false + }, + "3-10": { + vi: "Giỗ tổ Hùng Vương", + isHoliday: true + }, + "5-5": { + vi: "Tết Đoan ngọ", + isHoliday: false + }, + "7-7": { + vi: "Lễ Thất tịch", + zh: "七夕", + isHoliday: false + }, + "7-15": { + vi: "Lễ Vu Lan", + isHoliday: false + }, + "8-15": { + vi: "Tết Trung Thu", + zh: "中秋节", + isHoliday: false + }, + "12-23": { + vi: "Tết ông Công ông Táo", + isHoliday: false + } +} + +function getSpecialDays(date, lunarDate) { + const dateStr = date.toISOString().substring(5, 10) + const lunarStr = lunarDate.month + "-" + lunarDate.day + return [specialDaysSolar[dateStr], specialDaysLunar[lunarStr]] +} function updateOutputs() { if (dateInput.valueAsDate === null) { dateInput.valueAsDate = new Date() } const date = dateInput.valueAsDate - const tzOffset = 7 solarYearOutput.innerText = date.getFullYear() solarMonthOutputEN.innerText = monthFormatEN.format(date) solarMonthOutputVI.innerText = monthFormatVI.format(date) @@ -243,13 +454,64 @@ function updateOutputs() { const lunarDate = convertSolarToLunar(date, tzOffset) const zodiac = getZodiac(lunarDate) lunarYearOutputVI.innerText = "Năm " + getZodiacText(zodiac.yearZodiac, "vi") + lunarYearOutputZH.innerText = getZodiacText(zodiac.yearZodiac, "zh") + "年" lunarMonthOutputVI.innerText = "Tháng " + LUNAR_MONTH_VI[lunarDate.month - 1] + lunarMonthOutputZH.innerText = LUNAR_MONTH_ZH[lunarDate.month - 1] + "月" if (lunarDate.isLeap) { - lunarMonthOutputVI.innerText += " (nhuận)" + lunarMonthOutputVI.innerText += " nhuận" + } + if (isFullMonth(structuredClone(date), lunarDate)) { + lunarMonthOutputVI.innerText += " (đủ)" + lunarMonthOutputZH.innerText += "大" + } else { + lunarMonthOutputVI.innerText += " (thiếu)" + lunarMonthOutputZH.innerText += "小" + } + lunarDayOutput.innerText = lunarDate.day + lunarMonthZodiacOutputVI.innerText = "Tháng " + getZodiacText(zodiac.monthZodiac, "vi") + lunarMonthZodiacOutputZH.innerText = getZodiacText(zodiac.monthZodiac, "zh") + "月" + lunarDayZodiacOutputVI.innerText = "Ngày " + getZodiacText(zodiac.dayZodiac, "vi") + lunarDayOutputZH.innerText = getChineseDay(lunarDate.day) + lunarDayZodiacOutputZH.innerText = getZodiacText(zodiac.dayZodiac, "zh") + "曰" + + const solarTerm = getSolarTerm(lunarDate.jd, tzOffset) + solarTermVI.innerText = "Tiết " + TERM_VI[solarTerm] + solarTermZH.innerText = TERM_ZH[solarTerm] + + const specialDays = getSpecialDays(date, lunarDate) + specialDayOutputVI.innerText = "" + specialDayOutputZH.innerText = "" + let isHoliday = false + for (let sday of specialDays) { + if (sday === undefined) { + continue + } + specialDayOutputVI.innerText += "\n" + sday.vi + if (sday.zh) { + specialDayOutputZH.innerText += " · " + sday.zh + } + if (sday.isHoliday) { + isHoliday = true + } + } + if (isHoliday || date.getDay() === 0) { + calendar.className = "holiday" + } else { + calendar.className = "" } - lunarDayOutputVI.innerText = "Ngày " + lunarDate.day + } +dayBeforeBtn.onclick = () => { + let date = new Date(dateInput.valueAsDate.setDate(dateInput.valueAsDate.getDate() - 1)) + dateInput.valueAsDate = date + updateOutputs() +} +dayAfterBtn.onclick = () => { + let date = new Date(dateInput.valueAsDate.setDate(dateInput.valueAsDate.getDate() + 1)) + dateInput.valueAsDate = date + updateOutputs() +} document.addEventListener("DOMContentLoaded", updateOutputs) dateInput.onchange = updateOutputs |