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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/bin/norcal +54 -19
  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: bfb181fb12eccf2f5a2a573755d884474dc74eebddf4391fd6a88c5adc55ec7d
4
+ data.tar.gz: a6fe09085766141d71509c87c8ff79aec265453c1456eac18646112a39fe599e
5
5
  SHA512:
6
- metadata.gz: a23ac49843b37ed383b08d6215a5a9f4f24416471539654053abd2574c4d4f5aa46e714d56d6f78a50a14a9e43d17652d08173d2cb08ddb6a584e8d2a6515432
7
- data.tar.gz: d4392d35c14eda23aebf58669e627c908c754cda781cdba6d61f72e4dc1a9b135ed56c8ff387683bf4f3e2c919c512ed44c839aae7d2c6901f773f611e5281f7
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.2.0.gem
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) => "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",
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), "Nyttårsdag", true],
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), "St. Valentines dag", false],
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, "Kr. Himmelfartsdag", true],
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), "Jonsokaften", false],
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 = { bg: [], border: [], sep: [], labels: [], texts: [], buttons: [] }
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 { |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]) }
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
- third = (dates.size / 3.0).ceil
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
- $w[:border] << outer
306
+ $wn[:border] << outer
291
307
 
292
308
  inner = TkFrame.new(outer)
293
- $w[:bg] << inner
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
- $w[:texts] << tw
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
- $w[:sep] << sep
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
- build_notable(grid_f, year)
374
- .grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
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) }
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.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - baosen