bible270 0.15.0 → 0.15.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1a3221c4afb7b3ba3e568f4b783a763aed4d86080dfbd13807bae0bc71e61a1
4
- data.tar.gz: 30b56e503e05712358fe1314c657aa4224e68eee742cbfaad53f5b4587625c96
3
+ metadata.gz: 30168f88726808151fb47d82b1ccca08afdbdec56f1005d41d64575d85e21384
4
+ data.tar.gz: 9e63ced217294948d3e9e248ca0fc88da6b6be56e5d1b7988ac0b999661024a4
5
5
  SHA512:
6
- metadata.gz: 622094718971b6b74ea4e5d81440d19eb1dd4eb6d2d9ae6ce2695e51b6a4f80d413c6fc7bcd08f30e428cb8808b596a875370730e21836999c08293adf7778a6
7
- data.tar.gz: 67437bd6d453421a84c6c08e8589b4fb92666e387d107d4dd7c4828b6b264eace3d2dc88d5ed0e7bb3e0da8581323db66d9c257bd0c88748b60ec4699fc0e2aa
6
+ metadata.gz: 0b01ce5346e5a2689c8a203f2962edc2a6b826ebcab1952a0a44a1ffcfe43a56b570c7f3c3806da442c822e6b58d7bc409708e9f2f507fb387df9d628f05d776
7
+ data.tar.gz: 132d37fcdaa158e96a3e293ab293cb5934064c1514736df913743189b24cf75bacd980b2b333b0ea71407a629e4edbbf15faf289ad59c8f4533b914d2946ea23
data/CHANGELOG.md CHANGED
@@ -6,8 +6,35 @@ All notable changes to bible270. Format follows [Keep a Changelog](https://keepa
6
6
 
7
7
  See the changes since the last release:
8
8
 
9
- **[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.14.0...main)**
9
+ **[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.15.0...main)**
10
10
 
11
+ ## [0.15.0] - 2026-08-02
12
+
13
+ **[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.14.1...v0.15.0)**
14
+
15
+ ### Added
16
+
17
+ - per-chapter checkoffs for reading with multiple chapters
18
+ - github actions for Rails CI, and Coverage reporting
19
+ - add dummy app in /test to test Rails functions with gem
20
+
21
+ ### Fixed
22
+
23
+ - mobile session requiring sign-in every time: use persistent sessions using 'remember-me' cookie
24
+
25
+ ## [0.14.1] - 2026-07-30
26
+
27
+ **[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.14.0...v0.14.1)**
28
+
29
+ ### Changed
30
+
31
+ - update Admin panel display verbage on plan run status
32
+
33
+ ### Fixed
34
+
35
+ - don't display 'Today' badge unless it really is
36
+ - display 'Start' not 'Continue' if reader is on day 1
37
+ - adjust badge vertical alignment in styles
11
38
 
12
39
  ## [0.14.0] - 2026-07-30
13
40
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bible 270
2
2
 
3
- [![Gem Version](https://img.shields.io/gem/v/bible270)](https://rubygems.org/gems/bible270) [![Coverage Status](https://coveralls.io/repos/github/avonderluft/bible270/badge.svg?branch=main)](https://coveralls.io/github/avonderluft/bible270?branch=main?cacheSeconds=60) [![Downloads](https://img.shields.io/gem/dt/bible270)](https://rubygems.org/gems/bible270) [![GitHub Release Date - Published_At](https://img.shields.io/github/release-date/avonderluft/bible270?label=last%20release&color=seagreen)](https://github.com/avonderluft/bible270/releases)
3
+ [![Gem Version](https://img.shields.io/gem/v/bible270)](https://rubygems.org/gems/bible270) [![Coverage Status](https://img.shields.io/coverallsCoverage/github/avonderluft/bible270?branch=main&cacheSeconds=300)](https://coveralls.io/github/avonderluft/bible270?branch=main) [![Downloads](https://img.shields.io/gem/dt/bible270)](https://rubygems.org/gems/bible270) [![GitHub Release Date - Published_At](https://img.shields.io/github/release-date/avonderluft/bible270?label=last%20release&color=seagreen)](https://github.com/avonderluft/bible270/releases)
4
4
 
5
5
  A mountable **Rails engine** that drops a 270-day (9 month) interactive Bible reading plan into any Rails app, built with [ComfortableMediaSurfer](https://github.com/shakacode/comfortable-media-surfer) CMS in mind. Readers tick off each day's readings, post reflections, and see how everyone else is getting on, much like the social plans on Bible.com.
6
6
 
@@ -14,7 +14,7 @@ Three readings a day, sized by **verse count** so each day takes roughly the sam
14
14
  - **New Testament** — once through, a reading every day. 260 chapters over 270 days, long chapters are divided to even out the daily reading
15
15
  - **Psalms & Proverbs** — once each, interleaved in one track. 181 chapters have to cover 270 days, so some are divided, shared between the two books by verse load. **A psalm of 25 verses or fewer is never divided**, keeping 131 of the 150 whole; longer psalms and Proverbs chapters break at their turns of thought (see `CHAPTER_BREAKS`). **Psalm 119 is 11 sections of 16 verses** — two of its eight-verse acrostic stanzas each. Proverbs lands on 89 days, near its proportional share. **A divided chapter is always read on consecutive days**, so nothing is inserted between the parts of a split psalm.
16
16
 
17
- Genesis → Malachi and Revelation 22 both land on day 270, as does the second Proverbs 31 — the first falls on day 135, the midpoint. Psalm 150 comes in on day 269. Every day carries all three tracks. A typical day is ~119 verses (range 76–175).
17
+ Genesis → Malachi and Revelation 22 both land on day 270, as does the second part of Proverbs 31. Every day carries all three tracks. A typical day is ~119 verses (range 76–175).
18
18
 
19
19
  The schedule is pure deterministic Ruby (`Bible270::Plan`) — none of it is stored. Portions come from per-chapter verse counts in `Bible270::Versification`. The DB only holds readers, check-offs, comments, and sign-in tokens.
20
20
 
@@ -7,7 +7,17 @@ module Bible270
7
7
  counts = Checkoff.group(:reader_id, :day).count
8
8
  @days_completed = Hash.new(0)
9
9
  counts.each { |(rid, day), n| @days_completed[rid] += 1 if n >= Plan.total_parts(day) }
10
- @readers.sort_by! { |r| [-@days_completed[r.id], r.display_name.to_s] }
10
+ # Progress first, then by name — the same name ordering the admin list uses.
11
+ @readers.sort_by! { |r| [-@days_completed[r.id], r.sort_name] }
12
+ end
13
+
14
+ # The reader's own progress. Deliberately open to visitors: the panel shows an
15
+ # invitation to sign in rather than an error, and every value it needs comes
16
+ # from the reader it is given.
17
+ def progress
18
+ @reader = current_reader
19
+ # An empty relation rather than nil, so the view needs no safe navigation.
20
+ @recent_comments = @reader ? @reader.comments.recent.limit(5) : Comment.none
11
21
  end
12
22
 
13
23
  def show
@@ -51,6 +51,19 @@ module Bible270
51
51
  end
52
52
  end
53
53
 
54
+ # The mark beside the title in the header. Larger than the favicon and inlined
55
+ # as SVG, so it stays crisp at any size and needs no asset pipeline.
56
+ def b270_mark(size: 38)
57
+ configured = Bible270.config.header_mark
58
+ return nil if configured == false
59
+
60
+ if configured.is_a?(String) && configured.present?
61
+ return image_tag(configured, width: size, height: size, alt: '', class: 'b270-mark')
62
+ end
63
+
64
+ content_tag :span, Favicon.inline_svg(size: size).html_safe, class: 'b270-mark'
65
+ end
66
+
54
67
  def b270_favicon_tag
55
68
  favicon = Bible270.config.favicon
56
69
  return if favicon == false
@@ -136,8 +136,12 @@ module Bible270
136
136
  update(bible_version: Translations.normalize(code))
137
137
  end
138
138
 
139
+ # Readers are listed by first name, matching how they are shown — the display
140
+ # name is "First Last", so sorting on it needs only case folding. Surname
141
+ # order was inconsistent with the community page and read oddly next to names
142
+ # displayed first-name-first.
139
143
  def sort_name
140
- [last_name, first_name].map { |n| n.to_s.strip.downcase }.join(' ').strip.presence || display_name.to_s.downcase
144
+ display_name.to_s.strip.downcase
141
145
  end
142
146
 
143
147
  # ---- staying signed in -------------------------------------------------
@@ -88,32 +88,7 @@
88
88
  </div>
89
89
 
90
90
  <div class="b270-panel">
91
- <h2 class="b270-subhead">Their reflections</h2>
92
- <% if @comments.any? %>
93
- <% @comments.each do |comment| %>
94
- <div class="b270-comment">
95
- <div style="flex:1">
96
- <div class="b270-cmeta">
97
- <%= link_to "day #{comment.day}", day_path(comment.day) %>
98
- · <%= comment.created_at.strftime('%b %-d, %Y') %>
99
- <% if comment.hidden? %><span class="b270-badge">Hidden</span><% end %>
100
- </div>
101
- <p class="b270-cbody"><%= comment.body %></p>
102
- <div style="display:flex;gap:10px;margin-top:6px">
103
- <% if comment.hidden? %>
104
- <%= button_to 'Restore', admin_unhide_comment_path(comment), method: :patch,
105
- params: { return_to: request.fullpath }, class: 'b270-linkbtn' %>
106
- <% else %>
107
- <%= button_to 'Hide', admin_hide_comment_path(comment), method: :patch,
108
- params: { return_to: request.fullpath }, class: 'b270-linkbtn' %>
109
- <% end %>
110
- </div>
111
- </div>
112
- </div>
113
- <% end %>
114
- <% else %>
115
- <p class="b270-hint" style="margin-top:0">None yet.</p>
116
- <% end %>
91
+ <%= render "bible270/shared/reflections", comments: @comments, moderate: true %>
117
92
  </div>
118
93
 
119
94
  <div class="b270-panel">
@@ -3,47 +3,11 @@
3
3
  <h1><%= Bible270.config.app_name %> <em>— read God's whole story</em></h1>
4
4
  <p class="lede">Daily passages from the Old Testament, New Testament, and Psalms or Proverbs — portions sized to take about the same time to read. Check off what you read; your place is saved for you, and you can see how your friends are progressing as well.</p>
5
5
 
6
- <div class="b270-panel">
7
- <% if signed_in? %>
8
- <div class="b270-bignum">
9
- <span class="n"><%= current_reader.days_completed %></span>
10
- <span class="of">of <%= Bible270::Plan::DAYS %> days complete</span>
11
- <span class="pct"><%= current_reader.completion_percent %>%</span>
12
- </div>
13
- <div class="b270-tracks">
14
- <% [["ot", current_reader.days_read_in("ot"), Bible270::Plan::DAYS],
15
- ["nt", current_reader.days_read_in("nt"), Bible270::Plan.nt_content_days],
16
- ["pp", current_reader.days_read_in("pp"), Bible270::Plan::DAYS]].each do |track, read, total| %>
17
- <% t = b270_track(track) %>
18
- <div class="b270-tm">
19
- <span class="lab"><span class="b270-rib" style="background:<%= t[:color] %>"></span><%= t[:label] %></span>
20
- <span class="b270-bar"><i style="width:<%= total.zero? ? 0 : (read.to_f/total*100).round %>%;background:<%= t[:color] %>"></i></span>
21
- <span class="val"><%= read %>/<%= total %></span>
22
- </div>
23
- <% end %>
24
- </div>
25
- <p style="margin:16px 0 0">
26
- <% @day_verb = @start_day == 1 ? "Start" : "Continue" %>
27
- <%= link_to "#{@day_verb} reading — Day #{@start_day} →", day_path(@start_day), class: "b270-btn" %>
28
- <% if @today_day && @today_day != @start_day %>
29
- <%= link_to "Go to today (Day #{@today_day})", day_path(@today_day), style: "margin-left:12px" %>
30
- <% end %>
31
- </p>
32
- <%= render "bible270/days/start_date", reader: current_reader %>
33
- <% else %>
34
- <p class="b270-signedout"><%= link_to "Sign in", sign_in_path %> to track your progress and join
35
- the conversation. You can browse the whole plan and read others' reflections without an account.</p>
36
- <% if @community_start_date %>
37
- <p class="b270-startline">This community plan runs from <strong><%= @community_start_date.strftime("%B %-d, %Y") %></strong> to
38
- <strong><%= Bible270::Plan.end_date_for(@community_start_date).strftime("%B %-d, %Y") %></strong>.</p>
39
- <% end %>
40
- <p style="margin:14px 0 0"><%= link_to "Start at Day 1 →", day_path(1), class: "b270-btn" %></p>
41
- <% end %>
42
- </div>
6
+ <%= render "bible270/shared/progress" %>
43
7
 
44
8
  <% if @readers.any? %>
45
9
  <% rankings= @readers.count < 5 ? @readers.count : 5 %>
46
- <h2 class="b270-section-h">Reader Leaders ...</h2>
10
+ <h2 class="b270-section-h">Reader Leaders</h2>
47
11
  <div class="b270-list">
48
12
  <% @readers.first(rankings).each_with_index do |r, i| %>
49
13
  <div class="b270-li">
@@ -60,4 +24,3 @@
60
24
  </div>
61
25
  <p style="margin:12px 0 0"><%= link_to "See everyone →", community_path %></p>
62
26
  <% end %>
63
-
@@ -0,0 +1,33 @@
1
+ <% content_for :title, "Your progress — #{Bible270.config.app_name}" %>
2
+ <% content_for :hide_day_index, true %><%# the panel is followed by its own grid below %>
3
+
4
+ <p class="b270-eyebrow">Your progress</p>
5
+ <h1><%= @reader ? @reader.display_name : "Your progress" %></h1>
6
+
7
+ <%= render "bible270/shared/progress" %>
8
+
9
+ <div class="b270-panel">
10
+ <%= render "bible270/shared/reflections", comments: @recent_comments,
11
+ title: "Your recent reflections",
12
+ empty_text: "You have not written any reflections yet." %>
13
+ </div>
14
+
15
+ <% if @reader %>
16
+ <div class="b270-panel">
17
+ <h2 class="b270-subhead">Every day at a glance</h2>
18
+ <div class="b270-grid">
19
+ <% today = @reader.today_day %>
20
+ <% (1..Bible270::Plan::DAYS).each do |d| %>
21
+ <%= link_to d, day_path(d),
22
+ class: "b270-cell #{b270_day_status_class(@reader, d)} #{'now' if d == today}" %>
23
+ <% end %>
24
+ </div>
25
+ <p class="b270-hint">Filled squares are days you have finished; a lighter square means you have
26
+ read some of that day but not all of it.</p>
27
+ </div>
28
+
29
+ <p style="margin-top:18px">
30
+ <%= link_to "How others are doing →", community_path %>
31
+ · <%= link_to "Your profile", profile_path %>
32
+ </p>
33
+ <% end %>
@@ -12,18 +12,12 @@
12
12
  </div>
13
13
 
14
14
  <div class="b270-panel" style="margin-top:18px">
15
- <div class="b270-tracks">
16
- <% [["ot", @reader.days_read_in("ot"), Bible270::Plan::DAYS],
17
- ["nt", @reader.days_read_in("nt"), Bible270::Plan.nt_content_days],
18
- ["pp", @reader.days_read_in("pp"), Bible270::Plan::DAYS]].each do |track, read, total| %>
19
- <% t = b270_track(track) %>
20
- <div class="b270-tm">
21
- <span class="lab"><span class="b270-rib" style="background:<%= t[:color] %>"></span><%= t[:label] %></span>
22
- <span class="b270-bar"><i style="width:<%= total.zero? ? 0 : (read.to_f/total*100).round %>%;background:<%= t[:color] %>"></i></span>
23
- <span class="val"><%= read %>/<%= total %></span>
24
- </div>
25
- <% end %>
26
- </div>
15
+ <%= render "bible270/shared/track_bars", reader: @reader %>
16
+ </div>
17
+
18
+ <div class="b270-panel">
19
+ <%= render "bible270/shared/reflections", comments: @recent_comments,
20
+ title: "Their reflections", empty_text: "No reflections yet." %>
27
21
  </div>
28
22
 
29
23
  <div class="b270-grid">
@@ -32,14 +26,3 @@
32
26
  <% end %>
33
27
  </div>
34
28
 
35
- <% if @recent_comments.any? %>
36
- <h2 class="b270-section-h">Recent reflections</h2>
37
- <% @recent_comments.each do |c| %>
38
- <div class="b270-comment">
39
- <div style="flex:1">
40
- <div class="b270-cmeta"><%= link_to "Day #{c.day}", day_path(c.day), style: "text-decoration:none;color:var(--gold)" %> · <%= c.created_at.strftime("%b %-d, %Y") %></div>
41
- <p class="b270-cbody"><%= c.body %></p>
42
- </div>
43
- </div>
44
- <% end %>
45
- <% end %>
@@ -1,14 +1,19 @@
1
1
  <header class="b270-topbar">
2
2
  <div class="b270-brand">
3
- <%= link_to Bible270.config.app_name, root_path, class: "b270-title" %>
4
- <span class="b270-tagline"><%= Bible270.config.tagline %></span>
3
+ <%= link_to root_path, class: "b270-brandlink" do %>
4
+ <%= b270_mark %>
5
+ <span class="b270-brandtext">
6
+ <span class="b270-title"><%= Bible270.config.app_name %></span>
7
+ <span class="b270-tagline"><%= Bible270.config.tagline %></span>
8
+ </span>
9
+ <% end %>
5
10
  </div>
6
11
  <nav class="b270-nav">
7
12
  <%= link_to "Plan", root_path %>
8
13
  <%= link_to "People", community_path %>
9
14
  <% if signed_in? %>
10
15
  <% if Bible270.config.admin?(current_reader) %><%= link_to "Admin", admin_path %><% end %>
11
- <%= link_to "Progress", reader_path(current_reader) %>
16
+ <%= link_to "Progress", progress_path %>
12
17
  <%= link_to "Profile", profile_path %>
13
18
  <%= button_to "Sign out", sign_out_path, method: :delete, class: "b270-linkbtn",
14
19
  form: { style: "display:inline" } %>
@@ -0,0 +1,55 @@
1
+ <%# locals: (reader: nil, start_day: nil, today_day: nil, community_start_date: :unset) %>
2
+ <%#
3
+ The progress panel.
4
+
5
+ Every value is derived here rather than read from controller instance
6
+ variables, so it can be rendered from any page. @start_day, @today_day and
7
+ @community_start_date were set only by DaysController#index; anywhere else they
8
+ would silently have been nil.
9
+
10
+ Render it with no locals to describe the signed-in reader, or pass
11
+ reader: @reader to describe someone else.
12
+
13
+ community_start_date defaults to :unset rather than nil, so that passing nil
14
+ explicitly can mean "do not mention a community date".
15
+
16
+ NB: no ERB tags in this comment. The first close tag would close it, and everything
17
+ after would become live template code — which is exactly how this partial once
18
+ came to render itself.
19
+ %>
20
+ <%
21
+ panel_reader = reader || current_reader
22
+ panel_start_day = start_day || panel_reader&.current_day || 1
23
+ panel_today_day = today_day || panel_reader&.today_day
24
+ panel_community_date = community_start_date == :unset ? Bible270.config.start_date : community_start_date
25
+ day_verb = panel_start_day == 1 ? 'Start' : 'Continue'
26
+ %>
27
+ <div class="b270-panel">
28
+ <% if panel_reader %>
29
+ <div class="b270-bignum">
30
+ <span class="n"><%= panel_reader.days_completed %></span>
31
+ <span class="of">of <%= Bible270::Plan::DAYS %> days complete</span>
32
+ <span class="pct"><%= panel_reader.completion_percent %>%</span>
33
+ </div>
34
+
35
+ <%= render "bible270/shared/track_bars", reader: panel_reader %>
36
+
37
+ <p style="margin:16px 0 0">
38
+ <%= link_to "#{day_verb} reading — Day #{panel_start_day} →", day_path(panel_start_day), class: "b270-btn" %>
39
+ <% if panel_today_day && panel_today_day != panel_start_day %>
40
+ <%= link_to "Go to today (Day #{panel_today_day})", day_path(panel_today_day), style: "margin-left:12px" %>
41
+ <% end %>
42
+ </p>
43
+
44
+ <%= render "bible270/days/start_date", reader: panel_reader %>
45
+ <% else %>
46
+ <p class="b270-signedout"><%= link_to "Sign in", sign_in_path %> to track your progress and join
47
+ the conversation. You can browse the whole plan and read others' reflections without an account.</p>
48
+ <% if panel_community_date %>
49
+ <p class="b270-startline">This community plan runs from
50
+ <strong><%= panel_community_date.strftime("%B %-d, %Y") %></strong> to
51
+ <strong><%= Bible270::Plan.end_date_for(panel_community_date).strftime("%B %-d, %Y") %></strong>.</p>
52
+ <% end %>
53
+ <p style="margin:14px 0 0"><%= link_to "Start at Day 1 →", day_path(1), class: "b270-btn" %></p>
54
+ <% end %>
55
+ </div>
@@ -0,0 +1,44 @@
1
+ <%# locals: (comments:, title: "Their reflections", moderate: false, empty_text: "None yet.") %>
2
+ <%#
3
+ A reader's reflections. Three views showed near-identical markup: the admin
4
+ page, a reader's public page, and the progress page, differing only in whether
5
+ hide/restore controls appeared.
6
+
7
+ moderate: true adds those controls, and shows a Hidden badge. They are only
8
+ meaningful for an admin, so the caller decides — the partial does not check
9
+ permissions itself.
10
+
11
+ No ERB tags in this comment: the first close-tag would end it and the rest
12
+ would become live template code.
13
+ %>
14
+ <h2 class="b270-subhead"><%= title %></h2>
15
+
16
+ <% if comments.any? %>
17
+ <% comments.each do |comment| %>
18
+ <div class="b270-comment">
19
+ <div style="flex:1">
20
+ <div class="b270-cmeta">
21
+ <%= link_to "Day #{comment.day}", day_path(comment.day) %>
22
+ · <%= comment.created_at.strftime("%b %-d, %Y") %>
23
+ <% if moderate && comment.hidden? %><span class="b270-badge">Hidden</span><% end %>
24
+ </div>
25
+
26
+ <p class="b270-cbody"><%= comment.body %></p>
27
+
28
+ <% if moderate %>
29
+ <div style="display:flex;gap:10px;margin-top:6px">
30
+ <% if comment.hidden? %>
31
+ <%= button_to "Restore", admin_unhide_comment_path(comment), method: :patch,
32
+ params: { return_to: request.fullpath }, class: "b270-linkbtn" %>
33
+ <% else %>
34
+ <%= button_to "Hide", admin_hide_comment_path(comment), method: :patch,
35
+ params: { return_to: request.fullpath }, class: "b270-linkbtn" %>
36
+ <% end %>
37
+ </div>
38
+ <% end %>
39
+ </div>
40
+ </div>
41
+ <% end %>
42
+ <% else %>
43
+ <p class="b270-hint" style="margin-top:0"><%= empty_text %></p>
44
+ <% end %>
@@ -14,7 +14,12 @@
14
14
  .b270-wrap{max-width:820px;margin:0 auto;padding:clamp(14px,3.5vw,36px) clamp(14px,4vw,40px) 64px}
15
15
 
16
16
  .b270-topbar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-bottom:20px;border-bottom:1px solid var(--line-soft);margin-bottom:26px}
17
- .b270-brand{display:flex;flex-direction:column;margin-right:auto}
17
+ .b270-brand{display:flex;margin-right:auto}
18
+ /* The whole brand is one link, so the mark and the words highlight together. */
19
+ .b270-brandlink{display:flex;align-items:center;gap:12px;text-decoration:none}
20
+ .b270-brandtext{display:flex;flex-direction:column}
21
+ .b270-mark{display:flex;align-items:center;flex:none;line-height:0}
22
+ .b270-mark svg,.b270-mark img{display:block;border-radius:8px}
18
23
  .b270-title{font-family:"Spectral",Georgia,serif;font-weight:600;font-size:22px;text-decoration:none}
19
24
  .b270-tagline{font-size:12px;color:var(--faint);letter-spacing:.04em}
20
25
  .b270-nav{display:flex;align-items:center;gap:16px;font-size:14px}
@@ -0,0 +1,21 @@
1
+ <%# locals: (reader:) %>
2
+ <%#
3
+ The three progress bars. This markup was duplicated in days/index and
4
+ readers/show, differing only in which reader it described.
5
+
6
+ The New Testament total is nt_content_days rather than DAYS, because a plan
7
+ with rest days has fewer NT readings than days.
8
+ %>
9
+ <div class="b270-tracks">
10
+ <% [["ot", Bible270::Plan::DAYS],
11
+ ["nt", Bible270::Plan.nt_content_days],
12
+ ["pp", Bible270::Plan::DAYS]].each do |track, total| %>
13
+ <% t = b270_track(track) %>
14
+ <% read = reader.days_read_in(track) %>
15
+ <div class="b270-tm">
16
+ <span class="lab"><span class="b270-rib" style="background:<%= t[:color] %>"></span><%= t[:label] %></span>
17
+ <span class="b270-bar"><i style="width:<%= total.zero? ? 0 : (read.to_f / total * 100).round %>%;background:<%= t[:color] %>"></i></span>
18
+ <span class="val"><%= read %>/<%= total %></span>
19
+ </div>
20
+ <% end %>
21
+ </div>
data/config/routes.rb CHANGED
@@ -34,6 +34,8 @@ Bible270::Engine.routes.draw do
34
34
  patch 'profile', to: 'profiles#update'
35
35
  delete 'profile/avatar', to: 'profiles#remove_avatar', as: :profile_avatar
36
36
 
37
+ get 'progress', to: 'readers#progress', as: :progress
38
+
37
39
  get 'community', to: 'readers#index', as: :community
38
40
  get 'readers/:id', to: 'readers#show', as: :reader
39
41
 
@@ -292,7 +292,7 @@ module Bible270
292
292
  # from, so without this the notice names the reader but cannot link to them.
293
293
  attr_accessor :mailer_host
294
294
 
295
- attr_accessor :after_sign_out_path, :email_sign_in_max_per_window, :passage_url_builder, :tagline, :footer_html, :footer, :favicon, :avatar_max_bytes, :chapter_breaks, :admin_emails, :admin_resolver, :bible_version, :require_sign_in_to_participate
295
+ attr_accessor :after_sign_out_path, :email_sign_in_max_per_window, :passage_url_builder, :tagline, :footer_html, :footer, :favicon, :avatar_max_bytes, :chapter_breaks, :admin_emails, :admin_resolver, :bible_version, :remember_for, :require_sign_in_to_participate
296
296
 
297
297
  # Public labels.
298
298
  attr_accessor :app_name
@@ -318,7 +318,10 @@ module Bible270
318
318
  #
319
319
  # Expressed in seconds rather than 1.year because this file has to load
320
320
  # without ActiveSupport.
321
- attr_accessor :remember_for
321
+ # The mark beside the title in the header. nil uses the built-in loaf, false
322
+ # shows none, and a string is used as an image source — so a host can put its
323
+ # own logo there without overriding the partial.
324
+ attr_accessor :header_mark
322
325
 
323
326
  def remember_signed_in?
324
327
  remember_for.to_i.positive?
@@ -340,6 +343,7 @@ module Bible270
340
343
  end
341
344
  @app_name = 'Daily Bread'
342
345
  @tagline = 'Journeying through Scripture in 9 months'
346
+ @header_mark = nil
343
347
  @remember_for = 365 * 24 * 60 * 60
344
348
  @require_sign_in_to_participate = true
345
349
  self.mount_at = '/daily-bread'
@@ -32,5 +32,16 @@ module Bible270
32
32
  compact = SVG.gsub(%r{\s+}, ' ').strip
33
33
  "data:image/svg+xml,#{compact.gsub(' ', '%20')}"
34
34
  end
35
+
36
+ # The same mark for inline use in a page, at whatever size. The percent
37
+ # encoding above is only correct inside a data URI: inlined into HTML,
38
+ # '%23231f18' is not a colour, so it is decoded here.
39
+ def inline_svg(size: nil)
40
+ markup = SVG.gsub('%23', '#').strip
41
+ return markup if size.nil?
42
+
43
+ pixels = size.to_i
44
+ markup.sub('<svg ', "<svg width='#{pixels}' height='#{pixels}' ")
45
+ end
35
46
  end
36
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bible270
4
- VERSION = '0.15.0'
4
+ VERSION = '0.15.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bible270
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew vonderLuft
@@ -114,12 +114,16 @@ files:
114
114
  - app/views/bible270/notice_mailer/new_reader.text.erb
115
115
  - app/views/bible270/profiles/edit.html.erb
116
116
  - app/views/bible270/readers/index.html.erb
117
+ - app/views/bible270/readers/progress.html.erb
117
118
  - app/views/bible270/readers/show.html.erb
118
119
  - app/views/bible270/sessions/new.html.erb
119
120
  - app/views/bible270/shared/_day_index.html.erb
120
121
  - app/views/bible270/shared/_footer.html.erb
121
122
  - app/views/bible270/shared/_header.html.erb
123
+ - app/views/bible270/shared/_progress.html.erb
124
+ - app/views/bible270/shared/_reflections.html.erb
122
125
  - app/views/bible270/shared/_styles.html.erb
126
+ - app/views/bible270/shared/_track_bars.html.erb
123
127
  - app/views/bible270/sign_in_mailer/magic_link.html.erb
124
128
  - app/views/bible270/sign_in_mailer/magic_link.text.erb
125
129
  - app/views/layouts/bible270/application.html.erb