Created
April 8, 2026 03:59
-
-
Save a70437043b/c923689dabb60e50caf8155770a10709 to your computer and use it in GitHub Desktop.
Notion Calendar Widget
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="zh-TW"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <style> | |
| :root { | |
| --bg-color: #191919; --card-bg: #252525; --text-main: #ffffff; | |
| --holiday-red: #ff4d4f; --event-green: #52c41a; --vacation-pink: #eb2f96; --task-cyan: #13c2c2; | |
| } | |
| body { font-family: sans-serif; background: var(--bg-color); color: var(--text-main); margin: 0; padding: 10px; display: flex; flex-direction: column; align-items: center; } | |
| .calendar-container { width: 95%; max-width: 350px; background: var(--card-bg); border-radius: 15px; padding: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); } | |
| .header { text-align: center; font-size: 1.2em; font-weight: bold; margin-bottom: 15px; color: #ffd666; } | |
| .grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; text-align: center; } | |
| .day-name { font-size: 0.75em; color: #888; font-weight: bold; padding-bottom: 8px; } | |
| .day { aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 0.9em; border-radius: 8px; position: relative; cursor: pointer; border: 1px solid transparent; } | |
| .day:hover { border-color: #555; } | |
| .today { background: rgba(255,255,255,0.1); border: 1px solid #ffd666; } | |
| .dot-container { display: flex; gap: 2px; position: absolute; bottom: 3px; } | |
| .dot { width: 5px; height: 5px; border-radius: 50%; } | |
| .dot-red { background: var(--holiday-red); } .dot-green { background: var(--event-green); } | |
| .dot-pink { background: var(--vacation-pink); } .dot-cyan { background: var(--task-cyan); } | |
| /* 節日與輸入框樣式 */ | |
| .info-panel { width: 100%; margin-top: 15px; font-size: 0.85em; } | |
| .holiday-label { color: var(--holiday-red); margin-bottom: 8px; font-weight: bold; } | |
| .input-group { display: flex; gap: 5px; margin-top: 10px; } | |
| input { flex: 1; background: #333; border: 1px solid #444; color: white; padding: 5px 10px; border-radius: 5px; outline: none; } | |
| button { background: #4d4d4d; border: none; color: white; padding: 5px 10px; border-radius: 5px; cursor: pointer; } | |
| button:hover { background: #666; } | |
| .legend { display: flex; flex-wrap: wrap; gap: 10px; font-size: 0.7em; margin-top: 10px; color: #aaa; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="calendar-container"> | |
| <div class="header" id="monthYear"></div> | |
| <div class="grid" id="calendarGrid"></div> | |
| <div class="info-panel"> | |
| <div id="holidayText" class="holiday-label"></div> | |
| <div class="input-group"> | |
| <input type="text" id="eventInput" placeholder="輸入今日任務..."> | |
| <button onclick="addEvent()">加入</button> | |
| </div> | |
| <div class="legend"> | |
| <span><i class="dot dot-red" style="display:inline-block"></i> 節日</span> | |
| <span><i class="dot dot-pink" style="display:inline-block"></i> 假期</span> | |
| <span><i class="dot dot-green" style="display:inline-block"></i> 事件</span> | |
| <span><i class="dot dot-cyan" style="display:inline-block"></i> 任務</span> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| const holidays2026 = { | |
| "01-01": "元旦", "02-16": "春假", "02-17": "除夕", "02-18": "春節", "02-28": "228紀念日", | |
| "04-04": "兒童節/清明節", "05-01": "勞動節", "06-19": "端午節", "09-25": "中秋節", "10-10": "國慶日" | |
| }; | |
| const vacations = ["02-16", "02-17", "02-18", "02-19", "02-20"]; // 範例假期 | |
| function init() { | |
| const now = new Date(); | |
| const year = now.getFullYear(); | |
| const month = now.getMonth(); | |
| render(year, month); | |
| } | |
| function render(year, month) { | |
| const monthNames = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]; | |
| document.getElementById('monthYear').innerText = `${year}年 ${monthNames[month]}`; | |
| const grid = document.getElementById('calendarGrid'); | |
| grid.innerHTML = ["日", "一", "二", "三", "四", "五", "六"].map(d => `<div class="day-name">${d}</div>`).join(''); | |
| const firstDay = new Date(year, month, 1).getDay(); | |
| const daysInMonth = new Date(year, month + 1, 0).getDate(); | |
| const todayStr = new Date().toISOString().split('T')[0]; | |
| for (let i = 0; i < firstDay; i++) grid.innerHTML += `<div></div>`; | |
| for (let d = 1; d <= daysInMonth; d++) { | |
| const dateKey = `${String(month+1).padStart(2, '0')}-${String(d).padStart(2, '0')}`; | |
| const fullDate = `${year}-${dateKey}`; | |
| const isToday = fullDate === todayStr ? 'today' : ''; | |
| let dots = ""; | |
| if (holidays2026[dateKey]) dots += '<div class="dot dot-red"></div>'; | |
| if (vacations.includes(dateKey)) dots += '<div class="dot dot-pink"></div>'; | |
| // 檢查本地存儲的事件 | |
| const savedData = localStorage.getItem('notion_events_' + fullDate); | |
| if (savedData) { | |
| const data = JSON.parse(savedData); | |
| if (data.type === 'event') dots += '<div class="dot dot-green"></div>'; | |
| if (data.type === 'task') dots += '<div class="dot dot-cyan"></div>'; | |
| } | |
| grid.innerHTML += ` | |
| <div class="day ${isToday}" onclick="showInfo('${dateKey}')"> | |
| ${d} | |
| <div class="dot-container">${dots}</div> | |
| </div>`; | |
| if (fullDate === todayStr && holidays2026[dateKey]) { | |
| document.getElementById('holidayText').innerText = "今日節慶:" + holidays2026[dateKey]; | |
| } | |
| } | |
| } | |
| function addEvent() { | |
| const input = document.getElementById('eventInput'); | |
| if (!input.value) return; | |
| const today = new Date().toISOString().split('T')[0]; | |
| localStorage.setItem('notion_events_' + today, JSON.stringify({ text: input.value, type: 'task' })); | |
| alert("已加入今日任務!重新整理後會顯示青色點點"); | |
| input.value = ""; | |
| location.reload(); | |
| } | |
| function showInfo(key) { | |
| if (holidays2026[key]) document.getElementById('holidayText').innerText = "節日資訊:" + holidays2026[key]; | |
| else document.getElementById('holidayText').innerText = ""; | |
| } | |
| init(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment