From 6ad6ebd1c1de6c0422de9a985ff7bdca0518bc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Tue, 9 Sep 2025 23:40:52 +0200 Subject: [PATCH] Initial commit --- Library/Widgets/Calendar.md | 242 ++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 Library/Widgets/Calendar.md diff --git a/Library/Widgets/Calendar.md b/Library/Widgets/Calendar.md new file mode 100644 index 0000000..b38e4cd --- /dev/null +++ b/Library/Widgets/Calendar.md @@ -0,0 +1,242 @@ +```space-lua + +function generate_calendar(calendarID, year, month) + local month_names = { + "Januari", "Februari", "Mars", "April", + "Maj", "Juni", "Juli", "Augusti", + "September", "Oktober", "November", "December" + } + local day_names = {"Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"} + + -- A specified year and month will always display that calendar. + if year == 0 and month == 0 then + local wantedMonth = clientStore.get("calendar:" .. calendarID) + -- Calculate year and month from the current date plus a month offset. + if wantedMonth == nil then + wantedMonth = tonumber(os.date("%Y")) * 12 + tonumber(os.date("%m")) + end + year = (wantedMonth - (wantedMonth % 12)) / 12 + month = wantedMonth % 12 + if month == 0 then + month = 1 + end + end + + local events = query[[ + from index.tag "event" + where + _.at.match(string.format("^%d-%02d-", year, month)) + order by _.at + ]] + + local days = get_days_in_month(year, month) + + -- Get the first day of the month (1 = Sunday, 2 = Monday, ..., 7 = Saturday) + local first_day = tonumber(os.date("%w", os.time{year=year, month=month, day=1})) + 1 + + -- Adjust the first day based on the week start setting + if week_start_on_monday then + first_day = first_day - 1 + if first_day == 0 then + first_day = 7 + end + end + + local html = [[ + + + + + ]] + + html = html .. "" + for _, day_name in ipairs(day_names) do + html = html .. "" + end + html = html .. "\n" + + local day = 1 + local started = false + for week = 1, 6 do + html = html .. "" + for weekday = 1, 7 do + if not started and weekday == first_day then + started = true + end + if started and day <= days then + local cellcontent = "" + cellcontent = day + + for _, e in pairs(events) do + local datematch = e.at.match( + string.format("^%d-%02d-%02d( +[0-9]+:[0-9]+)?", year, month, day)) + if #datematch >= 2 and not datematch[2] then + cellcontent = cellcontent .. string.format( + [[
%s
]], + e.ref, e.name + ) + elseif #datematch >= 2 and datematch[2] then + cellcontent = cellcontent .. string.format( + [[ + +
+
%s
+
%s
+
+
+ ]], + e.ref, + datematch[2], + e.name + ) + end + end + + -- Mark today's date + if day == tonumber(os.date("%d")) and month == tonumber(os.date("%m")) and year == tonumber(os.date("%Y")) then + html = html .. string.format([[]], cellcontent) + else + html = html .. string.format([[]], cellcontent) + end + + day = day + 1 + else + html = html .. "" + end + end + html = html .. "" + if day > days then + break + end + end + + html = html .. "
+ < + Idag + > + ]] .. month_names[month] .. " " .. year .. [[ +
" .. day_name .. "
%s%s
" + + local tmpl = js.window.document.createElement("template") + tmpl.innerHTML = html + + tmpl.content.querySelector('.month-prev').addEventListener('click', function() + storeMonth(calendarID, year, month, -1) + codeWidget.refreshAll() + end) + + tmpl.content.querySelector('.month-next').addEventListener('click', function() + storeMonth(calendarID, year, month, 1) + codeWidget.refreshAll() + end) + + tmpl.content.querySelector('.month-now').addEventListener('click', function() + clientStore.delete("calendar:" .. calendarID) + storeMonth(calendarID, tonumber(os.date("%Y")), tonumber(os.date("%m")), 0) + codeWidget.refreshAll() + end) + + return widget.new{ + html = tmpl.content, + display = "block", + cssClasses = {"calendartable"} + } +end + +function storeMonth(calendarID, year, month, offset) + local storedMonth = clientStore.get("calendar:" .. calendarID) + if storedMonth == nil then + storedMonth = year * 12 + month + end + clientStore.set("calendar:" .. calendarID, storedMonth + offset) + codeWidget.refreshAll() +end + +-- Local function to get the correct number of days in a month (handles leap years) +local function get_days_in_month(year, month) + local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + + -- Check for leap year and adjust February + if month == 2 and ((year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)) then + return 29 + end + + return days_in_month[month] +end +``` + +```space-style +.calendartable { + border-collapse: collapse; + /* width: 500px; */ +} + +.calendartable table { + border-color: var(--panel-border-color); + border: 2px solid #444; + border-collapse: collapse; +} + +.calendartable th { + width: 14%; + padding: 3px; + text-align: left; + background-color: var(--panel-background-color); + color: #852624; + border: 1px solid #aaa; +} + + +.calendartable td { + width: 14%; + padding: 3px; + text-align: left; + vertical-align: top; + border: 1px solid #aaa; +} + +.calendartable td.today { + background-color: #f6f3c2; +} + +.calendartable a { + text-decoration-line: none; + color: var(--root-color); +} + +.calendartable a.mark { + text-decoration-line: none; + color: var(--ui-accent-text-color); +} + +.calendartable span.extramarker { + background-color: yellow; +} + +.calendartable .event { + background-color: #2ca05a; + color: #fff; + border-radius: 4px; + padding: 4px 8px; + margin-top: 8px; + max-width: 200px; + white-space: normal; + overflow-wrap: normal !important; + word-break: normal !important; +} + +.calendartable .event.all-day { + background-color: #852624; +} + +.calendartable .event .time { + font-weight: bold; +} + +.calendartable .month-prev, +.calendartable .month-next, +.calendartable .month-now { + cursor: pointer; +} + +```