recourse 7.8.3 → 7.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94653dc38ca1c788fce69b9406faddc48c189cefcd9fbe7dbe11e4d87ddc3faf
4
- data.tar.gz: c1282266e1e70de6bc5438661f86321e52948dee028baa7128efe4fac4317719
3
+ metadata.gz: '024485f23e83a52580fa55b3d73f858bf737ab1a2fd5e53819f283aaf29a57e3'
4
+ data.tar.gz: f1aaa536fd9085f5baa7b54cf9590d0387aa79bc65173a9ab97a853ffacbdbe9
5
5
  SHA512:
6
- metadata.gz: dbed84f6d5071f7be79cdb87c499c6a9c4ae23ceb74c70390606cfe33652236f38e782ecbae67347c4873b270c23cba660395d2451034202517af60fe9a0a8d6
7
- data.tar.gz: e04c3108e911aba9d08555b8d696994cc56df42ee21ee207f96cc0f1cf326491fcd62d867f38953e22c3fdb76e14297a50d22e4444db0bae1c28746a20b546db
6
+ metadata.gz: bbad80f3cda8598fb3773e8caad5b887aa02354a8dd2ba56f289669ae456a4ebca178830d20900cb0ec95a73c641cf95d9d47698c85654a48abd5a5eaa78214e
7
+ data.tar.gz: 07daefa230e19c573044eb613716eafa6d347cdeceb19e1d72af511696a458abb3e4771fb2d91f5784adb5e8053ef8f172e6f08dab09b3011acab7f6336b933c
data/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ For more information about changelogs, check [Keep a Changelog](http://keepachan
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## 7.9.0 - 2026-09-26
11
+
12
+ * [FEATURE] A pin or an area on a map leads to its row's page
13
+
14
+ Each point is sent as `[lat, lng, href, title]` and each place as `[id, href, title]`: the
15
+ record's own page wherever one is routed, and its label. bh's map controller makes a pin
16
+ or an area with an `href` clickable, following it through Turbo. Needs the bh that reads
17
+ these shapes: an older one still draws points, but takes a place's whole triple for its
18
+ ID and draws nothing, which is why this release requires bh 6.10.
19
+
20
+ * [FEATURE] A route named `enter` earns the sidebar a way in
21
+
22
+ The mirror of `exit`: `get 'session/new', to: 'sessions#new', as: :enter` draws a
23
+ `Sign in` link beside the toggle, to wherever the host signs people in. A host that
24
+ signs people in shows one or the other by answering `enter?` and `exit?` itself.
25
+
26
+ * [FEATURE] A bookmarks Proc answering nil draws no bookmark column
27
+
28
+ A visitor who never signed in has nowhere to keep a row, so `Recourse.bookmarks =
29
+ -> { Current.user&.bookmarks }` leaves them without the squares rather than raising.
30
+
10
31
  ## 7.8.3 - 2026-09-21
11
32
 
12
33
  * [FIX] A delete button in a table row is no taller than the row
data/README.md CHANGED
@@ -78,8 +78,8 @@ draws the route a dragged row reports its place to, and `retrievable: true` draw
78
78
  one a `Retrieve` button on the table posts to, for rows that came from somewhere else.
79
79
  Both are refused on a resource with no `index`, since there is nowhere for either to
80
80
  stand. The [routes guide](https://claudiob.github.io/recourse/guides/routes.html) has
81
- the rest: namespaces, the defaults a nested resource takes, and the `exit` route that
82
- earns the sidebar a log-out button.
81
+ the rest: namespaces, the defaults a nested resource takes, and the `enter` and `exit`
82
+ routes that earn the sidebar a sign-in link and a log-out button.
83
83
 
84
84
  ## Step 2. Enhance your models
85
85
 
@@ -211,7 +211,8 @@ Recourse.bookmarks = -> { Keepsake.where agent: Current.agent }
211
211
 
212
212
  A Proc rather than a relation, because at boot the viewer is nobody. Every model with a
213
213
  `has_many` at that class then opens its table with a square to keep a row by, and kept
214
- rows come first. A model that cannot hold a bookmark gets no column.
214
+ rows come first. A model that cannot hold a bookmark gets no column, and neither does a
215
+ visitor the Proc answers nil for — somebody who never signed in has nowhere to keep one.
215
216
 
216
217
  <img width="3824" height="1220" alt="Image" src="https://github.com/user-attachments/assets/d1db4adb-0b5c-4e41-8bb6-cf72a35288f0" />
217
218
 
@@ -51,6 +51,14 @@
51
51
  </div>
52
52
  <%# Submitted by the browser rather than by Turbo: a log out ends with a redirect to
53
53
  wherever the host signs people in, which is another origin a fetch cannot follow. -%>
54
+ <%# The way in, where the host drew a route named `enter`: a link, since what it
55
+ leads to is a form rather than a change. -%>
56
+ <% if enter? %>
57
+ <%= link_to enter_path, class: 'nav-link border-0 bg-transparent' do %>
58
+ <i class='bi bi-box-arrow-in-right'></i>
59
+ <span class='recourse-foot-word'><%= t 'recourse.enter' %></span>
60
+ <% end %>
61
+ <% end %>
54
62
  <% if exit? %>
55
63
  <%= button_to exit_path, method: :delete, class: 'nav-link border-0 bg-transparent',
56
64
  form: { data: { turbo: false } } do %>
@@ -53,6 +53,7 @@ en:
53
53
  deleted_error: "%{model} could not be deleted."
54
54
  destroy: Delete
55
55
  exit: Exit
56
+ enter: Sign in
56
57
  displaying:
57
58
  one: Displaying 1 item
58
59
  other: Displaying %{count} items
@@ -17,7 +17,8 @@ module Recourse
17
17
  # would run a host's Proc long before there is a request for it to read.
18
18
  def self.bookmarks? = !@declared_bookmarks.nil?
19
19
 
20
- # The viewer's bookmarks, resolved for this request.
20
+ # The viewer's bookmarks, resolved for this request, or nil where the Proc answered
21
+ # nil: nobody is looking whose rows could be kept, a visitor who never signed in.
21
22
  def self.bookmarks
22
23
  bookmarks = @declared_bookmarks
23
24
  bookmarks = bookmarks.call if bookmarks.respond_to? :call
@@ -28,10 +29,11 @@ module Recourse
28
29
  # How a model's bookmarks point back at it: its own `has_many` at the bookmark
29
30
  # class, which is both the opt-in and everything needed to write one. A model that
30
31
  # cannot hold a bookmark has not declared one, so it gets no column.
32
+ # And none for a viewer the Proc named nobody, who has nowhere to keep a row.
31
33
  def self.bookmarks_for(model)
32
34
  return unless bookmarks?
33
35
 
34
- klass = bookmarks.klass
36
+ klass = bookmarks&.klass or return
35
37
  model.reflect_on_all_associations(:has_many).find { |one| one.klass == klass }
36
38
  end
37
39
 
@@ -15,23 +15,38 @@ module Recourse
15
15
  end
16
16
 
17
17
  # The places, with the layer they are areas on — pins where the model is no geography
18
- # — or the points, where a model keeps no place.
18
+ # — or the points, where a model keeps no place. Each carries where its row leads and
19
+ # what it is called, so a pin or an area is clicked through to the record the way the
20
+ # row's own link in the table is.
19
21
  def map_rows(recourses)
20
22
  return { map_points_value: map_points(recourses) } unless Recourse.placed? resource_model
21
23
 
22
24
  {
23
25
  map_boundary_value: Recourse.boundary(resource_model)&.to_s&.upcase,
24
- map_places_value: recourses.filter_map { |one| one.attributes[Recourse::PLACE_COLUMN] },
26
+ map_places_value: map_places(recourses),
25
27
  }
26
28
  end
27
29
 
28
- # Only a row with both halves is a point; one with either missing is nowhere.
30
+ # Each place as `[id, href, title]`, for a row that names one.
31
+ def map_places(recourses)
32
+ recourses.filter_map do |one|
33
+ place = one.attributes[Recourse::PLACE_COLUMN]
34
+ [place, *map_lead(one)] if place
35
+ end
36
+ end
37
+
38
+ # Each point as `[lat, lng, href, title]`. Only a row with both halves is a point; one
39
+ # with either missing is nowhere.
29
40
  def map_points(recourses)
30
41
  recourses.filter_map do |one|
31
42
  point = one.attributes.values_at(*Recourse::POINT_COLUMNS)
32
- point.map(&:to_f) if point.all?
43
+ [*point.map(&:to_f), *map_lead(one)] if point.all?
33
44
  end
34
45
  end
46
+
47
+ # Where a row's pin leads, the record's own page wherever one is routed, and what the
48
+ # pin says on hover: nothing to lead to where no page is.
49
+ def map_lead(record) = [resource_action_path(:show, record), Recourse.record_title(record)]
35
50
  end
36
51
  end
37
52
  end
@@ -10,6 +10,13 @@ module Recourse
10
10
  # convention, and its helper existing is what the sidebar asks.
11
11
  def exit? = respond_to? :exit_path
12
12
 
13
+ # And the way in, its mirror: a route named `enter` — `resource :session, only:
14
+ # :new, as: :enter`, or a `get` of the host's own — earns a link beside the toggle
15
+ # to wherever the host signs people in. A link rather than a button, since asking
16
+ # for a form to sign in with changes nothing. Whether a viewer who already signed
17
+ # in still sees it is the host's to say, by answering this for them.
18
+ def enter? = respond_to? :enter_path
19
+
13
20
  # Sidebar entries as [name, title, path, key], in the order routes.rb declares
14
21
  # them, `key` being where in the title the letter that reaches it sits.
15
22
  def sidebar_resources
@@ -1,4 +1,4 @@
1
1
  module Recourse
2
2
  # Version of the gem, read by the gemspec and by hosts checking compatibility.
3
- VERSION = '7.8.3'
3
+ VERSION = '7.9.0'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recourse
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.8.3
4
+ version: 7.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - claudiob
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '6.7'
46
+ version: '6.10'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '6.7'
53
+ version: '6.10'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: pagy
56
56
  requirement: !ruby/object:Gem::Requirement