tiny_admin 0.10.1 → 0.11.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tiny_admin/actions/index.rb +4 -4
  3. data/lib/tiny_admin/authentication.rb +8 -8
  4. data/lib/tiny_admin/basic_app.rb +5 -3
  5. data/lib/tiny_admin/field.rb +5 -4
  6. data/lib/tiny_admin/plugins/active_record_repository.rb +1 -1
  7. data/lib/tiny_admin/plugins/base_repository.rb +2 -1
  8. data/lib/tiny_admin/plugins/no_auth.rb +2 -2
  9. data/lib/tiny_admin/plugins/simple_auth.rb +10 -10
  10. data/lib/tiny_admin/raw_html.rb +11 -0
  11. data/lib/tiny_admin/router.rb +36 -29
  12. data/lib/tiny_admin/settings.rb +22 -8
  13. data/lib/tiny_admin/store.rb +9 -12
  14. data/lib/tiny_admin/support.rb +14 -2
  15. data/lib/tiny_admin/utils.rb +7 -5
  16. data/lib/tiny_admin/version.rb +1 -1
  17. data/lib/tiny_admin/views/actions/index.rb +22 -26
  18. data/lib/tiny_admin/views/actions/show.rb +14 -20
  19. data/lib/tiny_admin/views/attributes.rb +18 -0
  20. data/lib/tiny_admin/views/basic_layout.rb +1 -6
  21. data/lib/tiny_admin/views/components/actions_buttons.rb +24 -0
  22. data/lib/tiny_admin/views/components/basic_component.rb +1 -5
  23. data/lib/tiny_admin/views/components/field_value.rb +14 -3
  24. data/lib/tiny_admin/views/components/filters_form.rb +20 -20
  25. data/lib/tiny_admin/views/components/flash.rb +4 -4
  26. data/lib/tiny_admin/views/components/head.rb +3 -3
  27. data/lib/tiny_admin/views/components/navbar.rb +16 -16
  28. data/lib/tiny_admin/views/components/pagination.rb +14 -14
  29. data/lib/tiny_admin/views/components/widgets.rb +22 -7
  30. data/lib/tiny_admin/views/default_layout.rb +7 -7
  31. data/lib/tiny_admin/views/pages/content.rb +3 -3
  32. data/lib/tiny_admin/views/pages/error_page.rb +26 -0
  33. data/lib/tiny_admin/views/pages/page_not_allowed.rb +2 -10
  34. data/lib/tiny_admin/views/pages/page_not_found.rb +2 -10
  35. data/lib/tiny_admin/views/pages/record_not_found.rb +2 -10
  36. data/lib/tiny_admin/views/pages/root.rb +2 -2
  37. data/lib/tiny_admin/views/pages/simple_auth_login.rb +11 -11
  38. data/lib/tiny_admin.rb +8 -8
  39. metadata +7 -6
@@ -15,22 +15,22 @@ module TinyAdmin
15
15
 
16
16
  def view_template
17
17
  super do
18
- div(class: 'index') {
19
- div(class: 'row') {
20
- div(class: 'col-4') {
21
- h1(class: 'title') {
18
+ div(class: "index") {
19
+ div(class: "row") {
20
+ div(class: "col-4") {
21
+ h1(class: "title") {
22
22
  title
23
23
  }
24
24
  }
25
- div(class: 'col-8') {
25
+ div(class: "col-8") {
26
26
  actions_buttons
27
27
  }
28
28
  }
29
29
 
30
- div(class: 'row') {
31
- div_class = filters&.any? ? 'col-9' : 'col-12'
30
+ div(class: "row") {
31
+ div_class = filters&.any? ? "col-9" : "col-12"
32
32
  div(class: div_class) {
33
- table(class: 'table') {
33
+ table(class: "table") {
34
34
  table_header if fields.any?
35
35
 
36
36
  table_body
@@ -40,7 +40,7 @@ module TinyAdmin
40
40
  }
41
41
 
42
42
  if filters&.any?
43
- div(class: 'col-3') {
43
+ div(class: "col-3") {
44
44
  filters_form = TinyAdmin::Views::Components::FiltersForm.new
45
45
  filters_form.update_attributes(section_path: TinyAdmin.route_for(slug), filters: filters)
46
46
  render filters_form
@@ -48,7 +48,8 @@ module TinyAdmin
48
48
  end
49
49
  }
50
50
 
51
- render TinyAdmin::Views::Components::Widgets.new(widgets)
51
+ context = { slug: slug, records: records, params: params }
52
+ render TinyAdmin::Views::Components::Widgets.new(widgets, context: context)
52
53
  }
53
54
  end
54
55
  end
@@ -75,20 +76,22 @@ module TinyAdmin
75
76
  attributes = prepare_record.call(record)
76
77
  attributes.each do |key, value|
77
78
  field = fields[key]
79
+ next unless field
80
+
78
81
  td(class: "field-value-#{field.name} field-value-type-#{field.type}") {
79
82
  render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
80
83
  }
81
84
  end
82
85
 
83
- td(class: 'actions p-1') {
84
- div(class: 'btn-group btn-group-sm') {
85
- link_class = 'btn btn-outline-secondary'
86
+ td(class: "actions p-1") {
87
+ div(class: "btn-group btn-group-sm") {
88
+ link_class = "btn btn-outline-secondary"
86
89
  if links
87
90
  links.each do |link|
88
91
  whitespace
89
- if link == 'show'
92
+ if link == "show"
90
93
  a(href: TinyAdmin.route_for(slug, reference: record.id), class: link_class) {
91
- label_for('Show', options: ['actions.index.links.show'])
94
+ label_for("Show", options: ["actions.index.links.show"])
92
95
  }
93
96
  else
94
97
  a(href: TinyAdmin.route_for(slug, reference: record.id, action: link), class: link_class) {
@@ -99,7 +102,7 @@ module TinyAdmin
99
102
  end
100
103
  else
101
104
  a(href: TinyAdmin.route_for(slug, reference: record.id), class: link_class) {
102
- label_for('Show', options: ['actions.index.links.show'])
105
+ label_for("Show", options: ["actions.index.links.show"])
103
106
  }
104
107
  end
105
108
  }
@@ -110,16 +113,9 @@ module TinyAdmin
110
113
  end
111
114
 
112
115
  def actions_buttons
113
- ul(class: 'nav justify-content-end') {
114
- (actions || {}).each do |action, action_class|
115
- li(class: 'nav-item mx-1') {
116
- href = TinyAdmin.route_for(slug, action: action)
117
- a(href: href, class: 'nav-link btn btn-outline-secondary') {
118
- action_class.respond_to?(:title) ? action_class.title : action
119
- }
120
- }
121
- end
122
- }
116
+ buttons = TinyAdmin::Views::Components::ActionsButtons.new
117
+ buttons.update_attributes(actions: actions, slug: slug)
118
+ render buttons
123
119
  end
124
120
  end
125
121
  end
@@ -13,29 +13,30 @@ module TinyAdmin
13
13
 
14
14
  def view_template
15
15
  super do
16
- div(class: 'show') {
17
- div(class: 'row') {
18
- div(class: 'col-4') {
19
- h1(class: 'title') { title }
16
+ div(class: "show") {
17
+ div(class: "row") {
18
+ div(class: "col-4") {
19
+ h1(class: "title") { title }
20
20
  }
21
- div(class: 'col-8') {
21
+ div(class: "col-8") {
22
22
  actions_buttons
23
23
  }
24
24
  }
25
25
 
26
26
  prepare_record.call(record).each do |key, value|
27
27
  field = fields[key]
28
+ next unless field
29
+
28
30
  div(class: "field-#{field.name} row lh-lg") {
29
- if field
30
- div(class: 'field-header col-2') { field.options[:header] || field.title }
31
- end
32
- div(class: 'field-value col-10') {
31
+ div(class: "field-header col-2") { field.options[:header] || field.title }
32
+ div(class: "field-value col-10") {
33
33
  render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
34
34
  }
35
35
  }
36
36
  end
37
37
 
38
- render TinyAdmin::Views::Components::Widgets.new(widgets)
38
+ context = { slug: slug, record: record, reference: reference, params: params }
39
+ render TinyAdmin::Views::Components::Widgets.new(widgets, context: context)
39
40
  }
40
41
  end
41
42
  end
@@ -43,16 +44,9 @@ module TinyAdmin
43
44
  private
44
45
 
45
46
  def actions_buttons
46
- ul(class: 'nav justify-content-end') {
47
- (actions || {}).each do |action, action_class|
48
- li(class: 'nav-item mx-1') {
49
- href = TinyAdmin.route_for(slug, reference: reference, action: action)
50
- a(href: href, class: 'nav-link btn btn-outline-secondary') {
51
- action_class.respond_to?(:title) ? action_class.title : action
52
- }
53
- }
54
- end
55
- }
47
+ buttons = TinyAdmin::Views::Components::ActionsButtons.new
48
+ buttons.update_attributes(actions: actions, slug: slug, reference: reference)
49
+ render buttons
56
50
  end
57
51
  end
58
52
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Attributes
6
+ def update_attributes(attributes)
7
+ attributes.each do |key, value|
8
+ setter = "#{key}="
9
+ unless respond_to?(setter)
10
+ raise ArgumentError, "#{self.class.name} does not support attribute '#{key}'"
11
+ end
12
+
13
+ send(setter, value)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,6 +3,7 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  class BasicLayout < Phlex::HTML
6
+ include Attributes
6
7
  include Utils
7
8
 
8
9
  attr_accessor :content, :params, :widgets
@@ -10,12 +11,6 @@ module TinyAdmin
10
11
  def label_for(value, options: [])
11
12
  TinyAdmin.settings.helper_class.label_for(value, options: options)
12
13
  end
13
-
14
- def update_attributes(attributes)
15
- attributes.each do |key, value|
16
- send("#{key}=", value)
17
- end
18
- end
19
14
  end
20
15
  end
21
16
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Components
6
+ class ActionsButtons < BasicComponent
7
+ attr_accessor :actions, :slug, :reference
8
+
9
+ def view_template
10
+ ul(class: "nav justify-content-end") {
11
+ (actions || {}).each do |action, action_class|
12
+ li(class: "nav-item mx-1") {
13
+ href = TinyAdmin.route_for(slug, reference: reference, action: action)
14
+ a(href: href, class: "nav-link btn btn-outline-secondary") {
15
+ action_class.respond_to?(:title) ? action_class.title : action
16
+ }
17
+ }
18
+ end
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,11 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Components
6
6
  class BasicComponent < Phlex::HTML
7
- def update_attributes(attributes)
8
- attributes.each do |key, value|
9
- send("#{key}=", value)
10
- end
11
- end
7
+ include Attributes
12
8
  end
13
9
  end
14
10
  end
@@ -14,19 +14,30 @@ module TinyAdmin
14
14
 
15
15
  def view_template
16
16
  translated_value = field.translate_value(value)
17
- value_class = field.options[:options]&.include?('value_class') ? "value-#{value}" : nil
17
+ display_value = field.apply_call_option(record) || translated_value
18
+ value_class = field.options[:options]&.include?("value_class") ? "value-#{value}" : nil
18
19
  if field.options[:link_to]
19
20
  a(href: TinyAdmin.route_for(field.options[:link_to], reference: translated_value)) {
20
21
  span(class: value_class) {
21
- field.apply_call_option(record) || translated_value
22
+ render_value(display_value)
22
23
  }
23
24
  }
24
25
  else
25
26
  span(class: value_class) {
26
- translated_value
27
+ render_value(display_value)
27
28
  }
28
29
  end
29
30
  end
31
+
32
+ private
33
+
34
+ def render_value(val)
35
+ if val.is_a?(TinyAdmin::RawHtml)
36
+ unsafe_raw(val.to_s)
37
+ else
38
+ val
39
+ end
40
+ end
30
41
  end
31
42
  end
32
43
  end
@@ -7,49 +7,49 @@ module TinyAdmin
7
7
  attr_accessor :filters, :section_path
8
8
 
9
9
  def view_template
10
- form(class: 'form_filters', method: 'get') {
10
+ form(class: "form_filters", method: "get") {
11
11
  filters.each do |field, filter|
12
12
  name = field.name
13
13
  filter_data = filter[:filter]
14
- div(class: 'mb-3') {
15
- label(for: "filter-#{name}", class: 'form-label') { field.title }
14
+ div(class: "mb-3") {
15
+ label(for: "filter-#{name}", class: "form-label") { field.title }
16
16
  case filter_data[:type]&.to_sym || field.type
17
17
  when :boolean
18
- select(class: 'form-select', id: "filter-#{name}", name: "q[#{name}]") {
19
- option(value: '') { '-' }
20
- option(value: '0', selected: filter[:value] == '0') {
21
- TinyAdmin.settings.helper_class.label_for('false', options: ['components.filters_form.boolean.false'])
18
+ select(class: "form-select", id: "filter-#{name}", name: "q[#{name}]") {
19
+ option(value: "") { "-" }
20
+ option(value: "0", selected: filter[:value] == "0") {
21
+ TinyAdmin.settings.helper_class.label_for("false", options: ["components.filters_form.boolean.false"])
22
22
  }
23
- option(value: '1', selected: filter[:value] == '1') {
24
- TinyAdmin.settings.helper_class.label_for('true', options: ['components.filters_form.boolean.true'])
23
+ option(value: "1", selected: filter[:value] == "1") {
24
+ TinyAdmin.settings.helper_class.label_for("true", options: ["components.filters_form.boolean.true"])
25
25
  }
26
26
  }
27
27
  when :date
28
- input(type: 'date', class: 'form-control', id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
28
+ input(type: "date", class: "form-control", id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
29
29
  when :datetime
30
- input(type: 'datetime-local', class: 'form-control', id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
30
+ input(type: "datetime-local", class: "form-control", id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
31
31
  when :integer
32
- input(type: 'number', class: 'form-control', id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
32
+ input(type: "number", class: "form-control", id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
33
33
  when :select
34
- select(class: 'form-select', id: "filter-#{name}", name: "q[#{name}]") {
35
- option(value: '') { '-' }
34
+ select(class: "form-select", id: "filter-#{name}", name: "q[#{name}]") {
35
+ option(value: "") { "-" }
36
36
  filter_data[:values].each do |value|
37
37
  option(selected: filter[:value] == value) { value }
38
38
  end
39
39
  }
40
40
  else
41
- input(type: 'text', class: 'form-control', id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
41
+ input(type: "text", class: "form-control", id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
42
42
  end
43
43
  }
44
44
  end
45
45
 
46
- div(class: 'mt-3') {
47
- a(href: section_path, class: 'button_clear btn btn-secondary text-white') {
48
- TinyAdmin.settings.helper_class.label_for('Clear', options: ['components.filters_form.buttons.clear'])
46
+ div(class: "mt-3") {
47
+ a(href: section_path, class: "button_clear btn btn-secondary text-white") {
48
+ TinyAdmin.settings.helper_class.label_for("Clear", options: ["components.filters_form.buttons.clear"])
49
49
  }
50
50
  whitespace
51
- button(type: 'submit', class: 'button_filter btn btn-secondary') {
52
- TinyAdmin.settings.helper_class.label_for('Filter', options: ['components.filters_form.buttons.submit'])
51
+ button(type: "submit", class: "button_filter btn btn-secondary") {
52
+ TinyAdmin.settings.helper_class.label_for("Filter", options: ["components.filters_form.buttons.submit"])
53
53
  }
54
54
  }
55
55
  }
@@ -12,10 +12,10 @@ module TinyAdmin
12
12
  warnings = messages[:warnings]
13
13
  errors = messages[:errors]
14
14
 
15
- div(class: 'flash') {
16
- div(class: 'notices alert alert-success', role: 'alert') { notices.join(', ') } if notices&.any?
17
- div(class: 'notices alert alert-warning', role: 'alert') { warnings.join(', ') } if warnings&.any?
18
- div(class: 'notices alert alert-danger', role: 'alert') { errors.join(', ') } if errors&.any?
15
+ div(class: "flash") {
16
+ div(class: "notices alert alert-success", role: "alert") { notices.join(", ") } if notices&.any?
17
+ div(class: "warnings alert alert-warning", role: "alert") { warnings.join(", ") } if warnings&.any?
18
+ div(class: "errors alert alert-danger", role: "alert") { errors.join(", ") } if errors&.any?
19
19
  }
20
20
  end
21
21
  end
@@ -8,12 +8,12 @@ module TinyAdmin
8
8
 
9
9
  def view_template
10
10
  head {
11
- meta charset: 'utf-8'
12
- meta name: 'viewport', content: 'width=device-width, initial-scale=1'
11
+ meta charset: "utf-8"
12
+ meta name: "viewport", content: "width=device-width, initial-scale=1"
13
13
  title {
14
14
  page_title
15
15
  }
16
- style_links.each do |style_link|
16
+ (style_links || []).each do |style_link|
17
17
  link(**style_link)
18
18
  end
19
19
  style { extra_styles } if extra_styles
@@ -7,29 +7,29 @@ module TinyAdmin
7
7
  attr_accessor :current_slug, :items, :root_path, :root_title
8
8
 
9
9
  def view_template
10
- nav(class: 'navbar navbar-expand-lg') {
11
- div(class: 'container') {
12
- a(class: 'navbar-brand', href: root_path) { root_title }
10
+ nav(class: "navbar navbar-expand-lg") {
11
+ div(class: "container") {
12
+ a(class: "navbar-brand", href: root_path) { root_title }
13
13
  button(
14
- class: 'navbar-toggler',
15
- type: 'button',
16
- 'data-bs-toggle' => 'collapse',
17
- 'data-bs-target' => '#navbarNav',
18
- 'aria-controls' => 'navbarNav',
19
- 'aria-expanded' => 'false',
20
- 'aria-label' => 'Toggle navigation'
14
+ class: "navbar-toggler",
15
+ type: "button",
16
+ "data-bs-toggle" => "collapse",
17
+ "data-bs-target" => "#navbarNav",
18
+ "aria-controls" => "navbarNav",
19
+ "aria-expanded" => "false",
20
+ "aria-label" => "Toggle navigation"
21
21
  ) {
22
- span(class: 'navbar-toggler-icon')
22
+ span(class: "navbar-toggler-icon")
23
23
  }
24
- div(class: 'collapse navbar-collapse', id: 'navbarNav') {
25
- ul(class: 'navbar-nav') {
24
+ div(class: "collapse navbar-collapse", id: "navbarNav") {
25
+ ul(class: "navbar-nav") {
26
26
  items.each do |item|
27
27
  classes = %w[nav-link]
28
- classes << 'active' if item.slug == current_slug
29
- link_attributes = { class: classes.join(' '), href: item.path, 'aria-current' => 'page' }
28
+ classes << "active" if item.slug == current_slug
29
+ link_attributes = { class: classes.join(" "), href: item.path, "aria-current" => "page" }
30
30
  link_attributes.merge!(item.options) if item.options
31
31
 
32
- li(class: 'nav-item') {
32
+ li(class: "nav-item") {
33
33
  a(**link_attributes) { item.name }
34
34
  }
35
35
  end
@@ -7,28 +7,28 @@ module TinyAdmin
7
7
  attr_accessor :current, :pages, :query_string, :total_count
8
8
 
9
9
  def view_template
10
- div(class: 'container') {
11
- div(class: 'row') {
12
- div(class: 'col total-count') {
10
+ div(class: "container") {
11
+ div(class: "row") {
12
+ div(class: "col total-count") {
13
13
  "#{total_count} items"
14
14
  }
15
- div(class: 'col col-6 text-center pagination-div') {
16
- nav(class: 'd-inline-block', 'aria-label': 'Pagination') {
17
- ul(class: 'pagination') {
15
+ div(class: "col col-6 text-center pagination-div") {
16
+ nav(class: "d-inline-block", "aria-label": "Pagination") {
17
+ ul(class: "pagination") {
18
18
  if pages <= 10
19
19
  pages_range(1..pages)
20
20
  elsif current <= 4 || current >= pages - 3
21
- pages_range(1..(current <= 4 ? current + 2 : 4), with_dots: true)
22
- pages_range((current > pages - 4 ? current - 2 : pages - 2)..pages)
21
+ pages_range(1..(current <= 4 ? (current + 2) : 4), with_dots: true)
22
+ pages_range((current > pages - 4 ? (current - 2) : (pages - 2))..pages)
23
23
  else
24
24
  pages_range(1..1, with_dots: true)
25
- pages_range(current - 2..current + 2, with_dots: true)
25
+ pages_range((current - 2)..(current + 2), with_dots: true)
26
26
  pages_range(pages..pages)
27
27
  end
28
28
  }
29
29
  }
30
30
  }
31
- div(class: 'col')
31
+ div(class: "col")
32
32
  }
33
33
  }
34
34
  end
@@ -37,17 +37,17 @@ module TinyAdmin
37
37
 
38
38
  def pages_range(range, with_dots: false)
39
39
  range.each do |page|
40
- li(class: page == current ? 'page-item active' : 'page-item') {
40
+ li(class: page == current ? "page-item active" : "page-item") {
41
41
  href = query_string.empty? ? "?p=#{page}" : "?#{query_string}&p=#{page}"
42
- a(class: 'page-link', href: href) { page }
42
+ a(class: "page-link", href: href) { page.to_s }
43
43
  }
44
44
  end
45
45
  dots if with_dots
46
46
  end
47
47
 
48
48
  def dots
49
- li(class: 'page-item disabled') {
50
- a(class: 'page-link') { '...' }
49
+ li(class: "page-item disabled") {
50
+ a(class: "page-link") { "..." }
51
51
  }
52
52
  end
53
53
  end
@@ -4,23 +4,24 @@ module TinyAdmin
4
4
  module Views
5
5
  module Components
6
6
  class Widgets < BasicComponent
7
- def initialize(widgets)
7
+ def initialize(widgets, context: {})
8
8
  @widgets = widgets
9
+ @context = context
9
10
  end
10
11
 
11
12
  def view_template
12
13
  return if @widgets.nil? || @widgets.empty?
13
14
 
14
- div(class: 'container widgets') {
15
+ div(class: "container widgets") {
15
16
  @widgets.each_slice(2).each do |row|
16
- div(class: 'row') {
17
+ div(class: "row") {
17
18
  row.each do |widget|
18
19
  next unless widget < Phlex::HTML
19
20
 
20
- div(class: 'col') {
21
- div(class: 'card') {
22
- div(class: 'card-body') {
23
- render widget.new
21
+ div(class: "col") {
22
+ div(class: "card") {
23
+ div(class: "card-body") {
24
+ render build_widget(widget)
24
25
  }
25
26
  }
26
27
  }
@@ -29,6 +30,20 @@ module TinyAdmin
29
30
  end
30
31
  }
31
32
  end
33
+
34
+ private
35
+
36
+ def build_widget(widget)
37
+ key_params = [:key, :keyreq]
38
+ if widget.instance_method(:initialize).arity != 0 ||
39
+ widget.instance_method(:initialize).parameters.any? { |type, _| key_params.include?(type) }
40
+ widget.new(context: @context)
41
+ else
42
+ widget.new
43
+ end
44
+ rescue ArgumentError
45
+ widget.new
46
+ end
32
47
  end
33
48
  end
34
49
  end
@@ -35,10 +35,10 @@ module TinyAdmin
35
35
  end
36
36
 
37
37
  def main_content
38
- div(class: 'container main-content py-4') do
38
+ div(class: "container main-content py-4") do
39
39
  if options&.include?(:compact_layout)
40
- div(class: 'row justify-content-center') {
41
- div(class: 'col-6') {
40
+ div(class: "row justify-content-center") {
41
+ div(class: "col-6") {
42
42
  yield
43
43
  }
44
44
  }
@@ -52,10 +52,10 @@ module TinyAdmin
52
52
  TinyAdmin.settings.style_links || [
53
53
  # Bootstrap CDN
54
54
  {
55
- href: 'https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css',
56
- rel: 'stylesheet',
57
- integrity: 'sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65',
58
- crossorigin: 'anonymous'
55
+ href: "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css",
56
+ rel: "stylesheet",
57
+ integrity: "sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65",
58
+ crossorigin: "anonymous"
59
59
  }
60
60
  ]
61
61
  end
@@ -6,12 +6,12 @@ module TinyAdmin
6
6
  class Content < DefaultLayout
7
7
  def view_template
8
8
  super do
9
- div(class: 'content') {
10
- div(class: 'content-data') {
9
+ div(class: "content") {
10
+ div(class: "content-data") {
11
11
  unsafe_raw(content)
12
12
  }
13
13
 
14
- render TinyAdmin::Views::Components::Widgets.new(widgets)
14
+ render TinyAdmin::Views::Components::Widgets.new(widgets, context: { params: params })
15
15
  }
16
16
  end
17
17
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Pages
6
+ class ErrorPage < DefaultLayout
7
+ def view_template
8
+ super do
9
+ div(class: css_class) {
10
+ h1(class: "title") { title }
11
+ }
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def css_class
18
+ self.class.name.split("::").last
19
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
20
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
21
+ .downcase
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -3,17 +3,9 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
- class PageNotAllowed < DefaultLayout
7
- def view_template
8
- super do
9
- div(class: 'page_not_allowed') {
10
- h1(class: 'title') { title }
11
- }
12
- end
13
- end
14
-
6
+ class PageNotAllowed < ErrorPage
15
7
  def title
16
- 'Page not allowed'
8
+ "Page not allowed"
17
9
  end
18
10
  end
19
11
  end