bible270 0.12.0 → 0.13.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 +21 -5
- data/README.md +38 -2
- data/app/controllers/bible270/admin_controller.rb +21 -5
- data/app/helpers/bible270/plan_helper.rb +40 -0
- data/app/views/bible270/admin/show.html.erb +25 -5
- data/app/views/bible270/days/index.html.erb +5 -3
- data/app/views/bible270/shared/_footer.html.erb +3 -0
- data/app/views/bible270/shared/_styles.html.erb +1 -1
- data/app/views/layouts/bible270/application.html.erb +2 -6
- data/config/routes.rb +2 -1
- data/lib/bible270/bible270.rb +14 -0
- data/lib/bible270/configuration.rb +61 -1
- data/lib/bible270/favicon.rb +36 -0
- data/lib/bible270/version.rb +1 -1
- data/lib/bible270.rb +1 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d1cc4a6173e82beae097bc870026ba3ae1ae0869a32f77efab2ea12fa1dbe2b
|
|
4
|
+
data.tar.gz: be16d337547c10478a9160bc9a7b229d1994f37305c0d68801564549a2c1bb78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 16dafcc090a16f119b5ca9db84c362116c44375ef5e729ca8a915cbe0b6421fb0772847372392624cdaef22d45a39d52e1f33426b1d4ca082dd3d7cc16ad547f
|
|
7
|
+
data.tar.gz: c24039c41a16d88e2cfc6f400f6054ab552c8a2fb3669260e3dee1eaddf2fbcbb0745f8acd4693a7875f6c2c4b8a7b42d87978c5869cde0fb5e40ee16bdeae8f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to bible270. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
4
|
-
this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html), treating pre-1.0 minor bumps as the place breaking changes may land.
|
|
3
|
+
All notable changes to bible270. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html), treating pre-1.0 minor bumps as the place breaking changes may land.
|
|
5
4
|
|
|
6
5
|
## Unreleased Changes
|
|
7
6
|
|
|
8
7
|
See the changes since the last release:
|
|
9
8
|
|
|
10
|
-
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.
|
|
9
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.12.0...main)**
|
|
10
|
+
|
|
11
|
+
## [0.12.0] — 2026-07-29
|
|
12
|
+
|
|
13
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.11.0...v0.12.0)**
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Readers can select their preferred Bible translation in profile edit view
|
|
18
|
+
- Scripture links show bible version in parens
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Top menu shows 'Progress' in place of user display name
|
|
23
|
+
- Dependabot gem updates to minitest and rubocop
|
|
11
24
|
|
|
12
25
|
## [0.11.0] — 2026-07-28
|
|
13
|
-
|
|
26
|
+
|
|
27
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.10.0...v0.11.0)**
|
|
28
|
+
|
|
14
29
|
### Added
|
|
15
30
|
|
|
16
31
|
- **Readers can edit their own name and picture** at `<mount>/profile`, linked from the nav. An admin
|
|
@@ -234,7 +249,8 @@ This is the initial public release.
|
|
|
234
249
|
|
|
235
250
|
* Email sign-in requires working Action Mailer delivery in the host application. Set `config.mailer_from`; delivery is inline by default, or set `email_sign_in_deliver_later` when a queue backend is available.
|
|
236
251
|
|
|
237
|
-
[0.
|
|
252
|
+
[0.12.0]: https://github.com/avonderluft/bible270/releases/tag/v0.12.0
|
|
253
|
+
[0.11.0]: https://github.com/avonderluft/bible270/releases/tag/v0.11.0
|
|
238
254
|
[0.10.0]: https://github.com/avonderluft/bible270/releases/tag/v0.10.0
|
|
239
255
|
[0.9.0]: https://github.com/avonderluft/bible270/releases/tag/v0.9.0
|
|
240
256
|
[0.6.2]: https://github.com/avonderluft/bible270/releases/tag/v0.6.2
|
data/README.md
CHANGED
|
@@ -297,8 +297,8 @@ Bible270.configure do |config|
|
|
|
297
297
|
config.tagline = "A 270-day journey through Scripture"
|
|
298
298
|
config.admin_emails = %w[andrew@example.org]
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
config.start_date = Date.new(2026, 9, 6)
|
|
300
|
+
config.start_date = nil # community start date, or nil for undated
|
|
301
|
+
# config.start_date = Date.new(2026, 9, 6)
|
|
302
302
|
config.allow_reader_start_date = true
|
|
303
303
|
|
|
304
304
|
config.parent_controller = "ActionController::Base" # or "::ApplicationController"
|
|
@@ -322,6 +322,42 @@ Bible270.configure do |config|
|
|
|
322
322
|
}
|
|
323
323
|
end
|
|
324
324
|
```
|
|
325
|
+
### Footer
|
|
326
|
+
|
|
327
|
+
The engine's pages end with a short note about how the plan works. Replace it with your own:
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
config.footer_partial = 'shared/footer' # a partial in your app
|
|
331
|
+
config.footer_html = '<p>© 2026 …</p>'
|
|
332
|
+
config.footer = false # no footer at all
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
By default yours replaces the engine's. To keep both:
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
config.footer_placement = :after # engine's note, then yours
|
|
339
|
+
config.footer_placement = :before # yours, then the engine's note
|
|
340
|
+
config.footer_placement = :replace # default
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
A partial is looked up in your app's view paths as well as the engine's, so `'shared/footer'` finds
|
|
344
|
+
`app/views/shared/_footer.html.erb`. Keep it reasonably self-contained: engine controllers include
|
|
345
|
+
the engine's helpers, not your app's, so a partial calling your own helpers needs
|
|
346
|
+
`helper ::ApplicationHelper` adding to the engine's controller — or just inline the markup.
|
|
347
|
+
|
|
348
|
+
### Favicon
|
|
349
|
+
|
|
350
|
+
Pages under the mount point carry their own favicon — a rustic loaf, inlined as an SVG data URI, so
|
|
351
|
+
there's nothing to add to your asset pipeline.
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
config.favicon = nil # built-in loaf (default)
|
|
355
|
+
config.favicon = '/icons/my-icon.svg' # your own
|
|
356
|
+
config.favicon = false # none; the host's favicon applies
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
It's emitted by the engine's layout, so if you point `config.layout` at your own layout, add
|
|
360
|
+
`<%= b270_favicon_tag %>` to its `<head>`.
|
|
325
361
|
|
|
326
362
|
References link to Bible Gateway by default — point `passage_url_builder` at your another reader if you wish, or your own reader if you host one.
|
|
327
363
|
|
|
@@ -10,7 +10,7 @@ module Bible270
|
|
|
10
10
|
class AdminController < ApplicationController
|
|
11
11
|
before_action :require_admin!
|
|
12
12
|
before_action :load_reader,
|
|
13
|
-
only: %i[show destroy update_start
|
|
13
|
+
only: %i[show destroy update_start update_profile remove_avatar complete_through toggle_day]
|
|
14
14
|
before_action :load_comment, only: %i[hide_comment unhide_comment destroy_comment]
|
|
15
15
|
|
|
16
16
|
# ---- enrolment --------------------------------------------------------
|
|
@@ -95,14 +95,30 @@ module Bible270
|
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
# Name and picture together, mirroring what a reader can change about
|
|
99
|
+
# themselves on their own profile.
|
|
100
|
+
def update_profile
|
|
101
|
+
problems = []
|
|
102
|
+
if (params[:first_name].present? || params[:last_name].present?) && !@reader.update_names(params[:first_name],
|
|
103
|
+
params[:last_name])
|
|
104
|
+
problems << 'both a first and last name'
|
|
105
|
+
end
|
|
106
|
+
if params[:avatar].present? && !@reader.attach_avatar(params[:avatar])
|
|
107
|
+
problems << (@reader.errors[:avatar].first || 'a valid image')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if problems.empty?
|
|
111
|
+
redirect_to admin_reader_path(@reader), notice: 'Updated.'
|
|
101
112
|
else
|
|
102
|
-
redirect_to admin_reader_path(@reader), alert:
|
|
113
|
+
redirect_to admin_reader_path(@reader), alert: "Needs #{problems.to_sentence}."
|
|
103
114
|
end
|
|
104
115
|
end
|
|
105
116
|
|
|
117
|
+
def remove_avatar
|
|
118
|
+
@reader.remove_avatar!
|
|
119
|
+
redirect_to admin_reader_path(@reader), notice: "Removed #{@reader.display_name}'s picture."
|
|
120
|
+
end
|
|
121
|
+
|
|
106
122
|
def complete_through
|
|
107
123
|
day = params[:day].to_i
|
|
108
124
|
if @reader.mark_through!(day)
|
|
@@ -20,6 +20,46 @@ module Bible270
|
|
|
20
20
|
|
|
21
21
|
# The signed-in reader's translation, falling back to the site default for
|
|
22
22
|
# visitors who aren't signed in.
|
|
23
|
+
# Applies to every page the engine's layout renders, i.e. everything under
|
|
24
|
+
# the mount point. Pages rendered inside a host layout need this in that
|
|
25
|
+
# layout's <head> instead.
|
|
26
|
+
# The footer, from whichever source the host configured. A partial is looked
|
|
27
|
+
# up in the host's view paths as well as the engine's, so 'shared/footer'
|
|
28
|
+
# finds app/views/shared/_footer.html.erb.
|
|
29
|
+
# The footer, from whichever source the host configured. A partial is looked
|
|
30
|
+
# up in the host's view paths as well as the engine's, so 'shared/footer'
|
|
31
|
+
# finds app/views/shared/_footer.html.erb. config.footer_placement decides
|
|
32
|
+
# whether a custom footer replaces the engine's or sits alongside it.
|
|
33
|
+
def b270_footer
|
|
34
|
+
config = Bible270.config
|
|
35
|
+
return if config.footer_style == :none
|
|
36
|
+
return render('bible270/shared/footer') if config.footer_style == :default
|
|
37
|
+
|
|
38
|
+
parts = [b270_custom_footer]
|
|
39
|
+
if config.keep_default_footer?
|
|
40
|
+
default = render('bible270/shared/footer')
|
|
41
|
+
config.resolved_footer_placement == :after ? parts.unshift(default) : parts.push(default)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
safe_join(parts)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def b270_custom_footer
|
|
48
|
+
case Bible270.config.footer_style
|
|
49
|
+
when :partial then render(Bible270.config.footer_partial)
|
|
50
|
+
when :html then content_tag(:footer, Bible270.config.footer_html.html_safe, class: 'b270-footer')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def b270_favicon_tag
|
|
55
|
+
favicon = Bible270.config.favicon
|
|
56
|
+
return if favicon == false
|
|
57
|
+
|
|
58
|
+
href = favicon.presence || Favicon.data_uri
|
|
59
|
+
type = href.start_with?('data:image/svg+xml', 'http') || href.end_with?('.svg') ? 'image/svg+xml' : nil
|
|
60
|
+
tag.link(rel: 'icon', type: type, href: href)
|
|
61
|
+
end
|
|
62
|
+
|
|
23
63
|
def b270_bible_version
|
|
24
64
|
current_reader&.effective_bible_version || Translations.resolve(nil)
|
|
25
65
|
end
|
|
@@ -10,17 +10,37 @@
|
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<div class="b270-panel">
|
|
13
|
-
<h2 class="b270-subhead">Name</h2>
|
|
14
|
-
<%= form_with url:
|
|
13
|
+
<h2 class="b270-subhead">Name and picture</h2>
|
|
14
|
+
<%= form_with url: admin_reader_profile_path(@reader), method: :patch, class: "b270-emailform",
|
|
15
|
+
html: { multipart: true } do %>
|
|
16
|
+
<div class="b270-avatarrow">
|
|
17
|
+
<%= b270_avatar(@reader, size: 64) %>
|
|
18
|
+
<% if Bible270::Reader.avatar_uploads? %>
|
|
19
|
+
<label class="b270-field" style="flex:1">
|
|
20
|
+
<span>Picture</span>
|
|
21
|
+
<%= file_field_tag :avatar, accept: Bible270::Avatars.content_types.join(',') %>
|
|
22
|
+
<span class="b270-hint" style="margin:0">
|
|
23
|
+
PNG, JPEG, GIF or WebP, up to <%= Bible270::Avatars.human_size(Bible270::Avatars.max_bytes) %>.
|
|
24
|
+
</span>
|
|
25
|
+
</label>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
15
29
|
<label class="b270-field">
|
|
16
30
|
<span>First name</span>
|
|
17
|
-
<%= text_field_tag :first_name, @reader.suggested_names[:first_name]
|
|
31
|
+
<%= text_field_tag :first_name, @reader.suggested_names[:first_name] %>
|
|
18
32
|
</label>
|
|
19
33
|
<label class="b270-field">
|
|
20
34
|
<span>Last name</span>
|
|
21
|
-
<%= text_field_tag :last_name, @reader.suggested_names[:last_name]
|
|
35
|
+
<%= text_field_tag :last_name, @reader.suggested_names[:last_name] %>
|
|
22
36
|
</label>
|
|
23
|
-
<%= submit_tag 'Save
|
|
37
|
+
<%= submit_tag 'Save', class: 'b270-btn' %>
|
|
38
|
+
<% end %>
|
|
39
|
+
|
|
40
|
+
<% if @reader.avatar_uploaded? %>
|
|
41
|
+
<%= button_to "Remove picture", admin_reader_avatar_path(@reader), method: :delete,
|
|
42
|
+
class: 'b270-linkbtn',
|
|
43
|
+
form: { data: { turbo_confirm: "Remove #{@reader.display_name}'s picture?" } } %>
|
|
24
44
|
<% end %>
|
|
25
45
|
</div>
|
|
26
46
|
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
<% end %>
|
|
24
24
|
</div>
|
|
25
25
|
<p style="margin:16px 0 0">
|
|
26
|
-
|
|
26
|
+
<% @day_verb = @start_day == 1 ? "Start" : "Continue" %>
|
|
27
|
+
<%= link_to "#{@day_verb} reading — Day #{@start_day} →", day_path(@start_day), class: "b270-btn" %>
|
|
27
28
|
<% if @today_day && @today_day != @start_day %>
|
|
28
29
|
<%= link_to "Go to today (Day #{@today_day})", day_path(@today_day), style: "margin-left:12px" %>
|
|
29
30
|
<% end %>
|
|
@@ -41,9 +42,10 @@
|
|
|
41
42
|
</div>
|
|
42
43
|
|
|
43
44
|
<% if @readers.any? %>
|
|
44
|
-
|
|
45
|
+
<% rankings= @readers.count < 5 ? @readers.count : 5 %>
|
|
46
|
+
<h2 class="b270-section-h">Top <%= rankings %> reader leaders ...</h2>
|
|
45
47
|
<div class="b270-list">
|
|
46
|
-
<% @readers.first(
|
|
48
|
+
<% @readers.first(rankings).each_with_index do |r, i| %>
|
|
47
49
|
<div class="b270-li">
|
|
48
50
|
<span class="rank"><%= i + 1 %></span>
|
|
49
51
|
<%= b270_avatar(r) %>
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
.b270-cell.complete{background:var(--teal);border-color:var(--teal);color:#eef3f2;font-weight:600}
|
|
152
152
|
.b270-cell.now{box-shadow:0 0 0 2px var(--gold)}
|
|
153
153
|
|
|
154
|
-
.b270-footer{margin-top:
|
|
154
|
+
.b270-footer{margin-top:20px;padding-top:11px;border-top:1px solid var(--line-soft);color:var(--faint);font-size:13px}
|
|
155
155
|
.b270-footer p{margin:0;line-height:1.5}
|
|
156
156
|
details.b270-index summary{cursor:pointer;font-family:"Spectral",serif;font-size:18px;font-weight:600;list-style:none;margin-top:30px}
|
|
157
157
|
details.b270-index summary::-webkit-details-marker{display:none}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,500;0,600;1,400&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
|
12
|
+
<%= b270_favicon_tag %>
|
|
12
13
|
<%= render "bible270/shared/styles" %>
|
|
13
14
|
<%= yield :head %>
|
|
14
15
|
</head>
|
|
@@ -20,12 +21,7 @@
|
|
|
20
21
|
<%= yield %>
|
|
21
22
|
<%# Pages with their own day grid opt out with content_for :hide_day_index %>
|
|
22
23
|
<%= render 'bible270/shared/day_index' unless content_for?(:hide_day_index) %>
|
|
23
|
-
|
|
24
|
-
<p>The Old Testament and New Testament are each read once across the 270 days, with a
|
|
25
|
-
reading from all three tracks every day. Alongside them the Psalms run once and
|
|
26
|
-
Proverbs twice; the longest chapters are divided so the readings fill each day
|
|
27
|
-
evenly, and Psalm 119 comes in eleven sections.</p>
|
|
28
|
-
</footer>
|
|
24
|
+
<%= b270_footer %>
|
|
29
25
|
</div>
|
|
30
26
|
</body>
|
|
31
27
|
</html>
|
data/config/routes.rb
CHANGED
|
@@ -15,7 +15,8 @@ Bible270::Engine.routes.draw do
|
|
|
15
15
|
get 'admin', to: 'admin#index', as: :admin
|
|
16
16
|
get 'admin/readers/:id', to: 'admin#show', as: :admin_reader
|
|
17
17
|
delete 'admin/readers/:id', to: 'admin#destroy'
|
|
18
|
-
patch 'admin/readers/:id/
|
|
18
|
+
patch 'admin/readers/:id/profile', to: 'admin#update_profile', as: :admin_reader_profile
|
|
19
|
+
delete 'admin/readers/:id/avatar', to: 'admin#remove_avatar', as: :admin_reader_avatar
|
|
19
20
|
patch 'admin/readers/:id/start', to: 'admin#update_start', as: :admin_reader_start
|
|
20
21
|
patch 'admin/readers/:id/through', to: 'admin#complete_through', as: :admin_reader_through
|
|
21
22
|
post 'admin/readers/:id/days/:day', to: 'admin#toggle_day', as: :admin_reader_day
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bible270/version'
|
|
4
|
+
require 'bible270/plan'
|
|
5
|
+
require 'bible270/email_sign_in'
|
|
6
|
+
require 'bible270/names'
|
|
7
|
+
require 'bible270/avatars'
|
|
8
|
+
require 'bible270/translations'
|
|
9
|
+
require 'bible270/favicon'
|
|
10
|
+
require 'bible270/configuration'
|
|
11
|
+
require 'bible270/engine' if defined?(Rails::Engine)
|
|
12
|
+
|
|
13
|
+
module Bible270
|
|
14
|
+
end
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
# URI.encode_www_form_component produces byte-identical output to CGI.escape.
|
|
7
7
|
require 'uri'
|
|
8
8
|
require 'bible270/plan'
|
|
9
|
+
require 'bible270/email_sign_in'
|
|
9
10
|
require 'bible270/avatars'
|
|
10
11
|
require 'bible270/translations'
|
|
12
|
+
require 'bible270/favicon'
|
|
11
13
|
|
|
12
14
|
module Bible270
|
|
13
15
|
class Configuration
|
|
@@ -141,6 +143,59 @@ module Bible270
|
|
|
141
143
|
# from the panel at runtime; setting this to false launches closed.
|
|
142
144
|
attr_accessor :enrollment_open
|
|
143
145
|
|
|
146
|
+
# Favicon for the engine's pages. nil uses the built-in loaf, false renders
|
|
147
|
+
# no link tag at all (so the host's own favicon applies), and a string is
|
|
148
|
+
# used as the href — a path, a URL, or your own data URI.
|
|
149
|
+
# Footer for the engine's pages. Three ways to set it, and they're checked in
|
|
150
|
+
# this order:
|
|
151
|
+
#
|
|
152
|
+
# config.footer_partial = 'shared/footer' # a partial in your app
|
|
153
|
+
# config.footer_html = '<p>…</p>' # raw HTML, marked safe
|
|
154
|
+
# config.footer = false # no footer at all
|
|
155
|
+
#
|
|
156
|
+
# With none of them set you get the engine's own note about how the plan works.
|
|
157
|
+
# Rails adds the leading underscore when looking a partial up, so
|
|
158
|
+
# 'layouts/_bible270_footer' would search for '__bible270_footer' and raise
|
|
159
|
+
# MissingTemplate. Accept either spelling and normalise.
|
|
160
|
+
attr_reader :footer_partial
|
|
161
|
+
|
|
162
|
+
def footer_partial=(path)
|
|
163
|
+
@footer_partial =
|
|
164
|
+
if path.nil?
|
|
165
|
+
nil
|
|
166
|
+
else
|
|
167
|
+
segments = path.to_s.strip.split('/')
|
|
168
|
+
segments[-1] = segments[-1].sub(%r{\A_}, '') unless segments.empty?
|
|
169
|
+
segments.join('/')
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Where your footer goes relative to the engine's own: :replace (default),
|
|
174
|
+
# :after, or :before. Anything else is treated as :replace.
|
|
175
|
+
attr_accessor :footer_placement
|
|
176
|
+
|
|
177
|
+
PLACEMENTS = %i[replace after before].freeze
|
|
178
|
+
|
|
179
|
+
def resolved_footer_placement
|
|
180
|
+
placement = footer_placement.to_s.downcase.to_sym
|
|
181
|
+
PLACEMENTS.include?(placement) ? placement : :replace
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Whether the engine's own footer is shown alongside yours.
|
|
185
|
+
def keep_default_footer?
|
|
186
|
+
footer_style != :none && %i[after before].include?(resolved_footer_placement)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# :none, :partial, :html or :default.
|
|
190
|
+
def footer_style
|
|
191
|
+
# Plain Ruby, not present?: this file has to load without ActiveSupport.
|
|
192
|
+
return :none if footer == false
|
|
193
|
+
return :partial unless footer_partial.to_s.strip.empty?
|
|
194
|
+
return :html unless footer_html.to_s.strip.empty?
|
|
195
|
+
|
|
196
|
+
:default
|
|
197
|
+
end
|
|
198
|
+
|
|
144
199
|
# Optional YAML file holding the same thing, re-read whenever it changes so
|
|
145
200
|
# breaks can be tuned without restarting:
|
|
146
201
|
#
|
|
@@ -206,7 +261,7 @@ module Bible270
|
|
|
206
261
|
# Bible270::Translations::VERSIONS; narrow it to offer fewer.
|
|
207
262
|
attr_accessor :bible_versions
|
|
208
263
|
|
|
209
|
-
attr_accessor :after_sign_out_path, :email_sign_in_max_per_window, :passage_url_builder, :tagline, :avatar_max_bytes, :chapter_breaks, :admin_emails, :admin_resolver, :bible_version
|
|
264
|
+
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
|
|
210
265
|
|
|
211
266
|
# Public labels.
|
|
212
267
|
attr_accessor :app_name
|
|
@@ -258,6 +313,11 @@ module Bible270
|
|
|
258
313
|
@email_sign_in_require_name = true
|
|
259
314
|
@email_sign_in_log_link = nil
|
|
260
315
|
@enrollment_open = true
|
|
316
|
+
@footer_partial = nil
|
|
317
|
+
@footer_placement = :replace
|
|
318
|
+
@footer_html = nil
|
|
319
|
+
@footer = nil
|
|
320
|
+
@favicon = nil
|
|
261
321
|
@avatar_max_bytes = Avatars::DEFAULT_MAX_BYTES
|
|
262
322
|
@chapter_breaks = {}
|
|
263
323
|
@chapter_breaks_path = nil
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bible270
|
|
4
|
+
# A favicon for the engine's own pages, inlined as a data URI.
|
|
5
|
+
#
|
|
6
|
+
# Inlined rather than served as an asset because the engine deliberately has no
|
|
7
|
+
# asset-pipeline dependency — its CSS is inlined the same way — so this works
|
|
8
|
+
# whether the host uses Propshaft, Sprockets or neither, and costs no request.
|
|
9
|
+
module Favicon
|
|
10
|
+
# A rustic loaf: a domed round on an ink board, with three slashed scores
|
|
11
|
+
# across the crust and a paler crumb showing at the base.
|
|
12
|
+
# Colours match the engine's palette (--ink, --gold, --paper).
|
|
13
|
+
SVG = <<~SVG
|
|
14
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>
|
|
15
|
+
<rect width='32' height='32' rx='7' fill='%23231f18'/>
|
|
16
|
+
<path d='M4.5 21c0-6.2 5.1-10.5 11.5-10.5S27.5 14.8 27.5 21c0 1.4-1 2.4-2.4 2.4H6.9C5.5 23.4 4.5 22.4 4.5 21z'
|
|
17
|
+
fill='%23c6a24a'/>
|
|
18
|
+
<path d='M6.9 23.4h18.2c1.1 0 2-.6 2.3-1.5H4.6c.3.9 1.2 1.5 2.3 1.5z' fill='%23ece6da'/>
|
|
19
|
+
<g stroke='%23231f18' stroke-width='1.6' stroke-linecap='round' opacity='.75'>
|
|
20
|
+
<path d='M10.6 17.6l2.6-3'/>
|
|
21
|
+
<path d='M15 16.8l2.6-3'/>
|
|
22
|
+
<path d='M19.4 17.6l2.6-3'/>
|
|
23
|
+
</g>
|
|
24
|
+
</svg>
|
|
25
|
+
SVG
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
# Percent-encoding matters here: a raw '#' would truncate the URI at the
|
|
30
|
+
# fragment, and raw spaces are invalid in one.
|
|
31
|
+
def data_uri
|
|
32
|
+
compact = SVG.gsub(%r{\s+}, ' ').strip
|
|
33
|
+
"data:image/svg+xml,#{compact.gsub(' ', '%20')}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/bible270/version.rb
CHANGED
data/lib/bible270.rb
CHANGED
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.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew vonderLuft
|
|
@@ -100,6 +100,7 @@ files:
|
|
|
100
100
|
- app/views/bible270/readers/show.html.erb
|
|
101
101
|
- app/views/bible270/sessions/new.html.erb
|
|
102
102
|
- app/views/bible270/shared/_day_index.html.erb
|
|
103
|
+
- app/views/bible270/shared/_footer.html.erb
|
|
103
104
|
- app/views/bible270/shared/_header.html.erb
|
|
104
105
|
- app/views/bible270/shared/_styles.html.erb
|
|
105
106
|
- app/views/bible270/sign_in_mailer/magic_link.html.erb
|
|
@@ -116,9 +117,11 @@ files:
|
|
|
116
117
|
- db/migrate/20260101000008_add_bible_version_to_bible270_readers.rb
|
|
117
118
|
- lib/bible270.rb
|
|
118
119
|
- lib/bible270/avatars.rb
|
|
120
|
+
- lib/bible270/bible270.rb
|
|
119
121
|
- lib/bible270/configuration.rb
|
|
120
122
|
- lib/bible270/email_sign_in.rb
|
|
121
123
|
- lib/bible270/engine.rb
|
|
124
|
+
- lib/bible270/favicon.rb
|
|
122
125
|
- lib/bible270/names.rb
|
|
123
126
|
- lib/bible270/plan.rb
|
|
124
127
|
- lib/bible270/translations.rb
|