katalyst-koi 4.20.1 → 5.0.0.alpha.1

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.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/koi/icons/add.svg +3 -0
  3. data/app/assets/images/koi/icons/close.svg +1 -0
  4. data/app/assets/images/koi/koi.png +0 -0
  5. data/app/assets/javascripts/koi/controllers/file_field_controller.js +2 -2
  6. data/app/assets/javascripts/koi/controllers/index.js +0 -3
  7. data/app/assets/javascripts/koi/controllers/koi/modal_controller.js +40 -0
  8. data/app/assets/javascripts/koi/controllers/navigation_controller.js +14 -21
  9. data/app/assets/javascripts/koi/controllers/webauthn_authentication_controller.js +12 -13
  10. data/app/assets/javascripts/koi/controllers/webauthn_registration_controller.js +11 -10
  11. data/app/assets/stylesheets/koi/blocks/actions.css +8 -0
  12. data/app/assets/stylesheets/koi/blocks/application-header.css +15 -0
  13. data/app/assets/stylesheets/koi/blocks/application-navigation.css +54 -0
  14. data/app/assets/stylesheets/koi/blocks/button.css +90 -0
  15. data/app/assets/stylesheets/koi/blocks/flash.css +19 -0
  16. data/app/assets/stylesheets/koi/blocks/icon.css +15 -0
  17. data/app/assets/stylesheets/koi/blocks/index.css +13 -0
  18. data/app/assets/stylesheets/koi/blocks/modal.css +26 -0
  19. data/app/assets/stylesheets/koi/blocks/navigation.css +23 -0
  20. data/app/assets/stylesheets/koi/blocks/page-header.css +31 -0
  21. data/app/assets/stylesheets/koi/blocks/pagy.css +82 -0
  22. data/app/assets/stylesheets/koi/blocks/prose.css +37 -0
  23. data/app/assets/stylesheets/koi/blocks/tables/index.css +4 -0
  24. data/app/assets/stylesheets/koi/{components/_query.scss → blocks/tables/query.css} +13 -13
  25. data/app/assets/stylesheets/koi/{base/_tables.scss → blocks/tables/table.css} +11 -59
  26. data/app/assets/stylesheets/koi/compositions/cover.css +17 -0
  27. data/app/assets/stylesheets/koi/{base/_flow.scss → compositions/flow.css} +1 -1
  28. data/app/assets/stylesheets/koi/compositions/index.css +4 -0
  29. data/app/assets/stylesheets/koi/compositions/wrapper.css +11 -0
  30. data/app/assets/stylesheets/koi/forms/caption.css +22 -0
  31. data/app/assets/stylesheets/koi/forms/checkboxes.css +153 -0
  32. data/app/assets/stylesheets/koi/forms/date-input.css +12 -0
  33. data/app/assets/stylesheets/koi/{components/_document-field.scss → forms/document-field.css} +20 -15
  34. data/app/assets/stylesheets/koi/forms/errors.css +38 -0
  35. data/app/assets/stylesheets/koi/forms/fieldset.css +73 -0
  36. data/app/assets/stylesheets/koi/forms/file-upload.css +20 -0
  37. data/app/assets/stylesheets/koi/forms/form-group.css +19 -0
  38. data/app/assets/stylesheets/koi/forms/hint.css +11 -0
  39. data/app/assets/stylesheets/koi/forms/image-field.css +96 -0
  40. data/app/assets/stylesheets/koi/forms/index.css +44 -0
  41. data/app/assets/stylesheets/koi/forms/input.css +194 -0
  42. data/app/assets/stylesheets/koi/forms/label.css +43 -0
  43. data/app/assets/stylesheets/koi/forms/password.css +18 -0
  44. data/app/assets/stylesheets/koi/forms/radios.css +162 -0
  45. data/app/assets/stylesheets/koi/forms/select.css +18 -0
  46. data/app/assets/stylesheets/koi/forms/textarea.css +3 -0
  47. data/app/assets/stylesheets/koi/forms/trix.css +33 -0
  48. data/app/assets/stylesheets/koi/global/fonts.css +22 -0
  49. data/app/assets/stylesheets/koi/global/global-styles.css +297 -0
  50. data/app/assets/stylesheets/koi/global/reset.css +98 -0
  51. data/app/assets/stylesheets/koi/global/variables.css +97 -0
  52. data/app/assets/stylesheets/koi/icons.css +14 -0
  53. data/app/assets/stylesheets/koi/{admin.scss → index.css} +16 -7
  54. data/app/assets/stylesheets/koi/login.css +26 -0
  55. data/app/assets/stylesheets/koi/themes/_index.scss +0 -1
  56. data/app/assets/stylesheets/koi/utilities/index.css +1 -0
  57. data/app/assets/stylesheets/koi/utilities/visually-hidden.css +18 -0
  58. data/app/components/concerns/koi/tables/cells.rb +3 -3
  59. data/app/components/koi/header/edit_component.rb +1 -1
  60. data/app/components/koi/header_component.html.erb +12 -11
  61. data/app/components/koi/header_component.rb +2 -0
  62. data/app/components/koi/table_component.rb +8 -0
  63. data/app/components/koi/tables/cells/link_component.rb +2 -2
  64. data/app/controllers/admin/admin_users_controller.rb +26 -20
  65. data/app/controllers/admin/application_controller.rb +1 -3
  66. data/app/controllers/admin/caches_controller.rb +1 -1
  67. data/app/controllers/admin/credentials_controller.rb +19 -15
  68. data/app/controllers/admin/otps_controller.rb +16 -14
  69. data/app/controllers/admin/sessions_controller.rb +18 -3
  70. data/app/controllers/admin/tokens_controller.rb +4 -2
  71. data/app/controllers/admin/url_rewrites_controller.rb +19 -17
  72. data/app/controllers/admin/well_knowns_controller.rb +20 -18
  73. data/app/controllers/concerns/koi/controller/records_authentication.rb +10 -23
  74. data/app/controllers/concerns/koi/controller.rb +25 -4
  75. data/app/controllers/well_knowns_controller.rb +1 -1
  76. data/app/helpers/koi/form_helper.rb +18 -0
  77. data/app/helpers/koi/header_helper.rb +122 -0
  78. data/app/helpers/koi/index_actions_helper.rb +3 -2
  79. data/app/helpers/koi/modal_helper.rb +71 -0
  80. data/app/models/admin/user.rb +7 -1
  81. data/app/models/url_rewrite.rb +1 -9
  82. data/app/views/admin/admin_users/_form.html+self.erb +8 -0
  83. data/app/views/admin/admin_users/_form.html.erb +8 -0
  84. data/app/views/admin/admin_users/archived.html.erb +7 -4
  85. data/app/views/admin/admin_users/edit.html+self.erb +12 -0
  86. data/app/views/admin/admin_users/edit.html.erb +13 -8
  87. data/app/views/admin/admin_users/index.html.erb +10 -5
  88. data/app/views/admin/admin_users/new.html.erb +8 -8
  89. data/app/views/admin/admin_users/show.html+self.erb +26 -14
  90. data/app/views/admin/admin_users/show.html.erb +22 -20
  91. data/app/views/admin/credentials/_credentials.html+self.erb +8 -6
  92. data/app/views/admin/credentials/_credentials.html.erb +3 -1
  93. data/app/views/admin/credentials/create.turbo_stream.erb +4 -3
  94. data/app/views/admin/credentials/destroy.turbo_stream.erb +4 -2
  95. data/app/views/admin/credentials/new.html.erb +42 -36
  96. data/app/views/admin/dashboards/show.html.erb +13 -1
  97. data/app/views/admin/otps/_form.html.erb +7 -7
  98. data/app/views/admin/otps/create.turbo_stream.erb +3 -3
  99. data/app/views/admin/otps/new.html.erb +5 -3
  100. data/app/views/admin/sessions/new.html.erb +2 -3
  101. data/app/views/admin/sessions/otp.html.erb +1 -3
  102. data/app/views/admin/sessions/password.html.erb +1 -3
  103. data/app/views/admin/tokens/show.html.erb +4 -6
  104. data/app/views/admin/url_rewrites/_form.html.erb +9 -0
  105. data/app/views/admin/url_rewrites/edit.html.erb +13 -9
  106. data/app/views/admin/url_rewrites/index.html.erb +10 -7
  107. data/app/views/admin/url_rewrites/new.html.erb +8 -8
  108. data/app/views/admin/url_rewrites/show.html.erb +17 -12
  109. data/app/views/admin/well_knowns/_form.html.erb +9 -0
  110. data/app/views/admin/well_knowns/edit.html.erb +13 -9
  111. data/app/views/admin/well_knowns/index.html.erb +8 -5
  112. data/app/views/admin/well_knowns/new.html.erb +8 -8
  113. data/app/views/admin/well_knowns/show.html.erb +14 -13
  114. data/app/views/katalyst/content/asides/_aside.html+form.erb +6 -4
  115. data/app/views/katalyst/content/columns/_column.html+form.erb +5 -3
  116. data/app/views/katalyst/content/contents/_content.html+form.erb +8 -6
  117. data/app/views/katalyst/content/figures/_figure.html+form.erb +8 -5
  118. data/app/views/katalyst/content/groups/_group.html+form.erb +5 -3
  119. data/app/views/katalyst/content/items/_item.html+form.erb +5 -3
  120. data/app/views/katalyst/content/sections/_section.html+form.erb +5 -3
  121. data/app/views/katalyst/content/tables/_table.html+form.erb +16 -11
  122. data/app/views/katalyst/navigation/items/_button.html.erb +6 -12
  123. data/app/views/katalyst/navigation/items/_heading.html.erb +3 -10
  124. data/app/views/katalyst/navigation/items/_link.html.erb +6 -11
  125. data/app/views/katalyst/navigation/menus/edit.html.erb +10 -6
  126. data/app/views/katalyst/navigation/menus/index.html.erb +4 -2
  127. data/app/views/katalyst/navigation/menus/new.html.erb +5 -3
  128. data/app/views/katalyst/navigation/menus/show.html.erb +8 -7
  129. data/app/views/layouts/koi/_application_header.html.erb +20 -0
  130. data/app/views/layouts/koi/_application_navigation.html.erb +34 -0
  131. data/app/views/layouts/koi/_flash.html.erb +6 -3
  132. data/app/views/layouts/koi/_navigation_header.html.erb +0 -2
  133. data/app/views/layouts/koi/application.html.erb +22 -27
  134. data/app/views/layouts/koi/frame.html.erb +1 -3
  135. data/app/views/layouts/koi/login.html.erb +12 -5
  136. data/config/importmap.rb +1 -0
  137. data/config/locales/koi.en.yml +9 -1
  138. data/config/locales/pagy.en.yml +11 -0
  139. data/config/routes.rb +1 -1
  140. data/lib/generators/koi/admin/admin_generator.rb +4 -13
  141. data/lib/generators/koi/admin_controller/admin_controller_generator.rb +7 -17
  142. data/lib/generators/koi/admin_controller/templates/controller.rb.tt +82 -18
  143. data/lib/generators/koi/admin_controller/templates/controller_spec.rb.tt +113 -47
  144. data/lib/generators/koi/admin_route/admin_route_generator.rb +63 -10
  145. data/lib/generators/koi/admin_views/USAGE +18 -7
  146. data/lib/generators/koi/admin_views/admin_views_generator.rb +19 -11
  147. data/lib/generators/koi/admin_views/templates/_form.html.erb.tt +8 -0
  148. data/lib/generators/koi/admin_views/templates/archived.html.erb.tt +33 -0
  149. data/lib/generators/koi/admin_views/templates/edit.html.erb.tt +17 -9
  150. data/lib/generators/koi/admin_views/templates/index.html.erb.tt +31 -3
  151. data/lib/generators/koi/admin_views/templates/new.html.erb.tt +8 -8
  152. data/lib/generators/koi/admin_views/templates/show.html.erb.tt +15 -18
  153. data/lib/generators/koi/helpers/attribute_helpers.rb +147 -0
  154. data/lib/generators/koi/helpers/attribute_types.rb +218 -0
  155. data/lib/generators/koi/helpers/resource_helpers.rb +121 -0
  156. data/lib/generators/koi/{active_record/active_record_generator.rb → model/model_generator.rb} +1 -1
  157. data/lib/koi/config.rb +3 -1
  158. data/lib/koi/engine.rb +1 -15
  159. data/lib/koi/form/builder.rb +6 -6
  160. data/lib/koi/form/content.rb +55 -0
  161. data/lib/koi/form/elements/document.rb +1 -1
  162. data/lib/koi/form/elements/file_element.rb +1 -1
  163. data/lib/koi/form/elements/image.rb +1 -1
  164. data/lib/koi/form_builder.rb +1 -0
  165. data/lib/koi/menu.rb +14 -1
  166. data/lib/koi/middleware/admin_authentication.rb +4 -32
  167. data/spec/factories/admins.rb +1 -1
  168. metadata +93 -109
  169. data/app/assets/builds/katalyst/koi.esm.js +0 -518
  170. data/app/assets/builds/katalyst/koi.js +0 -518
  171. data/app/assets/builds/katalyst/koi.min.js +0 -2
  172. data/app/assets/builds/katalyst/koi.min.js.map +0 -1
  173. data/app/assets/builds/koi/admin.css +0 -1
  174. data/app/assets/stylesheets/koi/base/_button.scss +0 -122
  175. data/app/assets/stylesheets/koi/base/_icon.scss +0 -29
  176. data/app/assets/stylesheets/koi/base/_index.scss +0 -21
  177. data/app/assets/stylesheets/koi/base/_input.scss +0 -19
  178. data/app/assets/stylesheets/koi/base/_link.scss +0 -26
  179. data/app/assets/stylesheets/koi/base/_list.scss +0 -11
  180. data/app/assets/stylesheets/koi/base/_typography.scss +0 -160
  181. data/app/assets/stylesheets/koi/components/_actions-group.scss +0 -7
  182. data/app/assets/stylesheets/koi/components/_image-field.scss +0 -95
  183. data/app/assets/stylesheets/koi/components/_index.scss +0 -9
  184. data/app/assets/stylesheets/koi/components/_pagy.scss +0 -30
  185. data/app/assets/stylesheets/koi/components/_summary-list.scss +0 -40
  186. data/app/assets/stylesheets/koi/layouts/_banner.scss +0 -7
  187. data/app/assets/stylesheets/koi/layouts/_content.scss +0 -40
  188. data/app/assets/stylesheets/koi/layouts/_flash.scss +0 -41
  189. data/app/assets/stylesheets/koi/layouts/_header.scss +0 -61
  190. data/app/assets/stylesheets/koi/layouts/_index.scss +0 -48
  191. data/app/assets/stylesheets/koi/layouts/_main.scss +0 -23
  192. data/app/assets/stylesheets/koi/layouts/_navigation.scss +0 -180
  193. data/app/assets/stylesheets/koi/layouts/_stack.scss +0 -13
  194. data/app/assets/stylesheets/koi/pages/_index.scss +0 -1
  195. data/app/assets/stylesheets/koi/pages/_login.scss +0 -46
  196. data/app/assets/stylesheets/koi/themes/_govuk.scss +0 -59
  197. data/app/assets/stylesheets/koi/themes/_kpop.scss +0 -5
  198. data/app/assets/stylesheets/koi/utils/_breakpoints.scss +0 -13
  199. data/app/assets/stylesheets/koi/utils/_hide.scss +0 -11
  200. data/app/assets/stylesheets/koi/utils/_index.scss +0 -2
  201. data/app/assets/stylesheets/koi/utils/_typography.scss +0 -42
  202. data/app/components/koi/content/editor/item_form_component.html.erb +0 -11
  203. data/app/components/koi/content/editor/item_form_component.rb +0 -94
  204. data/app/components/koi/summary_list/attachment_component.rb +0 -47
  205. data/app/components/koi/summary_list/base.rb +0 -59
  206. data/app/components/koi/summary_list/boolean_component.rb +0 -15
  207. data/app/components/koi/summary_list/date_component.rb +0 -17
  208. data/app/components/koi/summary_list/datetime_component.rb +0 -17
  209. data/app/components/koi/summary_list/item_component.rb +0 -26
  210. data/app/components/koi/summary_list/number_component.rb +0 -21
  211. data/app/components/koi/summary_list/rich_text_component.rb +0 -8
  212. data/app/components/koi/summary_list/text_component.rb +0 -8
  213. data/app/components/koi/summary_list_component.html.erb +0 -5
  214. data/app/components/koi/summary_list_component.rb +0 -75
  215. data/app/controllers/concerns/koi/controller/is_admin_controller.rb +0 -77
  216. data/app/helpers/koi/application_helper.rb +0 -7
  217. data/app/helpers/koi/date_helper.rb +0 -26
  218. data/app/helpers/koi/definition_list_helper.rb +0 -10
  219. data/app/views/admin/admin_users/_fields.html+self.erb +0 -3
  220. data/app/views/admin/admin_users/_fields.html.erb +0 -3
  221. data/app/views/admin/url_rewrites/_fields.html.erb +0 -4
  222. data/app/views/admin/well_knowns/_fields.html.erb +0 -6
  223. data/app/views/layouts/koi/_environment.html.erb +0 -4
  224. data/app/views/layouts/koi/_header.html.erb +0 -11
  225. data/app/views/layouts/koi/_navigation.html.erb +0 -23
  226. data/app/views/layouts/koi/_navigation_collapse.html.erb +0 -3
  227. data/config/initializers/dartsass.rb +0 -10
  228. data/config/locales/pagy/en.yml +0 -24
  229. data/db/migrate/20260501000000_add_last_sign_out_at_to_admin_users.rb +0 -7
  230. data/lib/generators/koi/admin_views/templates/_fields.html.erb.tt +0 -3
  231. data/lib/generators/koi/helpers/admin_generator_attributes.rb +0 -66
  232. data/lib/koi/extensions/dartsass.rb +0 -23
  233. /data/app/assets/stylesheets/koi/{components/_clipboard.scss → blocks/clipboard.css} +0 -0
  234. /data/app/assets/stylesheets/koi/{components/_index-actions.scss → blocks/index-actions.css} +0 -0
  235. /data/app/assets/stylesheets/koi/{components/_toolbar.scss → blocks/toolbar.css} +0 -0
  236. /data/app/assets/stylesheets/koi/{base/_repel.scss → compositions/repel.css} +0 -0
@@ -1,13 +1,14 @@
1
1
  <% content_for :header do %>
2
- <%= render Koi::Header::ShowComponent.new(resource: menu, title: menu.title) do |component| %>
3
- <% component.with_breadcrumb "Navigations", katalyst_navigation.menus_path %>
4
- <% component.with_action "Edit", katalyst_navigation.edit_menu_path(menu) %>
2
+ <%= breadcrumb_list do %>
3
+ <li><%= link_to "Navigations", katalyst_navigation.menus_path %></li>
4
+ <% end %>
5
+
6
+ <h1><%= menu.title %></h1>
7
+
8
+ <%= actions_list do %>
9
+ <li><%= link_to("Edit", katalyst_navigation.edit_menu_path(menu)) %></li>
5
10
  <% end %>
6
11
  <% end %>
7
12
 
8
13
  <%= render editor.status_bar %>
9
14
  <%= render editor %>
10
-
11
- <%= content_for :sidebar do %>
12
- <%= render editor.new_items %>
13
- <% end %>
@@ -0,0 +1,20 @@
1
+ <header data-environment="<%= Rails.env %>" class="application-header">
2
+ <div class="repel wrapper">
3
+ <%= link_to(main_app.admin_dashboard_path, class: "brand") do %>
4
+ <icon aria-hidden="true" class="icon" data-icon="koi">&nbsp;</icon>
5
+ Koi
6
+ <% end %>
7
+ <div>
8
+ <span class="environment"><%= Rails.env.capitalize %></span>
9
+ <span class="release">(<%= Koi::Release.version %>)</span>
10
+ </div>
11
+ <%= tag.button(class: "button",
12
+ data: {
13
+ controller: "navigation-toggle",
14
+ action: "navigation-toggle#trigger",
15
+ text_button: "",
16
+ }) do %>
17
+ Menu <kbd>G</kbd>
18
+ <% end %>
19
+ </div>
20
+ </header>
@@ -0,0 +1,34 @@
1
+ <dialog class="application-navigation"
2
+ data-controller="navigation"
3
+ data-action="shortcut:go@document->navigation#toggle
4
+ navigation:toggle@document->navigation#toggle
5
+ shortcut:nav-toggle@document->navigation#toggle
6
+ turbo:before-morph-attribute->navigation#onMorphAttribute
7
+ click->navigation#click">
8
+ <nav aria-label="Main menu" role="navigation" class="flow">
9
+ <div class="filter">
10
+ <input type="search" placeholder="Filter menu" autocomplete="off" autofocus
11
+ data-navigation-target="filter"
12
+ data-action="input->navigation#filter change->navigation#filter
13
+ keydown.enter->navigation#go keydown.esc->navigation#clear">
14
+ </div>
15
+ <ul class="navigation-group | flow" role="list">
16
+ <li>
17
+ <span><%= current_admin_user.name %></span>
18
+ <ul class="navigation-list | flow" role="list">
19
+ <li><%= link_to("Profile", main_app.admin_admin_user_path(current_admin_user)) %></li>
20
+ <li><%= link_to("Log out", main_app.admin_session_path, data: { turbo_method: :delete }) %></li>
21
+ </ul>
22
+ </li>
23
+ </ul>
24
+ <%= navigation_menu_with(
25
+ menu: Koi::Menu.admin_menu(self),
26
+ list: {
27
+ class: "navigation-list | flow",
28
+ role: "list",
29
+ },
30
+ class: "navigation-group | flow",
31
+ role: "list",
32
+ ) %>
33
+ </nav>
34
+ </dialog>
@@ -1,8 +1,11 @@
1
- <ul id="flash" aria-label="Notifications" data-controller="flash" class="stack">
1
+ <ul aria-label="Notifications" data-controller="flash" class="flash | flow" role="list">
2
2
  <% flash.each do |type, message| %>
3
- <%= tag.li role: "alertdialog", class: type do %>
3
+ <%= tag.li(role: "alertdialog", class: "flash | wrapper", data: { flash_type: type }) do %>
4
4
  <%= message %>
5
- <%= tag.button "Close", aria: { label: "Dismiss" }, data: { action: "flash#close" } %>
5
+ <%= tag.button("Dismiss",
6
+ aria: { label: "Dismiss" },
7
+ class: "button",
8
+ data: { action: "flash#close", ghost_button: "" }) %>
6
9
  <% end %>
7
10
  <% end %>
8
11
  </ul>
@@ -6,6 +6,4 @@
6
6
  <% else %>
7
7
  <h3 class="admin-name">Koi Admin</h3>
8
8
  <% end %>
9
- <%# default, prefer using an icon in a Koi override %>
10
- <span class="site-icon"><%= URI.parse(root_url).host[0] %></span>
11
9
  </header>
@@ -1,7 +1,6 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <!-- meta -->
5
4
  <meta charset="UTF-8">
6
5
 
7
6
  <!-- title -->
@@ -18,12 +17,7 @@
18
17
  <meta name="turbo-refresh-scroll" content="preserve">
19
18
  <%= yield :head %>
20
19
 
21
- <%# Deprecated: meta, use :head instead %>
22
- <%= yield :meta %>
23
-
24
20
  <!-- STYLES -->
25
- <link rel="stylesheet" href="https://unpkg.com/modern-css-reset/dist/reset.min.css">
26
- <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
27
21
  <%= stylesheet_link_tag Koi.config.admin_stylesheet, "data-turbo-track": "reload" %>
28
22
 
29
23
  <!-- SCRIPTS -->
@@ -35,33 +29,34 @@
35
29
  Slash->shortcut:search
36
30
  KeyN->shortcut:create
37
31
  KeyG->shortcut:go
38
- BracketLeft->shortcut:nav-toggle
39
32
  Escape->shortcut:cancel
40
33
  ArrowLeft->shortcut:page-prev
41
34
  ArrowRight->shortcut:page-next
42
35
  ">
43
- <%= render "layouts/koi/navigation" %>
44
- <main>
45
- <% if content_for? :header %>
46
- <%= yield :header %>
47
- <% else %>
48
- <%= render "layouts/koi/header" %>
49
- <% end %>
36
+ <!-- application header -->
37
+ <%= render "layouts/koi/application_header" %>
50
38
 
51
- <div class="page <%= "has-sidebar" if content_for?(:sidebar) %>">
52
- <div class="page--content stack" role="main">
53
- <%= render "layouts/koi/flash" unless flash.empty? %>
54
- <%= yield %>
39
+ <!-- header -->
40
+ <% if content_for?(:header) %>
41
+ <header class="page-header">
42
+ <div class="flow wrapper">
43
+ <%= yield(:header) %>
55
44
  </div>
56
- <%= tag.div class: "page--sidebar" do %>
57
- <%= yield :sidebar %>
58
- <% end if content_for?(:sidebar) %>
59
- </div>
60
- </main>
61
- <%= render "layouts/koi/environment" %>
62
- <%= render ScrimComponent.new %>
63
- <%= render Kpop::FrameComponent.new do %>
64
- <%= content_for :kpop %>
45
+ </header>
65
46
  <% end %>
47
+
48
+ <main class="flow wrapper">
49
+ <% unless flash.empty? %>
50
+ <!-- flash -->
51
+ <%= render "layouts/koi/flash" %>
52
+ <% end %>
53
+
54
+ <!-- content -->
55
+ <%= yield %>
56
+ </main>
57
+
58
+ <!-- application navigation -->
59
+ <%= render "layouts/koi/application_navigation" %>
60
+
66
61
  </body>
67
62
  </html>
@@ -10,8 +10,6 @@
10
10
  <%= yield :head %>
11
11
  </head>
12
12
  <body>
13
- <%= render Kpop::FrameComponent.new do %>
14
- <%= yield %>
15
- <% end %>
13
+ <%= yield %>
16
14
  </body>
17
15
  </html>
@@ -14,16 +14,23 @@
14
14
  <%= yield :meta %>
15
15
 
16
16
  <!-- STYLES -->
17
- <link rel="stylesheet" href="https://unpkg.com/modern-css-reset/dist/reset.min.css">
18
- <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
17
+ <%= stylesheet_link_tag path_to_stylesheet("koi/login.css"), "data-turbo-track": "reload" %>
19
18
  <%= stylesheet_link_tag Koi.config.admin_stylesheet, "data-turbo-track": "reload" %>
20
19
 
21
20
  <!-- SCRIPTS -->
22
21
  <%= javascript_importmap_tags "koi/admin" %>
23
22
  </head>
24
- <body class="admin-login">
25
- <main class="stack">
26
- <%= yield %>
23
+ <body>
24
+ <main class="cover" data-centered>
25
+ <div class="login | modal">
26
+ <header>
27
+ <img src="<%= path_to_image("koi/koi.png") %>" alt="Koi" aria-hidden>
28
+ <h1>Koi</h1>
29
+ <h2 class="site-name"><%= URI.parse(root_url).host %></h2>
30
+ </header>
31
+
32
+ <%= yield %>
33
+ </div>
27
34
  </main>
28
35
  </body>
29
36
  </html>
data/config/importmap.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
4
4
  pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
5
5
  pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
6
+ pin "@github/webauthn-json/browser-ponyfill", to: "https://ga.jspm.io/npm:@github/webauthn-json@2.1.1/dist/esm/webauthn-json.browser-ponyfill.js"
6
7
  pin "@rails/actiontext", to: "actiontext.js", preload: true
7
8
  pin "trix"
8
9
 
@@ -16,9 +16,17 @@ en:
16
16
  new: New
17
17
  search: Search
18
18
  activerecord:
19
+ attributes:
20
+ url_rewrite/status_code:
21
+ 303: "See other (303)"
22
+ 307: "Temporary redirect (307)"
23
+ 308: "Permanent redirect (308)"
24
+ well_known/content_type:
25
+ text: "Plain text"
26
+ json: "JSON"
19
27
  errors:
20
28
  models:
21
- admin:
29
+ admin_user:
22
30
  invalid: "Invalid login credentials"
23
31
  helpers:
24
32
  hint:
@@ -0,0 +1,11 @@
1
+ en:
2
+ pagy:
3
+ aria_label:
4
+ nav:
5
+ one: "Pagination"
6
+ other: "Pagination"
7
+ prev: "Previous page"
8
+ next: "Next page"
9
+ prev: "←&nbsp;&nbsp;Previous"
10
+ next: "Next&nbsp;&nbsp;→"
11
+ gap: "&hellip;"
data/config/routes.rb CHANGED
@@ -30,5 +30,5 @@ Rails.application.routes.draw do
30
30
  mount Flipper::UI.app(Flipper) => "flipper" if Object.const_defined?("Flipper::UI")
31
31
  end
32
32
 
33
- resources :well_knowns, path: ".well-known", param: :name, only: %i[show], name: /[^\/]+/
33
+ resources :well_knowns, path: ".well-known", param: :name, only: %i[show], name: /.+/
34
34
  end
@@ -1,27 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rails/generators/rails/scaffold/scaffold_generator"
3
+ require "rails/generators/named_base"
4
4
 
5
5
  module Koi
6
- class AdminGenerator < Rails::Generators::ScaffoldGenerator
7
- # Replace the default model generator with our own
8
- remove_hook_for(:orm)
9
- hook_for(:orm, in: :koi, as: :admin, default: true)
6
+ class AdminGenerator < Rails::Generators::NamedBase
10
7
 
11
- # Disable default controller generation as we do not want to generate public
12
- # controllers by default
13
- remove_hook_for(:scaffold_controller)
14
- remove_hook_for(:resource_route)
8
+ class_option :force, type: :boolean, default: true
15
9
 
16
10
  hook_for :admin_controller, in: :koi, as: :admin, type: :boolean, default: true do |instance, controller|
17
11
  args, opts, config = @_initializer
18
- opts ||= {}
12
+ opts ||= {}
19
13
 
20
14
  # setting model_name so that generators will use the controller_class_path
21
15
  instance.invoke controller, args, { model_name: instance.name, **opts }, config
22
16
  end
23
-
24
- Rails::Generators::ModelGenerator.hook_for :admin_search, type: :boolean, default: true
25
- Rails::Generators::ModelGenerator.hook_for :ordinal_scope, type: :boolean, default: true
26
17
  end
27
18
  end
@@ -3,12 +3,13 @@
3
3
  require "rails/generators/named_base"
4
4
  require "rails/generators/resource_helpers"
5
5
 
6
- require_relative "../helpers/admin_generator_attributes"
6
+ require_relative "../helpers/attribute_helpers"
7
+ require_relative "../helpers/resource_helpers"
7
8
 
8
9
  module Koi
9
10
  class AdminControllerGenerator < Rails::Generators::NamedBase
10
- include Rails::Generators::ResourceHelpers
11
- include Helpers::AdminGeneratorAttributes
11
+ include Helpers::AttributeHelpers
12
+ include Helpers::ResourceHelpers
12
13
 
13
14
  source_root File.expand_path("templates", __dir__)
14
15
 
@@ -16,6 +17,8 @@ module Koi
16
17
 
17
18
  argument :attributes, type: :array, default: [], banner: "field:type field:type"
18
19
 
20
+ class_option :force, type: :boolean, default: true
21
+
19
22
  def create_controller_files
20
23
  template("controller.rb",
21
24
  File.join("app/controllers",
@@ -35,24 +38,11 @@ module Koi
35
38
 
36
39
  private
37
40
 
38
- def controller_class_path
39
- ["admin"] + super
40
- end
41
-
42
41
  def permitted_params
43
42
  attachments, others = attributes_names.partition { |name| attachments?(name) }
44
43
  params = others.map { |name| ":#{name}" }
45
- params += attachments.map { |name| "#{name}: []" }
44
+ params += attachments.map { |name| "#{name}: []" }
46
45
  params.join(", ")
47
46
  end
48
-
49
- def attachments?(name)
50
- attribute = attributes.find { |attr| attr.name == name }
51
- attribute&.attachments?
52
- end
53
-
54
- def sort_attribute
55
- attributes.find { |attr| attr.type == :string }&.name
56
- end
57
47
  end
58
48
  end
@@ -3,51 +3,110 @@
3
3
  class <%= controller_class_name %>Controller < ApplicationController
4
4
  before_action :set_<%= singular_name %>, only: %i[show edit update destroy]
5
5
 
6
+ attr_reader :collection, :<%= singular_name %>
7
+
6
8
  def index
7
- collection = Collection.new.with_params(params).apply(::<%= class_name %>.strict_loading.all)
9
+ <%- if archivable? -%>
10
+ @collection = Collection.with_params(params).apply(<%= class_name %>.not_archived.strict_loading)
11
+ <%- else -%>
12
+ @collection = Collection.with_params(params).apply(<%= class_name %>.strict_loading)
13
+ <%- end -%>
14
+
15
+ render locals: { collection: }
16
+ end
17
+
18
+ <%- if archivable? -%>
19
+ def archived
20
+ collection = Collection.with_params(params).apply(<%= class_name %>.archived.strict_loading)
8
21
 
9
22
  render locals: { collection: }
10
23
  end
24
+ <%- end -%>
11
25
 
12
26
  def show
13
- render locals: { <%= singular_name %>: @<%= singular_name %> }
27
+ render locals: { <%= singular_name %>: }
14
28
  end
15
29
 
16
30
  def new
17
- render locals: { <%= singular_name %>: ::<%= class_name %>.new }
31
+ @<%= singular_name %> = <%= class_name %>.new
32
+
33
+ render locals: { <%= singular_name %>: }
18
34
  end
19
35
 
20
36
  def edit
21
- render locals: { <%= singular_name %>: @<%= singular_name %> }
37
+ render locals: { <%= singular_name %>: }
22
38
  end
23
39
 
24
40
  def create
25
- @<%= singular_name %> = ::<%= class_name %>.new(<%= singular_table_name %>_params)
41
+ @<%= singular_name %> = <%= class_name %>.new(<%= singular_table_name %>_params)
26
42
 
27
- if @<%= singular_name %>.save
28
- redirect_to [:admin, @<%= singular_name %>], status: :see_other
43
+ if <%= singular_name %>.save
44
+ redirect_to <%= admin_show_helper %>, status: :see_other
29
45
  else
30
- render :new, locals: { <%= singular_name %>: @<%= singular_name %> }, status: :unprocessable_content
46
+ render :new, locals: { <%= singular_name %>: }, status: :unprocessable_content
31
47
  end
32
48
  end
33
49
 
34
50
  def update
35
- if @<%= singular_name %>.update(<%= singular_table_name %>_params)
36
- redirect_to action: :show, status: :see_other
51
+ if <%= singular_name %>.update(<%= singular_table_name %>_params)
52
+ redirect_to <%= admin_show_helper %>, status: :see_other
37
53
  else
38
- render :edit, locals: { <%= singular_name %>: @<%= singular_name %> }, status: :unprocessable_content
54
+ render :edit, locals: { <%= singular_name %>: }, status: :unprocessable_content
55
+ end
56
+ end
57
+
58
+ <%- if archivable? -%>
59
+ def archive
60
+ <%= class_name %>.where(id: params[:id]).each(&:archive!)
61
+
62
+ redirect_back(fallback_location: <%= admin_index_helper %>, status: :see_other)
63
+ end
64
+
65
+ def restore
66
+ <%= class_name %>.archived.where(id: params[:id]).each(&:restore!)
67
+
68
+ redirect_back(fallback_location: <%= admin_index_helper %>, status: :see_other)
69
+ end
70
+ <%- end -%>
71
+
72
+ <%- if orderable? -%>
73
+ def order
74
+ order_params[:<%= table_name %>].each do |id, attrs|
75
+ <%= class_name %>.find(id).update(attrs)
39
76
  end
77
+
78
+ redirect_back(fallback_location: <%= admin_index_helper %>, status: :see_other)
40
79
  end
80
+ <%- end -%>
41
81
 
42
82
  def destroy
43
- @<%= singular_name %>.destroy!
83
+ <%- if archivable? -%>
84
+ if <%= singular_name %>.archived?
85
+ <%= singular_name %>.destroy!
86
+
87
+ redirect_to <%= admin_index_helper %>, status: :see_other
88
+ else
89
+ <%= singular_name %>.archive!
44
90
 
45
- redirect_to action: :index, status: :see_other
91
+ redirect_back_or_to(<%= admin_show_helper %>, status: :see_other)
92
+ end
93
+ <%- else -%>
94
+ <%= singular_name %>.destroy!
95
+
96
+ redirect_to <%= admin_index_helper %>, status: :see_other
97
+ <%- end -%>
46
98
  end
47
99
 
48
100
  private
49
101
 
50
- # Only allow a list of trusted parameters through.
102
+ def set_<%= singular_name %>
103
+ <%- if archivable? -%>
104
+ @<%= singular_name %> = <%= class_name %>.with_archived.find(params[:id])
105
+ <%- else -%>
106
+ @<%= singular_name %> = <%= class_name %>.find(params[:id])
107
+ <%- end -%>
108
+ end
109
+
51
110
  def <%= "#{singular_table_name}_params" %>
52
111
  <%- if attributes_names.empty? -%>
53
112
  params.expect(<%= singular_table_name %>: [])
@@ -56,14 +115,19 @@ class <%= controller_class_name %>Controller < ApplicationController
56
115
  <%- end -%>
57
116
  end
58
117
 
59
- # Use callbacks to share common setup or constraints between actions.
60
- def set_<%= singular_name %>
61
- @<%= singular_name %> = ::<%= class_name %>.find(params[:id])
118
+ <%- if orderable? -%>
119
+ def order_params
120
+ params.expect(order: { <%= table_name %>: [[:ordinal]] })
62
121
  end
122
+ <%- end -%>
63
123
 
64
124
  class Collection < Admin::Collection
65
- config.sorting = :<%= sort_attribute %>
125
+ <%- if sortable? %>
126
+ config.sorting = :<%= default_sort_attribute %>
127
+ <%- end -%>
128
+ <%- if paginate? -%>
66
129
  config.paginate = true
130
+ <%- end -%>
67
131
 
68
132
  <%- attributes.each do |attribute| -%>
69
133
  <% definition = collection_attribute_for(attribute) -%>