panda-cms 0.8.0 → 0.10.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/README.md +83 -4
  3. data/app/components/panda/cms/code_component.rb +117 -39
  4. data/app/components/panda/cms/grid_component.rb +26 -6
  5. data/app/components/panda/cms/menu_component.rb +66 -34
  6. data/app/components/panda/cms/page_menu_component.rb +94 -13
  7. data/app/components/panda/cms/rich_text_component.rb +198 -140
  8. data/app/components/panda/cms/text_component.rb +77 -44
  9. data/app/controllers/panda/cms/admin/base_controller.rb +19 -3
  10. data/app/controllers/panda/cms/admin/dashboard_controller.rb +3 -3
  11. data/app/controllers/panda/cms/admin/files_controller.rb +7 -0
  12. data/app/controllers/panda/cms/admin/menus_controller.rb +47 -3
  13. data/app/controllers/panda/cms/admin/pages_controller.rb +6 -1
  14. data/app/controllers/panda/cms/pages_controller.rb +2 -2
  15. data/app/helpers/panda/cms/application_helper.rb +15 -1
  16. data/app/helpers/panda/cms/asset_helper.rb +14 -3
  17. data/app/javascript/panda/cms/application_panda_cms.js +1 -1
  18. data/app/javascript/panda/cms/controllers/code_editor_controller.js +95 -0
  19. data/app/javascript/panda/cms/controllers/file_gallery_controller.js +128 -0
  20. data/app/javascript/panda/cms/controllers/index.js +48 -13
  21. data/app/javascript/panda/cms/controllers/inline_code_editor_controller.js +96 -0
  22. data/app/javascript/panda/cms/controllers/menu_form_controller.js +40 -0
  23. data/app/javascript/panda/cms/controllers/nested_form_controller.js +35 -0
  24. data/app/javascript/panda/cms/controllers/tree_controller.js +214 -0
  25. data/app/javascript/panda/cms/stimulus-loading.js +5 -7
  26. data/app/models/panda/cms/block_content.rb +9 -0
  27. data/app/models/panda/cms/page.rb +41 -0
  28. data/app/models/panda/cms/post.rb +1 -0
  29. data/app/views/panda/cms/admin/dashboard/show.html.erb +5 -5
  30. data/app/views/panda/cms/admin/files/_file_details.html.erb +45 -0
  31. data/app/views/panda/cms/admin/files/index.html.erb +11 -118
  32. data/app/views/panda/cms/admin/forms/index.html.erb +2 -2
  33. data/app/views/panda/cms/admin/forms/new.html.erb +1 -2
  34. data/app/views/panda/cms/admin/forms/show.html.erb +15 -30
  35. data/app/views/panda/cms/admin/menus/_menu_item_fields.html.erb +11 -0
  36. data/app/views/panda/cms/admin/menus/edit.html.erb +64 -0
  37. data/app/views/panda/cms/admin/menus/index.html.erb +3 -2
  38. data/app/views/panda/cms/admin/menus/new.html.erb +40 -0
  39. data/app/views/panda/cms/admin/pages/edit.html.erb +15 -9
  40. data/app/views/panda/cms/admin/pages/index.html.erb +49 -11
  41. data/app/views/panda/cms/admin/pages/new.html.erb +3 -11
  42. data/app/views/panda/cms/admin/posts/_form.html.erb +4 -14
  43. data/app/views/panda/cms/admin/posts/edit.html.erb +2 -2
  44. data/app/views/panda/cms/admin/posts/index.html.erb +3 -3
  45. data/app/views/panda/cms/admin/posts/new.html.erb +1 -1
  46. data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +1 -1
  47. data/app/views/panda/cms/admin/settings/index.html.erb +3 -3
  48. data/config/importmap.rb +4 -6
  49. data/config/initializers/panda/cms/healthcheck_log_silencer.rb.disabled +31 -0
  50. data/config/initializers/panda/cms.rb +52 -10
  51. data/config/routes.rb +4 -2
  52. data/db/migrate/20240305000000_convert_html_content_to_editor_js.rb +9 -2
  53. data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +6 -1
  54. data/db/migrate/20250809231125_migrate_users_to_panda_core.rb +23 -21
  55. data/db/migrate/20251104150640_add_cached_last_updated_at_to_panda_cms_pages.rb +22 -0
  56. data/db/migrate/20251104172242_add_page_type_to_panda_cms_pages.rb +6 -0
  57. data/db/migrate/20251104172638_set_page_types_for_existing_pages.rb +27 -0
  58. data/db/migrate/20251105000001_add_pending_review_status_to_pages_and_posts.panda_cms.rb +21 -0
  59. data/lib/generators/panda/cms/install_generator.rb +2 -5
  60. data/lib/panda/cms/asset_loader.rb +36 -16
  61. data/lib/panda/cms/debug.rb +29 -0
  62. data/lib/panda/cms/engine.rb +107 -48
  63. data/lib/panda/cms/features.rb +52 -0
  64. data/lib/panda-cms/version.rb +1 -1
  65. data/lib/panda-cms.rb +5 -6
  66. data/lib/tasks/assets.rake +5 -52
  67. data/lib/tasks/panda_cms_tasks.rake +16 -0
  68. metadata +22 -29
  69. data/app/components/panda/cms/admin/container_component.html.erb +0 -13
  70. data/app/components/panda/cms/admin/flash_message_component.html.erb +0 -31
  71. data/app/components/panda/cms/admin/panel_component.html.erb +0 -7
  72. data/app/components/panda/cms/admin/slideover_component.html.erb +0 -9
  73. data/app/components/panda/cms/admin/slideover_component.rb +0 -15
  74. data/app/components/panda/cms/admin/statistics_component.html.erb +0 -4
  75. data/app/components/panda/cms/admin/statistics_component.rb +0 -16
  76. data/app/components/panda/cms/admin/tab_bar_component.html.erb +0 -35
  77. data/app/components/panda/cms/admin/tab_bar_component.rb +0 -15
  78. data/app/components/panda/cms/admin/table_component.html.erb +0 -29
  79. data/app/components/panda/cms/admin/user_activity_component.html.erb +0 -7
  80. data/app/components/panda/cms/admin/user_activity_component.rb +0 -20
  81. data/app/components/panda/cms/admin/user_display_component.html.erb +0 -17
  82. data/app/components/panda/cms/admin/user_display_component.rb +0 -21
  83. data/app/components/panda/cms/grid_component.html.erb +0 -6
  84. data/app/components/panda/cms/menu_component.html.erb +0 -6
  85. data/app/components/panda/cms/page_menu_component.html.erb +0 -21
  86. data/app/components/panda/cms/rich_text_component.html.erb +0 -90
  87. data/app/views/layouts/panda/cms/application.html.erb +0 -42
  88. data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +0 -28
  89. data/app/views/panda/cms/admin/shared/_flash.html.erb +0 -5
  90. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +0 -41
  91. data/app/views/panda/cms/shared/_footer.html.erb +0 -2
  92. data/app/views/panda/cms/shared/_header.html.erb +0 -25
  93. data/config/initializers/panda/cms/healthcheck_log_silencer.rb +0 -13
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
- - Otaina Limited t/a Tasty Bamboo
7
+ - Otaina Limited
8
8
  - James Inman
9
9
  bindir: bin
10
10
  cert_chain: []
@@ -263,7 +263,7 @@ dependencies:
263
263
  - !ruby/object:Gem::Version
264
264
  version: '0'
265
265
  email:
266
- - bamboo@pandacms.io
266
+ - james@otaina.co.uk
267
267
  executables: []
268
268
  extensions: []
269
269
  extra_rdoc_files: []
@@ -276,28 +276,10 @@ files:
276
276
  - app/assets/stylesheets/panda/cms/editor.css
277
277
  - app/assets/tailwind/application.css
278
278
  - app/assets/tailwind/tailwind.config.js
279
- - app/components/panda/cms/admin/container_component.html.erb
280
- - app/components/panda/cms/admin/flash_message_component.html.erb
281
- - app/components/panda/cms/admin/panel_component.html.erb
282
- - app/components/panda/cms/admin/slideover_component.html.erb
283
- - app/components/panda/cms/admin/slideover_component.rb
284
- - app/components/panda/cms/admin/statistics_component.html.erb
285
- - app/components/panda/cms/admin/statistics_component.rb
286
- - app/components/panda/cms/admin/tab_bar_component.html.erb
287
- - app/components/panda/cms/admin/tab_bar_component.rb
288
- - app/components/panda/cms/admin/table_component.html.erb
289
- - app/components/panda/cms/admin/user_activity_component.html.erb
290
- - app/components/panda/cms/admin/user_activity_component.rb
291
- - app/components/panda/cms/admin/user_display_component.html.erb
292
- - app/components/panda/cms/admin/user_display_component.rb
293
279
  - app/components/panda/cms/code_component.rb
294
- - app/components/panda/cms/grid_component.html.erb
295
280
  - app/components/panda/cms/grid_component.rb
296
- - app/components/panda/cms/menu_component.html.erb
297
281
  - app/components/panda/cms/menu_component.rb
298
- - app/components/panda/cms/page_menu_component.html.erb
299
282
  - app/components/panda/cms/page_menu_component.rb
300
- - app/components/panda/cms/rich_text_component.html.erb
301
283
  - app/components/panda/cms/rich_text_component.rb
302
284
  - app/components/panda/cms/text_component.rb
303
285
  - app/controllers/panda/cms/admin/base_controller.rb
@@ -328,11 +310,17 @@ files:
328
310
  - app/javascript/panda/cms/@hotwired--turbo.js
329
311
  - app/javascript/panda/cms/@rails--actioncable--src.js
330
312
  - app/javascript/panda/cms/application_panda_cms.js
313
+ - app/javascript/panda/cms/controllers/code_editor_controller.js
331
314
  - app/javascript/panda/cms/controllers/dashboard_controller.js
332
315
  - app/javascript/panda/cms/controllers/editor_form_controller.js
333
316
  - app/javascript/panda/cms/controllers/editor_iframe_controller.js
317
+ - app/javascript/panda/cms/controllers/file_gallery_controller.js
334
318
  - app/javascript/panda/cms/controllers/index.js
319
+ - app/javascript/panda/cms/controllers/inline_code_editor_controller.js
320
+ - app/javascript/panda/cms/controllers/menu_form_controller.js
321
+ - app/javascript/panda/cms/controllers/nested_form_controller.js
335
322
  - app/javascript/panda/cms/controllers/slug_controller.js
323
+ - app/javascript/panda/cms/controllers/tree_controller.js
336
324
  - app/javascript/panda/cms/stimulus-loading.js
337
325
  - app/javascript/panda/cms/tailwindcss-stimulus-components.js
338
326
  - app/javascript/panda_cms/stimulus-loading.js
@@ -360,16 +348,19 @@ files:
360
348
  - app/views/layouts/different_page.html.erb
361
349
  - app/views/layouts/homepage.html.erb
362
350
  - app/views/layouts/page.html.erb
363
- - app/views/layouts/panda/cms/application.html.erb
364
351
  - app/views/layouts/panda/cms/public.html.erb
365
352
  - app/views/panda/cms/admin/dashboard/show.html.erb
353
+ - app/views/panda/cms/admin/files/_file_details.html.erb
366
354
  - app/views/panda/cms/admin/files/index.html.erb
367
355
  - app/views/panda/cms/admin/files/show.html.erb
368
356
  - app/views/panda/cms/admin/forms/edit.html.erb
369
357
  - app/views/panda/cms/admin/forms/index.html.erb
370
358
  - app/views/panda/cms/admin/forms/new.html.erb
371
359
  - app/views/panda/cms/admin/forms/show.html.erb
360
+ - app/views/panda/cms/admin/menus/_menu_item_fields.html.erb
361
+ - app/views/panda/cms/admin/menus/edit.html.erb
372
362
  - app/views/panda/cms/admin/menus/index.html.erb
363
+ - app/views/panda/cms/admin/menus/new.html.erb
373
364
  - app/views/panda/cms/admin/pages/edit.html.erb
374
365
  - app/views/panda/cms/admin/pages/index.html.erb
375
366
  - app/views/panda/cms/admin/pages/new.html.erb
@@ -381,14 +372,9 @@ files:
381
372
  - app/views/panda/cms/admin/settings/bulk_editor/new.html.erb
382
373
  - app/views/panda/cms/admin/settings/index.html.erb
383
374
  - app/views/panda/cms/admin/settings/insta.html
384
- - app/views/panda/cms/admin/shared/_breadcrumbs.html.erb
385
- - app/views/panda/cms/admin/shared/_flash.html.erb
386
- - app/views/panda/cms/admin/shared/_sidebar.html.erb
387
375
  - app/views/panda/cms/form_mailer/notification_email.html.erb
388
376
  - app/views/panda/cms/shared/_editor.html.erb
389
377
  - app/views/panda/cms/shared/_favicons.html.erb
390
- - app/views/panda/cms/shared/_footer.html.erb
391
- - app/views/panda/cms/shared/_header.html.erb
392
378
  - app/views/panda/cms/shared/_importmap.html.erb
393
379
  - app/views/shared/_footer.html.erb
394
380
  - app/views/shared/_header.html.erb
@@ -396,7 +382,7 @@ files:
396
382
  - config/initializers/inflections.rb
397
383
  - config/initializers/panda/cms.rb
398
384
  - config/initializers/panda/cms/form_errors.rb
399
- - config/initializers/panda/cms/healthcheck_log_silencer.rb
385
+ - config/initializers/panda/cms/healthcheck_log_silencer.rb.disabled
400
386
  - config/initializers/zeitwork.rb
401
387
  - config/locales/en.yml
402
388
  - config/puma/test.rb
@@ -447,6 +433,10 @@ files:
447
433
  - db/migrate/20250126234001_create_panda_social_instagram_posts.rb
448
434
  - db/migrate/20250809231125_migrate_users_to_panda_core.rb
449
435
  - db/migrate/20250811111000_make_post_user_references_nullable.rb
436
+ - db/migrate/20251104150640_add_cached_last_updated_at_to_panda_cms_pages.rb
437
+ - db/migrate/20251104172242_add_page_type_to_panda_cms_pages.rb
438
+ - db/migrate/20251104172638_set_page_types_for_existing_pages.rb
439
+ - db/migrate/20251105000001_add_pending_review_status_to_pages_and_posts.panda_cms.rb
450
440
  - db/migrate/migrate
451
441
  - db/seeds.rb
452
442
  - lib/generators/panda/cms/install_generator.rb
@@ -455,9 +445,11 @@ files:
455
445
  - lib/panda/cms.rb
456
446
  - lib/panda/cms/asset_loader.rb
457
447
  - lib/panda/cms/bulk_editor.rb
448
+ - lib/panda/cms/debug.rb
458
449
  - lib/panda/cms/demo_site_generator.rb
459
450
  - lib/panda/cms/engine.rb
460
451
  - lib/panda/cms/exceptions_app.rb
452
+ - lib/panda/cms/features.rb
461
453
  - lib/panda/cms/railtie.rb
462
454
  - lib/panda/cms/slug.rb
463
455
  - lib/tasks/assets.rake
@@ -465,6 +457,7 @@ files:
465
457
  - lib/tasks/panda/cms/migrations.rake
466
458
  - lib/tasks/panda/social/instagram.rake
467
459
  - lib/tasks/panda_cms.rake
460
+ - lib/tasks/panda_cms_tasks.rake
468
461
  - lib/templates/erb/scaffold/_form.html.erb.tt
469
462
  - lib/templates/erb/scaffold/edit.html.erb.tt
470
463
  - lib/templates/erb/scaffold/index.html.erb.tt
@@ -519,7 +512,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
519
512
  - !ruby/object:Gem::Version
520
513
  version: '0'
521
514
  requirements: []
522
- rubygems_version: 3.6.9
515
+ rubygems_version: 3.7.2
523
516
  specification_version: 4
524
517
  summary: Better websites on Rails.
525
518
  test_files: []
@@ -1,13 +0,0 @@
1
- <main class="overflow-auto flex-1 h-full min-h-full max-h-full">
2
- <div class="overflow-auto px-2 pt-4 mx-auto sm:px-6 lg:px-6">
3
- <%= heading %>
4
- <%= tab_bar %>
5
- <%# I mean, you can edit this CSS if you want, but I hope you want to lose 2 hours to iFrame joy? %>
6
- <section class="flex-auto h-[calc(100vh-10rem)]">
7
- <div class="flex-1 mt-4 w-full h-full">
8
- <%= content %>
9
- </div>
10
- <%= slideover %>
11
- </section>
12
- </div>
13
- </main>
@@ -1,31 +0,0 @@
1
- <div class="fixed top-2 right-2 z-[9999] p-2 space-y-4 w-full max-w-sm sm:items-end"
2
- data-controller="alert"
3
- <% if @temporary %> data-alert-dismiss-after-value="3000"<% end %>
4
- data-transition-enter="ease-in-out duration-500"
5
- data-transition-enter-from="translate-x-full opacity-0"
6
- data-transition-enter-to="translate-x-0 opacity-100"
7
- data-transition-leave="ease-in-out duration-500"
8
- data-transition-leave-from="translate-x-0 opacity-100"
9
- data-transition-leave-to="translate-x-full opacity-0">
10
- <div class="overflow-hidden w-full max-w-sm bg-white rounded-lg ring-1 ring-black ring-opacity-5 shadow-lg">
11
- <div class="p-4">
12
- <div class="flex items-start">
13
- <div class="flex-shrink-0">
14
- <i class="fa-regular text-xl <%= icon_css %> <%= text_colour_css %>"></i>
15
- </div>
16
- <div class="flex-1 pt-0.5 ml-3 w-0">
17
- <p class="mb-1 text-sm font-medium flash-message-title <%= text_colour_css %>"><%= kind.to_s.titleize %></p>
18
- <p class="mt-1 mb-0 text-sm text-gray-500 flash-message-text"><%= message %></p>
19
- </div>
20
- <div class="flex flex-shrink-0 ml-4">
21
- <button data-action="alert#close" type="button" class="inline-flex text-gray-400 bg-white rounded-md transition duration-150 ease-in-out hover:text-gray-500 focus:ring-2 focus:ring-offset-2 focus:outline-none focus:ring-sky-500">
22
- <span class="sr-only">Close</span>
23
- <svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
24
- <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
25
- </svg>
26
- </button>
27
- </div>
28
- </div>
29
- </div>
30
- </div>
31
- </div>
@@ -1,7 +0,0 @@
1
- <div class="col-span-3 mt-5 rounded-lg shadow-md bg-mid shadow-inherit/20">
2
- <%= heading %>
3
-
4
- <div class="p-4 text-black bg-white rounded-b-lg">
5
- <%= content %>
6
- </div>
7
- </div>
@@ -1,9 +0,0 @@
1
- <% content_for :sidebar do %>
2
- <aside class="hidden overflow-y-auto w-96 h-full bg-white lg:block">
3
- <%= content %>
4
- </aside>
5
- <% end %>
6
-
7
- <% content_for :sidebar_title do %>
8
- <%= title %>
9
- <% end %>
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class SlideoverComponent < ViewComponent::Base
7
- attr_reader :title
8
-
9
- def initialize(title: "Settings")
10
- @title = title
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,4 +0,0 @@
1
- <div class="overflow-hidden p-4 bg-gradient-to-br rounded-lg border-2 from-light/20 to-light border-mid">
2
- <dt class="text-base font-medium truncate text-dark"><%= metric %></dt>
3
- <dd class="mt-1 text-3xl font-medium tracking-tight text-dark"><%= value %></dd>
4
- </div>
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class StatisticsComponent < ViewComponent::Base
7
- attr_reader :metric, :value
8
-
9
- def initialize(metric:, value:)
10
- @metric = metric
11
- @value = value
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,35 +0,0 @@
1
- <div class="mt-3 sm:mt-2">
2
- <div class="sm:hidden">
3
- <label for="tabs" class="sr-only">Select a tab</label>
4
- <!-- Use an "onChange" listener to redirect the user to the selected tab URL. -->
5
- <select id="tabs" name="tabs" class="block py-1.5 pr-10 pl-3 w-full text-gray-900 rounded-md border-0 ring-1 ring-inset focus:ring-2 focus:ring-inset ring-mid focus:border-panda-dark focus:ring-panda-dark">
6
- <% tabs.each do |tab| %>
7
- <option><%= tab %></option>
8
- <% end %>
9
- </select>
10
- </div>
11
- <div class="hidden sm:block">
12
- <div class="flex items-center border-b border-gray-200">
13
- <nav class="flex flex-1 -mb-px space-x-6 xl:space-x-8" aria-label="Tabs">
14
- <!-- Current: "border-panda-dark text-panda-dark", Default: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" -->
15
- <a href="#" aria-current="page" class="py-4 px-1 text-sm font-medium whitespace-nowrap border-b-2 border-panda-dark text-panda-dark">Recently Viewed</a>
16
- <a href="#" class="py-4 px-1 text-sm font-medium text-gray-500 whitespace-nowrap border-b-2 border-transparent hover:text-gray-700 hover:border-gray-300">Recently Added</a>
17
- <a href="#" class="py-4 px-1 text-sm font-medium text-gray-500 whitespace-nowrap border-b-2 border-transparent hover:text-gray-700 hover:border-gray-300">Favourited</a>
18
- </nav>
19
- <div class="hidden items-center p-0.5 ml-6 bg-gray-100 rounded-lg sm:flex">
20
- <button type="button" class="p-1.5 text-gray-400 rounded-md hover:bg-white hover:shadow-sm focus:ring-2 focus:ring-inset focus:outline-none focus:ring-panda-dark">
21
- <svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
22
- <path fill-rule="evenodd" d="M2 3.75A.75.75 0 012.75 3h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4.167a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75zm0 4.166a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75zm0 4.167a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z" clip-rule="evenodd" />
23
- </svg>
24
- <span class="sr-only">Use list view</span>
25
- </button>
26
- <button type="button" class="p-1.5 ml-0.5 text-gray-400 bg-white rounded-md shadow-sm focus:ring-2 focus:ring-inset focus:outline-none focus:ring-panda-dark">
27
- <svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
28
- <path fill-rule="evenodd" d="M4.25 2A2.25 2.25 0 002 4.25v2.5A2.25 2.25 0 004.25 9h2.5A2.25 2.25 0 009 6.75v-2.5A2.25 2.25 0 006.75 2h-2.5zm0 9A2.25 2.25 0 002 13.25v2.5A2.25 2.25 0 004.25 18h2.5A2.25 2.25 0 009 15.75v-2.5A2.25 2.25 0 006.75 11h-2.5zm9-9A2.25 2.25 0 0011 4.25v2.5A2.25 2.25 0 0013.25 9h2.5A2.25 2.25 0 0018 6.75v-2.5A2.25 2.25 0 0015.75 2h-2.5zm0 9A2.25 2.25 0 0011 13.25v2.5A2.25 2.25 0 0013.25 18h2.5A2.25 2.25 0 0018 15.75v-2.5A2.25 2.25 0 0015.75 11h-2.5z" clip-rule="evenodd" />
29
- </svg>
30
- <span class="sr-only">Use grid view</span>
31
- </button>
32
- </div>
33
- </div>
34
- </div>
35
- </div>
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class TabBarComponent < ViewComponent::Base
7
- attr_reader :tabs
8
-
9
- def initialize(tabs: [])
10
- @tabs = tabs
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,29 +0,0 @@
1
- <div class="table overflow-x-auto mb-12 w-full rounded-lg border border-mid">
2
- <div class="table-header-group">
3
- <div class="table-row text-base font-medium text-white bg-mid">
4
- <% columns.each_with_index do |column, i| %>
5
- <div class="table-cell sticky top-0 z-10 p-4 <% if i.zero? %>rounded-tl-md<% elsif i == columns.size - 1 %>rounded-tr-md<% end %>"><%= column.label %></div>
6
- <% end %>
7
- </div>
8
- </div>
9
-
10
- <% if @rows.any? %>
11
- <div class="table-row-group">
12
- <% @rows.each do |row| %>
13
- <div class="table-row relative bg-mid/5 hover:bg-mid/20" data-post-id="<%= row.id %>">
14
- <% @columns.each do |column| %>
15
- <div class="table-cell py-5 px-3 h-20 text-sm align-middle whitespace-nowrap border-b border-mid/20">
16
- <%= view_context.capture(row, &column.cell) %>
17
- </div>
18
- <% end %>
19
- </div>
20
- <% end %>
21
- </div>
22
- </div>
23
- <% else %>
24
- </div>
25
- <div class="text-center mx-12 block border border-dashed py-12 rounded-lg">
26
- <h3 class="py-1 text-xl font-semibold text-gray-900">No <%= @term.pluralize %></h3>
27
- <p class="py-1 text-base text-gray-500">Get started by creating a new <%= @term %>.</p>
28
- </div>
29
- <% end %>
@@ -1,7 +0,0 @@
1
- <% if user.is_a?(Panda::Core::User) && time %>
2
- <%= render Panda::CMS::Admin::UserDisplayComponent.new(user: user, metadata: "#{time_ago_in_words(time)} ago") %>
3
- <% elsif user.is_a?(Panda::Core::User) %>
4
- <%= render Panda::CMS::Admin::UserDisplayComponent.new(user: user, metadata: "Not published") %>
5
- <% elsif time %>
6
- <div class="text-black/60"><%= time_ago_in_words(time) %> ago</div>
7
- <% end %>
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class UserActivityComponent < ViewComponent::Base
7
- attr_accessor :model, :time, :user
8
-
9
- # @param model [ActiveRecord::Base] Model instance to which the user activity is related
10
- # @param at [ActiveSupport::TimeWithZone] Time of the activity
11
- # @param user [Panda::Core::User] User who performed the activity
12
- def initialize(model: nil, at: nil, user: nil)
13
- @model = model
14
- @user = user if user.is_a?(::Panda::Core::User)
15
- @time = at if at.is_a?(::ActiveSupport::TimeWithZone)
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,17 +0,0 @@
1
- <div class="block flex-shrink-0 group">
2
- <div class="flex items-center">
3
- <% unless user.image_url.empty? %>
4
- <div>
5
- <img class="inline-block w-10 h-10 rounded-full" src="<%= user.image_url %>" alt="">
6
- </div>
7
- <% else %>
8
- <div class="inline-block w-10 h-10 bg-gray-200 rounded-full">
9
- <span class="text-center"><i class="text-mid/50 text-4xl fa-sharp fa-circle-user fa-fw"></i></span>
10
- </div>
11
- <% end %>
12
- <div class="ml-3">
13
- <p class="text-sm text-black"><%= user.name %></p>
14
- <% if metadata %><p class="text-sm text-black/60"><%= metadata %></p><% end %>
15
- </div>
16
- </div>
17
- </div>
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Panda
4
- module CMS
5
- module Admin
6
- class UserDisplayComponent < ViewComponent::Base
7
- attr_accessor :user_id, :user, :metadata
8
-
9
- def initialize(user_id: nil, user: nil, metadata: "")
10
- @user = if user.nil? && user_id.present? && Panda::Core::User.find(user_id)
11
- Panda::Core::User.find(user_id)
12
- else
13
- user
14
- end
15
-
16
- @metadata = metadata
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,6 +0,0 @@
1
- <div class="w-full grid <%= @columns %> min-h-20">
2
- <% @colspans.each do |colspan| %>
3
- <div class="border border-red-500 bg-red-50 <%= colspan %>" onDragOver="parent.onDragOver(event);" onDrop="parent.onDrop(event);">
4
- </div>
5
- <% end %>
6
- </div>
@@ -1,6 +0,0 @@
1
- <% @menu_items.each do |menu_item| %>
2
- <a href="<%= menu_item.resolved_link %>" class="<%= menu_item.css_classes %>"><%= menu_item.text %></a>
3
- <% if @render_page_menu && menu_item.page %>
4
- <%= render Panda::CMS::PageMenuComponent.new(page: menu_item.page, start_depth: 1, styles: @page_menu_styles, show_heading: false) %>
5
- <% end %>
6
- <% end %>
@@ -1,21 +0,0 @@
1
- <nav class="<%= styles[:container] %>">
2
- <ul role="list" class="p-0 m-0">
3
- <% if @show_heading %>
4
- <li>
5
- <a href="<%= menu_item.page.path %>" class="<%= menu_item.page == Panda::CMS::Current.page ? styles[:current_page_active] : styles[:current_page_inactive] %>">
6
- <%= menu_item.text %>
7
- </a>
8
- </li>
9
- <% end %>
10
- <ul>
11
- <% Panda::CMS::MenuItem.includes(:page).each_with_level(menu_item.descendants) do |submenu_item, level| %>
12
- <% next if Panda::CMS::Current.page == menu_item.page && level > 1 # If we're on the "top" menu item, only show its direct ancestors %>
13
- <% next if submenu_item.page&.path[/\:/] %>
14
- <% next if submenu_item&.page.nil? || Panda::CMS::Current.page.nil? || (submenu_item.page&.depth&.to_i > Panda::CMS::Current.page&.depth&.to_i && !Panda::CMS::Current.page&.in?(submenu_item.page.ancestors)) %>
15
- <li data-level="<%= level %>" data-page-id="<%= submenu_item.page.id %>" class="<%= submenu_item.page == Panda::CMS::Current.page ? @styles[:active] : @styles[:inactive] %>">
16
- <a href="<%= submenu_item.page&.path %>" class="<%= helpers.menu_indent(submenu_item, indent_with: @styles[:indent_with]) %>"><%= submenu_item.page&.title %></a>
17
- </li>
18
- <% end %>
19
- </ul>
20
- </ul>
21
- </nav>
@@ -1,90 +0,0 @@
1
- <%
2
- editor_data = if @editable
3
- begin
4
- content = if @content.is_a?(String)
5
- if @content.start_with?("{")
6
- JSON.parse(@content)
7
- else
8
- # If it's HTML content, convert it to EditorJS format
9
- {
10
- "time" => Time.current.to_i * 1000,
11
- "blocks" => [
12
- {
13
- "type" => "paragraph",
14
- "data" => {
15
- "text" => @content.to_s
16
- }
17
- }
18
- ],
19
- "version" => "2.28.2"
20
- }
21
- end
22
- else
23
- @content
24
- end
25
-
26
- content = content.deep_transform_keys(&:to_s)
27
- content["blocks"] = (content["blocks"] || []).map do |block|
28
- case block["type"]
29
- when "paragraph"
30
- block["data"] = block["data"].merge(
31
- "text" => block["data"]["text"].to_s.presence || ""
32
- )
33
- when "header"
34
- block["data"] = block["data"].merge(
35
- "text" => block["data"]["text"].to_s.presence || "",
36
- "level" => block["data"]["level"].to_i
37
- )
38
- when "list"
39
- block["data"] = block["data"].merge(
40
- "items" => (block["data"]["items"] || []).map { |item| item.to_s.presence || "" }
41
- )
42
- end
43
- block
44
- end
45
-
46
- content["version"] ||= "2.28.2"
47
- content["time"] ||= Time.current.to_i * 1000
48
-
49
- Base64.strict_encode64(content.to_json)
50
- rescue StandardError => e
51
- Rails.logger.error("Error encoding editor data: #{e.message}")
52
- Rails.logger.error("Original content: #{@content.inspect}")
53
- # Fall back to a simple paragraph with the original content
54
- fallback_content = {
55
- "time" => Time.current.to_i * 1000,
56
- "blocks" => [
57
- {
58
- "type" => "paragraph",
59
- "data" => {
60
- "text" => @content.to_s
61
- }
62
- }
63
- ],
64
- "version" => "2.28.2"
65
- }
66
- Base64.strict_encode64(fallback_content.to_json)
67
- end
68
- end
69
- %>
70
- <% if @editable %>
71
- <div class="panda-cms-content"
72
- data-editable-previous-data="<%= editor_data %>"
73
- data-editable-content="<%= editor_data %>"
74
- data-editable-initialized="false"
75
- data-editable-version="2.28.2"
76
- data-editable-autosave="false"
77
- data-editable-tools='{"paragraph":true,"header":true,"list":true,"quote":true,"table":true}'
78
- id="editor-<%= @options[:id] %>"
79
- data-editable-kind="rich_text"
80
- data-editable-block-content-id="<%= @options[:id] %>"
81
- data-editable-page-id="<%= @options[:data][:page_id] %>"
82
- data-controller="editor-js"
83
- data-editor-js-initialized-value="false"
84
- data-editor-js-content-value="<%= editor_data %>">
85
- </div>
86
- <% else %>
87
- <div class="panda-cms-content">
88
- <%= @content.presence || "<p></p>".html_safe %>
89
- </div>
90
- <% end %>
@@ -1,42 +0,0 @@
1
- <%= render "panda/cms/shared/header", html_class: "h-full bg-white" %>
2
- <div class="flex h-full" id="panda-container">
3
- <div class="absolute top-0 w-full lg:flex lg:fixed lg:inset-y-0 lg:z-50 lg:flex-col lg:w-72">
4
- <div class="flex overflow-y-auto flex-col gap-y-5 px-4 pb-4 max-h-16 bg-gradient-to-br lg:max-h-full grow from-dark to-mid" data-transition-enter="transition-all ease-in-out duration-300" data-transition-enter-from="m-h-16" data-transition-enter-to="max-h-full" data-transition-leave="transition-all ease-in-out duration-300" data-transition-leave-from="max-h-full" data-transition-leave-to="max-h-16">
5
- <%= render "panda/cms/admin/shared/sidebar" %>
6
- </div>
7
- </div>
8
- <div class="flex flex-col flex-1 mt-16 ml-0 lg:mt-0 lg:ml-72" id="panda-inner-container" <% if content_for :sidebar %> data-controller="toggle" data-action="keydown.esc->modal#close" tabindex="-1"<% end %>>
9
- <section id="panda-main" class="flex flex-row h-full">
10
- <div class="flex-1 h-full" id="panda-cms-primary-content">
11
- <%= render "panda/cms/admin/shared/breadcrumbs" %>
12
- <%= render "panda/cms/admin/shared/flash" %>
13
- <%= yield %>
14
- </div>
15
- <% if content_for :sidebar %>
16
- <div data-toggle-target="toggleable" class="hidden flex absolute right-0 flex-col h-full bg-white divide-y divide-gray-200 shadow-xl basis-3/12"
17
- data-transition-enter="transform transition ease-in-out duration-500"
18
- data-transition-enter-from="translate-x-full"
19
- data-transition-enter-to="translate-x-0"
20
- data-transition-leave="transform transition ease-in-out duration-500"
21
- data-transition-leave-from="translate-x-full"
22
- data-transition-leave-to="translate-x-0"
23
- id="slideover">
24
- <div class="overflow-y-auto flex-1 h-0">
25
- <div class="py-3 px-4 mb-4 bg-black">
26
- <div class="flex justify-between items-center">
27
- <h2 class="text-base font-semibold leading-6 text-white" id="slideover-title"><i class="mr-2 fa-light fa-gear"></i> <%= yield :sidebar_title %> </h2>
28
- <button type="button" data-action="click->toggle#toggle touch->toggle#toggle"><i class="font-bold text-white fa-regular fa-xmark right"></i></button>
29
- </div>
30
- </div>
31
- <div class="flex flex-col flex-1 justify-between">
32
- <div class="px-4 space-y-6">
33
- <%= yield :sidebar %>
34
- </div>
35
- </div>
36
- </div>
37
- </div>
38
- <% end %>
39
- </section>
40
- </div>
41
- </div>
42
- <%= render "panda/cms/shared/footer" %>
@@ -1,28 +0,0 @@
1
- <% breadcrumb_styles = "text-black/60 hover:text-black/80" %>
2
-
3
- <div class="flex mt-1 -mb-1">
4
- <nav aria-label="Breadcrumb" id="panda-breadcrumbs" class="grow">
5
- <ol role="list" class="px-4 w-full sm:px-6">
6
- <li class="inline-block">
7
- <a href="/admin" class="<%= breadcrumb_styles %>">
8
- <i class="fa fa-regular fa-house"></i>
9
- <span class="sr-only">Home</span>
10
- </a>
11
- </li>
12
- <% breadcrumbs.each do |crumb| %>
13
- <li class="inline-block">
14
- <i class="fa fa-regular fa-chevron-right font-light <%= breadcrumb_styles %> py-5 px-2"></i>
15
- <a href="<%= crumb.path %>" class="text-sm font-normal <%= breadcrumb_styles %>"><%= crumb.name %></a>
16
- </li>
17
- <% end %>
18
- </ol>
19
- </nav>
20
-
21
- <% if content_for :sidebar %>
22
- <div class="pt-4 pr-8 text-black/80" tabindex="-1" data-controller="toggle">
23
- <button type="button" id="slideover-toggle" data-action="click->toggle#toggle touch->toggle#toggle" class="text-sm font-light">
24
- <i class="mr-1 fa-light fa-gear"></i> <%= yield :sidebar_title %>
25
- </button>
26
- </div>
27
- <% end %>
28
- </div>
@@ -1,5 +0,0 @@
1
- <% if flash.any? %>
2
- <% flash.each do |kind, message| %>
3
- <%= render Panda::Core::Admin::FlashMessageComponent.new(kind: kind, message: message) %>
4
- <% end %>
5
- <% end %>