bible270 1.0.0 → 1.1.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/CHANGELOG.md +57 -9
- data/README.md +7 -10
- data/app/controllers/bible270/admin_controller.rb +2 -3
- data/app/controllers/bible270/days_controller.rb +1 -36
- data/app/controllers/bible270/profiles_controller.rb +20 -1
- data/app/controllers/bible270/readers_controller.rb +1 -66
- data/app/mailers/bible270/notice_mailer.rb +32 -8
- data/app/models/bible270/comment.rb +33 -9
- data/app/models/bible270/reader.rb +8 -40
- data/app/views/bible270/comments/create.turbo_stream.erb +0 -2
- data/app/views/bible270/comments/index.html.erb +0 -24
- data/app/views/bible270/days/_completers.html.erb +0 -2
- data/app/views/bible270/days/_day_progress.html.erb +3 -3
- data/app/views/bible270/days/index.html.erb +1 -27
- data/app/views/bible270/days/show.html.erb +4 -16
- data/app/views/bible270/notice_mailer/{mentioned.html.erb → comment_notice.html.erb} +5 -2
- data/app/views/bible270/notice_mailer/{mentioned.text.erb → comment_notice.text.erb} +5 -2
- data/app/views/bible270/profiles/edit.html.erb +11 -0
- data/app/views/bible270/readers/_next_steps.html.erb +24 -60
- data/app/views/bible270/readers/index.html.erb +2 -3
- data/app/views/bible270/readers/progress.html.erb +6 -30
- data/app/views/bible270/readers/show.html.erb +1 -6
- data/app/views/bible270/shared/_day_index.html.erb +6 -4
- data/app/views/bible270/shared/_header.html.erb +21 -4
- data/app/views/bible270/shared/_progress.html.erb +3 -14
- data/app/views/bible270/shared/_styles.html.erb +3 -32
- data/config/routes.rb +0 -4
- data/db/migrate/20260101000011_add_mention_notices_to_bible270_readers.rb +3 -3
- data/lib/bible270/configuration.rb +8 -5
- data/lib/bible270/mentions.rb +0 -9
- data/lib/bible270/version.rb +1 -1
- data/lib/generators/bible270/install/install_generator.rb +2 -0
- data/lib/generators/bible270/install/templates/bible270.rb.tt +2 -0
- metadata +3 -5
- data/app/views/bible270/days/_start_date.html.erb +0 -43
- data/app/views/bible270/shared/_reading_mode.html.erb +0 -62
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"aria-label": "Previous day unavailable" %>
|
|
15
15
|
<% end %>
|
|
16
16
|
<div class="b270-dayhead">
|
|
17
|
-
<div class="k">Day <%= day %><% if complete %><span class="b270-badge"
|
|
17
|
+
<div class="k">Day <%= day %><% if complete %><span class="b270-badge">Complete</span><% end %></div>
|
|
18
18
|
<% if reader&.dated? %>
|
|
19
19
|
<div class="date">
|
|
20
20
|
<%= reader.date_for_day(day).strftime("%A, %B %-d, %Y") %>
|
|
21
|
-
<% if reader.today?(day) %><span class="b270-badge"
|
|
21
|
+
<% if reader.today?(day) %><span class="b270-badge">Today</span><% end %>
|
|
22
22
|
</div>
|
|
23
23
|
<% end %>
|
|
24
24
|
</div>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
<% if complete %>
|
|
35
35
|
<div class="b270-day-complete" role="status" aria-live="polite">
|
|
36
|
-
<div
|
|
36
|
+
<div>
|
|
37
37
|
<strong>Day <%= day %> complete</strong>
|
|
38
38
|
<span>All <%= total_parts %> portions are checked off.</span>
|
|
39
39
|
</div>
|
|
@@ -5,30 +5,4 @@
|
|
|
5
5
|
|
|
6
6
|
<%= render "bible270/shared/progress" %>
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
<h2 class="b270-section-h">Reading together</h2>
|
|
10
|
-
<p class="b270-community-intro">
|
|
11
|
-
Showing <%= [@readers.size, 5].min %> of <%= pluralize(@readers.size, "reader") %>, ordered by recent
|
|
12
|
-
checkoffs and reflections; new readers by join date.
|
|
13
|
-
</p>
|
|
14
|
-
<div class="b270-list">
|
|
15
|
-
<% @readers.first(5).each do |r| %>
|
|
16
|
-
<div class="b270-li">
|
|
17
|
-
<%= b270_avatar(r) %>
|
|
18
|
-
<div>
|
|
19
|
-
<div class="name"><%= link_to r.display_name, reader_path(r), style: "text-decoration:none" %></div>
|
|
20
|
-
<% day_word = @days_completed[r.id] == 1 ? "day" : "days" %>
|
|
21
|
-
<% activity = @reader_activity.fetch(r.id) %>
|
|
22
|
-
<% activity_verb = { reading: "read", reflection: "reflected", joined: "joined" }.fetch(activity[:kind]) %>
|
|
23
|
-
<div class="sub">
|
|
24
|
-
<%= @days_completed[r.id] %> <%= day_word %> read ·
|
|
25
|
-
<span class="b270-reader-activity"><%= activity_verb %>
|
|
26
|
-
<time datetime="<%= activity[:at].iso8601 %>" title="<%= b270_datetime(activity[:at]) %>"><%= time_ago_in_words(activity[:at]) %> ago</time>
|
|
27
|
-
</span>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
<% end %>
|
|
32
|
-
</div>
|
|
33
|
-
<p style="margin:12px 0 0"><%= link_to "Meet the community →", community_path %></p>
|
|
34
|
-
<% end %>
|
|
8
|
+
<p style="margin:12px 0 0"><%= link_to "Meet your fellow readers →", community_path %></p>
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<% content_for :title, "Day #{@day} — #{Bible270.config.app_name}" %>
|
|
2
2
|
|
|
3
|
-
<div class="b270-day-page"
|
|
3
|
+
<div class="b270-day-page">
|
|
4
4
|
<%= render "bible270/days/day_progress", day: @day, reader: current_reader %>
|
|
5
5
|
|
|
6
|
-
<div class="b270-reading-options" data-b270-reading-options hidden>
|
|
7
|
-
<button type="button" class="b270-linkbtn b270-reading-mode-toggle"
|
|
8
|
-
data-b270-compact-toggle aria-pressed="false">Compact reading</button>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
6
|
<%= render "bible270/shared/interaction_status" %>
|
|
12
7
|
|
|
13
8
|
<div id="readings" class="b270-readings">
|
|
@@ -16,19 +11,15 @@
|
|
|
16
11
|
</div>
|
|
17
12
|
|
|
18
13
|
<% unless signed_in? %>
|
|
19
|
-
<p class="b270-signin-hint" style="margin-top:12px"><%= link_to "Sign in", sign_in_path(origin: request.fullpath) %> to
|
|
14
|
+
<p class="b270-signin-hint" style="margin-top:12px"><%= link_to "Sign in", sign_in_path(origin: request.fullpath) %> to track your reading and join the conversation.</p>
|
|
20
15
|
<% end %>
|
|
21
16
|
|
|
22
|
-
<div class="b270-day-community"
|
|
17
|
+
<div class="b270-day-community">
|
|
23
18
|
<%= render "bible270/days/completers", day: @day, completers: @completers %>
|
|
24
19
|
|
|
25
20
|
<h2 class="b270-section-h">Reflections</h2>
|
|
26
21
|
<div id="comments">
|
|
27
|
-
|
|
28
|
-
<%= render partial: "bible270/comments/comment", collection: @comments, as: :comment %>
|
|
29
|
-
<% else %>
|
|
30
|
-
<p style="color:var(--faint)" id="no_comments">No reflections yet. Share the first.</p>
|
|
31
|
-
<% end %>
|
|
22
|
+
<%= render partial: "bible270/comments/comment", collection: @comments, as: :comment %>
|
|
32
23
|
</div>
|
|
33
24
|
|
|
34
25
|
<% if signed_in? %>
|
|
@@ -36,11 +27,8 @@
|
|
|
36
27
|
<%= render "bible270/comments/form", day: @day, comment: @new_comment %>
|
|
37
28
|
</div>
|
|
38
29
|
<%= render "bible270/shared/comment_drafts" %>
|
|
39
|
-
<% else %>
|
|
40
|
-
<p class="b270-signin-hint" style="margin-top:14px"><%= link_to "Sign in", sign_in_path(origin: request.fullpath) %> to leave a reflection.</p>
|
|
41
30
|
<% end %>
|
|
42
31
|
</div>
|
|
43
32
|
</div>
|
|
44
33
|
|
|
45
|
-
<%= render "bible270/shared/reading_mode" %>
|
|
46
34
|
<%= render "bible270/shared/interaction_ui" %>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<body style="margin:0;padding:24px;background:#ece6da;font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#231f18">
|
|
4
4
|
<div style="max-width:520px;margin:0 auto;background:#f4efe6;border:1px solid #d7cfbf;border-radius:14px;padding:28px">
|
|
5
5
|
<h1 style="margin:0 0 6px;font-family:Georgia,serif;font-size:20px;font-weight:600">
|
|
6
|
-
<%= @
|
|
6
|
+
<%= @heading %>
|
|
7
7
|
</h1>
|
|
8
8
|
<p style="margin:0 0 18px;font-size:14px;color:#6d6558">
|
|
9
9
|
Day <%= @comment.day %> · <%= @app_name %>
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
<% end %>
|
|
21
21
|
|
|
22
22
|
<p style="margin:22px 0 0;font-size:12px;color:#9a9082">
|
|
23
|
-
|
|
23
|
+
<%= @reason %>
|
|
24
|
+
<% if @profile_url %>
|
|
25
|
+
<a href="<%= @profile_url %>" style="color:#6d6558">Manage email preferences</a>.
|
|
26
|
+
<% end %>
|
|
24
27
|
</p>
|
|
25
28
|
</div>
|
|
26
29
|
</body>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= @
|
|
1
|
+
<%= @introduction %>
|
|
2
2
|
|
|
3
3
|
<%= @comment.body %>
|
|
4
4
|
|
|
@@ -8,4 +8,7 @@ Read it and reply: <%= @day_url %>
|
|
|
8
8
|
You can find it on day <%= @comment.day %> of <%= @app_name %>.
|
|
9
9
|
<% end %>
|
|
10
10
|
--
|
|
11
|
-
|
|
11
|
+
<%= @reason %>
|
|
12
|
+
<% if @profile_url %>
|
|
13
|
+
Manage email preferences: <%= @profile_url %>
|
|
14
|
+
<% end %>
|
|
@@ -37,6 +37,17 @@
|
|
|
37
37
|
</label>
|
|
38
38
|
<%= render "bible270/shared/passage_source", reader: current_reader %>
|
|
39
39
|
|
|
40
|
+
<% if @comment_notifications_available %>
|
|
41
|
+
<div class="b270-field">
|
|
42
|
+
<span>Email notifications</span>
|
|
43
|
+
<label class="b270-reminder-optin">
|
|
44
|
+
<%= hidden_field_tag :notify_on_mention, "0", id: nil %>
|
|
45
|
+
<%= check_box_tag :notify_on_mention, "1", @notify_on_mention %>
|
|
46
|
+
<span>Email me about replies and mentions</span>
|
|
47
|
+
</label>
|
|
48
|
+
</div>
|
|
49
|
+
<% end %>
|
|
50
|
+
|
|
40
51
|
<% if @daily_reminders_available %>
|
|
41
52
|
<% reminder_hour, reminder_minute = @daily_reminder_time.to_s.split(":", 2) %>
|
|
42
53
|
<div class="b270-field">
|
|
@@ -1,63 +1,27 @@
|
|
|
1
|
-
<%# locals: (
|
|
1
|
+
<%# locals: (partial_day_tasks:, remaining_partial_days:) %>
|
|
2
2
|
<div class="b270-panel b270-next-steps">
|
|
3
|
-
<h2 class="b270-subhead">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</div>
|
|
22
|
-
<%= link_to "Continue →", day_path(day, anchor: "reading_#{day}_#{first_track}"),
|
|
23
|
-
class: "b270-task-link" %>
|
|
24
|
-
</li>
|
|
25
|
-
<% end %>
|
|
26
|
-
</ul>
|
|
27
|
-
<% if remaining_partial_days.positive? %>
|
|
28
|
-
<p class="b270-next-note"><%= remaining_partial_days %> more partially read
|
|
29
|
-
<%= "day".pluralize(remaining_partial_days) %> are highlighted in the grid below.</p>
|
|
30
|
-
<% end %>
|
|
31
|
-
<% else %>
|
|
32
|
-
<p class="b270-next-note">No partially read days. Your next reading is ready above.</p>
|
|
3
|
+
<h2 class="b270-subhead">Finish what you started</h2>
|
|
4
|
+
<ul class="b270-task-list">
|
|
5
|
+
<% partial_day_tasks.each do |task| %>
|
|
6
|
+
<% day = task[:day] %>
|
|
7
|
+
<% first_track = task[:remaining].first&.fetch(:track) %>
|
|
8
|
+
<li class="b270-task">
|
|
9
|
+
<div class="b270-task-body">
|
|
10
|
+
<strong><%= link_to "Day #{day}", day_path(day, anchor: "reading_#{day}_#{first_track}") %></strong>
|
|
11
|
+
<span>
|
|
12
|
+
Still to read:
|
|
13
|
+
<%= safe_join(task[:remaining].map { |part|
|
|
14
|
+
link_to(part[:reference], day_path(day, anchor: "reading_#{day}_#{part[:track]}"))
|
|
15
|
+
}, " · ") %>
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
18
|
+
<%= link_to "Continue →", day_path(day, anchor: "reading_#{day}_#{first_track}"),
|
|
19
|
+
class: "b270-task-link" %>
|
|
20
|
+
</li>
|
|
33
21
|
<% end %>
|
|
34
|
-
</
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<p class="b270-week-count"><strong><%= week_completed %> of <%= week_days.size %></strong>
|
|
40
|
-
scheduled <%= "day".pluralize(week_days.size) %> complete so far this week</p>
|
|
41
|
-
<progress class="b270-week-progress" value="<%= week_completed %>" max="<%= week_days.size %>"
|
|
42
|
-
aria-label="<%= week_completed %> of <%= week_days.size %> scheduled days complete this week"></progress>
|
|
43
|
-
<% elsif reader.dated? %>
|
|
44
|
-
<p class="b270-next-note">No plan days are scheduled so far this week.</p>
|
|
45
|
-
<% elsif Bible270.config.allow_reader_start_date %>
|
|
46
|
-
<p class="b270-next-note">Set a start date to see your weekly progress.</p>
|
|
47
|
-
<% else %>
|
|
48
|
-
<p class="b270-next-note">This plan is not tied to calendar dates.</p>
|
|
49
|
-
<% end %>
|
|
50
|
-
</section>
|
|
51
|
-
|
|
52
|
-
<section class="b270-next-section" aria-labelledby="milestone-heading">
|
|
53
|
-
<h3 id="milestone-heading">Next milestone</h3>
|
|
54
|
-
<% if next_milestone %>
|
|
55
|
-
<% milestone_day, milestone_label = next_milestone %>
|
|
56
|
-
<p class="b270-milestone"><strong><%= milestone_day %> days</strong> · <%= milestone_label %></p>
|
|
57
|
-
<p class="b270-next-note"><%= days_to_milestone %>
|
|
58
|
-
<%= "day".pluralize(days_to_milestone) %> to go.</p>
|
|
59
|
-
<% else %>
|
|
60
|
-
<p class="b270-milestone"><strong>All <%= Bible270::Plan::DAYS %> days complete.</strong></p>
|
|
61
|
-
<% end %>
|
|
62
|
-
</section>
|
|
22
|
+
</ul>
|
|
23
|
+
<% if remaining_partial_days.positive? %>
|
|
24
|
+
<p class="b270-next-note">View <%= remaining_partial_days %> more partially read
|
|
25
|
+
<%= "day".pluralize(remaining_partial_days) %> under “View all 270 days”.</p>
|
|
26
|
+
<% end %>
|
|
63
27
|
</div>
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
<div class="b270-list">
|
|
8
8
|
<% @readers.each do |r| %>
|
|
9
9
|
<div class="b270-li">
|
|
10
|
-
<%= b270_avatar(r, size: 72) %>
|
|
10
|
+
<%= link_to b270_avatar(r, size: 72), reader_path(r), "aria-label": r.display_name %>
|
|
11
11
|
<div>
|
|
12
12
|
<div class="name"><%= link_to r.display_name, reader_path(r), style: "text-decoration:none" %></div>
|
|
13
|
-
|
|
14
|
-
<div class="sub"><%= @days_completed[r.id] %> <%= day_word %> read · joined <%= Bible270.local_time(r.created_at).strftime("%b %Y") %></div>
|
|
13
|
+
<div class="sub">joined <%= Bible270.local_time(r.created_at).strftime("%b %-d %Y") %></div>
|
|
15
14
|
</div>
|
|
16
15
|
</div>
|
|
17
16
|
<% end %>
|
|
@@ -1,43 +1,19 @@
|
|
|
1
1
|
<% content_for :title, "My Progress — #{Bible270.config.app_name}" %>
|
|
2
|
-
<% content_for :hide_day_index, true %><%# the panel is followed by its own grid below %>
|
|
3
2
|
|
|
4
3
|
<p class="b270-eyebrow">My Progress</p>
|
|
5
4
|
<h1>Your reading journey</h1>
|
|
6
5
|
|
|
7
6
|
<%= render "bible270/shared/progress" %>
|
|
8
7
|
|
|
9
|
-
<% if @reader %>
|
|
10
|
-
<%= render "bible270/readers/next_steps",
|
|
11
|
-
|
|
12
|
-
remaining_partial_days: @remaining_partial_days,
|
|
13
|
-
week_days: @week_days,
|
|
14
|
-
week_completed: @week_completed,
|
|
15
|
-
next_milestone: @next_milestone,
|
|
16
|
-
days_to_milestone: @days_to_milestone %>
|
|
8
|
+
<% if @reader && @partial_day_tasks.any? %>
|
|
9
|
+
<%= render "bible270/readers/next_steps", partial_day_tasks: @partial_day_tasks,
|
|
10
|
+
remaining_partial_days: @remaining_partial_days %>
|
|
17
11
|
<% end %>
|
|
18
12
|
|
|
19
|
-
<div class="b270-panel">
|
|
20
|
-
<%= render "bible270/shared/reflections", comments: @recent_comments,
|
|
21
|
-
title: "Your recent reflections",
|
|
22
|
-
empty_text: "You have not written any reflections yet." %>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
13
|
<% if @reader %>
|
|
26
14
|
<div class="b270-panel">
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<% (1..Bible270::Plan::DAYS).each do |d| %>
|
|
31
|
-
<%= b270_day_cell(d, reader: @reader, today: today) %>
|
|
32
|
-
<% end %>
|
|
33
|
-
</div>
|
|
34
|
-
<p class="b270-gridnote">Dot indicates days with reflections.</p>
|
|
35
|
-
<p class="b270-hint">Filled squares are days you have finished; a lighter square means you have
|
|
36
|
-
read some of that day but not all of it.</p>
|
|
15
|
+
<%= render "bible270/shared/reflections", comments: @recent_comments,
|
|
16
|
+
title: "Your recent reflections",
|
|
17
|
+
empty_text: "You have not written any reflections yet." %>
|
|
37
18
|
</div>
|
|
38
|
-
|
|
39
|
-
<p style="margin-top:18px">
|
|
40
|
-
<%= link_to "How others are doing →", community_path %>
|
|
41
|
-
· <%= link_to "Your profile", profile_path %>
|
|
42
|
-
</p>
|
|
43
19
|
<% end %>
|
|
@@ -20,9 +20,4 @@
|
|
|
20
20
|
title: "Their reflections", empty_text: "No reflections yet." %>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
<% (1..Bible270::Plan::DAYS).each do |d| %>
|
|
25
|
-
<%= b270_day_cell(d, reader: @reader) %>
|
|
26
|
-
<% end %>
|
|
27
|
-
</div>
|
|
28
|
-
<p class="b270-gridnote">Dot indicates days with reflections.</p>
|
|
23
|
+
<%= render "bible270/shared/day_index", reader: @reader %>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
<%# locals: (reader: nil) %>
|
|
1
2
|
<% if Bible270::Plan::DAYS.positive? %>
|
|
3
|
+
<% grid_reader = reader || current_reader %>
|
|
4
|
+
<% today = signed_in? && grid_reader == current_reader ? current_reader.today_day : nil %>
|
|
2
5
|
<details class="b270-index">
|
|
3
|
-
<summary>
|
|
6
|
+
<summary>View all <%= Bible270::Plan::DAYS %> days</summary>
|
|
4
7
|
<div class="b270-grid">
|
|
5
|
-
<% today = signed_in? ? current_reader.today_day : nil %>
|
|
6
8
|
<% (1..Bible270::Plan::DAYS).each do |d| %>
|
|
7
|
-
<%= b270_day_cell(d, reader:
|
|
9
|
+
<%= b270_day_cell(d, reader: grid_reader, today: today) %>
|
|
8
10
|
<% end %>
|
|
9
11
|
</div>
|
|
10
|
-
<p class="b270-gridnote">Dot indicates days with reflections.</p>
|
|
12
|
+
<p class="b270-gridnote">Dot indicates days with reflections.</p>
|
|
11
13
|
</details>
|
|
12
14
|
<% end %>
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
<div class="b270-brand">
|
|
3
3
|
<%= link_to root_path, class: "b270-brandlink" do %>
|
|
4
4
|
<%= b270_mark %>
|
|
5
|
-
<span class="b270-
|
|
6
|
-
<span class="b270-title"><%= Bible270.config.app_name %></span>
|
|
7
|
-
<span class="b270-tagline"><%= Bible270.config.tagline %></span>
|
|
8
|
-
</span>
|
|
5
|
+
<span class="b270-title"><%= Bible270.config.app_name %></span>
|
|
9
6
|
<% end %>
|
|
10
7
|
</div>
|
|
11
8
|
<nav class="b270-nav" aria-label="Primary navigation">
|
|
@@ -24,3 +21,23 @@
|
|
|
24
21
|
</details>
|
|
25
22
|
</nav>
|
|
26
23
|
</header>
|
|
24
|
+
|
|
25
|
+
<script nonce="<%= content_security_policy_nonce %>">
|
|
26
|
+
(() => {
|
|
27
|
+
if (window.Bible270NavigationMenu) return;
|
|
28
|
+
|
|
29
|
+
document.addEventListener("click", (event) => {
|
|
30
|
+
const target = event.target;
|
|
31
|
+
const toggle = target.closest && target.closest("summary.b270-navtoggle");
|
|
32
|
+
if (!toggle) return;
|
|
33
|
+
|
|
34
|
+
const menu = toggle.closest("details.b270-navmenu");
|
|
35
|
+
if (!menu) return;
|
|
36
|
+
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
menu.open = !menu.open;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
window.Bible270NavigationMenu = true;
|
|
42
|
+
})();
|
|
43
|
+
</script>
|
|
@@ -36,19 +36,9 @@
|
|
|
36
36
|
<%= render "bible270/shared/track_bars", reader: panel_reader %>
|
|
37
37
|
|
|
38
38
|
<% if panel_behind %>
|
|
39
|
-
<div class="b270-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<div class="b270-progress-actions b270-recovery-actions">
|
|
43
|
-
<%= link_to "Catch up from Day #{panel_start_day} →", day_path(panel_start_day), class: "b270-btn" %>
|
|
44
|
-
<%= link_to "Read with the community — Day #{panel_today_day}", day_path(panel_today_day), class: "b270-todaylink" %>
|
|
45
|
-
<% if Bible270.config.allow_reader_start_date %>
|
|
46
|
-
<%= button_to "Make Day #{panel_start_day} my new today", restart_schedule_path,
|
|
47
|
-
method: :patch, class: "b270-linkbtn",
|
|
48
|
-
form: { class: "b270-restart-form",
|
|
49
|
-
data: { turbo_confirm: "Make Day #{panel_start_day} today? Your existing check-offs and reflections will not change." } } %>
|
|
50
|
-
<% end %>
|
|
51
|
-
</div>
|
|
39
|
+
<div class="b270-progress-actions">
|
|
40
|
+
<%= link_to "Catch up from Day #{panel_start_day} →", day_path(panel_start_day), class: "b270-btn" %>
|
|
41
|
+
<%= link_to "Read with the community — Day #{panel_today_day}", day_path(panel_today_day), class: "b270-todaylink" %>
|
|
52
42
|
</div>
|
|
53
43
|
<% else %>
|
|
54
44
|
<div class="b270-progress-actions">
|
|
@@ -59,7 +49,6 @@
|
|
|
59
49
|
</div>
|
|
60
50
|
<% end %>
|
|
61
51
|
|
|
62
|
-
<%= render "bible270/days/start_date", reader: panel_reader %>
|
|
63
52
|
<% else %>
|
|
64
53
|
<p class="b270-signedout"><%= link_to "Sign in", sign_in_path %> to track your progress and join
|
|
65
54
|
the conversation. You can browse the whole plan and read others' reflections without an account.</p>
|
|
@@ -18,11 +18,9 @@
|
|
|
18
18
|
.b270-brand{display:flex;margin-right:auto}
|
|
19
19
|
/* The whole brand is one link, so the mark and the words highlight together. */
|
|
20
20
|
.b270-brandlink{display:flex;align-items:center;gap:12px;text-decoration:none}
|
|
21
|
-
.b270-brandtext{display:flex;flex-direction:column}
|
|
22
21
|
.b270-mark{display:flex;align-items:center;flex:none;line-height:0}
|
|
23
22
|
.b270-mark svg,.b270-mark img{display:block;border-radius:8px}
|
|
24
23
|
.b270-title{font-family:"Spectral",Georgia,serif;font-weight:600;font-size:22px;text-decoration:none}
|
|
25
|
-
.b270-tagline{font-size:12px;color:var(--faint);letter-spacing:.04em}
|
|
26
24
|
.b270-nav{display:flex;align-items:center;font-size:14px}
|
|
27
25
|
.b270-desktopnav{display:flex;align-items:center;gap:16px}
|
|
28
26
|
.b270-navmenu{display:none}
|
|
@@ -97,16 +95,8 @@
|
|
|
97
95
|
.b270-progress-actions{display:flex;flex-direction:column;align-items:flex-start;gap:7px;margin:16px 0 0}
|
|
98
96
|
.b270-todaylink{margin-left:16px;font-size:12px;color:var(--muted);text-decoration:none}
|
|
99
97
|
.b270-todaylink:hover{color:var(--gold);text-decoration:underline}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.b270-recovery-copy{margin:4px 0 0;color:var(--muted);font-size:13px;line-height:1.45}
|
|
103
|
-
.b270-recovery-actions{margin-top:12px}
|
|
104
|
-
.b270-recovery-actions .b270-todaylink{margin-left:0}
|
|
105
|
-
.b270-restart-form{margin:0}
|
|
106
|
-
.b270-recovery-actions .b270-linkbtn{margin:2px 0 0;color:var(--muted)}
|
|
107
|
-
.b270-next-steps>.b270-subhead{margin-bottom:2px}
|
|
108
|
-
.b270-next-section{padding-top:15px;margin-top:15px;border-top:1px solid var(--line-soft)}
|
|
109
|
-
.b270-next-section h3{margin:0 0 9px;font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
|
|
98
|
+
|
|
99
|
+
|
|
110
100
|
.b270-task-list{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
|
111
101
|
.b270-task{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:10px 12px;border:1px solid var(--line-soft);border-radius:9px;background:rgba(255,255,255,.35)}
|
|
112
102
|
.b270-task-body{display:grid;gap:3px;min-width:0}
|
|
@@ -118,21 +108,10 @@
|
|
|
118
108
|
.b270-task-link:hover{text-decoration:underline}
|
|
119
109
|
.b270-next-note{margin:0;color:var(--faint);font-size:12.5px;line-height:1.45}
|
|
120
110
|
.b270-task-list+.b270-next-note{margin-top:8px}
|
|
121
|
-
.b270-week-count{margin:0 0 7px;color:var(--muted);font-size:13px}
|
|
122
|
-
.b270-week-count strong{color:var(--ink)}
|
|
123
|
-
.b270-week-progress{display:block;width:100%;height:8px;accent-color:var(--teal)}
|
|
124
|
-
.b270-milestone{margin:0 0 3px;color:var(--muted);font-size:13px}
|
|
125
|
-
.b270-milestone strong{color:var(--ink);font-family:"Spectral",serif;font-size:17px}
|
|
126
111
|
.b270-signedout{color:var(--muted);font-size:14px;margin:4px 0 0}
|
|
127
112
|
|
|
128
|
-
.b270-startdate{margin-top:18px;padding-top:16px;border-top:1px solid var(--line-soft)}
|
|
129
113
|
.b270-startline{margin:0;font-size:13.5px;color:var(--muted)}
|
|
130
114
|
.b270-startline strong{color:var(--ink)}
|
|
131
|
-
.b270-startline em{font-style:normal;color:var(--gold);font-weight:600}
|
|
132
|
-
.b270-startedit{margin-top:10px}
|
|
133
|
-
.b270-startedit summary{cursor:pointer;font-size:13px;color:var(--muted);list-style:none}
|
|
134
|
-
.b270-startedit summary::-webkit-details-marker{display:none}
|
|
135
|
-
.b270-startedit summary:hover{color:var(--gold)}
|
|
136
115
|
.b270-startform{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
|
|
137
116
|
.b270-startform input[type=date]{font:inherit;font-size:14px;padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--ink)}
|
|
138
117
|
.b270-linkbtn{background:none;border:none;padding:0;margin-top:8px;font:inherit;font-size:12.5px;color:var(--oxblood);cursor:pointer;text-decoration:underline}
|
|
@@ -146,12 +125,7 @@
|
|
|
146
125
|
.b270-tm .val{color:var(--faint);font-variant-numeric:tabular-nums;min-width:56px;text-align:right}
|
|
147
126
|
|
|
148
127
|
/* day nav */
|
|
149
|
-
|
|
150
|
-
.b270-reading-options{display:flex;justify-content:flex-end;margin:-4px 0 10px}
|
|
151
|
-
.b270-reading-options .b270-linkbtn{margin:0;color:var(--muted)}
|
|
152
|
-
.b270-reading-mode-toggle[aria-pressed="true"]{color:var(--gold);font-weight:600}
|
|
153
|
-
.b270-day-page[data-b270-reading-mode="compact"] [data-b270-compact-hide]{display:none!important}
|
|
154
|
-
.b270-day-page[data-b270-reading-mode="compact"] .b270-day-complete{justify-content:flex-end;padding:0;border:0;background:transparent;box-shadow:none}
|
|
128
|
+
|
|
155
129
|
.b270-daynav{display:flex;align-items:center;gap:10px;margin-bottom:12px}
|
|
156
130
|
.b270 .b270-arrow{width:38px;height:38px;padding:0;border-radius:10px;border:1px solid var(--line);background:var(--card);cursor:pointer;font:inherit;font-size:17px;line-height:1;color:var(--muted);display:grid;place-items:center;text-decoration:none}
|
|
157
131
|
.b270-arrow:hover{border-color:var(--gold);color:var(--gold)}
|
|
@@ -287,7 +261,6 @@
|
|
|
287
261
|
.b270-li .sub{font-size:12.5px;color:var(--faint)}
|
|
288
262
|
.b270-li .stat{margin-left:auto;text-align:right}
|
|
289
263
|
.b270-li .stat .big{font-family:"Spectral",serif;font-size:20px;font-weight:600}
|
|
290
|
-
.b270-community-intro{margin:-8px 0 12px;color:var(--muted);font-size:13px}
|
|
291
264
|
|
|
292
265
|
/* calendar grid */
|
|
293
266
|
.b270-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(30px,1fr));gap:6px;margin-top:16px}
|
|
@@ -339,8 +312,6 @@
|
|
|
339
312
|
@media (max-width:620px){
|
|
340
313
|
.b270-topbar{flex-wrap:nowrap;align-items:center}
|
|
341
314
|
.b270-brand{min-width:0}
|
|
342
|
-
.b270-brandtext{min-width:0}
|
|
343
|
-
.b270-tagline{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
344
315
|
.b270-nav{position:relative;flex:none}
|
|
345
316
|
.b270-desktopnav{display:none}
|
|
346
317
|
.b270-navmenu{display:block}
|
data/config/routes.rb
CHANGED
|
@@ -45,10 +45,6 @@ Bible270::Engine.routes.draw do
|
|
|
45
45
|
get 'community', to: 'readers#index', as: :community
|
|
46
46
|
get 'readers/:id', to: 'readers#show', as: :reader
|
|
47
47
|
|
|
48
|
-
patch 'start-date', to: 'readers#update_start_date', as: :start_date
|
|
49
|
-
delete 'start-date', to: 'readers#clear_start_date', as: :clear_start_date
|
|
50
|
-
patch 'schedule/restart', to: 'readers#restart_schedule', as: :restart_schedule
|
|
51
|
-
|
|
52
48
|
# Built-in OmniAuth sign-in. The request phase (POST <mount>/auth/:provider)
|
|
53
49
|
# is handled by the OmniAuth middleware in the host app, not by these routes.
|
|
54
50
|
get 'sign_in', to: 'sessions#new', as: :sign_in
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class AddMentionNoticesToBible270Readers < ActiveRecord::Migration[7.0]
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Default true
|
|
4
|
+
# Replies and explicit mentions share one preference: both are direct responses
|
|
5
|
+
# from another reader, and separate switches would add needless complexity.
|
|
6
|
+
# Default true so existing conversations remain connected.
|
|
7
7
|
def change
|
|
8
8
|
add_column :bible270_readers, :notify_on_mention, :boolean, null: false, default: true
|
|
9
9
|
end
|
|
@@ -297,7 +297,7 @@ module Bible270
|
|
|
297
297
|
# application owns scheduling the bible270:reminders:send task.
|
|
298
298
|
attr_accessor :daily_reminders
|
|
299
299
|
|
|
300
|
-
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, :header_mark, :remember_for, :require_sign_in_to_participate
|
|
300
|
+
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, :header_mark, :remember_for, :require_sign_in_to_participate
|
|
301
301
|
|
|
302
302
|
# Public labels.
|
|
303
303
|
attr_accessor :app_name
|
|
@@ -311,8 +311,9 @@ module Bible270
|
|
|
311
311
|
# (defaulting to the day they first check something off).
|
|
312
312
|
attr_reader :start_date
|
|
313
313
|
|
|
314
|
-
# Whether
|
|
315
|
-
#
|
|
314
|
+
# Whether individual readers may follow personal start dates. When false,
|
|
315
|
+
# everyone is pinned to config.start_date; administrators may still store
|
|
316
|
+
# individual dates for use if personal calendars are enabled later.
|
|
316
317
|
attr_accessor :allow_reader_start_date
|
|
317
318
|
|
|
318
319
|
# Only signed-in readers may check off and comment (viewing is always open).
|
|
@@ -334,8 +335,10 @@ module Bible270
|
|
|
334
335
|
# config.time_zone = 'America/Los_Angeles' # a named zone
|
|
335
336
|
attr_accessor :time_zone
|
|
336
337
|
|
|
337
|
-
# Email
|
|
338
|
-
# out
|
|
338
|
+
# Email readers about direct replies and explicit @mentions. Readers can opt
|
|
339
|
+
# out with one profile preference; this switches the whole feature off.
|
|
340
|
+
attr_accessor :mention_notifications
|
|
341
|
+
|
|
339
342
|
# How many threads each Reflections page shows. A thread resurfaces when someone
|
|
340
343
|
# replies to it, so this is a count of conversations, not of messages.
|
|
341
344
|
attr_accessor :reflections_page_size
|
data/lib/bible270/mentions.rb
CHANGED
|
@@ -49,15 +49,6 @@ module Bible270
|
|
|
49
49
|
handles.uniq
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# The form to write when there is more than one reader with the same first
|
|
53
|
-
# name: the longer handle is unambiguous.
|
|
54
|
-
def preferred_handle(first_name, last_name, ambiguous: false)
|
|
55
|
-
handles = handles_for(first_name, last_name)
|
|
56
|
-
return nil if handles.empty?
|
|
57
|
-
|
|
58
|
-
ambiguous ? handles.last : handles.first
|
|
59
|
-
end
|
|
60
|
-
|
|
61
52
|
# Wraps each mention so a view can style it, leaving the text otherwise
|
|
62
53
|
# untouched. The block receives the handle and returns the replacement.
|
|
63
54
|
def highlight(text)
|
data/lib/bible270/version.rb
CHANGED
|
@@ -510,12 +510,14 @@ module Bible270
|
|
|
510
510
|
# --- Start date -----------------------------------------------------------
|
|
511
511
|
# A community-wide start date, or leave nil for an undated plan.
|
|
512
512
|
# config.start_date = Date.new(#{Date.today.year}, 1, 1)
|
|
513
|
+
# Allow personal calendars, stamped when an undated reader first checks off.
|
|
513
514
|
config.allow_reader_start_date = true
|
|
514
515
|
|
|
515
516
|
# --- Daily reading reminders -----------------------------------------------
|
|
516
517
|
# Readers choose an opt-in time only when enabled. This application owns
|
|
517
518
|
# scheduling: run `bin/rails bible270:reminders:send` every 15 minutes.
|
|
518
519
|
config.daily_reminders = false
|
|
520
|
+
config.mention_notifications = true # direct replies and @mentions; readers may opt out
|
|
519
521
|
# config.mailer_host = 'example.com' # links back to the day and profile
|
|
520
522
|
|
|
521
523
|
# --- Reading links --------------------------------------------------------
|
|
@@ -53,12 +53,14 @@ Bible270.configure do |config|
|
|
|
53
53
|
# --- Start date ------------------------------------------------------------
|
|
54
54
|
# Community-wide start date (Date, Time, or "YYYY-MM-DD"), or nil for undated.
|
|
55
55
|
# config.start_date = Date.new(2026, 9, 6)
|
|
56
|
+
# Allow personal calendars, stamped when an undated reader first checks off.
|
|
56
57
|
config.allow_reader_start_date = true
|
|
57
58
|
|
|
58
59
|
# --- Daily reading reminders -----------------------------------------------
|
|
59
60
|
# Readers choose an opt-in time on their profile only when this is enabled.
|
|
60
61
|
# The host app owns scheduling: run `bin/rails bible270:reminders:send` every 15 minutes.
|
|
61
62
|
config.daily_reminders = false
|
|
63
|
+
config.mention_notifications = true # direct replies and @mentions; readers may opt out
|
|
62
64
|
# config.mailer_host = "example.com" # required for day/profile links in email
|
|
63
65
|
|
|
64
66
|
# --- Reading links ---------------------------------------------------------
|