norcal 1.2.0 → 1.3.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.
- checksums.yaml +4 -4
- data/README.md +3 -2
- data/bin/norcal +54 -19
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bfb181fb12eccf2f5a2a573755d884474dc74eebddf4391fd6a88c5adc55ec7d
|
|
4
|
+
data.tar.gz: a6fe09085766141d71509c87c8ff79aec265453c1456eac18646112a39fe599e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de5b45e2e61b174ec3a3e7b1910f0f50eb063ebc3deeecbe74996750a942aa50ed8d4d46e60bea7be0a47a5cdcddbce9e8433ffd596d7e7eeee031a500b48178
|
|
7
|
+
data.tar.gz: f832d1ff523264fdf967f3ce98cd00bb8f77ada069d3b5ec6df432bc36b08cebe90c851824c2df22380cd381842c7af9aca63c23945c8750711d921804de965a
|
data/README.md
CHANGED
|
@@ -31,7 +31,7 @@ gem install norcal
|
|
|
31
31
|
git clone https://github.com/baosen/norcal.git
|
|
32
32
|
cd norcal
|
|
33
33
|
gem build norcal.gemspec
|
|
34
|
-
gem install norcal-1.
|
|
34
|
+
gem install norcal-1.3.0.gem
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Usage
|
|
@@ -49,7 +49,8 @@ norcal --light 2026 # light mode, specific year
|
|
|
49
49
|
- ISO week numbers, Monday-first weeks
|
|
50
50
|
- Sundays and public holidays in red, Saturdays in gray
|
|
51
51
|
- Easter-based movable holidays (Computus algorithm)
|
|
52
|
-
- Notable dates: royal birthdays, Samefolkets dag, Morsdag, Farsdag, solverv, sommertid, and more
|
|
52
|
+
- Notable dates: royal birthdays, Samefolkets dag, Morsdag, Farsdag, solverv, sommertid, advent, and more
|
|
53
|
+
- Filter to show only red days (public holidays)
|
|
53
54
|
- Today highlighted with yellow background
|
|
54
55
|
- Dark mode (default) and light mode, with toggle button
|
|
55
56
|
- Zoom in/out (`+`/`–` buttons, Ctrl+scroll, Ctrl++/Ctrl+-)
|
data/bin/norcal
CHANGED
|
@@ -61,13 +61,13 @@ end
|
|
|
61
61
|
def red_days(year)
|
|
62
62
|
e = easter(year)
|
|
63
63
|
{
|
|
64
|
-
Date.new(year, 1, 1) => "
|
|
64
|
+
Date.new(year, 1, 1) => "Første nyttårsdag",
|
|
65
65
|
e - 3 => "Skjærtorsdag",
|
|
66
66
|
e - 2 => "Langfredag",
|
|
67
67
|
e => "1. påskedag",
|
|
68
68
|
e + 1 => "2. påskedag",
|
|
69
69
|
Date.new(year, 5, 1) => "Arbeidernes dag",
|
|
70
|
-
e + 39 => "
|
|
70
|
+
e + 39 => "Kristi himmelfartsdag",
|
|
71
71
|
Date.new(year, 5, 17) => "Grunnlovsdag",
|
|
72
72
|
e + 49 => "1. pinsedag",
|
|
73
73
|
e + 50 => "2. pinsedag",
|
|
@@ -87,44 +87,55 @@ def notable_dates(year)
|
|
|
87
87
|
nov27 = Date.new(year, 11, 27)
|
|
88
88
|
advent1 = nov27 + ((7 - nov27.cwday) % 7)
|
|
89
89
|
|
|
90
|
+
botsdag = last_wday(year, 10, 7) # last Sunday in October
|
|
91
|
+
|
|
90
92
|
[
|
|
91
|
-
[Date.new(year, 1, 1), "
|
|
93
|
+
[Date.new(year, 1, 1), "Første nyttårsdag", true],
|
|
92
94
|
[Date.new(year, 1, 21), "Prinsesse Ingrid Alexandra, #{year - 2004} år", false],
|
|
93
95
|
[Date.new(year, 2, 6), "Samefolkets dag", false],
|
|
94
96
|
[morsdag, "Morsdag", false],
|
|
95
|
-
[Date.new(year, 2, 14), "
|
|
97
|
+
[Date.new(year, 2, 14), "Valentinsdag", false],
|
|
96
98
|
[fastelavn, "Fastelavn", false],
|
|
97
99
|
[Date.new(year, 2, 21), "Kong Harald, #{year - 1937} år", false],
|
|
100
|
+
[Date.new(year, 3, 8), "Kvinnedagen", false],
|
|
98
101
|
[Date.new(year, 3, 20), "Vårjevndøgn", false],
|
|
99
102
|
[sommer_start, "Sommertid start", false],
|
|
100
103
|
[e - 7, "Palmesøndag", true],
|
|
101
104
|
[e - 3, "Skjærtorsdag", true],
|
|
102
105
|
[e - 2, "Langfredag", true],
|
|
106
|
+
[e - 1, "Påskeaften", false],
|
|
103
107
|
[e, "1. påskedag", true],
|
|
104
108
|
[e + 1, "2. påskedag", true],
|
|
105
109
|
[Date.new(year, 5, 1), "Arbeidernes dag", true],
|
|
106
110
|
[Date.new(year, 5, 8), "Frigjøringsdag 1945", false],
|
|
107
|
-
[e + 39, "
|
|
111
|
+
[e + 39, "Kristi himmelfartsdag", true],
|
|
108
112
|
[Date.new(year, 5, 17), "Grunnlovsdag 1814", true],
|
|
113
|
+
[e + 48, "Pinseaften", false],
|
|
109
114
|
[e + 49, "1. pinsedag", true],
|
|
110
115
|
[e + 50, "2. pinsedag", true],
|
|
111
116
|
[Date.new(year, 6, 7), "Unionsoppløsning 1905", false],
|
|
112
117
|
[Date.new(year, 6, 21), "Sommersolverv", false],
|
|
113
|
-
[Date.new(year, 6, 23), "
|
|
118
|
+
[Date.new(year, 6, 23), "Sankthansaften", false],
|
|
114
119
|
[Date.new(year, 7, 4), "Dronning Sonja, #{year - 1937} år", false],
|
|
115
120
|
[Date.new(year, 7, 20), "Kronprins Haakon, #{year - 1973} år", false],
|
|
116
121
|
[Date.new(year, 7, 29), "Olsokdagen", false],
|
|
117
122
|
[Date.new(year, 8, 19), "Kronprinsesse Mette-Marit, #{year - 1973} år", false],
|
|
118
123
|
[Date.new(year, 9, 23), "Høstjevndøgn", false],
|
|
124
|
+
[botsdag, "Bots- og bededag", false],
|
|
119
125
|
[sommer_slutt, "Sommertid slutt", false],
|
|
120
126
|
[Date.new(year, 10, 31), "Halloween", false],
|
|
121
127
|
[Date.new(year, 11, 1), "Allehelgensdag", false],
|
|
122
128
|
[farsdag, "Farsdag", false],
|
|
123
129
|
[advent1, "1. søndag i advent", false],
|
|
130
|
+
[advent1 + 7, "2. søndag i advent", false],
|
|
124
131
|
[Date.new(year, 12, 13), "Luciadagen", false],
|
|
132
|
+
[advent1 + 14, "3. søndag i advent", false],
|
|
133
|
+
[advent1 + 21, "4. søndag i advent", false],
|
|
125
134
|
[Date.new(year, 12, 21), "Vintersolverv", false],
|
|
135
|
+
[Date.new(year, 12, 24), "Julaften", false],
|
|
126
136
|
[Date.new(year, 12, 25), "1. juledag", true],
|
|
127
137
|
[Date.new(year, 12, 26), "2. juledag", true],
|
|
138
|
+
[Date.new(year, 12, 31), "Nyttårsaften", false],
|
|
128
139
|
].sort_by { |d, _, _| d }
|
|
129
140
|
end
|
|
130
141
|
|
|
@@ -149,6 +160,7 @@ THEME = {
|
|
|
149
160
|
$dark = ARGV.delete('--light') ? false : true
|
|
150
161
|
$year = (ARGV[0] || Date.today.year).to_i
|
|
151
162
|
$zoom = 0
|
|
163
|
+
$red_only = false
|
|
152
164
|
|
|
153
165
|
def theme
|
|
154
166
|
THEME[$dark ? :dark : :light]
|
|
@@ -179,7 +191,8 @@ end
|
|
|
179
191
|
# All trackable widgets, grouped by update type.
|
|
180
192
|
# Labels store {w: widget, fg: theme_key, bg: theme_key, font: font_key}.
|
|
181
193
|
# Buttons store {w: widget, fg: theme_key, text_key: theme_key or nil, text: static}.
|
|
182
|
-
$w
|
|
194
|
+
$w = { bg: [], border: [], sep: [], labels: [], texts: [], buttons: [] }
|
|
195
|
+
$wn = { bg: [], border: [], sep: [], texts: [] } # notable-only (rebuilt on filter)
|
|
183
196
|
|
|
184
197
|
# Apply current theme + zoom to all tracked widgets (no widget recreation).
|
|
185
198
|
def restyle
|
|
@@ -191,15 +204,15 @@ def restyle
|
|
|
191
204
|
$scrollbar.configure(background: t[:bg], troughcolor: t[:bg])
|
|
192
205
|
$root.title = "Kalender #{$year}"
|
|
193
206
|
|
|
194
|
-
$w[:bg].each
|
|
195
|
-
$w[:border].each { |w| w.configure(background: t[:bg], highlightbackground: t[:border]) }
|
|
196
|
-
$w[:sep].each
|
|
207
|
+
($w[:bg] + $wn[:bg]).each { |w| w.configure(background: t[:bg]) }
|
|
208
|
+
($w[:border] + $wn[:border]).each { |w| w.configure(background: t[:bg], highlightbackground: t[:border]) }
|
|
209
|
+
($w[:sep] + $wn[:sep]).each { |w| w.configure(background: t[:sep]) }
|
|
197
210
|
|
|
198
211
|
$w[:labels].each do |e|
|
|
199
212
|
e[:w].configure(foreground: t[e[:fg]], background: t[e[:bg]], font: f[e[:font]])
|
|
200
213
|
end
|
|
201
214
|
|
|
202
|
-
$w[:texts].each do |tw|
|
|
215
|
+
($w[:texts] + $wn[:texts]).each do |tw|
|
|
203
216
|
tab = [65 + $zoom * 4, 40].max
|
|
204
217
|
tw.configure(background: t[:bg], font: f[:note], tabs: tab.to_s)
|
|
205
218
|
tw.tag_configure('dt', foreground: t[:fg], font: f[:note_b])
|
|
@@ -208,7 +221,7 @@ def restyle
|
|
|
208
221
|
end
|
|
209
222
|
|
|
210
223
|
$w[:buttons].each do |e|
|
|
211
|
-
text = e[:text_key] ? t[e[:text_key]] : e[:text]
|
|
224
|
+
text = e[:text_key] ? t[e[:text_key]] : (e[:text].respond_to?(:call) ? e[:text].call : e[:text])
|
|
212
225
|
e[:w].configure(text: text, font: f[:btn], foreground: t[e[:fg]],
|
|
213
226
|
background: t[:bg], activebackground: t[:bg], activeforeground: t[:fg])
|
|
214
227
|
end
|
|
@@ -282,15 +295,18 @@ def build_month(parent, year, month, holidays)
|
|
|
282
295
|
end
|
|
283
296
|
|
|
284
297
|
def build_notable(parent, year)
|
|
298
|
+
$wn.each_value(&:clear)
|
|
299
|
+
|
|
285
300
|
dates = notable_dates(year)
|
|
286
|
-
|
|
301
|
+
dates = dates.select { |_, _, is_red| is_red } if $red_only
|
|
302
|
+
third = [(dates.size / 3.0).ceil, 1].max
|
|
287
303
|
cols = dates.each_slice(third).to_a
|
|
288
304
|
|
|
289
305
|
outer = TkFrame.new(parent) { borderwidth 1; relief 'solid'; highlightthickness 0 }
|
|
290
|
-
$
|
|
306
|
+
$wn[:border] << outer
|
|
291
307
|
|
|
292
308
|
inner = TkFrame.new(outer)
|
|
293
|
-
$
|
|
309
|
+
$wn[:bg] << inner
|
|
294
310
|
inner.pack(padx: 5, pady: 5, fill: 'both')
|
|
295
311
|
|
|
296
312
|
cols.each_with_index do |entries, ci|
|
|
@@ -299,7 +315,7 @@ def build_notable(parent, year)
|
|
|
299
315
|
borderwidth 0; highlightthickness 0
|
|
300
316
|
wrap 'word'; padx 3; pady 2; cursor ''; insertwidth 0
|
|
301
317
|
}
|
|
302
|
-
$
|
|
318
|
+
$wn[:texts] << tw
|
|
303
319
|
|
|
304
320
|
entries.each_with_index do |(date, desc, is_red), i|
|
|
305
321
|
dtag = is_red ? 'dtr' : 'dt'
|
|
@@ -315,13 +331,20 @@ def build_notable(parent, year)
|
|
|
315
331
|
|
|
316
332
|
if ci < cols.size - 1
|
|
317
333
|
sep = TkFrame.new(inner) { width 1 }
|
|
318
|
-
$
|
|
334
|
+
$wn[:sep] << sep
|
|
319
335
|
sep.grid(row: 0, column: ci * 2 + 1, sticky: 'ns', padx: 4)
|
|
320
336
|
end
|
|
321
337
|
end
|
|
322
338
|
outer
|
|
323
339
|
end
|
|
324
340
|
|
|
341
|
+
def rebuild_notable
|
|
342
|
+
$notable_frame&.destroy
|
|
343
|
+
$notable_frame = build_notable($notable_parent, $year)
|
|
344
|
+
$notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
|
|
345
|
+
restyle
|
|
346
|
+
end
|
|
347
|
+
|
|
325
348
|
def build_buttons(parent)
|
|
326
349
|
btn_bar = TkFrame.new(parent)
|
|
327
350
|
$w[:bg] << btn_bar
|
|
@@ -342,6 +365,17 @@ def build_buttons(parent)
|
|
|
342
365
|
b4 = TkButton.new(btn_bar) { relief 'flat'; borderwidth 0; command { $fit.call(false) } }
|
|
343
366
|
$w[:buttons] << { w: b4, fg: :dkgray, text_key: nil, text: 'fit' }
|
|
344
367
|
b4.pack(side: 'left', padx: 2)
|
|
368
|
+
|
|
369
|
+
b5 = TkButton.new(btn_bar) { relief 'flat'; borderwidth 0
|
|
370
|
+
command {
|
|
371
|
+
$red_only = !$red_only
|
|
372
|
+
rebuild_notable
|
|
373
|
+
restyle # update button text
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
$w[:buttons] << { w: b5, fg: :dkgray, text_key: nil,
|
|
377
|
+
text: -> { $red_only ? 'alle dager' : "bare r\u00f8de dager" } }
|
|
378
|
+
b5.pack(side: 'left', padx: 2)
|
|
345
379
|
end
|
|
346
380
|
|
|
347
381
|
def build_all(year)
|
|
@@ -370,8 +404,9 @@ def build_all(year)
|
|
|
370
404
|
.grid(row: idx / 3, column: idx % 3, padx: 3, pady: 3, sticky: 'nsew')
|
|
371
405
|
end
|
|
372
406
|
|
|
373
|
-
|
|
374
|
-
|
|
407
|
+
$notable_parent = grid_f
|
|
408
|
+
$notable_frame = build_notable(grid_f, year)
|
|
409
|
+
$notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
|
|
375
410
|
|
|
376
411
|
build_buttons(grid_f)
|
|
377
412
|
3.times { |c| grid_f.grid_columnconfigure(c, weight: 1) }
|