recourse 5.3.0 → 5.4.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 +18 -0
- data/README.md +31 -0
- data/app/controllers/concerns/recourse/weeks.rb +40 -0
- data/app/controllers/recourse/base_controller.rb +9 -5
- data/app/views/layouts/recourses.html.erb +11 -10
- data/app/views/recourses/_calendar.html.erb +40 -0
- data/app/views/recourses/_footer.html.erb +5 -4
- data/app/views/recourses/_results.html.erb +7 -3
- data/app/views/recourses/_week.html.erb +19 -0
- data/app/views/recourses/index.html.erb +2 -2
- data/config/locales/recourse.en.yml +14 -0
- data/lib/recourse/calendars.rb +27 -0
- data/lib/recourse/engine.rb +4 -3
- data/lib/recourse/helpers/calendars.rb +55 -0
- data/lib/recourse/helpers/events.rb +79 -0
- data/lib/recourse/helpers/maps.rb +2 -17
- data/lib/recourse/helpers/searches.rb +10 -1
- data/lib/recourse/helpers/shapes.rb +42 -0
- data/lib/recourse/helpers/spans.rb +59 -0
- data/lib/recourse/helpers/weeks.rb +53 -0
- data/lib/recourse/helpers.rb +9 -4
- data/lib/recourse/themes.rb +1 -1
- data/lib/recourse/version.rb +1 -1
- data/lib/recourse.rb +6 -0
- metadata +10 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fcfda63efd2c2320ea4e97b5805d1ba4aadeb0686b78d613c2b2c4ad71b9fc17
|
|
4
|
+
data.tar.gz: ffaa33863a46cdf213c5ab2fab3266b7266bf4e73073e88be42928e72838471f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45bfd3ce50837e3a0d28a02f226f0eca777ebb2b25e880059db61052313a67ebd311b8c2404f0281b147713fa346d8cf3653effb9f180ba0743d998acba12a10
|
|
7
|
+
data.tar.gz: 20f922caf3230244b441b47dcfd3fa4ca7fe7abd5045c1f765f47cad8ce54d737be6aabf22dce13c0d81720e15c1cc7803b9b8077df9fcbfda90ac5a9a4fd311
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ For more information about changelogs, check [Keep a Changelog](http://keepachan
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## 5.4.0 - 2026-09-17
|
|
11
|
+
|
|
12
|
+
* [Feature] A table of events can be read as a week
|
|
13
|
+
|
|
14
|
+
The second shape a page of rows can take, beside the map: a model keeping a `starts_at`
|
|
15
|
+
and an `ends_at` offers `Display as calendar` in its footer, and `/shifts.cal` draws
|
|
16
|
+
them as a week — a column a day from Sunday, the hours that week's own rows cover down
|
|
17
|
+
the side, and each row placed by the share of the day it takes, in a lane of its own
|
|
18
|
+
where a day's rows overlap, saying what it is, whoever it points at and the hours
|
|
19
|
+
themselves. The grid is as tall as a table's own first page, so the two shapes carry
|
|
20
|
+
their footers at one height. A week rather than a page is the unit, so `?week=` moves it
|
|
21
|
+
and `<<`, `<`, `>` and `>>` stand where a table's pages stand — a week either side and
|
|
22
|
+
four weeks beyond each — with the week named between them;
|
|
23
|
+
the search, the filters and the reader's own time zone all travel with it. A search or
|
|
24
|
+
a filter now answers in the shape it was picked in rather than falling back to the
|
|
25
|
+
table, and `Display as map` and `Display as table` are drawn by one helper, so a model
|
|
26
|
+
earning both shapes offers both.
|
|
27
|
+
|
|
10
28
|
## 5.3.0 - 2026-09-16
|
|
11
29
|
|
|
12
30
|
* [Feature] A record's files are a field, a value and a page
|
data/README.md
CHANGED
|
@@ -208,6 +208,37 @@ Security Policy allows `maps.googleapis.com` for scripts and connections, and Go
|
|
|
208
208
|
tile hosts for images.
|
|
209
209
|
|
|
210
210
|
|
|
211
|
+
### Calendars
|
|
212
|
+
|
|
213
|
+
A table whose model keeps a `starts_at` and an `ends_at` can be read as a week of the same
|
|
214
|
+
rows: the footer offers `Display as calendar`, and `/shifts.cal` draws a column a day with
|
|
215
|
+
each row placed by the hours it runs between — rows that overlap in lanes of their own.
|
|
216
|
+
A row says what it is, whoever it points at, and the hours themselves, each led to its own
|
|
217
|
+
page where the routes drew one.
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
recourses :shifts
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
A week rather than a page is what a calendar shows, so there is nothing to paginate:
|
|
224
|
+
`?week=2026-09-13` moves to the week holding that day, and `<<`, `<`, `>` and `>>` stand
|
|
225
|
+
where the pages stand under a table — a week either side and four weeks beyond each —
|
|
226
|
+
with the week named between them. The search and the
|
|
227
|
+
filters travel with it — and answer in the shape they were picked in — so a calendar
|
|
228
|
+
narrowed to one person stays a narrowed calendar as the weeks move.
|
|
229
|
+
|
|
230
|
+
The grid stands as tall as a table's own first page, so the weeks under a calendar sit
|
|
231
|
+
where the pages under a table do. The week opens on Sunday and the hours are the reader's
|
|
232
|
+
own — the same cookie every other
|
|
233
|
+
time on these pages is drawn against — and the scale runs only over the hours that week's
|
|
234
|
+
rows cover, or a working day where it holds none. A row running past midnight is drawn on
|
|
235
|
+
the day it opens, down to the foot of its column.
|
|
236
|
+
|
|
237
|
+
Both columns have to be datetimes, asked through `type_for_attribute`, so an
|
|
238
|
+
`attribute :starts_at, :datetime` override counts and a column of another kind named
|
|
239
|
+
`starts_at` earns nothing.
|
|
240
|
+
|
|
241
|
+
|
|
211
242
|
## Development
|
|
212
243
|
|
|
213
244
|
```bash
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
# Which week a calendar draws, and the rows that fall inside it.
|
|
3
|
+
module Weeks
|
|
4
|
+
# How a week is written into an address: `?week=2026-09-13`, any day of the one
|
|
5
|
+
# meant, since a reader following a link never types one.
|
|
6
|
+
WEEK_FORMAT = '%Y-%m-%d'
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# The Sunday the calendar opens on: the week the address names, or the reader's
|
|
11
|
+
# own. An address is a stranger's to write, so a day nothing can be made of is
|
|
12
|
+
# this week rather than a 500.
|
|
13
|
+
def recourse_week
|
|
14
|
+
Recourse.week_of Date.strptime(params[:week].to_s, WEEK_FORMAT)
|
|
15
|
+
rescue Date::Error
|
|
16
|
+
Recourse.week_of Time.zone.today
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# What the index lists, as the pair it assigns: one week where the calendar was
|
|
20
|
+
# asked for, and one page everywhere else. A calendar has no pages to take and a
|
|
21
|
+
# table has no week, so neither shape carries the other's.
|
|
22
|
+
def week_or_page(scope)
|
|
23
|
+
return pagy scope, limit: recourse_limit unless request.format.cal?
|
|
24
|
+
|
|
25
|
+
[nil, week_resources(scope)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The week's rows, earliest first and all of them: a week is how much a calendar
|
|
29
|
+
# shows, so the sort a heading asked for is not what a grid reads by. Against the
|
|
30
|
+
# reader's own clock, which `Zoning` has already put in `Time.zone` — the same
|
|
31
|
+
# midnight the grid draws from.
|
|
32
|
+
def week_resources(scope)
|
|
33
|
+
@recourse_week = recourse_week
|
|
34
|
+
opening = @recourse_week.in_time_zone
|
|
35
|
+
|
|
36
|
+
scope.reorder(Recourse::START_COLUMN => :asc)
|
|
37
|
+
.where Recourse::START_COLUMN => opening...(opening + 1.week)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -6,7 +6,7 @@ module Recourse
|
|
|
6
6
|
include Pagy::Method, AttachmentResolution, AttachmentWriting,
|
|
7
7
|
Landing, Paging, ListResolution, ParentNaming,
|
|
8
8
|
ParentResolution, ReferenceResolution, ResourceResolution,
|
|
9
|
-
Zoning
|
|
9
|
+
Weeks, Zoning
|
|
10
10
|
|
|
11
11
|
helper Helpers
|
|
12
12
|
|
|
@@ -19,13 +19,17 @@ module Recourse
|
|
|
19
19
|
# The model broadcasts refreshes for its index, before `create` commits its own.
|
|
20
20
|
before_action :broadcast_resource_changes
|
|
21
21
|
|
|
22
|
-
# Lists one page of the model the route is named after
|
|
22
|
+
# Lists one page of the model the route is named after, or one week of it where the
|
|
23
|
+
# calendar was asked for — a week is how much that shape shows. `@q` is Ransack's own.
|
|
23
24
|
def index
|
|
24
25
|
search = Search.new recourse_relation, params[:q]
|
|
25
26
|
@q = search.query
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
|
|
28
|
+
@pagy, @resources = week_or_page search.scope
|
|
29
|
+
|
|
30
|
+
# A map and a calendar are the same page in another shape: the HTML templates draw
|
|
31
|
+
# both.
|
|
32
|
+
render :index, formats: :html if SHAPES.include? request.format.symbol
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
# Builds a blank record under the name Rails would use: @contact for contacts, with
|
|
@@ -17,15 +17,16 @@
|
|
|
17
17
|
<%= yield :head %>
|
|
18
18
|
|
|
19
19
|
<%# Everything the page is styled by, from the one place every HouseAccount app draws
|
|
20
|
-
on: Bootstrap 6, its icons and the house's own rules for this gem's markup.
|
|
21
|
-
to a version, so a change there
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<link rel='preconnect' href='https://
|
|
28
|
-
<link rel='
|
|
20
|
+
on: Bootstrap 6, its icons and the house's own rules for this gem's markup. Served
|
|
21
|
+
from the `houseaccount` package on a CDN, pinned to a version, so a change there
|
|
22
|
+
reaches these pages when somebody moves the pin here and not before; the same
|
|
23
|
+
version stands in the script below and in `Recourse::THEMES_PATH`. A published
|
|
24
|
+
version is never written again, so the bytes behind that URL cannot move under us.
|
|
25
|
+
Two connections opened before the parser finds either tag: the stylesheet's plain
|
|
26
|
+
one and the CORS one a module script and a font are fetched over. -%>
|
|
27
|
+
<link rel='preconnect' href='https://cdn.jsdelivr.net'>
|
|
28
|
+
<link rel='preconnect' href='https://cdn.jsdelivr.net' crossorigin>
|
|
29
|
+
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/houseaccount@0.11.0/public/css/houseaccount.css'>
|
|
29
30
|
<%# The one thing these screens set that the house's stylesheet does not: system faces
|
|
30
31
|
at a compact size, for pages dense with figures. 14px as rem, so a browser's own
|
|
31
32
|
text-size setting still scales it. After the stylesheet, since both are `:root`. -%>
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
<%# Turbo, Bootstrap and a Stimulus application with every controller this markup
|
|
50
51
|
names, started once under `window.Stimulus`. In the head, so a controller exists
|
|
51
52
|
before the body's first `data-controller`. -%>
|
|
52
|
-
<script type='module' src='https://
|
|
53
|
+
<script type='module' src='https://cdn.jsdelivr.net/npm/houseaccount@0.11.0/public/js/houseaccount.js'></script>
|
|
53
54
|
</head>
|
|
54
55
|
|
|
55
56
|
<%# The reader's zone is told to the server here rather than from a page of its
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<%# locals: (recourses:, week:) %>
|
|
2
|
+
<div class='card overflow-hidden mb-3'>
|
|
3
|
+
<div class='overflow-x-auto'>
|
|
4
|
+
<%# One grid rather than a row of columns: the days have to line up under their own
|
|
5
|
+
headings, and a column whose width is what it happens to hold does not. The
|
|
6
|
+
gutter is as wide as `12am` reads, and the seven take equal shares of the rest.
|
|
7
|
+
A minimum width so a phone scrolls the week rather than crushing it. -%>
|
|
8
|
+
<div class='d-grid' style='grid-template-columns: 4rem repeat(7, 1fr); min-width: 48rem'>
|
|
9
|
+
<div class='border-bottom'></div>
|
|
10
|
+
|
|
11
|
+
<% calendar_days(week).each do |day| %>
|
|
12
|
+
<div class='border-bottom border-start text-center py-2'><%= calendar_day_title day %></div>
|
|
13
|
+
<% end %>
|
|
14
|
+
|
|
15
|
+
<%# Every column is the same height whatever hours it draws — a table's own first
|
|
16
|
+
page — and the bands share it out, so the week nav under the grid stands where
|
|
17
|
+
a table's pages stand. -%>
|
|
18
|
+
<div class='d-flex flex-column' style='<%= calendar_grid_style %>'>
|
|
19
|
+
<% calendar_hours(recourses).each do |hour| %>
|
|
20
|
+
<div class='small fg-2 text-end pe-2 flex-fill'><%= calendar_hour_title hour %></div>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<%# Each day is those same bands with its own rows laid over them, which is what
|
|
25
|
+
`position-relative` is here for: a row is placed by the share of the grid it
|
|
26
|
+
takes rather than by anything the flow could work out. -%>
|
|
27
|
+
<% calendar_days(week).each do |day| %>
|
|
28
|
+
<div class='d-flex flex-column border-start position-relative' style='<%= calendar_grid_style %>'>
|
|
29
|
+
<% calendar_hours(recourses).each do %>
|
|
30
|
+
<div class='border-top flex-fill'></div>
|
|
31
|
+
<% end %>
|
|
32
|
+
|
|
33
|
+
<%= calendar_events recourses, day, calendar_hours(recourses) %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<%= render 'week', recourses: recourses, week: week %>
|
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
<% else %>
|
|
19
19
|
<%= t 'recourse.displaying', count: pagy.count %>
|
|
20
20
|
<% end %>
|
|
21
|
-
<%# And
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
<%# And every other shape the same rows can take, where the model's own columns
|
|
22
|
+
earn one: a place or a point makes a map of this page's rows, the two ends of
|
|
23
|
+
an event make a week of them, and either leads back to the table. -%>
|
|
24
|
+
<% view_links.each do |link| %>
|
|
24
25
|
<span class='fg-2'>·</span>
|
|
25
|
-
<%=
|
|
26
|
+
<%= link %>
|
|
26
27
|
<% end %>
|
|
27
28
|
</div>
|
|
28
29
|
<%# Centered on the row of their own a phone gives them, and at the end of the shared row from `sm` up. -%>
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
<%# locals: (resources:, pagy:) %>
|
|
1
|
+
<%# locals: (resources:, pagy:, week:) %>
|
|
2
2
|
<%# Both branches, so a search that matches nothing still answers with the frame
|
|
3
|
-
it was asked for. `advance` puts the query in the address bar.
|
|
3
|
+
it was asked for. `advance` puts the query in the address bar. A calendar is the
|
|
4
|
+
exception to the empty one: a week with nothing in it is still a week to draw, or
|
|
5
|
+
there would be nothing to reach the weeks either side by. -%>
|
|
4
6
|
<turbo-frame id='results' data-turbo-action='advance'>
|
|
5
|
-
<% if
|
|
7
|
+
<% if calendar_view? %>
|
|
8
|
+
<%= render 'calendar', recourses: resources, week: week %>
|
|
9
|
+
<% elsif resources.blank? %>
|
|
6
10
|
<%= render 'none' %>
|
|
7
11
|
<% else %>
|
|
8
12
|
<%= render map_view? ? 'map' : 'table', recourses: resources, pagy: pagy %>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%# locals: (recourses:, week:) %>
|
|
2
|
+
<%# What the footer is to a table: how much is showing, the other shapes the same rows
|
|
3
|
+
take after it, and at the end of the row — where a table's pages stand, and drawn as
|
|
4
|
+
they are — the weeks either side with this one named between them. A week is how much
|
|
5
|
+
a calendar shows, so there is no page size to offer. -%>
|
|
6
|
+
<div class='d-flex flex-column sm:flex-row sm:align-items-center'>
|
|
7
|
+
<div class='ps-2 flex-grow-1 text-center sm:text-start'>
|
|
8
|
+
<%= t 'recourse.displaying', count: recourses.size %>
|
|
9
|
+
|
|
10
|
+
<% view_links.each do |link| %>
|
|
11
|
+
<span class='fg-2'>·</span>
|
|
12
|
+
<%= link %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class='px-2 mt-2 sm:mt-0 d-flex justify-content-center sm:justify-content-end'>
|
|
17
|
+
<ul class='pagination mb-0'><%= week_links week %></ul>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
card, beside the record's other pages — its tab, the count, the current one. -%>
|
|
27
27
|
<% if resource_parent %>
|
|
28
28
|
<%= render layout: 'card', locals: { record: resource_parent } do %>
|
|
29
|
-
<%= render 'results', resources: @resources, pagy: @pagy %>
|
|
29
|
+
<%= render 'results', resources: @resources, pagy: @pagy, week: @recourse_week %>
|
|
30
30
|
<% end %>
|
|
31
31
|
<% else %>
|
|
32
|
-
<%= render 'results', resources: @resources, pagy: @pagy %>
|
|
32
|
+
<%= render 'results', resources: @resources, pagy: @pagy, week: @recourse_week %>
|
|
33
33
|
<% end %>
|
|
@@ -3,14 +3,22 @@ en:
|
|
|
3
3
|
date:
|
|
4
4
|
formats:
|
|
5
5
|
recourse: "%b %-d, %Y"
|
|
6
|
+
# A calendar's own two: the day over one of its columns, `Sun, Aug 30`, and the
|
|
7
|
+
# month a week is named by, whose day is an ordinal Ruby writes, not a format.
|
|
8
|
+
recourse_day: "%a, %b %-d"
|
|
9
|
+
recourse_month: "%B"
|
|
6
10
|
time:
|
|
7
11
|
formats:
|
|
8
12
|
recourse: "%b %-d at %I:%M%P %Z"
|
|
13
|
+
# The scale down a calendar, `9am`, and the hours one row runs between, `9:30am`.
|
|
14
|
+
recourse_hour: "%-I%P"
|
|
15
|
+
recourse_time: "%-I:%M%P"
|
|
9
16
|
recourse:
|
|
10
17
|
add: Add %{model}
|
|
11
18
|
ago: "%{distance} ago"
|
|
12
19
|
all: All %{models}
|
|
13
20
|
all_values: All
|
|
21
|
+
as_calendar: Display as calendar
|
|
14
22
|
as_map: Display as map
|
|
15
23
|
as_table: Display as table
|
|
16
24
|
# One message in four spellings: what a record is holding, under the field that
|
|
@@ -58,11 +66,15 @@ en:
|
|
|
58
66
|
more: "%{first} + %{count} more"
|
|
59
67
|
new: New %{model}
|
|
60
68
|
new_tab: Open in a new tab
|
|
69
|
+
next_week: Next week
|
|
70
|
+
next_weeks: Next four weeks
|
|
61
71
|
no_results: No results found
|
|
62
72
|
none: "No %{models}."
|
|
63
73
|
optional: Optional
|
|
64
74
|
per_page: "%{limit} per page"
|
|
65
75
|
preview: Preview
|
|
76
|
+
previous_week: Previous week
|
|
77
|
+
previous_weeks: Previous four weeks
|
|
66
78
|
ambiguous: "matches more than one record, so it does not say which: %{label}"
|
|
67
79
|
reference: "%{model} %{attribute}"
|
|
68
80
|
reveal: Show
|
|
@@ -79,6 +91,8 @@ en:
|
|
|
79
91
|
updated: "%{record} was updated."
|
|
80
92
|
updated_error: "%{model} could not be updated."
|
|
81
93
|
unset: None
|
|
94
|
+
# The two days a calendar's week runs between, and the year both are in.
|
|
95
|
+
week: "%{from} – %{to}, %{year}"
|
|
82
96
|
deletion:
|
|
83
97
|
delete: Delete
|
|
84
98
|
title: Delete %{record}?
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Reopened for the calendar a table of events can be read as.
|
|
2
|
+
module Recourse
|
|
3
|
+
# The column an event opens at, which is the day and the hour a calendar draws it on.
|
|
4
|
+
START_COLUMN = 'starts_at'
|
|
5
|
+
|
|
6
|
+
# And the one it closes at, which is how far down the day it reaches.
|
|
7
|
+
FINISH_COLUMN = 'ends_at'
|
|
8
|
+
|
|
9
|
+
# The two together, which is what a model is asked for its rows to be a week's events.
|
|
10
|
+
EVENT_COLUMNS = [START_COLUMN, FINISH_COLUMN].freeze
|
|
11
|
+
|
|
12
|
+
# The day a week opens on. Sunday, which is the column a calendar leads with wherever
|
|
13
|
+
# these pages are read — `Date.beginning_of_week` is the host's own setting, and a
|
|
14
|
+
# grid of seven is not a thing to draw two ways.
|
|
15
|
+
WEEK_START = :sunday
|
|
16
|
+
|
|
17
|
+
# Whether a model's rows can be drawn on a calendar: both ends of an event, and both
|
|
18
|
+
# an instant rather than a day — a date has no hour for a week to place it by. Asked
|
|
19
|
+
# of the type the model reports, so an `attribute` override counts and a column of
|
|
20
|
+
# another kind named `starts_at` earns nothing.
|
|
21
|
+
def self.calendarable?(model)
|
|
22
|
+
EVENT_COLUMNS.all? { |column| model.type_for_attribute(column).type == :datetime }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The Sunday a day belongs to, which is the week a calendar of it opens on.
|
|
26
|
+
def self.week_of(day) = day.beginning_of_week WEEK_START
|
|
27
|
+
end
|
data/lib/recourse/engine.rb
CHANGED
|
@@ -15,10 +15,11 @@ module Recourse
|
|
|
15
15
|
ActionDispatch::Routing::Mapper.include Scopes, Routes
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
# `/counties.map`
|
|
19
|
-
# HTML: without
|
|
18
|
+
# `/counties.map` and `/shifts.cal` are the same page in another shape, so each
|
|
19
|
+
# format is a name for HTML: without one Rails has no type for the extension and
|
|
20
|
+
# answers 406.
|
|
20
21
|
initializer 'recourse.formats' do
|
|
21
|
-
Mime::Type.register_alias 'text/html',
|
|
22
|
+
SHAPES.each { |shape| Mime::Type.register_alias 'text/html', shape }
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# The grid a table of events is read as: the seven days across it, the hours down
|
|
4
|
+
# it, and how tall the whole of it stands. What the week is called is `Weeks`.
|
|
5
|
+
module Calendars
|
|
6
|
+
# The hours a week with nothing in it draws: a working day, which is what a
|
|
7
|
+
# reader moving through empty weeks has to place the next one's rows against.
|
|
8
|
+
DEFAULT_HOURS = (8...18)
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
# The seven days the grid draws, Sunday first.
|
|
13
|
+
def calendar_days(week) = week..(week + 6)
|
|
14
|
+
|
|
15
|
+
# A day's heading, `Sun, Aug 30`, and today's said louder — the one column a reader
|
|
16
|
+
# is looking for before they read a single row.
|
|
17
|
+
def calendar_day_title(day)
|
|
18
|
+
tag.span l(day, format: :recourse_day),
|
|
19
|
+
class: day == Time.zone.today ? 'fw-semibold' : 'fg-2'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# How tall the grid stands, whatever hours it draws, and why the figure is stated
|
|
23
|
+
# here: a table's own first page is `LIMITS.first` rows, so a grid that height
|
|
24
|
+
# leaves the weeks under a calendar where the pages under a table already are. A
|
|
25
|
+
# row is its line box, the two paddings a cell keeps — Bootstrap's
|
|
26
|
+
# `--bs-table-cell-padding-y`, which is declared inside a table and nowhere a
|
|
27
|
+
# calendar could read it — and the rule under it.
|
|
28
|
+
def calendar_grid_style
|
|
29
|
+
"height: calc(#{Recourse::LIMITS.first} * (1em * var(--bs-body-line-height) + " \
|
|
30
|
+
'1rem + var(--bs-border-width)))'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The hours the grid runs between, one band of that height each. Remembered per
|
|
34
|
+
# render: every one of the eight columns asks, and a page draws one grid.
|
|
35
|
+
def calendar_hours(recourses)
|
|
36
|
+
@recourse_hours ||= hours_of recourses
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# From the hour the week's earliest row opens in to the one its latest closes
|
|
40
|
+
# in, so a week of evenings is a grid of evenings rather than a day of empty
|
|
41
|
+
# bands. `blank?` and not `empty?`: the rows are about to be drawn either way.
|
|
42
|
+
def hours_of(recourses)
|
|
43
|
+
return DEFAULT_HOURS if recourses.blank?
|
|
44
|
+
|
|
45
|
+
minutes = recourses.map { |one| event_minutes one }
|
|
46
|
+
|
|
47
|
+
(minutes.map(&:first).min / 60)...(minutes.map(&:last).max / 60.0).ceil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# An hour of the scale, `9am`, read off a clock rather than named in Ruby: which
|
|
51
|
+
# words those are is a locale's to say, like every other time on the page.
|
|
52
|
+
def calendar_hour_title(hour) = l(Time.zone.now.change(hour:), format: :recourse_hour)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# What a calendar draws of one row: the lane it is given where a day's rows overlap,
|
|
4
|
+
# and what it says once it has one. Where it is placed is `Spans`.
|
|
5
|
+
module Events
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# One day's rows, in the lanes that day needed: a row takes the first lane whose
|
|
9
|
+
# last row has closed, so rows that overlap stand side by side. The lanes are
|
|
10
|
+
# counted over the whole day rather than over each run of overlaps — a column is
|
|
11
|
+
# a day, and two days are read against each other.
|
|
12
|
+
def calendar_events(recourses, day, hours)
|
|
13
|
+
lanes = []
|
|
14
|
+
placed = recourses.select { |one| opens_on? one, day }
|
|
15
|
+
.map { |one| [one, take_lane(one, lanes)] }
|
|
16
|
+
|
|
17
|
+
safe_join(placed.map { |one, lane| event_chip one, hours, lane, lanes.size })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def opens_on?(recourse, day) = recourse.attributes[Recourse::START_COLUMN].to_date == day
|
|
21
|
+
|
|
22
|
+
# The first lane free by the time this row opens, or one of its own, with the
|
|
23
|
+
# minute it closes at left in it for whatever comes next.
|
|
24
|
+
def take_lane(recourse, lanes)
|
|
25
|
+
opening, closing = event_minutes recourse
|
|
26
|
+
lane = lanes.index { |taken| taken <= opening } || lanes.size
|
|
27
|
+
lanes[lane] = closing
|
|
28
|
+
|
|
29
|
+
lane
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# One row, placed by the hours it runs between and saying what it is.
|
|
33
|
+
def event_chip(recourse, hours, lane, lanes)
|
|
34
|
+
tag.div event_words(recourse),
|
|
35
|
+
class: 'position-absolute overflow-hidden small rounded border bg-1 px-1',
|
|
36
|
+
style: event_style(recourse, hours, lane, lanes)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# What it says, a line each: its own label, whoever it is for, and the hours. In
|
|
40
|
+
# that order because a chip is as tall as the row is long — an hour at the foot of
|
|
41
|
+
# a full week is two lines — so what is clipped first is what the grid itself has
|
|
42
|
+
# already said.
|
|
43
|
+
def event_words(recourse)
|
|
44
|
+
label = led Recourse.record_title(recourse), resource_model.name, recourse.id
|
|
45
|
+
named = event_references recourse
|
|
46
|
+
|
|
47
|
+
safe_join [
|
|
48
|
+
tag.div(label, class: 'text-truncate'),
|
|
49
|
+
named && tag.div(named, class: 'fg-2 text-truncate'),
|
|
50
|
+
tag.div(event_times(recourse), class: 'fg-2 text-truncate'),
|
|
51
|
+
].compact
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Whoever the row points at, each led to its own page: a shift is read as whose
|
|
55
|
+
# it is after it is read as what it is. Every `belongs_to` the model can follow,
|
|
56
|
+
# and the same label a table's own cell would draw for it — already loaded, since
|
|
57
|
+
# the index eager-loads every one of them.
|
|
58
|
+
def event_references(recourse)
|
|
59
|
+
named = resource_model.recourse_references.filter_map do |association|
|
|
60
|
+
named_cell recourse, association
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
safe_join named, ' · ' if named.any?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The two ends of a row, each carrying what a machine reads, like every other
|
|
67
|
+
# time on these pages.
|
|
68
|
+
def event_times(recourse)
|
|
69
|
+
ends = Recourse::EVENT_COLUMNS.filter_map do |column|
|
|
70
|
+
value = recourse.attributes[column]
|
|
71
|
+
|
|
72
|
+
time_tag value, l(value, format: :recourse_time) if value
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
safe_join ends, '–'
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
module Recourse
|
|
2
2
|
module Helpers
|
|
3
|
-
# The map a table of places is read as
|
|
4
|
-
#
|
|
3
|
+
# The map a table of places is read as. Which shapes a page has and the links
|
|
4
|
+
# between them are `Shapes`, since a map is only one of them.
|
|
5
5
|
module Maps
|
|
6
6
|
private
|
|
7
7
|
|
|
8
|
-
# Whether this page is the map rather than the table.
|
|
9
|
-
def map_view? = request.format.map?
|
|
10
|
-
|
|
11
|
-
# The link under the rows to the other shape of the page, or nothing where the
|
|
12
|
-
# model keeps neither a place nor a point to draw one by. The query goes with it —
|
|
13
|
-
# the search, the sort and the page — so the map shows the rows the table did.
|
|
14
|
-
def view_link
|
|
15
|
-
return unless Recourse.mappable? resource_model
|
|
16
|
-
|
|
17
|
-
params = request.query_parameters
|
|
18
|
-
return link_to t('recourse.as_table'), url_for(params.merge(format: nil)) if map_view?
|
|
19
|
-
|
|
20
|
-
link_to t('recourse.as_map'), url_for(params.merge(format: :map))
|
|
21
|
-
end
|
|
22
|
-
|
|
23
8
|
# What the map controller needs: the key and the map from the host's credentials,
|
|
24
9
|
# and this page's rows as the places or the points they keep.
|
|
25
10
|
def map_data(recourses)
|
|
@@ -24,11 +24,20 @@ module Recourse
|
|
|
24
24
|
filters = resource_filter_fields
|
|
25
25
|
return if field.blank? && filters.empty?
|
|
26
26
|
|
|
27
|
-
render 'recourses/search', query: resource_search, url:
|
|
27
|
+
render 'recourses/search', query: resource_search, url: search_url,
|
|
28
28
|
field: field, prompt: resource_search_prompt,
|
|
29
29
|
filters: filters, sort: sort_param
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Where the form submits: this page's own shape, so a filter picked on the map or
|
|
33
|
+
# on the calendar answers with the map or the calendar. Only a shape's format goes
|
|
34
|
+
# into the address — the table is the page at its own, with no extension at all.
|
|
35
|
+
def search_url
|
|
36
|
+
format = request.format.symbol
|
|
37
|
+
|
|
38
|
+
url_for action: :index, format: (format if Recourse::SHAPES.include? format)
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
# The model's search field, less the reach-through a nested route already
|
|
33
42
|
# answered: a page pinned to one provider offers no box to search them all.
|
|
34
43
|
def resource_search_field
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# The shapes one page of rows can be read in — a table, a map of where they are, a
|
|
4
|
+
# calendar of when they are — and the links from the one showing to the others.
|
|
5
|
+
module Shapes
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Whether this page is the map rather than the table.
|
|
9
|
+
def map_view? = request.format.map?
|
|
10
|
+
|
|
11
|
+
# Whether this page is the calendar rather than the table.
|
|
12
|
+
def calendar_view? = request.format.cal?
|
|
13
|
+
|
|
14
|
+
# What this page can be, by the format each shape is addressed as and the word
|
|
15
|
+
# the link to it reads: the table every model has, and whichever of the other
|
|
16
|
+
# two the model's own columns earn.
|
|
17
|
+
def view_shapes
|
|
18
|
+
model = resource_model
|
|
19
|
+
shapes = { html: 'recourse.as_table' }
|
|
20
|
+
shapes[:map] = 'recourse.as_map' if Recourse.mappable? model
|
|
21
|
+
shapes[:cal] = 'recourse.as_calendar' if Recourse.calendarable? model
|
|
22
|
+
|
|
23
|
+
shapes
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# A link to each shape the page is not in, carrying the query it was asked with —
|
|
27
|
+
# the search, the sort and the page — so another shape shows the rows the table
|
|
28
|
+
# did. The week stays behind: only a calendar has one, and a calendar reached
|
|
29
|
+
# from the table opens on this week.
|
|
30
|
+
def view_links
|
|
31
|
+
shapes = view_shapes
|
|
32
|
+
query = request.query_parameters.except 'week'
|
|
33
|
+
|
|
34
|
+
# The table is the page at its own address, which is the one shape asked for by
|
|
35
|
+
# carrying no extension at all.
|
|
36
|
+
shapes.except(request.format.symbol).map do |shape, key|
|
|
37
|
+
link_to t(key), url_for(query.merge(format: (shape unless shape == :html)))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# How much of a day one row takes, and where in the grid that puts it. Every figure
|
|
4
|
+
# here is minutes on the way in and a share of the grid on the way out, so a row and
|
|
5
|
+
# the hours behind it agree however tall an hour is drawn.
|
|
6
|
+
module Spans
|
|
7
|
+
# Minutes in a day, which is where a row running into the next one stops: a
|
|
8
|
+
# calendar draws a row on the day it opens, and a block past the foot of its
|
|
9
|
+
# column would be drawn over the week.
|
|
10
|
+
DAY_MINUTES = 1440
|
|
11
|
+
|
|
12
|
+
# And the least a row may be drawn as, so one nobody gave a length to is still
|
|
13
|
+
# something to read and to click rather than a line.
|
|
14
|
+
LEAST_MINUTES = 15
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Where the row sits: how far down the grid it opens, how much of the grid it
|
|
19
|
+
# takes, and which lane of its day it was given.
|
|
20
|
+
def event_style(recourse, hours, lane, lanes)
|
|
21
|
+
width = 100.0 / lanes
|
|
22
|
+
shares = event_shares(recourse, hours).merge left: lane * width, width: width
|
|
23
|
+
|
|
24
|
+
shares.map { |side, share| "#{side}: #{share.round 2}%" }.join '; '
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# The two the hours decide: everything above the row, and the row itself.
|
|
28
|
+
def event_shares(recourse, hours)
|
|
29
|
+
opening, closing = event_minutes recourse
|
|
30
|
+
minutes = hours.count * 60.0
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
top: (opening - (hours.first * 60)) * 100 / minutes,
|
|
34
|
+
height: (closing - opening) * 100 / minutes,
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# When a row opens and closes, as minutes from the midnight of the day it opens
|
|
39
|
+
# on — the two figures every measurement above is made from.
|
|
40
|
+
def event_minutes(recourse)
|
|
41
|
+
opening = recourse.attributes[Recourse::START_COLUMN]
|
|
42
|
+
opened = minute_of opening
|
|
43
|
+
|
|
44
|
+
[opened, [closing_minute(opening, recourse), opened + LEAST_MINUTES].max]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Midnight for a row that runs into the next day, and for one nothing has closed
|
|
48
|
+
# yet — an end nobody has written is a row still open rather than one over at once.
|
|
49
|
+
def closing_minute(opening, recourse)
|
|
50
|
+
closing = recourse.attributes[Recourse::FINISH_COLUMN]
|
|
51
|
+
return DAY_MINUTES if closing.nil? || closing.to_date != opening.to_date
|
|
52
|
+
|
|
53
|
+
minute_of closing
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def minute_of(value) = (value.hour * 60) + value.min
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# What a week is called, and the ways out of one into the next.
|
|
4
|
+
module Weeks
|
|
5
|
+
# The four ways out of a week, in the order they stand, each as the weeks it moves
|
|
6
|
+
# and the arrow it is drawn as. The outer pair jump four weeks, which is a month as
|
|
7
|
+
# near as a grid drawn in weeks can hold one.
|
|
8
|
+
WEEK_STEPS = {
|
|
9
|
+
previous_weeks: [-4, '<<'], previous_week: [-1, '<'],
|
|
10
|
+
next_week: [1, '>'], next_weeks: [4, '>>'],
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# The week the grid draws, named as the two days it runs between: `September 13th
|
|
16
|
+
# – September 19th, 2026`. The year is said once, at the end, being the one thing
|
|
17
|
+
# the two ends of a week almost always agree about.
|
|
18
|
+
def week_title(week)
|
|
19
|
+
finish = week + 6
|
|
20
|
+
|
|
21
|
+
t 'recourse.week', from: week_day(week), to: week_day(finish), year: finish.year
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def week_day(day) = "#{l day, format: :recourse_month} #{day.day.ordinalize}"
|
|
25
|
+
|
|
26
|
+
# The ways out of a week, drawn as a table's pages are drawn — pagy's own markup,
|
|
27
|
+
# down to the arrows and to the item it leaves unlinked — with the week showing
|
|
28
|
+
# named in the middle, where pagy names the page.
|
|
29
|
+
def week_links(week)
|
|
30
|
+
shown = tag.a week_title(week), role: :link, class: 'page-link',
|
|
31
|
+
aria: { current: :page, disabled: true }
|
|
32
|
+
|
|
33
|
+
safe_join [
|
|
34
|
+
week_step(week, :previous_weeks), week_step(week, :previous_week),
|
|
35
|
+
tag.li(shown, class: 'page-item active'),
|
|
36
|
+
week_step(week, :next_week), week_step(week, :next_weeks),
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# One step: its own arrow, and the words behind it for a reader who is hearing
|
|
41
|
+
# the page rather than seeing it. The query goes with the week, so a search or a
|
|
42
|
+
# filter stands while the weeks move under it.
|
|
43
|
+
def week_step(week, key)
|
|
44
|
+
weeks, arrow = WEEK_STEPS[key]
|
|
45
|
+
query = request.query_parameters.merge week: (week + weeks.weeks).to_s
|
|
46
|
+
step = link_to arrow, url_for(query.merge(format: :cal)),
|
|
47
|
+
class: 'page-link', aria: { label: t("recourse.#{key}") }
|
|
48
|
+
|
|
49
|
+
tag.li step, class: "page-item #{weeks.negative? ? 'previous' : 'next'}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/recourse/helpers.rb
CHANGED
|
@@ -3,6 +3,7 @@ require_relative 'helpers/attachments'
|
|
|
3
3
|
require_relative 'helpers/blobs'
|
|
4
4
|
require_relative 'helpers/bookmarks'
|
|
5
5
|
require_relative 'helpers/buttons'
|
|
6
|
+
require_relative 'helpers/calendars'
|
|
6
7
|
require_relative 'helpers/cards'
|
|
7
8
|
require_relative 'helpers/cells'
|
|
8
9
|
require_relative 'helpers/choices'
|
|
@@ -13,6 +14,7 @@ require_relative 'helpers/counters'
|
|
|
13
14
|
require_relative 'helpers/deletions'
|
|
14
15
|
require_relative 'helpers/densities'
|
|
15
16
|
require_relative 'helpers/details'
|
|
17
|
+
require_relative 'helpers/events'
|
|
16
18
|
require_relative 'helpers/examples'
|
|
17
19
|
require_relative 'helpers/fields'
|
|
18
20
|
require_relative 'helpers/filters'
|
|
@@ -34,25 +36,28 @@ require_relative 'helpers/routing'
|
|
|
34
36
|
require_relative 'helpers/rows'
|
|
35
37
|
require_relative 'helpers/themes'
|
|
36
38
|
require_relative 'helpers/searches'
|
|
39
|
+
require_relative 'helpers/shapes'
|
|
37
40
|
require_relative 'helpers/shortcuts'
|
|
38
41
|
require_relative 'helpers/sidebars'
|
|
39
42
|
require_relative 'helpers/sorts'
|
|
43
|
+
require_relative 'helpers/spans'
|
|
40
44
|
require_relative 'helpers/tabs'
|
|
41
45
|
require_relative 'helpers/times'
|
|
42
46
|
require_relative 'helpers/values'
|
|
47
|
+
require_relative 'helpers/weeks'
|
|
43
48
|
require_relative 'helpers/zones'
|
|
44
49
|
|
|
45
50
|
module Recourse
|
|
46
51
|
# View helpers for the pages the gem renders, and what the parts share.
|
|
47
52
|
module Helpers
|
|
48
|
-
include Actions, Attachments, Blobs, Bookmarks, Buttons, Cards,
|
|
53
|
+
include Actions, Attachments, Blobs, Bookmarks, Buttons, Calendars, Cards,
|
|
49
54
|
Cells, Choices, Colors, Comboboxes, Constraints, Counters, Deletions, Densities,
|
|
50
55
|
Details,
|
|
51
|
-
Examples, Fields, Filters, Flashes, Formats, Inputs, Kinds, Limits, Maps,
|
|
56
|
+
Events, Examples, Fields, Filters, Flashes, Formats, Inputs, Kinds, Limits, Maps,
|
|
52
57
|
Names, Navigation, Parents, Pictures, Previews, References, Refreshes,
|
|
53
58
|
Routing,
|
|
54
|
-
Resources, Rows, Searches, Shortcuts, Sidebars, Sorts,
|
|
55
|
-
Times, Values, Zones
|
|
59
|
+
Resources, Rows, Searches, Shapes, Shortcuts, Sidebars, Sorts, Spans, Tabs,
|
|
60
|
+
Themes, Times, Values, Weeks, Zones
|
|
56
61
|
|
|
57
62
|
# The grid a record's own two pages lay an attribute out in: two columns on a large
|
|
58
63
|
# viewport, and the same padding on both, so a value and the field that edits it sit
|
data/lib/recourse/themes.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Recourse
|
|
|
25
25
|
# Where the palettes are served from, named once: the layout links one, the layout's
|
|
26
26
|
# own script puts back the one a reader chose, and the sidebar's controller swaps it.
|
|
27
27
|
# The version is the one the layout links its stylesheet and script at.
|
|
28
|
-
THEMES_PATH = 'https://
|
|
28
|
+
THEMES_PATH = 'https://cdn.jsdelivr.net/npm/houseaccount@0.11.0/public/theme'
|
|
29
29
|
|
|
30
30
|
# Where a reader's chosen palette and mode are kept in their browser. Named once for
|
|
31
31
|
# the same reason: the sidebar's controller writes it and the layout reads it back.
|
data/lib/recourse/version.rb
CHANGED
data/lib/recourse.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative 'recourse/version'
|
|
|
7
7
|
require_relative 'recourse/attachments'
|
|
8
8
|
require_relative 'recourse/blobs'
|
|
9
9
|
require_relative 'recourse/bookmarks'
|
|
10
|
+
require_relative 'recourse/calendars'
|
|
10
11
|
require_relative 'recourse/colors'
|
|
11
12
|
require_relative 'recourse/columns'
|
|
12
13
|
require_relative 'recourse/themes'
|
|
@@ -35,6 +36,11 @@ module Recourse
|
|
|
35
36
|
# them. Named once: three places ask which columns these are.
|
|
36
37
|
TIMESTAMPS = %w[created_at updated_at].freeze
|
|
37
38
|
|
|
39
|
+
# The shapes a page of rows takes besides the table, by the format each is asked
|
|
40
|
+
# for. Every one of them is the same HTML drawn another way, which is why none has
|
|
41
|
+
# a template of its own and all three answer to one controller action.
|
|
42
|
+
SHAPES = %i[map cal].freeze
|
|
43
|
+
|
|
38
44
|
class << self
|
|
39
45
|
# Resources `recourses` has drawn, in the order config/routes.rb lists them.
|
|
40
46
|
attr_reader :declared
|
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: 5.
|
|
4
|
+
version: 5.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- claudiob
|
|
@@ -130,12 +130,14 @@ files:
|
|
|
130
130
|
- app/controllers/concerns/recourse/parent_resolution.rb
|
|
131
131
|
- app/controllers/concerns/recourse/reference_resolution.rb
|
|
132
132
|
- app/controllers/concerns/recourse/resource_resolution.rb
|
|
133
|
+
- app/controllers/concerns/recourse/weeks.rb
|
|
133
134
|
- app/controllers/concerns/recourse/zoning.rb
|
|
134
135
|
- app/controllers/recourse/base_controller.rb
|
|
135
136
|
- app/controllers/recourse/bookmarks_controller.rb
|
|
136
137
|
- app/controllers/recourses_controller.rb
|
|
137
138
|
- app/views/layouts/recourses.html.erb
|
|
138
139
|
- app/views/recourses/_breadcrumb.html.erb
|
|
140
|
+
- app/views/recourses/_calendar.html.erb
|
|
139
141
|
- app/views/recourses/_card.html.erb
|
|
140
142
|
- app/views/recourses/_color.html.erb
|
|
141
143
|
- app/views/recourses/_combobox.html.erb
|
|
@@ -152,6 +154,7 @@ files:
|
|
|
152
154
|
- app/views/recourses/_sidebar.html.erb
|
|
153
155
|
- app/views/recourses/_table.html.erb
|
|
154
156
|
- app/views/recourses/_values.html.erb
|
|
157
|
+
- app/views/recourses/_week.html.erb
|
|
155
158
|
- app/views/recourses/edit.html.erb
|
|
156
159
|
- app/views/recourses/index.html.erb
|
|
157
160
|
- app/views/recourses/new.html.erb
|
|
@@ -162,6 +165,7 @@ files:
|
|
|
162
165
|
- lib/recourse/blobs.rb
|
|
163
166
|
- lib/recourse/bookmarks.rb
|
|
164
167
|
- lib/recourse/broadcasting.rb
|
|
168
|
+
- lib/recourse/calendars.rb
|
|
165
169
|
- lib/recourse/colors.rb
|
|
166
170
|
- lib/recourse/columns.rb
|
|
167
171
|
- lib/recourse/controllers.rb
|
|
@@ -173,6 +177,7 @@ files:
|
|
|
173
177
|
- lib/recourse/helpers/blobs.rb
|
|
174
178
|
- lib/recourse/helpers/bookmarks.rb
|
|
175
179
|
- lib/recourse/helpers/buttons.rb
|
|
180
|
+
- lib/recourse/helpers/calendars.rb
|
|
176
181
|
- lib/recourse/helpers/cards.rb
|
|
177
182
|
- lib/recourse/helpers/cells.rb
|
|
178
183
|
- lib/recourse/helpers/choices.rb
|
|
@@ -183,6 +188,7 @@ files:
|
|
|
183
188
|
- lib/recourse/helpers/deletions.rb
|
|
184
189
|
- lib/recourse/helpers/densities.rb
|
|
185
190
|
- lib/recourse/helpers/details.rb
|
|
191
|
+
- lib/recourse/helpers/events.rb
|
|
186
192
|
- lib/recourse/helpers/examples.rb
|
|
187
193
|
- lib/recourse/helpers/fields.rb
|
|
188
194
|
- lib/recourse/helpers/filters.rb
|
|
@@ -203,13 +209,16 @@ files:
|
|
|
203
209
|
- lib/recourse/helpers/routing.rb
|
|
204
210
|
- lib/recourse/helpers/rows.rb
|
|
205
211
|
- lib/recourse/helpers/searches.rb
|
|
212
|
+
- lib/recourse/helpers/shapes.rb
|
|
206
213
|
- lib/recourse/helpers/shortcuts.rb
|
|
207
214
|
- lib/recourse/helpers/sidebars.rb
|
|
208
215
|
- lib/recourse/helpers/sorts.rb
|
|
216
|
+
- lib/recourse/helpers/spans.rb
|
|
209
217
|
- lib/recourse/helpers/tabs.rb
|
|
210
218
|
- lib/recourse/helpers/themes.rb
|
|
211
219
|
- lib/recourse/helpers/times.rb
|
|
212
220
|
- lib/recourse/helpers/values.rb
|
|
221
|
+
- lib/recourse/helpers/weeks.rb
|
|
213
222
|
- lib/recourse/helpers/zones.rb
|
|
214
223
|
- lib/recourse/icons.rb
|
|
215
224
|
- lib/recourse/limits.rb
|