spina-admin-journal 0.6.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -48
  3. data/app/assets/config/spina_admin_journal_manifest.js +1 -2
  4. data/app/assets/javascripts/spina/admin/journal/application.js +0 -0
  5. data/app/components/spina/admin/journal/affiliations_list_component.rb +32 -0
  6. data/app/components/spina/admin/journal/application_component.rb +11 -0
  7. data/app/components/spina/admin/journal/articles_list_component.rb +54 -0
  8. data/app/components/spina/admin/journal/authors_list_component.rb +37 -0
  9. data/app/components/spina/admin/journal/authorships_list_component.rb +45 -0
  10. data/app/components/spina/admin/journal/empty_list_component.html.haml +1 -0
  11. data/app/components/spina/admin/journal/empty_list_component.rb +14 -0
  12. data/app/components/spina/admin/journal/form_group_component.html.haml +4 -0
  13. data/app/components/spina/admin/journal/form_group_component.rb +17 -0
  14. data/app/components/spina/admin/journal/institutions_list_component.rb +32 -0
  15. data/app/components/spina/admin/journal/issues_list_component.rb +47 -0
  16. data/app/components/spina/admin/journal/licences_list_component.rb +32 -0
  17. data/app/components/spina/admin/journal/list_component.html.haml +11 -0
  18. data/app/components/spina/admin/journal/list_component.rb +22 -0
  19. data/app/components/spina/admin/journal/list_item_component.html.haml +17 -0
  20. data/app/components/spina/admin/journal/list_item_component.rb +23 -0
  21. data/app/components/spina/admin/journal/volumes_list_component.rb +34 -0
  22. data/app/controllers/spina/admin/journal/application_controller.rb +1 -1
  23. data/app/controllers/spina/admin/journal/articles_controller.rb +18 -24
  24. data/app/controllers/spina/admin/journal/authors_controller.rb +18 -26
  25. data/app/controllers/spina/admin/journal/institutions_controller.rb +13 -5
  26. data/app/controllers/spina/admin/journal/issues_controller.rb +20 -27
  27. data/app/controllers/spina/admin/journal/journals_controller.rb +4 -1
  28. data/app/controllers/spina/admin/journal/licences_controller.rb +8 -4
  29. data/app/controllers/spina/admin/journal/volumes_controller.rb +16 -21
  30. data/app/models/spina/admin/journal/author.rb +1 -0
  31. data/app/models/spina/admin/journal/authorship.rb +9 -0
  32. data/app/views/spina/admin/hooks/journal/_primary_navigation.html.haml +35 -26
  33. data/app/views/spina/admin/journal/articles/_form.html.haml +23 -23
  34. data/app/views/spina/admin/journal/articles/_form_authors.html.haml +3 -15
  35. data/app/views/spina/admin/journal/articles/_form_details.html.haml +37 -56
  36. data/app/views/spina/admin/journal/articles/index.html.haml +7 -17
  37. data/app/views/spina/admin/journal/articles/view_authors.html.haml +2 -0
  38. data/app/views/spina/admin/journal/authors/_form.html.haml +24 -24
  39. data/app/views/spina/admin/journal/authors/_form_affiliation.html.haml +12 -20
  40. data/app/views/spina/admin/journal/authors/_form_articles.html.haml +3 -18
  41. data/app/views/spina/admin/journal/authors/_form_details.html.haml +27 -5
  42. data/app/views/spina/admin/journal/authors/index.html.haml +7 -15
  43. data/app/views/spina/admin/journal/authors/view_articles.html.haml +2 -0
  44. data/app/views/spina/admin/journal/institutions/_form.html.haml +24 -24
  45. data/app/views/spina/admin/journal/institutions/_form_details.html.haml +3 -8
  46. data/app/views/spina/admin/journal/institutions/_form_view_affiliations.html.haml +3 -10
  47. data/app/views/spina/admin/journal/institutions/index.html.haml +7 -15
  48. data/app/views/spina/admin/journal/institutions/view_affiliations.html.haml +2 -0
  49. data/app/views/spina/admin/journal/issues/_form.html.haml +23 -23
  50. data/app/views/spina/admin/journal/issues/_form_articles.html.haml +3 -14
  51. data/app/views/spina/admin/journal/issues/_form_details.html.haml +14 -28
  52. data/app/views/spina/admin/journal/issues/index.html.haml +7 -16
  53. data/app/views/spina/admin/journal/issues/view_articles.html.haml +3 -0
  54. data/app/views/spina/admin/journal/journals/_form.html.haml +22 -30
  55. data/app/views/spina/admin/journal/licences/_form.html.haml +24 -37
  56. data/app/views/spina/admin/journal/licences/index.html.haml +7 -16
  57. data/app/views/spina/admin/journal/volumes/_form.html.haml +25 -12
  58. data/app/views/spina/admin/journal/volumes/_form_details.html.haml +5 -10
  59. data/app/views/spina/admin/journal/volumes/_form_issues.html.haml +2 -13
  60. data/app/views/spina/admin/journal/volumes/index.html.haml +7 -16
  61. data/app/views/spina/admin/journal/volumes/view_issues.html.haml +2 -0
  62. data/app/views/spina/admin/parts/admin/journal/page_ranges/_form.html.haml +3 -4
  63. data/config/locales/en.yml +70 -8
  64. data/config/routes.rb +26 -6
  65. data/db/migrate/20220130171603_add_orcid_to_spina_admin_journal_author.rb +7 -0
  66. data/lib/spina/admin/journal/engine.rb +12 -0
  67. data/lib/spina/admin/journal/version.rb +1 -1
  68. data/lib/spina/admin/journal.rb +1 -0
  69. metadata +53 -63
  70. data/app/assets/javascripts/spina/admin/journal/application.es6 +0 -72
  71. data/app/views/layouts/spina/admin/journal/articles.html.haml +0 -10
  72. data/app/views/layouts/spina/admin/journal/authors.html.haml +0 -10
  73. data/app/views/layouts/spina/admin/journal/institutions.html.haml +0 -10
  74. data/app/views/layouts/spina/admin/journal/issues.html.haml +0 -10
  75. data/app/views/layouts/spina/admin/journal/journals.html.haml +0 -10
  76. data/app/views/layouts/spina/admin/journal/licences.html.haml +0 -10
  77. data/app/views/layouts/spina/admin/journal/volumes.html.haml +0 -10
  78. data/app/views/spina/admin/journal/affiliations/_affiliation.html.haml +0 -8
  79. data/app/views/spina/admin/journal/application/_empty_list.html.haml +0 -3
  80. data/app/views/spina/admin/journal/articles/_article.html.haml +0 -10
  81. data/app/views/spina/admin/journal/authors/_author.html.haml +0 -8
  82. data/app/views/spina/admin/journal/authorships/_authorship.html.haml +0 -9
  83. data/app/views/spina/admin/journal/institutions/_institution.html.haml +0 -9
  84. data/app/views/spina/admin/journal/issues/_issue.html.haml +0 -9
  85. data/app/views/spina/admin/journal/journals/index.html.haml +0 -27
  86. data/app/views/spina/admin/journal/licences/_licence.html.haml +0 -11
  87. data/app/views/spina/admin/journal/volumes/_volume.html.haml +0 -7
  88. data/vendor/assets/javascripts/spina/admin/journal/html5sortable.js +0 -1295
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afadf6fe1f99997005bc61d4c3d31b6a1fd02ea35e400539a6e3f3806010910a
4
- data.tar.gz: 7a4375228d01fa343613e8978860ff64c4ba8b1d3232d439efc71e150cab6d93
3
+ metadata.gz: 6a0055e328c3ad9ed3d723edb02c58062caf6621d4dd0a286021930957f42dd1
4
+ data.tar.gz: 303734e1e4dc5d2c90b45e24d2399872ada559e50ed60571316d35a48fbbd363
5
5
  SHA512:
6
- metadata.gz: 63d5deaf2bc734aafefcbd7ddb814f1593ab18ea6a3653beeadfede9ddb386579107f87147a78d036d9e95e5f1fd868f088a03352de57652b9a30afcc3a2fa58
7
- data.tar.gz: ad6606f902897fc5ffa29d00241c89c1c4cb68a666313e53bc21227e357dd06e760a9d7e011c7f6e1870b6f872327f4052ceacc77c63fbd5745d8ba10bda1800
6
+ metadata.gz: 8efcbe772ec874d7c1c5359b2ae00b62a9fba78af47a270371d3120f2845e11df8c808c3d7d3928ac97682dabb8d6cd5f365dbac94e4989c5da49f825e0c0a86
7
+ data.tar.gz: 0b2012a0505383c60e5fbd92c1c4718f76258032a7d428c0a6292f75dc9d87710fe43cf54ee1cb68fcf0164a8c1592df511174a2102cfb429ff1251ce6d1334d
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Spina::Admin::Journal
2
2
 
3
+ *Journal* is a plugin for [Spina](https://www.spinacms.com/) that provides a fully-fledged journal management package, intended to provide a more streamlined, easy-to-use, modern alternative to [OJS](https://pkp.sfu.ca/ojs/).
4
+
5
+ Spina is a content management system built in [Ruby on Rails](http://rubyonrails.org/). *Journal* augments Spina by providing an admin interface for managing an academic journal.
6
+
3
7
  ![Rails tests](https://github.com/louis-vs/spina-admin-journal/workflows/Verify/badge.svg?branch=master&event=push)
4
8
  [![codecov](https://codecov.io/gh/louis-vs/spina-admin-journal/branch/master/graph/badge.svg?token=9TZ9QGGLAH)](https://codecov.io/gh/louis-vs/spina-admin-journal)
5
9
  [![CodeFactor](https://www.codefactor.io/repository/github/louis-vs/spina-admin-journal/badge)](https://www.codefactor.io/repository/github/louis-vs/spina-admin-journal)
@@ -7,69 +11,48 @@
7
11
  [![Code quality: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/louis-vs/spina-admin-journal.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/louis-vs/spina-admin-journal/context:javascript)
8
12
  [![Inline docs](http://inch-ci.org/github/louis-vs/spina-admin-journal.svg?branch=master)](http://inch-ci.org/github/louis-vs/spina-admin-journal)
9
13
 
10
- *Journal* is a plugin for [Spina](https://www.spinacms.com/), a content management system built in [Ruby on Rails](http://rubyonrails.org/). *Journal* augments Spina by providing an admin interface for managing an academic journal.
11
-
12
- ## Usage
13
-
14
- The plugin adds two menus to Spina's primary navigation:
15
-
16
- * **Journal settings** provides access to global properties of the journal. It is divided into 3 submenus:
17
- * **Journal** allows you to change the name of the journal.
18
- * **Institutions** allows you to add institutions, to which authors can be affiliated.
19
- * **Authors** allows you to add authors, who can then be added to articles.
20
- * The **journal content** menu will be named after the journal as specified in Journal Settings. It provides a means of editing the content of the journal and is divided into three submenus:
21
- * **Volumes** allows you to add and remove volumes of the journal, and edit their respective issues.
22
- * **Issues** allows you to add, edit and remove issues of particular volumes of the journal, and edit their respective articles.
23
- * **Articles** allows you to add, edit and remove articles belonging to particular issues.
14
+ ## Features
24
15
 
25
- The plugin does not provide any public-facing frontend. However, an example implementation can be found at **[TBC]**.
16
+ The journal plugin covers many of the needs of a professional online journal publication, including:
26
17
 
27
- **NB this plugin is currently a work in progress**: please wait until an official release to use this plugin in production.
18
+ - Simple, responsive, intuitive interface that builds upon Spina's own.
19
+ - Seamlessly integrate published content with other information about the journal.
20
+ - Manage volumes, issues, articles and authors in a highly structured and organised manner.
21
+ - Keep track of individual authors with multiple affiliations, e.g. if they change name or institution, connecting with [ORCID](https://orcid.org/).
28
22
 
29
- ## Installation
30
-
31
- ### From scratch
32
-
33
- Make sure you have a working installation of Ruby on Rails 6.1. You can find a setup guide [here](https://guides.rubyonrails.org/getting_started.html).
34
-
35
- Then run:
36
-
37
- ```bash
38
- $ rails new your-app --database=postgresql
39
- $ cd your-app
40
- $ bin/rails db:create
41
- $ bin/rails active_storage:install
42
- ```
23
+ Currently, a submissions management system is not included, but this is planned for a future release. This will allow you to manage the submissions process for the journal in a streamlined manner in parallel to publication.
43
24
 
44
- Add this line to your new application's Gemfile:
25
+ ## Usage
45
26
 
46
- ```ruby
47
- gem 'spina', '~> 2.0'
48
- ```
27
+ The plugin adds two menus to Spina's primary navigation:
49
28
 
50
- And then execute:
29
+ - **Journal settings** provides access to global properties of the journal. It is divided into 3 submenus:
30
+ - **Journal** allows you to change metadata such as the name of the journal, as well as content that will appear on the journal homepage.
31
+ - **Institutions** allows you to add institutions, to which authors can be affiliated.
32
+ - **Authors** allows you to add authors and their affiliations, which can then be added to articles.
33
+ - **Licences** allows you to add licences and association information, which can be associated with individual articles, representing the licence under which the content is released.
34
+ - The **journal content** menu will be named after the journal as specified in Journal Settings. It provides a means of editing the content of the journal and is divided into three submenus:
35
+ - **Volumes** allows you to add and remove volumes of the journal, and edit their respective issues.
36
+ - **Issues** allows you to add, edit and remove issues of particular volumes of the journal, and edit their respective articles.
37
+ - **Articles** allows you to add, edit and remove articles belonging to particular issues.
51
38
 
52
- ```bash
53
- $ bundle install
54
- ```
39
+ **NB:** This release of the plugin does not provide any public-facing frontend or Spina theme. An example implementation can be found within the [Conferences Primer Theme](https://github.com/louis-vs/spina-conferences-primer_theme-fork). Note that this theme also contains frontends for two other Spina plugins, [Spina Conferences Blog](https://github.com/louis-vs/spina-admin-conferences-blog) and [Spina Admin Conferences](https://github.com/louis-vs/spina-admin-conferences-fork/). You can use the theme in your project as is, or copy whichever parts of the code you need.
55
40
 
56
- Run the Spina install generator:
41
+ A dedicated journal theme, coupled with an automatic installer, is being planned. A system to manage submissions is also on the roadmap.
57
42
 
58
- ```bash
59
- $ bin/rails g spina:install
60
- ```
43
+ ## Installation
61
44
 
62
- And follow the prompts. Once this is complete, follow the instructions below.
45
+ Make sure you have a working installation of Ruby on Rails 7. You can find a setup guide [here](https://guides.rubyonrails.org/getting_started.html).
63
46
 
64
- ### For existing Spina installations
47
+ You then need to install Spina, following the guide [on the Spina website](https://spinacms.com/docs).
65
48
 
66
- Add this line to your application's Gemfile:
49
+ To install the plugin, add this line to your application's Gemfile:
67
50
 
68
51
  ```ruby
69
- gem 'spina-admin-journal', '~> 0.1'
52
+ gem 'spina-admin-journal', '~> 1.0'
70
53
  ```
71
54
 
72
- And then execute:
55
+ Then execute:
73
56
 
74
57
  ```bash
75
58
  $ bundle install
@@ -78,7 +61,7 @@ $ bundle install
78
61
  You'll then need to install and run the migrations for the journal:
79
62
 
80
63
  ```bash
81
- $ bin/rails spina_admin_journal_engine:install:migrations
64
+ $ bin/rails spina_admin_journal:install:migrations
82
65
  $ bin/rails db:migrate
83
66
  ```
84
67
 
@@ -94,6 +77,11 @@ You can manually populate the database from within the app, or alternatively you
94
77
 
95
78
  Bug reports and feature requests are welcome in the [Issues](https://github.com/louis-vs/spina-admin-journal/issues) section. Translations are also very welcome!
96
79
 
80
+ ### Planned features
81
+
82
+ - [ ] Submissions management
83
+ - [ ] Translations
84
+
97
85
  ## License
98
86
 
99
87
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,3 +1,2 @@
1
- //= link spina/admin/journal/application.js
2
1
  //= link spina/admin/journal/application.css
3
- //= link spina_manifest.js
2
+ //= link spina/admin/journal/application.js
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of licences. Not sortable.
7
+ class AffiliationsListComponent < ListComponent
8
+ def initialize(affiliations:)
9
+ @affiliations = affiliations
10
+ end
11
+
12
+ def before_render
13
+ @list_items = generate_list_items(@affiliations)
14
+ end
15
+
16
+ def call
17
+ render ListComponent.new(list_items: @list_items, sortable: false)
18
+ end
19
+
20
+ private
21
+
22
+ def generate_list_items(affiliations)
23
+ affiliations.map do |affiliation|
24
+ { id: affiliation.id,
25
+ label: affiliation.reversed_name,
26
+ path: helpers.spina.edit_admin_journal_author_path(affiliation.author) }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # Base class for components.
7
+ class ApplicationComponent < Spina::ApplicationComponent
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of articles. Articles should only be sortable if presented within the contex of an
7
+ # issue.
8
+ class ArticlesListComponent < ListComponent
9
+ attr_reader :sortable
10
+
11
+ def initialize(articles:, sortable: false)
12
+ @articles = articles
13
+ @sortable = sortable
14
+ end
15
+
16
+ def before_render
17
+ @list_items = generate_list_items(@articles)
18
+ end
19
+
20
+ def call
21
+ render ListComponent.new(list_items: @list_items,
22
+ sortable: sortable?,
23
+ sort_path: generate_sort_path)
24
+ end
25
+
26
+ def sortable?
27
+ sortable
28
+ end
29
+
30
+ private
31
+
32
+ def generate_list_items(articles)
33
+ articles.map do |article|
34
+ { id: article.id,
35
+ label: generate_label(article),
36
+ path: helpers.spina.edit_admin_journal_article_path(article.id) }
37
+ end
38
+ end
39
+
40
+ def generate_label(article) # rubocop:disable Metrics/AbcSize
41
+ t('spina.admin.journal.articles.article_number', volume_number: article.issue.volume.number, # rubocop:disable Style/StringConcatenation
42
+ issue_number: article.issue.number,
43
+ article_number: article.number
44
+ ) + ' | ' + t('spina.admin.journal.articles.title_author', title: article.title, # rubocop:disable Layout/MultilineMethodCallBraceLayout Layout/SpaceInsideParens
45
+ author: article.authorships.sorted_within_article.map { |authorship| authorship.affiliation.surname }.join(', ')) # rubocop:disable Layout/LineLength
46
+ end
47
+
48
+ def generate_sort_path
49
+ @articles.any? ? helpers.spina.sort_admin_journal_issues_path(@articles.first.issue.id) : ''
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of authors. Not sortable.
7
+ class AuthorsListComponent < ListComponent
8
+ def initialize(authors:)
9
+ @authors = authors
10
+ end
11
+
12
+ def before_render
13
+ @list_items = generate_list_items(@authors)
14
+ end
15
+
16
+ def call
17
+ render ListComponent.new(list_items: @list_items, sortable: false)
18
+ end
19
+
20
+ private
21
+
22
+ def generate_list_items(authors)
23
+ authors.map do |author|
24
+ { id: author.id,
25
+ label: generate_label(author),
26
+ path: helpers.spina.edit_admin_journal_author_path(author) }
27
+ end
28
+ end
29
+
30
+ def generate_label(author)
31
+ t 'spina.admin.journal.authors.name_institution', name: author.primary_affiliation.name,
32
+ institution: author.primary_affiliation.institution.name
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of authorships. Sortable when displayed in their corresponding article.
7
+ class AuthorshipsListComponent < ListComponent
8
+ attr_reader :sortable
9
+
10
+ def initialize(authorships:, sortable: false)
11
+ @authorships = authorships
12
+ @sortable = sortable
13
+ end
14
+
15
+ def before_render
16
+ @list_items = generate_list_items(@authorships)
17
+ end
18
+
19
+ def call
20
+ render ListComponent.new(list_items: @list_items,
21
+ sortable: sortable?,
22
+ sort_path: generate_sort_path)
23
+ end
24
+
25
+ def sortable?
26
+ sortable
27
+ end
28
+
29
+ private
30
+
31
+ def generate_list_items(authorships)
32
+ authorships.map do |authorship|
33
+ { id: authorship.id,
34
+ label: authorship.affiliation.reversed_name,
35
+ path: helpers.spina.edit_admin_journal_author_path(authorship.affiliation.author) }
36
+ end
37
+ end
38
+
39
+ def generate_sort_path
40
+ @authorships.any? ? helpers.spina.sort_admin_journal_authors_path(@authorships.first.article.id) : ''
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # Displays a message indicating that a {ListComponent} has no items.
7
+ class EmptyListComponent < ApplicationComponent
8
+ def initialize(message: t('spina.admin.journal.empty_list'))
9
+ @message = message
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ .mt-6
2
+ %label.block.text-sm.leading-5.font-medium.text-gray-700= label
3
+ .text-gray-400.text-sm= description
4
+ .mt-1= content
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # Correctly styles label, description and content of form fields.
7
+ class FormGroupComponent < ApplicationComponent
8
+ attr_reader :label, :description
9
+
10
+ def initialize(label:, description: '')
11
+ @label = label
12
+ @description = description
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of institutions. Not sortable.
7
+ class InstitutionsListComponent < ListComponent
8
+ def initialize(institutions:)
9
+ @institutions = institutions
10
+ end
11
+
12
+ def before_render
13
+ @list_items = generate_list_items(@institutions)
14
+ end
15
+
16
+ def call
17
+ render ListComponent.new(list_items: @list_items, sortable: false)
18
+ end
19
+
20
+ private
21
+
22
+ def generate_list_items(institutions)
23
+ institutions.map do |institution|
24
+ { id: institution.id,
25
+ label: institution.name,
26
+ path: helpers.spina.edit_admin_journal_institution_path(institution.id) }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of issues. Issues should only be sortable if presented within the contex of a
7
+ # volume.
8
+ class IssuesListComponent < ListComponent
9
+ attr_reader :sortable
10
+
11
+ def initialize(issues:, sortable: false)
12
+ @issues = issues
13
+ @sortable = sortable
14
+ end
15
+
16
+ def before_render
17
+ @list_items = generate_list_items(@issues)
18
+ end
19
+
20
+ def call
21
+ render ListComponent.new(list_items: @list_items,
22
+ sortable: sortable?,
23
+ sort_path: generate_sort_path)
24
+ end
25
+
26
+ def sortable?
27
+ sortable
28
+ end
29
+
30
+ private
31
+
32
+ def generate_list_items(issues)
33
+ issues.map do |issue|
34
+ { id: issue.id,
35
+ label: t('spina.admin.journal.issues.volume_issue', volume_number: issue.volume.number,
36
+ issue_number: issue.number),
37
+ path: helpers.spina.edit_admin_journal_issue_path(issue.id) }
38
+ end
39
+ end
40
+
41
+ def generate_sort_path
42
+ @issues.any? ? helpers.spina.sort_admin_journal_issues_path(@issues.first.volume.id) : ''
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A list of licences. Not sortable.
7
+ class LicencesListComponent < ListComponent
8
+ def initialize(licences:)
9
+ @licences = licences
10
+ end
11
+
12
+ def before_render
13
+ @list_items = generate_list_items(@licences)
14
+ end
15
+
16
+ def call
17
+ render ListComponent.new(list_items: @list_items, sortable: false)
18
+ end
19
+
20
+ private
21
+
22
+ def generate_list_items(licences)
23
+ licences.map do |licence|
24
+ { id: licence.id,
25
+ label: licence.name,
26
+ path: helpers.spina.edit_admin_journal_licence_path(licence) }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ .my-6.md:m-8
2
+ - if sortable?
3
+ .mb-4.text-gray-600.text-sm= t 'spina.admin.journal.sort_info'
4
+ .bg-white.md:rounded-lg.border-l-0.border-r-0.border.md:border-r.md:border-l.border-gray-200.border-b-0.shadow-sm{ data: { controller: 'sortable' } }
5
+ = form_with(url: @sort_path, data: { sortable_target: 'form' }) { |f| }
6
+ %ul{ data: { sortable_target: 'list' } }
7
+ - if @list_items.any?
8
+ - @list_items.each do |item|
9
+ = render Spina::Admin::Journal::ListItemComponent.new(id: item[:id], label: item[:label], path: item[:path], sortable: sortable?)
10
+ - else
11
+ = render Spina::Admin::Journal::EmptyListComponent.new
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A generic implementation of a list, resembling Spina's page list.
7
+ class ListComponent < ApplicationComponent
8
+ attr_reader :sortable
9
+
10
+ def initialize(list_items:, sortable: false, sort_path: '')
11
+ @sortable = sortable
12
+ @list_items = list_items
13
+ @sort_path = sort_path
14
+ end
15
+
16
+ def sortable?
17
+ sortable
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ %li{data: { id: @id }}
2
+ .flex.items-center.border-gray-200.border-b.bg-opacity-50.w-full
3
+ - if sortable?
4
+ .p-4.text-gray-300.hover:text-gray-600.cursor-move{ data: { 'sortable-handle': true } }
5
+ = helpers.heroicon('menu-alt-4', style: :solid, class: 'w-4 h-4 -mr-4')
6
+
7
+ .flex-auto
8
+ .block.text-spina.font-medium.text-sm.p-4{class: 'hover:text-spina-dark' }
9
+ = link_to @path do
10
+ = @label
11
+
12
+ .flex-1
13
+
14
+ = link_to @path, class: 'btn btn-link mr-4' do
15
+ .flex.flex-nowrap.items-center.px-8.py-1
16
+ = helpers.heroicon 'pencil-alt', style: :outline, class: 'w-4 h-4'
17
+ .ml-2= t 'spina.admin.journal.edit'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A generic list item that is only intended to be called by {ListItemComponent}.
7
+ class ListItemComponent < ApplicationComponent
8
+ attr_reader :sortable
9
+
10
+ def initialize(id:, label:, path:, sortable: false)
11
+ @label = label
12
+ @id = id
13
+ @path = path
14
+ @sortable = sortable
15
+ end
16
+
17
+ def sortable?
18
+ sortable
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Journal
6
+ # A sortable list of volumes.
7
+ class VolumesListComponent < ListComponent
8
+ def initialize(volumes:)
9
+ @volumes = volumes
10
+ end
11
+
12
+ def before_render
13
+ @list_items = generate_list_items(@volumes)
14
+ end
15
+
16
+ def call
17
+ render ListComponent.new(list_items: @list_items,
18
+ sortable: true,
19
+ sort_path: helpers.spina.sort_admin_journal_volumes_path(Journal.instance.id))
20
+ end
21
+
22
+ private
23
+
24
+ def generate_list_items(volumes)
25
+ volumes.map do |volume|
26
+ { id: volume.id,
27
+ label: t('spina.admin.journal.volumes.volume_number', number: volume.number),
28
+ path: helpers.spina.edit_admin_journal_volume_path(volume.id) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -9,7 +9,7 @@ module Spina
9
9
 
10
10
  add_flash_types :success
11
11
 
12
- layout :admin_layout, only: %i[new edit]
12
+ layout :admin_layout
13
13
 
14
14
  before_action :set_locale
15
15