norcal 1.2.0 → 1.4.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/bin/norcal +99 -55
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 628317b98eb4536e13c1199961ce51f89f246add68275897845fa08654060de1
4
- data.tar.gz: 23ef85bb70d9342b372fb443b6ab26a3664c7b39b69ec479bbc54fe7a10c6423
3
+ metadata.gz: 9be7e8ddb9dd50827b5f06ebb3df0f77198839e50e243fe2a5afe2b9c3013de4
4
+ data.tar.gz: f4c4991791a1cfffe455411d4c08534f4f65a60539cf9ee01dd43f1084ab70e0
5
5
  SHA512:
6
- metadata.gz: a23ac49843b37ed383b08d6215a5a9f4f24416471539654053abd2574c4d4f5aa46e714d56d6f78a50a14a9e43d17652d08173d2cb08ddb6a584e8d2a6515432
7
- data.tar.gz: d4392d35c14eda23aebf58669e627c908c754cda781cdba6d61f72e4dc1a9b135ed56c8ff387683bf4f3e2c919c512ed44c839aae7d2c6901f773f611e5281f7
6
+ metadata.gz: 39d0619b9c32fad49beeb6f720d7776c11e5238c4d85ac19d0a642aadf749b8196174b8e64be1bc5f37a585edb44a6db3369102e9f54a89be333593cc0694df9
7
+ data.tar.gz: 7f4cc6f41397632c34854ecee9cbbe24eccde9bc0dc6ca3741891ba161c78af61968fcf286b3a1b9e9f32806bb0891b1f681e91085923fb499675d020fae6dcf
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.2.0.gem
34
+ gem install norcal-1.4.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,14 +61,14 @@ end
61
61
  def red_days(year)
62
62
  e = easter(year)
63
63
  {
64
- Date.new(year, 1, 1) => "Nyttårsdag",
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 => "Kr. Himmelfartsdag",
71
- Date.new(year, 5, 17) => "Grunnlovsdag",
70
+ e + 39 => "Kristi himmelfartsdag",
71
+ Date.new(year, 5, 17) => "Grunnlovsdagen",
72
72
  e + 49 => "1. pinsedag",
73
73
  e + 50 => "2. pinsedag",
74
74
  Date.new(year, 12, 25) => "1. juledag",
@@ -77,55 +77,75 @@ def red_days(year)
77
77
  end
78
78
 
79
79
  # Notable dates: [date, description, show_date_in_red?]
80
+ # Red days are auto-included from red_days(); some get extra context in the
81
+ # notable_names override below.
80
82
  def notable_dates(year)
81
83
  e = easter(year)
84
+ holidays = red_days(year)
85
+
82
86
  morsdag = nth_wday(year, 2, 7, 2)
83
87
  farsdag = nth_wday(year, 11, 7, 2)
84
88
  sommer_start = last_wday(year, 3, 7)
85
89
  sommer_slutt = last_wday(year, 10, 7)
86
90
  fastelavn = e - 49
91
+ botsdag = last_wday(year, 10, 7)
87
92
  nov27 = Date.new(year, 11, 27)
88
93
  advent1 = nov27 + ((7 - nov27.cwday) % 7)
89
94
 
90
- [
91
- [Date.new(year, 1, 1), "Nyttårsdag", true],
92
- [Date.new(year, 1, 21), "Prinsesse Ingrid Alexandra, #{year - 2004} år", false],
93
- [Date.new(year, 2, 6), "Samefolkets dag", false],
94
- [morsdag, "Morsdag", false],
95
- [Date.new(year, 2, 14), "St. Valentines dag", false],
96
- [fastelavn, "Fastelavn", false],
97
- [Date.new(year, 2, 21), "Kong Harald, #{year - 1937} år", false],
98
- [Date.new(year, 3, 20), "Vårjevndøgn", false],
99
- [sommer_start, "Sommertid start", false],
100
- [e - 7, "Palmesøndag", true],
101
- [e - 3, "Skjærtorsdag", true],
102
- [e - 2, "Langfredag", true],
103
- [e, "1. påskedag", true],
104
- [e + 1, "2. påskedag", true],
105
- [Date.new(year, 5, 1), "Arbeidernes dag", true],
106
- [Date.new(year, 5, 8), "Frigjøringsdag 1945", false],
107
- [e + 39, "Kr. Himmelfartsdag", true],
108
- [Date.new(year, 5, 17), "Grunnlovsdag 1814", true],
109
- [e + 49, "1. pinsedag", true],
110
- [e + 50, "2. pinsedag", true],
111
- [Date.new(year, 6, 7), "Unionsoppløsning 1905", false],
112
- [Date.new(year, 6, 21), "Sommersolverv", false],
113
- [Date.new(year, 6, 23), "Jonsokaften", false],
114
- [Date.new(year, 7, 4), "Dronning Sonja, #{year - 1937} år", false],
115
- [Date.new(year, 7, 20), "Kronprins Haakon, #{year - 1973} år", false],
116
- [Date.new(year, 7, 29), "Olsokdagen", false],
117
- [Date.new(year, 8, 19), "Kronprinsesse Mette-Marit, #{year - 1973} år", false],
118
- [Date.new(year, 9, 23), "Høstjevndøgn", false],
119
- [sommer_slutt, "Sommertid slutt", false],
120
- [Date.new(year, 10, 31), "Halloween", false],
121
- [Date.new(year, 11, 1), "Allehelgensdag", false],
122
- [farsdag, "Farsdag", false],
123
- [advent1, "1. søndag i advent", false],
124
- [Date.new(year, 12, 13), "Luciadagen", false],
125
- [Date.new(year, 12, 21), "Vintersolverv", false],
126
- [Date.new(year, 12, 25), "1. juledag", true],
127
- [Date.new(year, 12, 26), "2. juledag", true],
128
- ].sort_by { |d, _, _| d }
95
+ # Override display names for some red days in the notable list
96
+ notable_names = {
97
+ e + 39 => "Kristi himmelfartsdag",
98
+ Date.new(year, 5, 17) => "Grunnlovsdagen 1814",
99
+ }
100
+
101
+ # Start with all red days
102
+ entries = holidays.map { |date, name|
103
+ [date, notable_names[date] || name, true]
104
+ }
105
+
106
+ # Red-in-list but not a public holiday
107
+ entries += [
108
+ [e - 7, "Palmesøndag", true],
109
+ ]
110
+
111
+ # Non-red notable dates
112
+ entries += [
113
+ [Date.new(year, 1, 21), "Prinsesse Ingrid Alexandra, #{year - 2004} år"],
114
+ [Date.new(year, 2, 6), "Samefolkets dag"],
115
+ [morsdag, "Morsdag"],
116
+ [Date.new(year, 2, 14), "Valentinsdag"],
117
+ [fastelavn, "Fastelavn"],
118
+ [Date.new(year, 2, 21), "Kong Harald, #{year - 1937} år"],
119
+ [Date.new(year, 3, 8), "Kvinnedagen"],
120
+ [Date.new(year, 3, 20), "Vårjevndøgn"],
121
+ [sommer_start, "Sommertid start"],
122
+ [e - 1, "Påskeaften"],
123
+ [Date.new(year, 5, 8), "Frigjøringsdagen 1945"],
124
+ [e + 48, "Pinseaften"],
125
+ [Date.new(year, 6, 7), "Unionsoppløsning 1905"],
126
+ [Date.new(year, 6, 21), "Sommersolverv"],
127
+ [Date.new(year, 6, 23), "Sankthansaften"],
128
+ [Date.new(year, 7, 4), "Dronning Sonja, #{year - 1937} år"],
129
+ [Date.new(year, 7, 20), "Kronprins Haakon, #{year - 1973} år"],
130
+ [Date.new(year, 7, 29), "Olsokdagen"],
131
+ [Date.new(year, 8, 19), "Kronprinsesse Mette-Marit, #{year - 1973} år"],
132
+ [Date.new(year, 9, 23), "Høstjevndøgn"],
133
+ [botsdag, "Bots- og bededag"],
134
+ [sommer_slutt, "Sommertid slutt"],
135
+ [Date.new(year, 10, 31), "Halloween"],
136
+ [Date.new(year, 11, 1), "Allehelgensdag"],
137
+ [farsdag, "Farsdag"],
138
+ [advent1, "1. søndag i advent"],
139
+ [advent1 + 7, "2. søndag i advent"],
140
+ [Date.new(year, 12, 13), "Luciadagen"],
141
+ [advent1 + 14, "3. søndag i advent"],
142
+ [advent1 + 21, "4. søndag i advent"],
143
+ [Date.new(year, 12, 21), "Vintersolverv"],
144
+ [Date.new(year, 12, 24), "Julaften"],
145
+ [Date.new(year, 12, 31), "Nyttårsaften"],
146
+ ].map { |date, name| [date, name, false] }
147
+
148
+ entries.sort_by { |d, _, _| d }
129
149
  end
130
150
 
131
151
  # -- GUI -----------------------------------------------------------------------
@@ -149,6 +169,7 @@ THEME = {
149
169
  $dark = ARGV.delete('--light') ? false : true
150
170
  $year = (ARGV[0] || Date.today.year).to_i
151
171
  $zoom = 0
172
+ $red_only = false
152
173
 
153
174
  def theme
154
175
  THEME[$dark ? :dark : :light]
@@ -179,7 +200,8 @@ end
179
200
  # All trackable widgets, grouped by update type.
180
201
  # Labels store {w: widget, fg: theme_key, bg: theme_key, font: font_key}.
181
202
  # Buttons store {w: widget, fg: theme_key, text_key: theme_key or nil, text: static}.
182
- $w = { bg: [], border: [], sep: [], labels: [], texts: [], buttons: [] }
203
+ $w = { bg: [], border: [], sep: [], labels: [], texts: [], buttons: [] }
204
+ $wn = { bg: [], border: [], sep: [], texts: [] } # notable-only (rebuilt on filter)
183
205
 
184
206
  # Apply current theme + zoom to all tracked widgets (no widget recreation).
185
207
  def restyle
@@ -191,15 +213,15 @@ def restyle
191
213
  $scrollbar.configure(background: t[:bg], troughcolor: t[:bg])
192
214
  $root.title = "Kalender #{$year}"
193
215
 
194
- $w[:bg].each { |w| w.configure(background: t[:bg]) }
195
- $w[:border].each { |w| w.configure(background: t[:bg], highlightbackground: t[:border]) }
196
- $w[:sep].each { |w| w.configure(background: t[:sep]) }
216
+ ($w[:bg] + $wn[:bg]).each { |w| w.configure(background: t[:bg]) }
217
+ ($w[:border] + $wn[:border]).each { |w| w.configure(background: t[:bg], highlightbackground: t[:border]) }
218
+ ($w[:sep] + $wn[:sep]).each { |w| w.configure(background: t[:sep]) }
197
219
 
198
220
  $w[:labels].each do |e|
199
221
  e[:w].configure(foreground: t[e[:fg]], background: t[e[:bg]], font: f[e[:font]])
200
222
  end
201
223
 
202
- $w[:texts].each do |tw|
224
+ ($w[:texts] + $wn[:texts]).each do |tw|
203
225
  tab = [65 + $zoom * 4, 40].max
204
226
  tw.configure(background: t[:bg], font: f[:note], tabs: tab.to_s)
205
227
  tw.tag_configure('dt', foreground: t[:fg], font: f[:note_b])
@@ -208,7 +230,7 @@ def restyle
208
230
  end
209
231
 
210
232
  $w[:buttons].each do |e|
211
- text = e[:text_key] ? t[e[:text_key]] : e[:text]
233
+ text = e[:text_key] ? t[e[:text_key]] : (e[:text].respond_to?(:call) ? e[:text].call : e[:text])
212
234
  e[:w].configure(text: text, font: f[:btn], foreground: t[e[:fg]],
213
235
  background: t[:bg], activebackground: t[:bg], activeforeground: t[:fg])
214
236
  end
@@ -282,15 +304,18 @@ def build_month(parent, year, month, holidays)
282
304
  end
283
305
 
284
306
  def build_notable(parent, year)
307
+ $wn.each_value(&:clear)
308
+
285
309
  dates = notable_dates(year)
286
- third = (dates.size / 3.0).ceil
310
+ dates = dates.select { |_, _, is_red| is_red } if $red_only
311
+ third = [(dates.size / 3.0).ceil, 1].max
287
312
  cols = dates.each_slice(third).to_a
288
313
 
289
314
  outer = TkFrame.new(parent) { borderwidth 1; relief 'solid'; highlightthickness 0 }
290
- $w[:border] << outer
315
+ $wn[:border] << outer
291
316
 
292
317
  inner = TkFrame.new(outer)
293
- $w[:bg] << inner
318
+ $wn[:bg] << inner
294
319
  inner.pack(padx: 5, pady: 5, fill: 'both')
295
320
 
296
321
  cols.each_with_index do |entries, ci|
@@ -299,7 +324,7 @@ def build_notable(parent, year)
299
324
  borderwidth 0; highlightthickness 0
300
325
  wrap 'word'; padx 3; pady 2; cursor ''; insertwidth 0
301
326
  }
302
- $w[:texts] << tw
327
+ $wn[:texts] << tw
303
328
 
304
329
  entries.each_with_index do |(date, desc, is_red), i|
305
330
  dtag = is_red ? 'dtr' : 'dt'
@@ -315,13 +340,20 @@ def build_notable(parent, year)
315
340
 
316
341
  if ci < cols.size - 1
317
342
  sep = TkFrame.new(inner) { width 1 }
318
- $w[:sep] << sep
343
+ $wn[:sep] << sep
319
344
  sep.grid(row: 0, column: ci * 2 + 1, sticky: 'ns', padx: 4)
320
345
  end
321
346
  end
322
347
  outer
323
348
  end
324
349
 
350
+ def rebuild_notable
351
+ $notable_frame&.destroy
352
+ $notable_frame = build_notable($notable_parent, $year)
353
+ $notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
354
+ restyle
355
+ end
356
+
325
357
  def build_buttons(parent)
326
358
  btn_bar = TkFrame.new(parent)
327
359
  $w[:bg] << btn_bar
@@ -342,6 +374,17 @@ def build_buttons(parent)
342
374
  b4 = TkButton.new(btn_bar) { relief 'flat'; borderwidth 0; command { $fit.call(false) } }
343
375
  $w[:buttons] << { w: b4, fg: :dkgray, text_key: nil, text: 'fit' }
344
376
  b4.pack(side: 'left', padx: 2)
377
+
378
+ b5 = TkButton.new(btn_bar) { relief 'flat'; borderwidth 0
379
+ command {
380
+ $red_only = !$red_only
381
+ rebuild_notable
382
+ restyle # update button text
383
+ }
384
+ }
385
+ $w[:buttons] << { w: b5, fg: :dkgray, text_key: nil,
386
+ text: -> { $red_only ? 'alle dager' : "bare r\u00f8de dager" } }
387
+ b5.pack(side: 'left', padx: 2)
345
388
  end
346
389
 
347
390
  def build_all(year)
@@ -370,8 +413,9 @@ def build_all(year)
370
413
  .grid(row: idx / 3, column: idx % 3, padx: 3, pady: 3, sticky: 'nsew')
371
414
  end
372
415
 
373
- build_notable(grid_f, year)
374
- .grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
416
+ $notable_parent = grid_f
417
+ $notable_frame = build_notable(grid_f, year)
418
+ $notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
375
419
 
376
420
  build_buttons(grid_f)
377
421
  3.times { |c| grid_f.grid_columnconfigure(c, weight: 1) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: norcal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - baosen