panda-cms 0.7.5 → 0.8.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/panda/cms/admin/user_activity_component.html.erb +2 -2
  3. data/app/components/panda/cms/admin/user_activity_component.rb +2 -2
  4. data/app/components/panda/cms/admin/user_display_component.html.erb +1 -1
  5. data/app/components/panda/cms/admin/user_display_component.rb +2 -2
  6. data/app/components/panda/cms/rich_text_component.rb +5 -5
  7. data/app/controllers/panda/cms/admin/base_controller.rb +18 -0
  8. data/app/controllers/panda/cms/admin/block_contents_controller.rb +1 -2
  9. data/app/controllers/panda/cms/admin/dashboard_controller.rb +5 -4
  10. data/app/controllers/panda/cms/admin/files_controller.rb +1 -3
  11. data/app/controllers/panda/cms/admin/forms_controller.rb +3 -4
  12. data/app/controllers/panda/cms/admin/menus_controller.rb +2 -3
  13. data/app/controllers/panda/cms/admin/pages_controller.rb +7 -7
  14. data/app/controllers/panda/cms/admin/posts_controller.rb +9 -10
  15. data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +4 -4
  16. data/app/controllers/panda/cms/admin/settings_controller.rb +2 -3
  17. data/app/controllers/panda/cms/application_controller.rb +13 -5
  18. data/app/controllers/panda/cms/pages_controller.rb +2 -2
  19. data/app/helpers/panda/cms/application_helper.rb +3 -3
  20. data/app/helpers/panda/cms/asset_helper.rb +14 -1
  21. data/app/javascript/panda/cms/application_panda_cms.js +2 -34
  22. data/app/javascript/panda/cms/controllers/index.js +5 -15
  23. data/app/models/panda/cms/block_content.rb +1 -1
  24. data/app/models/panda/cms/current.rb +3 -12
  25. data/app/models/panda/cms/post.rb +3 -3
  26. data/app/models/panda/cms/visit.rb +1 -1
  27. data/app/views/layouts/panda/cms/application.html.erb +1 -1
  28. data/app/views/panda/cms/admin/dashboard/show.html.erb +2 -2
  29. data/app/views/panda/cms/admin/files/index.html.erb +1 -1
  30. data/app/views/panda/cms/admin/forms/index.html.erb +4 -4
  31. data/app/views/panda/cms/admin/forms/new.html.erb +2 -2
  32. data/app/views/panda/cms/admin/forms/show.html.erb +1 -1
  33. data/app/views/panda/cms/admin/menus/index.html.erb +4 -4
  34. data/app/views/panda/cms/admin/pages/edit.html.erb +6 -6
  35. data/app/views/panda/cms/admin/pages/index.html.erb +5 -5
  36. data/app/views/panda/cms/admin/pages/new.html.erb +2 -2
  37. data/app/views/panda/cms/admin/posts/_form.html.erb +1 -1
  38. data/app/views/panda/cms/admin/posts/edit.html.erb +2 -2
  39. data/app/views/panda/cms/admin/posts/index.html.erb +5 -5
  40. data/app/views/panda/cms/admin/posts/new.html.erb +1 -1
  41. data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +1 -1
  42. data/app/views/panda/cms/admin/settings/index.html.erb +3 -3
  43. data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +3 -3
  44. data/app/views/panda/cms/admin/shared/_flash.html.erb +1 -1
  45. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +8 -8
  46. data/config/initializers/panda/cms.rb +6 -3
  47. data/config/routes.rb +8 -16
  48. data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +3 -1
  49. data/db/migrate/20250126234001_create_panda_social_instagram_posts.rb +2 -0
  50. data/db/migrate/20250809231125_migrate_users_to_panda_core.rb +111 -0
  51. data/db/migrate/20250811111000_make_post_user_references_nullable.rb +11 -0
  52. data/lib/panda/cms/asset_loader.rb +4 -4
  53. data/lib/panda/cms/engine.rb +42 -98
  54. data/lib/panda-cms/version.rb +1 -1
  55. data/lib/panda-cms.rb +50 -40
  56. data/lib/tasks/assets.rake +162 -122
  57. data/lib/tasks/panda/cms/migrations.rake +13 -0
  58. metadata +19 -36
  59. data/app/builders/panda/cms/form_builder.rb +0 -225
  60. data/app/components/panda/cms/admin/button_component.rb +0 -70
  61. data/app/components/panda/cms/admin/container_component.rb +0 -13
  62. data/app/components/panda/cms/admin/flash_message_component.rb +0 -47
  63. data/app/components/panda/cms/admin/heading_component.rb +0 -46
  64. data/app/components/panda/cms/admin/panel_component.rb +0 -13
  65. data/app/components/panda/cms/admin/table_component.rb +0 -46
  66. data/app/components/panda/cms/admin/tag_component.rb +0 -35
  67. data/app/constraints/panda/cms/admin_constraint.rb +0 -21
  68. data/app/controllers/panda/cms/admin/my_profile_controller.rb +0 -44
  69. data/app/controllers/panda/cms/admin/sessions_controller.rb +0 -92
  70. data/app/javascript/panda/cms/controllers/theme_form_controller.js +0 -25
  71. data/app/javascript/panda/cms/editor/css_extractor.js +0 -80
  72. data/app/javascript/panda/cms/editor/editor_js_config.js +0 -306
  73. data/app/javascript/panda/cms/editor/editor_js_initializer.js +0 -334
  74. data/app/javascript/panda/cms/editor/plain_text_editor.js +0 -110
  75. data/app/javascript/panda/cms/editor/resource_loader.js +0 -204
  76. data/app/javascript/panda/cms/editor/rich_text_editor.js +0 -162
  77. data/app/models/panda/cms/breadcrumb.rb +0 -14
  78. data/app/models/panda/cms/user.rb +0 -33
  79. data/app/services/panda/cms/html_to_editor_js_converter.rb +0 -195
  80. data/app/views/panda/cms/admin/my_profile/edit.html.erb +0 -35
  81. data/app/views/panda/cms/admin/sessions/new.html.erb +0 -17
  82. data/db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb +0 -7
  83. data/lib/panda/cms/editor_js/blocks/alert.rb +0 -36
  84. data/lib/panda/cms/editor_js/blocks/base.rb +0 -35
  85. data/lib/panda/cms/editor_js/blocks/header.rb +0 -17
  86. data/lib/panda/cms/editor_js/blocks/image.rb +0 -39
  87. data/lib/panda/cms/editor_js/blocks/list.rb +0 -34
  88. data/lib/panda/cms/editor_js/blocks/paragraph.rb +0 -18
  89. data/lib/panda/cms/editor_js/blocks/quote.rb +0 -44
  90. data/lib/panda/cms/editor_js/blocks/table.rb +0 -52
  91. data/lib/panda/cms/editor_js/renderer.rb +0 -127
  92. data/lib/panda/cms/editor_js.rb +0 -18
  93. data/lib/panda/cms/editor_js_content.rb +0 -61
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Otaina Limited t/a Tasty Bamboo
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: panda-editor
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: pg
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -262,15 +276,9 @@ files:
262
276
  - app/assets/stylesheets/panda/cms/editor.css
263
277
  - app/assets/tailwind/application.css
264
278
  - app/assets/tailwind/tailwind.config.js
265
- - app/builders/panda/cms/form_builder.rb
266
- - app/components/panda/cms/admin/button_component.rb
267
279
  - app/components/panda/cms/admin/container_component.html.erb
268
- - app/components/panda/cms/admin/container_component.rb
269
280
  - app/components/panda/cms/admin/flash_message_component.html.erb
270
- - app/components/panda/cms/admin/flash_message_component.rb
271
- - app/components/panda/cms/admin/heading_component.rb
272
281
  - app/components/panda/cms/admin/panel_component.html.erb
273
- - app/components/panda/cms/admin/panel_component.rb
274
282
  - app/components/panda/cms/admin/slideover_component.html.erb
275
283
  - app/components/panda/cms/admin/slideover_component.rb
276
284
  - app/components/panda/cms/admin/statistics_component.html.erb
@@ -278,8 +286,6 @@ files:
278
286
  - app/components/panda/cms/admin/tab_bar_component.html.erb
279
287
  - app/components/panda/cms/admin/tab_bar_component.rb
280
288
  - app/components/panda/cms/admin/table_component.html.erb
281
- - app/components/panda/cms/admin/table_component.rb
282
- - app/components/panda/cms/admin/tag_component.rb
283
289
  - app/components/panda/cms/admin/user_activity_component.html.erb
284
290
  - app/components/panda/cms/admin/user_activity_component.rb
285
291
  - app/components/panda/cms/admin/user_display_component.html.erb
@@ -294,16 +300,14 @@ files:
294
300
  - app/components/panda/cms/rich_text_component.html.erb
295
301
  - app/components/panda/cms/rich_text_component.rb
296
302
  - app/components/panda/cms/text_component.rb
297
- - app/constraints/panda/cms/admin_constraint.rb
303
+ - app/controllers/panda/cms/admin/base_controller.rb
298
304
  - app/controllers/panda/cms/admin/block_contents_controller.rb
299
305
  - app/controllers/panda/cms/admin/dashboard_controller.rb
300
306
  - app/controllers/panda/cms/admin/files_controller.rb
301
307
  - app/controllers/panda/cms/admin/forms_controller.rb
302
308
  - app/controllers/panda/cms/admin/menus_controller.rb
303
- - app/controllers/panda/cms/admin/my_profile_controller.rb
304
309
  - app/controllers/panda/cms/admin/pages_controller.rb
305
310
  - app/controllers/panda/cms/admin/posts_controller.rb
306
- - app/controllers/panda/cms/admin/sessions_controller.rb
307
311
  - app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb
308
312
  - app/controllers/panda/cms/admin/settings_controller.rb
309
313
  - app/controllers/panda/cms/application_controller.rb
@@ -329,13 +333,6 @@ files:
329
333
  - app/javascript/panda/cms/controllers/editor_iframe_controller.js
330
334
  - app/javascript/panda/cms/controllers/index.js
331
335
  - app/javascript/panda/cms/controllers/slug_controller.js
332
- - app/javascript/panda/cms/controllers/theme_form_controller.js
333
- - app/javascript/panda/cms/editor/css_extractor.js
334
- - app/javascript/panda/cms/editor/editor_js_config.js
335
- - app/javascript/panda/cms/editor/editor_js_initializer.js
336
- - app/javascript/panda/cms/editor/plain_text_editor.js
337
- - app/javascript/panda/cms/editor/resource_loader.js
338
- - app/javascript/panda/cms/editor/rich_text_editor.js
339
336
  - app/javascript/panda/cms/stimulus-loading.js
340
337
  - app/javascript/panda/cms/tailwindcss-stimulus-components.js
341
338
  - app/javascript/panda_cms/stimulus-loading.js
@@ -346,7 +343,6 @@ files:
346
343
  - app/models/panda/cms/application_record.rb
347
344
  - app/models/panda/cms/block.rb
348
345
  - app/models/panda/cms/block_content.rb
349
- - app/models/panda/cms/breadcrumb.rb
350
346
  - app/models/panda/cms/current.rb
351
347
  - app/models/panda/cms/form.rb
352
348
  - app/models/panda/cms/form_submission.rb
@@ -356,10 +352,8 @@ files:
356
352
  - app/models/panda/cms/post.rb
357
353
  - app/models/panda/cms/redirect.rb
358
354
  - app/models/panda/cms/template.rb
359
- - app/models/panda/cms/user.rb
360
355
  - app/models/panda/cms/visit.rb
361
356
  - app/models/panda/social/instagram_post.rb
362
- - app/services/panda/cms/html_to_editor_js_converter.rb
363
357
  - app/services/panda/social/instagram_feed_service.rb
364
358
  - app/views/active_storage/blobs/blobs/_blob.html.erb
365
359
  - app/views/layouts/action_text/contents/_content.html.erb
@@ -376,7 +370,6 @@ files:
376
370
  - app/views/panda/cms/admin/forms/new.html.erb
377
371
  - app/views/panda/cms/admin/forms/show.html.erb
378
372
  - app/views/panda/cms/admin/menus/index.html.erb
379
- - app/views/panda/cms/admin/my_profile/edit.html.erb
380
373
  - app/views/panda/cms/admin/pages/edit.html.erb
381
374
  - app/views/panda/cms/admin/pages/index.html.erb
382
375
  - app/views/panda/cms/admin/pages/new.html.erb
@@ -385,7 +378,6 @@ files:
385
378
  - app/views/panda/cms/admin/posts/edit.html.erb
386
379
  - app/views/panda/cms/admin/posts/index.html.erb
387
380
  - app/views/panda/cms/admin/posts/new.html.erb
388
- - app/views/panda/cms/admin/sessions/new.html.erb
389
381
  - app/views/panda/cms/admin/settings/bulk_editor/new.html.erb
390
382
  - app/views/panda/cms/admin/settings/index.html.erb
391
383
  - app/views/panda/cms/admin/settings/insta.html
@@ -453,7 +445,8 @@ files:
453
445
  - db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb
454
446
  - db/migrate/20250120235542_remove_paper_trail.rb
455
447
  - db/migrate/20250126234001_create_panda_social_instagram_posts.rb
456
- - db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb
448
+ - db/migrate/20250809231125_migrate_users_to_panda_core.rb
449
+ - db/migrate/20250811111000_make_post_user_references_nullable.rb
457
450
  - db/migrate/migrate
458
451
  - db/seeds.rb
459
452
  - lib/generators/panda/cms/install_generator.rb
@@ -463,23 +456,13 @@ files:
463
456
  - lib/panda/cms/asset_loader.rb
464
457
  - lib/panda/cms/bulk_editor.rb
465
458
  - lib/panda/cms/demo_site_generator.rb
466
- - lib/panda/cms/editor_js.rb
467
- - lib/panda/cms/editor_js/blocks/alert.rb
468
- - lib/panda/cms/editor_js/blocks/base.rb
469
- - lib/panda/cms/editor_js/blocks/header.rb
470
- - lib/panda/cms/editor_js/blocks/image.rb
471
- - lib/panda/cms/editor_js/blocks/list.rb
472
- - lib/panda/cms/editor_js/blocks/paragraph.rb
473
- - lib/panda/cms/editor_js/blocks/quote.rb
474
- - lib/panda/cms/editor_js/blocks/table.rb
475
- - lib/panda/cms/editor_js/renderer.rb
476
- - lib/panda/cms/editor_js_content.rb
477
459
  - lib/panda/cms/engine.rb
478
460
  - lib/panda/cms/exceptions_app.rb
479
461
  - lib/panda/cms/railtie.rb
480
462
  - lib/panda/cms/slug.rb
481
463
  - lib/tasks/assets.rake
482
464
  - lib/tasks/panda/cms/install.rake
465
+ - lib/tasks/panda/cms/migrations.rake
483
466
  - lib/tasks/panda/social/instagram.rake
484
467
  - lib/tasks/panda_cms.rake
485
468
  - lib/templates/erb/scaffold/_form.html.erb.tt
@@ -1,225 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- class FormBuilder < ActionView::Helpers::FormBuilder
6
- include ActionView::Helpers::TagHelper
7
- include ActionView::Helpers::FormTagHelper
8
-
9
- def label(attribute, text = nil, options = {})
10
- super(attribute, text, options.reverse_merge(class: label_styles))
11
- end
12
-
13
- def text_field(attribute, options = {})
14
- if options.dig(:data, :prefix)
15
- content_tag :div, class: container_styles do
16
- label(attribute) + meta_text(options) +
17
- content_tag(:div, class: "flex flex-grow") do
18
- content_tag(:span,
19
- class: "inline-flex items-center px-3 text-base border border-r-none rounded-s-md whitespace-nowrap break-keep") do
20
- options.dig(:data, :prefix)
21
- end +
22
- super(attribute, options.reverse_merge(class: "#{input_styles_prefix} input-prefix rounded-l-none border-l-none"))
23
- end + error_message(attribute)
24
- end
25
- else
26
- content_tag :div, class: container_styles do
27
- label(attribute) + meta_text(options) + super(attribute, options.reverse_merge(class: input_styles)) + error_message(attribute)
28
- end
29
- end
30
- end
31
-
32
- def email_field(method, options = {})
33
- content_tag :div, class: container_styles do
34
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles)) + error_message(method)
35
- end
36
- end
37
-
38
- def datetime_field(method, options = {})
39
- content_tag :div, class: container_styles do
40
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles)) + error_message(method)
41
- end
42
- end
43
-
44
- def text_area(method, options = {})
45
- content_tag :div, class: container_styles do
46
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles)) + error_message(method)
47
- end
48
- end
49
-
50
- def password_field(attribute, options = {})
51
- content_tag :div, class: container_styles do
52
- label(attribute) + meta_text(options) + super(attribute, options.reverse_merge(class: input_styles)) + error_message(attribute)
53
- end
54
- end
55
-
56
- def select(method, choices = nil, options = {}, html_options = {})
57
- content_tag :div, class: container_styles do
58
- label(method) + meta_text(options) + super(method, choices, options, html_options.reverse_merge(class: select_styles)) + select_svg + error_message(method)
59
- end
60
- end
61
-
62
- def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
63
- content_tag :div, class: container_styles do
64
- label(method) + meta_text(options) + super(method, collection, value_method, text_method, options, html_options.reverse_merge(class: input_styles)) + error_message(method)
65
- end
66
- end
67
-
68
- def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
69
- wrap_field(method, options) do
70
- super(
71
- method,
72
- priority_zones,
73
- options,
74
- html_options.reverse_merge(class: select_styles)
75
- )
76
- end
77
- end
78
-
79
- def file_field(method, options = {})
80
- content_tag :div, class: container_styles do
81
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: "file:rounded file:border-0 file:text-sm file:bg-white file:text-gray-500 hover:file:bg-gray-50 bg-white px-2.5 hover:bg-gray-50".concat(input_styles)))
82
- end
83
- end
84
-
85
- def button(value = nil, options = {}, &block)
86
- value ||= submit_default_value
87
- options = options.dup
88
-
89
- # Handle formmethod specially
90
- if options[:formmethod] == "delete"
91
- options[:name] = "_method"
92
- options[:value] = "delete"
93
- end
94
-
95
- base_classes = [
96
- "inline-flex items-center rounded-md",
97
- "px-3 py-2",
98
- "text-base font-semibold",
99
- "shadow-sm"
100
- ]
101
-
102
- # Only add fa-circle-check for non-block buttons
103
- base_classes << "fa-circle-check" unless block_given?
104
-
105
- options[:class] = [
106
- *base_classes,
107
- options[:class]
108
- ].compact.join(" ")
109
-
110
- if block_given?
111
- @template.button_tag(options, &block)
112
- else
113
- @template.button_tag(value, options)
114
- end
115
- end
116
-
117
- def submit(value = nil, options = {})
118
- value ||= submit_default_value
119
-
120
- # Use the same style logic as ButtonComponent
121
- action = object.persisted? ? :save : :create
122
- button_classes = case action
123
- when :save, :create
124
- "text-white bg-active"
125
- when :save_inactive
126
- "text-white bg-inactive"
127
- when :secondary
128
- "text-dark border-2 border-mid bg-transparent hover:bg-light transition-all"
129
- else
130
- "text-dark border-2 border-mid bg-transparent hover:bg-light transition-all"
131
- end
132
-
133
- # Combine with common button classes
134
- classes = "inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 #{button_classes}"
135
-
136
- options[:class] = options[:class] ? "#{options[:class]} #{classes}" : classes
137
-
138
- super
139
- end
140
-
141
- def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
142
- content_tag :div, class: container_styles do
143
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: "border-gray-300 ml-2"), checked_value, unchecked_value)
144
- end
145
- end
146
-
147
- def date_field(method, options = {})
148
- content_tag :div, class: container_styles do
149
- label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles))
150
- end
151
- end
152
-
153
- def meta_text(options)
154
- return unless options[:meta]
155
-
156
- @template.content_tag(:p, options[:meta], class: "block text-black/60 text-sm mb-2")
157
- end
158
-
159
- private
160
-
161
- def label_styles
162
- "font-light inline-block mb-1 text-base leading-6"
163
- end
164
-
165
- def base_input_styles
166
- "bg-white block w-full rounded-md border border-mid focus:border-mid p-2 text-dark outline-0 focus:outline-0 ring-0 focus:ring-0 focus:ring-mid ring-offset-0 focus:ring-offset-0 shadow-none focus:shadow-none border-mid"
167
- end
168
-
169
- def input_styles
170
- base_input_styles
171
- end
172
-
173
- def input_styles_prefix
174
- input_styles.concat(" prefix")
175
- end
176
-
177
- def select_styles
178
- "col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-1.5 pl-3 pr-8 text-dark text-base outline-0 outline-dark focus:outline focus:-outline-offset-2 focus:outline-dark"
179
- end
180
-
181
- def select_svg
182
- @template.content_tag(:svg,
183
- class: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400", aria_hidden: true) do
184
- @template.content_tag(:path, d: "M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z")
185
- end
186
- end
187
-
188
- def button_styles
189
- "inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-0 focus-visible:outline-offset-none text-dark border-2 border-mid bg-transparent hover:bg-light transition-all gap-x-1.5 px-3 py-2 text-base gap-x-1.5 px-2.5 py-1.5 mt-2 "
190
- end
191
-
192
- def container_styles
193
- "panda-cms-field-container mb-4"
194
- end
195
-
196
- def textarea_styles
197
- input_styles.concat(" min-h-32")
198
- end
199
-
200
- def submit_default_value
201
- object.persisted? ? "Update #{object.class.name.demodulize}" : "Create #{object.class.name.demodulize}"
202
- end
203
-
204
- def wrap_field(method, options = {}, &block)
205
- @template.content_tag(:div, class: "panda-cms-field-container") do
206
- label(method, class: "font-light inline-block mb-1 text-base leading-6") +
207
- meta_text(options) +
208
- @template.content_tag(:div, class: field_wrapper_styles, &block)
209
- end
210
- end
211
-
212
- def field_wrapper_styles
213
- "mt-1"
214
- end
215
-
216
- def error_message(attribute)
217
- return unless object.respond_to?(:errors) && object.errors[attribute]&.any?
218
-
219
- content_tag(:p, class: "mt-2 text-sm text-red-600") do
220
- object.errors[attribute].join(", ")
221
- end
222
- end
223
- end
224
- end
225
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class ButtonComponent < ViewComponent::Base
7
- attr_accessor :text, :action, :link, :icon, :size, :data
8
-
9
- def initialize(text: "Button", action: nil, data: {}, link: "#", icon: nil, size: :regular, id: nil)
10
- @text = text
11
- @action = action
12
- @data = data
13
- @link = link
14
- @icon = icon
15
- @size = size
16
- @id = id
17
- end
18
-
19
- def call
20
- @icon = set_icon_from_action(@action) if @action && @icon.nil?
21
- icon = content_tag(:i, "", class: "mr-2 fa-regular fa-#{@icon}") if @icon
22
- @text = "#{icon} #{@text.titleize}".html_safe
23
-
24
- classes = "inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
25
-
26
- case @size
27
- when :small, :sm
28
- classes += "gap-x-1.5 px-2.5 py-1.5 text-sm "
29
- when :medium, :regular, :md
30
- classes += "gap-x-1.5 px-3 py-2 text-base "
31
- when :large, :lg
32
- classes += "gap-x-2 px-3.5 py-2.5 text-lg "
33
- end
34
-
35
- classes += case @action
36
- when :save, :create
37
- "text-white bg-active"
38
- when :save_inactive
39
- "text-white bg-inactive"
40
- when :secondary
41
- "text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
42
- when :delete, :destroy, :danger
43
- "text-error border border-error bg-red-100 hover:bg-red-200 hover:text-error focus-visible:outline-red-300 "
44
- else
45
- "text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
46
- end
47
-
48
- content_tag :a, href: @link, class: classes, data: @data, id: @id do
49
- @text
50
- end
51
- end
52
-
53
- private
54
-
55
- def set_icon_from_action(action)
56
- case action
57
- when :add, :new, :create
58
- "plus"
59
- when :save
60
- "check"
61
- when :edit, :update
62
- "pencil"
63
- when :delete, :destroy
64
- "trash"
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class ContainerComponent < ViewComponent::Base
7
- renders_one :heading, "Panda::CMS::Admin::HeadingComponent"
8
- renders_one :tab_bar, "Panda::CMS::Admin::TabBarComponent"
9
- renders_one :slideover, "Panda::CMS::Admin::SlideoverComponent"
10
- end
11
- end
12
- end
13
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class FlashMessageComponent < ::ViewComponent::Base
7
- attr_reader :kind, :message
8
-
9
- def initialize(message:, kind:, temporary: true)
10
- @kind = kind.to_sym
11
- @message = message
12
- @temporary = temporary
13
- end
14
-
15
- def text_colour_css
16
- case kind
17
- when :success
18
- "text-active"
19
- when :alert, :error
20
- "text-error"
21
- when :warning
22
- "text-warning"
23
- when :info, :notice
24
- "text-active"
25
- else
26
- "text-mid"
27
- end
28
- end
29
-
30
- def icon_css
31
- case kind
32
- when :success
33
- "fa-circle-check"
34
- when :alert
35
- "fa-circle-xmark"
36
- when :warning
37
- "fa-triangle-exclamation"
38
- when :info, :notice
39
- "fa-circle-info"
40
- else
41
- "fa-circle-info"
42
- end
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class HeadingComponent < ViewComponent::Base
7
- renders_many :buttons, Panda::CMS::Admin::ButtonComponent
8
-
9
- attr_reader :text, :level, :icon, :additional_styles
10
-
11
- def initialize(text:, level: 2, icon: "", additional_styles: "")
12
- @text = text
13
- @level = level
14
- @icon = icon
15
- @additional_styles = additional_styles
16
- @additional_styles = @additional_styles.split(" ") if @additional_styles.is_a?(String)
17
- end
18
-
19
- def call
20
- output = ""
21
- output += content_tag(:div, @text, class: "grow")
22
-
23
- if buttons?
24
- output += content_tag(:span, class: "actions flex gap-x-2 -mt-1") do
25
- safe_join(buttons, "")
26
- end
27
- end
28
-
29
- output = output.html_safe
30
- base_heading_styles = "flex pt-1 text-black mb-5 -mt-1"
31
-
32
- case level
33
- when 1
34
- content_tag(:h1, output, class: [base_heading_styles, "text-2xl font-medium", @additional_styles])
35
- when 2
36
- content_tag(:h2, output, class: [base_heading_styles, "text-xl font-medium", @additional_styles])
37
- when 3
38
- content_tag(:h3, output, class: [base_heading_styles, "text-xl", "font-light", @additional_styles])
39
- when :panel
40
- content_tag(:h3, output, class: ["text-base font-medium p-4 text-white"])
41
- end
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class PanelComponent < ViewComponent::Base
7
- renders_one :heading, lambda { |text:, icon: "", level: :panel, additional_styles: ""|
8
- Panda::CMS::Admin::HeadingComponent.new(text: text, icon: icon, level: level, additional_styles: additional_styles)
9
- }
10
- end
11
- end
12
- end
13
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class TableComponent < ViewComponent::Base
7
- attr_reader :columns
8
-
9
- def initialize(term:, rows:)
10
- @term = term
11
- @rows = rows
12
- @columns = []
13
- end
14
-
15
- def column(label, &)
16
- @columns << Column.new(label, &)
17
- end
18
-
19
- private
20
-
21
- # Ensures @columns gets populated [https://dev.to/rolandstuder/supercharged-table-component-built-with-viewcomponent-3j6i]
22
- def before_render
23
- content
24
- end
25
- end
26
-
27
- class Column
28
- attr_reader :label, :cell
29
-
30
- def initialize(label, &block)
31
- @label = label
32
- @cell = block
33
- end
34
- end
35
-
36
- class TagColumn < Column
37
- attr_reader :label, :cell
38
-
39
- def initialize(label, &block)
40
- @label = label
41
- @cell = Panda::CMS::Admin::TagComponent.new(status: block)
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class TagComponent < ViewComponent::Base
7
- attr_accessor :status, :text
8
-
9
- def initialize(status: :active, text: nil)
10
- @status = status.to_sym
11
- @text = text || status.to_s.humanize
12
- end
13
-
14
- def call
15
- classes = "inline-flex items-center py-1 px-2 text-xs font-medium rounded-md ring-1 ring-inset "
16
-
17
- classes += case @status
18
- when :active
19
- "text-white ring-black/30 bg-active border-0 "
20
- when :draft
21
- "text-black ring-black/30 bg-warning "
22
- when :inactive, :hidden
23
- "text-black ring-black/30 bg-black/5 bg-white "
24
- else
25
- "text-black bg-white "
26
- end
27
-
28
- content_tag :span, class: classes do
29
- @text
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- class AdminConstraint
6
- def initialize(&block)
7
- @block = block
8
- end
9
-
10
- def matches?(request)
11
- user = current_user(request)
12
- user.present? && user.admin? && @block&.call(user)
13
- end
14
-
15
- def current_user(request)
16
- user_id = request.session[:user_id]
17
- User.find_by(id: user_id)
18
- end
19
- end
20
- end
21
- end