panda-cms 0.7.4 → 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.
- checksums.yaml +4 -4
- data/README.md +37 -2
- data/Rakefile +2 -0
- data/app/components/panda/cms/admin/statistics_component.rb +1 -2
- data/app/components/panda/cms/admin/user_activity_component.html.erb +3 -1
- data/app/components/panda/cms/admin/user_activity_component.rb +3 -5
- data/app/components/panda/cms/admin/user_display_component.html.erb +1 -1
- data/app/components/panda/cms/admin/user_display_component.rb +2 -2
- data/app/components/panda/cms/code_component.rb +8 -4
- data/app/components/panda/cms/menu_component.rb +7 -6
- data/app/components/panda/cms/page_menu_component.rb +15 -17
- data/app/components/panda/cms/rich_text_component.rb +10 -11
- data/app/components/panda/cms/text_component.rb +6 -7
- data/app/controllers/panda/cms/admin/base_controller.rb +18 -0
- data/app/controllers/panda/cms/admin/block_contents_controller.rb +1 -2
- data/app/controllers/panda/cms/admin/dashboard_controller.rb +14 -9
- data/app/controllers/panda/cms/admin/files_controller.rb +1 -3
- data/app/controllers/panda/cms/admin/forms_controller.rb +3 -6
- data/app/controllers/panda/cms/admin/menus_controller.rb +2 -3
- data/app/controllers/panda/cms/admin/pages_controller.rb +9 -8
- data/app/controllers/panda/cms/admin/posts_controller.rb +9 -11
- data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +32 -25
- data/app/controllers/panda/cms/admin/settings_controller.rb +13 -10
- data/app/controllers/panda/cms/application_controller.rb +19 -6
- data/app/controllers/panda/cms/errors_controller.rb +5 -2
- data/app/controllers/panda/cms/form_submissions_controller.rb +2 -0
- data/app/controllers/panda/cms/pages_controller.rb +34 -31
- data/app/controllers/panda/cms/posts_controller.rb +2 -0
- data/app/helpers/panda/cms/admin/files_helper.rb +5 -1
- data/app/helpers/panda/cms/admin/pages_helper.rb +5 -1
- data/app/helpers/panda/cms/application_helper.rb +3 -3
- data/app/helpers/panda/cms/asset_helper.rb +195 -0
- data/app/helpers/panda/cms/pages_helper.rb +2 -0
- data/app/helpers/panda/cms/posts_helper.rb +2 -0
- data/app/helpers/panda/cms/theme_helper.rb +2 -0
- data/app/javascript/panda/cms/application_panda_cms.js +2 -34
- data/app/javascript/panda/cms/controllers/editor_form_controller.js +59 -6
- data/app/javascript/panda/cms/controllers/index.js +8 -24
- data/app/javascript/panda/cms/stimulus-loading.js +39 -0
- data/app/javascript/panda_cms/stimulus-loading.js +39 -0
- data/app/jobs/panda/cms/application_job.rb +2 -0
- data/app/jobs/panda/cms/record_visit_job.rb +2 -0
- data/app/mailers/panda/cms/application_mailer.rb +2 -0
- data/app/mailers/panda/cms/form_mailer.rb +3 -1
- data/app/models/panda/cms/application_record.rb +2 -0
- data/app/models/panda/cms/block.rb +4 -1
- data/app/models/panda/cms/block_content.rb +3 -1
- data/app/models/panda/cms/current.rb +5 -12
- data/app/models/panda/cms/form.rb +2 -0
- data/app/models/panda/cms/form_submission.rb +2 -0
- data/app/models/panda/cms/menu.rb +12 -9
- data/app/models/panda/cms/menu_item.rb +10 -6
- data/app/models/panda/cms/page.rb +14 -12
- data/app/models/panda/cms/post.rb +12 -8
- data/app/models/panda/cms/redirect.rb +6 -3
- data/app/models/panda/cms/template.rb +12 -7
- data/app/models/panda/cms/visit.rb +3 -1
- data/app/models/panda/social/instagram_post.rb +2 -0
- data/app/services/panda/social/instagram_feed_service.rb +3 -1
- data/app/views/layouts/different_page.html.erb +6 -0
- data/app/views/layouts/homepage.html.erb +37 -0
- data/app/views/layouts/page.html.erb +18 -0
- data/app/views/layouts/panda/cms/application.html.erb +2 -1
- data/app/views/panda/cms/admin/dashboard/show.html.erb +2 -2
- data/app/views/panda/cms/admin/files/index.html.erb +1 -1
- data/app/views/panda/cms/admin/forms/index.html.erb +4 -4
- data/app/views/panda/cms/admin/forms/new.html.erb +2 -2
- data/app/views/panda/cms/admin/forms/show.html.erb +1 -1
- data/app/views/panda/cms/admin/menus/index.html.erb +4 -4
- data/app/views/panda/cms/admin/pages/edit.html.erb +6 -6
- data/app/views/panda/cms/admin/pages/index.html.erb +5 -5
- data/app/views/panda/cms/admin/pages/new.html.erb +16 -10
- data/app/views/panda/cms/admin/posts/_form.html.erb +1 -1
- data/app/views/panda/cms/admin/posts/edit.html.erb +2 -2
- data/app/views/panda/cms/admin/posts/index.html.erb +5 -5
- data/app/views/panda/cms/admin/posts/new.html.erb +1 -1
- data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +1 -1
- data/app/views/panda/cms/admin/settings/index.html.erb +4 -4
- data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +3 -3
- data/app/views/panda/cms/admin/shared/_flash.html.erb +1 -1
- data/app/views/panda/cms/admin/shared/_sidebar.html.erb +8 -8
- data/app/views/panda/cms/shared/_header.html.erb +10 -2
- data/app/views/panda/cms/shared/_importmap.html.erb +1 -1
- data/app/views/shared/_footer.html.erb +3 -0
- data/app/views/shared/_header.html.erb +11 -0
- data/config/importmap.rb +2 -0
- data/config/initializers/inflections.rb +2 -0
- data/config/initializers/panda/cms/form_errors.rb +20 -21
- data/config/initializers/panda/cms/healthcheck_log_silencer.rb +2 -0
- data/config/initializers/panda/cms.rb +8 -3
- data/config/initializers/zeitwork.rb +2 -0
- data/config/puma/test.rb +3 -1
- data/config/routes.rb +11 -19
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +2 -0
- data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +2 -0
- data/db/migrate/20240303002805_create_panda_cms_templates.rb +4 -1
- data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +2 -0
- data/db/migrate/20240303022441_create_panda_cms_blocks.rb +4 -1
- data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +2 -0
- data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +2 -0
- data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +2 -0
- data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +2 -0
- data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +2 -0
- data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +7 -5
- data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +2 -0
- data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +3 -1
- data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +2 -0
- data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +2 -0
- data/db/migrate/20240317010532_create_panda_cms_users.rb +2 -0
- data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +2 -0
- data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +2 -0
- data/db/migrate/20240317214827_create_panda_cms_redirects.rb +2 -0
- data/db/migrate/20240317230622_create_panda_cms_visits.rb +2 -0
- data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +5 -2
- data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +2 -0
- data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +8 -6
- data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +2 -0
- data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +2 -0
- data/db/migrate/20240804235210_create_panda_cms_forms.rb +2 -0
- data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +2 -0
- data/db/migrate/20240805121123_create_panda_cms_posts.rb +3 -1
- data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +2 -0
- data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +2 -0
- data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +2 -0
- data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +2 -0
- data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +6 -4
- data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +2 -0
- data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +2 -0
- data/db/migrate/20241120000419_remove_post_tag_references.rb +2 -0
- data/db/migrate/20241120110943_add_editor_js_to_posts.rb +2 -0
- data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +2 -0
- data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +2 -0
- data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +5 -1
- data/db/migrate/20250120235542_remove_paper_trail.rb +5 -4
- data/db/migrate/20250126234001_create_panda_social_instagram_posts.rb +4 -0
- data/db/migrate/20250809231125_migrate_users_to_panda_core.rb +111 -0
- data/db/migrate/20250811111000_make_post_user_references_nullable.rb +11 -0
- data/db/seeds.rb +2 -0
- data/lib/generators/panda/cms/install_generator.rb +2 -0
- data/lib/panda/cms/asset_loader.rb +390 -0
- data/lib/panda/cms/bulk_editor.rb +7 -3
- data/lib/panda/cms/demo_site_generator.rb +2 -0
- data/lib/panda/cms/engine.rb +57 -116
- data/lib/panda/cms/exceptions_app.rb +2 -0
- data/lib/panda/cms/railtie.rb +2 -0
- data/lib/panda/cms/slug.rb +3 -1
- data/lib/panda-cms/version.rb +3 -1
- data/lib/panda-cms.rb +54 -42
- data/lib/tasks/assets.rake +587 -0
- data/lib/tasks/panda/cms/install.rake +2 -0
- data/lib/tasks/panda/cms/migrations.rake +13 -0
- data/lib/tasks/panda/social/instagram.rake +2 -0
- data/lib/tasks/panda_cms.rake +3 -30
- data/public/panda-cms-assets/manifest.json +20 -0
- data/public/panda-cms-assets/panda-cms-0.7.4.css +26 -0
- data/public/panda-cms-assets/panda-cms-0.7.4.js +150 -0
- metadata +186 -49
- data/app/builders/panda/cms/form_builder.rb +0 -217
- data/app/components/panda/cms/admin/button_component.rb +0 -70
- data/app/components/panda/cms/admin/container_component.rb +0 -13
- data/app/components/panda/cms/admin/flash_message_component.rb +0 -47
- data/app/components/panda/cms/admin/heading_component.rb +0 -45
- data/app/components/panda/cms/admin/panel_component.rb +0 -13
- data/app/components/panda/cms/admin/table_component.rb +0 -46
- data/app/components/panda/cms/admin/tag_component.rb +0 -35
- data/app/constraints/panda/cms/admin_constraint.rb +0 -18
- data/app/controllers/panda/cms/admin/my_profile_controller.rb +0 -43
- data/app/controllers/panda/cms/admin/sessions_controller.rb +0 -94
- data/app/javascript/panda/cms/controllers/theme_form_controller.js +0 -9
- data/app/javascript/panda/cms/editor/css_extractor.js +0 -80
- data/app/javascript/panda/cms/editor/editor_js_config.js +0 -306
- data/app/javascript/panda/cms/editor/editor_js_initializer.js +0 -334
- data/app/javascript/panda/cms/editor/plain_text_editor.js +0 -110
- data/app/javascript/panda/cms/editor/resource_loader.js +0 -204
- data/app/javascript/panda/cms/editor/rich_text_editor.js +0 -162
- data/app/models/panda/cms/breadcrumb.rb +0 -12
- data/app/models/panda/cms/user.rb +0 -31
- data/app/services/panda/cms/html_to_editor_js_converter.rb +0 -193
- data/app/views/panda/cms/admin/my_profile/edit.html.erb +0 -35
- data/app/views/panda/cms/admin/sessions/new.html.erb +0 -17
- data/db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb +0 -5
- data/lib/panda/cms/editor_js/blocks/alert.rb +0 -34
- data/lib/panda/cms/editor_js/blocks/base.rb +0 -33
- data/lib/panda/cms/editor_js/blocks/header.rb +0 -15
- data/lib/panda/cms/editor_js/blocks/image.rb +0 -36
- data/lib/panda/cms/editor_js/blocks/list.rb +0 -32
- data/lib/panda/cms/editor_js/blocks/paragraph.rb +0 -15
- data/lib/panda/cms/editor_js/blocks/quote.rb +0 -41
- data/lib/panda/cms/editor_js/blocks/table.rb +0 -50
- data/lib/panda/cms/editor_js/renderer.rb +0 -124
- data/lib/panda/cms/editor_js.rb +0 -16
- data/lib/panda/cms/editor_js_content.rb +0 -55
@@ -0,0 +1,37 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Test Homepage</title>
|
5
|
+
<% if params[:embed_id].present? %>
|
6
|
+
<!-- Include Panda CMS assets for editor functionality when in edit mode -->
|
7
|
+
<%= panda_cms_complete_assets %>
|
8
|
+
<% end %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<h1><%= @page.title %></h1>
|
12
|
+
<h2>Homepage Layout</h2>
|
13
|
+
|
14
|
+
<div class="prose">
|
15
|
+
<p>On this page we expect:</p>
|
16
|
+
<ul>
|
17
|
+
<li>Header</li>
|
18
|
+
<li>Footer</li>
|
19
|
+
<li>Some content</li>
|
20
|
+
<li>Tailwind-styled content</li>
|
21
|
+
<li>JS injected content through vanilla JS:
|
22
|
+
<div class="mt-0 font-bold" id="vanilla-injected-content">
|
23
|
+
Hello, Stimulus!
|
24
|
+
</div>
|
25
|
+
</li>
|
26
|
+
<li>JS injected content through <code>hello-controller</code>:
|
27
|
+
<div class="mt-0 font-bold" data-controller="hello" id="stimulus-injected-content">
|
28
|
+
Hello, Stimulus!
|
29
|
+
</div>
|
30
|
+
</li>
|
31
|
+
</ul>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<%= render Panda::CMS::RichTextComponent.new(key: :hero_content) %>
|
35
|
+
<%= yield %>
|
36
|
+
</body>
|
37
|
+
</html>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Test Page</title>
|
5
|
+
<% if params[:embed_id].present? %>
|
6
|
+
<!-- Include Panda CMS assets for editor functionality when in edit mode -->
|
7
|
+
<%= panda_cms_complete_assets %>
|
8
|
+
<% end %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<h1><%= @page.title %></h1>
|
12
|
+
<h2>Basic Page Layout</h2>
|
13
|
+
<%= render Panda::CMS::TextComponent.new(key: :plain_text) %>
|
14
|
+
<%= render Panda::CMS::CodeComponent.new(key: :html_code) %>
|
15
|
+
<%= render Panda::CMS::RichTextComponent.new(key: :main_content) %>
|
16
|
+
<%= yield %>
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -9,6 +9,7 @@
|
|
9
9
|
<section id="panda-main" class="flex flex-row h-full">
|
10
10
|
<div class="flex-1 h-full" id="panda-cms-primary-content">
|
11
11
|
<%= render "panda/cms/admin/shared/breadcrumbs" %>
|
12
|
+
<%= render "panda/cms/admin/shared/flash" %>
|
12
13
|
<%= yield %>
|
13
14
|
</div>
|
14
15
|
<% if content_for :sidebar %>
|
@@ -24,7 +25,7 @@
|
|
24
25
|
<div class="py-3 px-4 mb-4 bg-black">
|
25
26
|
<div class="flex justify-between items-center">
|
26
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>
|
27
|
-
<
|
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>
|
28
29
|
</div>
|
29
30
|
</div>
|
30
31
|
<div class="flex flex-col flex-1 justify-between">
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="" data-controller="dashboard">
|
2
|
-
<%= render Panda::
|
2
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |container| %>
|
3
3
|
<% container.with_heading(text: "Dashboard", level: 1) do |heading| %>
|
4
|
-
<% heading.with_button(action: :add, text: "Add Page", link:
|
4
|
+
<% heading.with_button(action: :add, text: "Add Page", link: new_admin_cms_page_path) %>
|
5
5
|
<% end %>
|
6
6
|
<dl class="grid grid-cols-1 gap-5 mt-5 sm:grid-cols-3">
|
7
7
|
<%= render Panda::CMS::Admin::StatisticsComponent.new(metric: "Views Today", value: Panda::CMS::Visit.group_by_day(:visited_at, last: 1).count.values.first) %>
|
@@ -1,10 +1,10 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Forms", level: 1) do |heading| %>
|
3
3
|
<% end %>
|
4
4
|
|
5
|
-
<%= render Panda::
|
6
|
-
<% table.column("Name") { |form| block_link_to form.name,
|
7
|
-
<% table.column("Status") { |form| render Panda::
|
5
|
+
<%= render Panda::Core::Admin::TableComponent.new(term: "form", rows: forms) do |table| %>
|
6
|
+
<% table.column("Name") { |form| block_link_to form.name, admin_cms_form_path(form) } %>
|
7
|
+
<% table.column("Status") { |form| render Panda::Core::Admin::TagComponent.new(status: :active) } %>
|
8
8
|
<% table.column("Last Submission") do |form| %>
|
9
9
|
<%= "#{time_ago_in_words(form.form_submissions&.last&.created_at)} ago" if form.form_submissions&.last %>
|
10
10
|
<% end %>
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Add Page", level: 1) do |heading| %>
|
3
3
|
<% end %>
|
4
|
-
<%= panda_cms_form_with model: page, url:
|
4
|
+
<%= panda_cms_form_with model: page, url: admin_cms_pages_path, method: :post do |f| %>
|
5
5
|
<% options = nested_set_options(Panda::CMS::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %>
|
6
6
|
<div data-controller="slug">
|
7
7
|
<input type="hidden" value="<%= Panda::CMS::Current.root %>" data-slug-target="existing_root">
|
@@ -1,8 +1,8 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Menus", level: 1) do |heading| %>
|
3
3
|
<% end %>
|
4
|
-
<%= render Panda::
|
5
|
-
<% table.column("Name") { |menu| link_to menu.name,
|
6
|
-
<% table.column("Kind") { |menu| render Panda::
|
4
|
+
<%= render Panda::Core::Admin::TableComponent.new(term: "menu", rows: menus) do |table| %>
|
5
|
+
<% table.column("Name") { |menu| link_to menu.name, edit_admin_cms_menu_path(menu) } %>
|
6
|
+
<% table.column("Kind") { |menu| render Panda::Core::Admin::TagComponent.new(status: :active, text: menu.kind.titleize) } %>
|
7
7
|
<% end %>
|
8
8
|
<% end %>
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "#{page.title}", level: 1) %>
|
3
3
|
<% component.with_slideover(title: "Page Details") do %>
|
4
|
-
<%= panda_cms_form_with model: page, url:
|
4
|
+
<%= panda_cms_form_with model: page, url: admin_cms_page_path, method: :put do |f| %>
|
5
5
|
<%= f.text_field :title, class: "block w-full rounded-md border-0 p-2 text-gray-900 ring-1 ring-inset ring-mid placeholder:text-gray-300 focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
6
6
|
<%= f.text_field :template, value: template.name, readonly: true, class: "read-only:bg-gray-100 block w-full rounded-md border-0 p-2 text-gray-900 ring-1 ring-inset ring-mid placeholder:text-gray-300 focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
7
7
|
<%= f.select :status, options_for_select([["Active", "active"], ["Draft", "draft"], ["Hidden", "hidden"], ["Archived", "archived"]], selected: page.status), {}, class: "block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-mid focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
@@ -9,17 +9,17 @@
|
|
9
9
|
<% end %>
|
10
10
|
<% end %>
|
11
11
|
<div id="successMessage" class="hidden">
|
12
|
-
<%= render Panda::
|
12
|
+
<%= render Panda::Core::Admin::FlashMessageComponent.new(kind: "success", message: "This page was successfully updated!", temporary: false) %>
|
13
13
|
</div>
|
14
14
|
<div id="errorMessage" class="hidden">
|
15
|
-
<%= render Panda::
|
15
|
+
<%= render Panda::Core::Admin::FlashMessageComponent.new(kind: "error", message: "There was an error updating this page.", temporary: false) %>
|
16
16
|
</div>
|
17
17
|
<div class="grid grid-cols-2 mb-4 -mt-5">
|
18
18
|
<div>
|
19
19
|
<a class="inline-block mb-2 text-sm text-black/60" target="_blank" href="<%= @page.path %>"><%= @page.path %> <i class="ml-2 fa-solid fa-arrow-up-right-from-square"></i></a>
|
20
20
|
</div>
|
21
21
|
<div class="relative -mt-5">
|
22
|
-
<span class="absolute right-0"><%= render Panda::
|
22
|
+
<span class="absolute right-0"><%= render Panda::Core::Admin::ButtonComponent.new(text: "Save Changes", action: :save_inactive, icon: "check", link: "#", size: :regular, id: "saveEditableButton") %></span>
|
23
23
|
</div>
|
24
24
|
</div>
|
25
25
|
<%= content_tag :iframe, nil,
|
@@ -30,7 +30,7 @@
|
|
30
30
|
data: {
|
31
31
|
controller: "editor-iframe",
|
32
32
|
editor_iframe_page_id_value: @page.id,
|
33
|
-
editor_iframe_admin_path_value: "#{
|
33
|
+
editor_iframe_admin_path_value: "#{admin_cms_dashboard_url}",
|
34
34
|
editor_iframe_autosave_value: false
|
35
35
|
} %>
|
36
36
|
<% end %>
|
@@ -1,17 +1,17 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Pages", level: 1) do |heading| %>
|
3
|
-
<% heading.with_button(action: :add, text: "Add Page", link:
|
3
|
+
<% heading.with_button(action: :add, text: "Add Page", link: new_admin_cms_page_path) %>
|
4
4
|
<% end %>
|
5
5
|
|
6
6
|
<% if root_page %>
|
7
|
-
<%= render Panda::
|
7
|
+
<%= render Panda::Core::Admin::TableComponent.new(term: "page", rows: root_page.self_and_descendants) do |table| %>
|
8
8
|
<% table.column("Name") do |page| %>
|
9
9
|
<div class="<%= table_indent(page) %>">
|
10
|
-
<%= link_to page.title,
|
10
|
+
<%= link_to page.title, edit_admin_cms_page_path(page), class: "block h-full w-full" %>
|
11
11
|
<span class="block text-xs text-black/60"><%= page.path %></span>
|
12
12
|
</div>
|
13
13
|
<% end %>
|
14
|
-
<% table.column("Status") { |page| render Panda::
|
14
|
+
<% table.column("Status") { |page| render Panda::Core::Admin::TagComponent.new(status: page.status) } %>
|
15
15
|
<% table.column("Last Updated") { |page| render Panda::CMS::Admin::UserActivityComponent.new(model: page) } %>
|
16
16
|
<% end %>
|
17
17
|
<% else %>
|
@@ -1,15 +1,21 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Add Page", level: 1) do |heading| %>
|
3
3
|
<% end %>
|
4
|
-
<%= panda_cms_form_with model: page, url:
|
4
|
+
<%= panda_cms_form_with model: page, url: admin_cms_pages_path, method: :post do |f| %>
|
5
|
+
<% if page.errors.any? %>
|
6
|
+
<div class="mb-4 p-4 bg-red-50 border border-red-200 rounded-md">
|
7
|
+
<div class="text-sm text-red-600">
|
8
|
+
<% page.errors.full_messages.each do |message| %>
|
9
|
+
<p><%= message %></p>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
5
14
|
<% options = nested_set_options(Panda::CMS::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %>
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<%= f.collection_select :panda_cms_template_id, available_templates, :id, :name %>
|
12
|
-
<%= f.button "Create Page" %>
|
13
|
-
</div>
|
15
|
+
<%= f.select :parent_id, options %>
|
16
|
+
<%= f.text_field :title %>
|
17
|
+
<%= f.text_field :path, { meta: t(".path.meta") } %>
|
18
|
+
<%= f.collection_select :panda_cms_template_id, available_templates, :id, :name %>
|
19
|
+
<%= f.button "Create Page" %>
|
14
20
|
<% end %>
|
15
21
|
<% end %>
|
@@ -22,7 +22,7 @@
|
|
22
22
|
"slug-target": "output_text"
|
23
23
|
} %>
|
24
24
|
</div>
|
25
|
-
<%= f.select :author_id, Panda::
|
25
|
+
<%= f.select :author_id, Panda::Core::User.admin.map { |u| [u.name, u.id] }, {}, class: "block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-mid focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
26
26
|
<%= f.datetime_field :published_at, class: "block w-full rounded-md border-0 p-2 text-gray-900 ring-1 ring-inset ring-mid placeholder:text-gray-300 focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
27
27
|
<%= f.select :status, options_for_select([["Active", "active"], ["Draft", "draft"], ["Hidden", "hidden"], ["Archived", "archived"]], selected: post.status), {}, class: "block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-mid focus:ring-1 focus:ring-inset focus:ring-dark sm:leading-6 hover:pointer" %>
|
28
28
|
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: post.title, level: 1) do |heading| %>
|
3
3
|
<% heading.with_button(action: :view, text: "View Post", link: post_path(post.admin_param)) %>
|
4
4
|
<% end %>
|
5
5
|
|
6
|
-
<%= render "form", post: post, url:
|
6
|
+
<%= render "form", post: post, url: admin_cms_post_path(post.admin_param), method: :patch %>
|
7
7
|
<% end %>
|
@@ -1,18 +1,18 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Posts", level: 1) do |heading| %>
|
3
|
-
<% heading.with_button(action: :add, text: "Add Post", link:
|
3
|
+
<% heading.with_button(action: :add, text: "Add Post", link: new_admin_cms_post_path) %>
|
4
4
|
<% end %>
|
5
5
|
|
6
|
-
<%= render Panda::
|
6
|
+
<%= render Panda::Core::Admin::TableComponent.new(term: "post", rows: posts) do |table| %>
|
7
7
|
<% table.column("Title") do |post| %>
|
8
8
|
<div>
|
9
|
-
<%= link_to post.title,
|
9
|
+
<%= link_to post.title, edit_admin_cms_post_path(post.admin_param), class: "block h-full w-full" %>
|
10
10
|
<span class="block text-xs text-black/60">
|
11
11
|
<%= CGI.unescape("#{Panda::CMS.config.posts[:prefix]}#{post.slug}") %>
|
12
12
|
</span>
|
13
13
|
</div>
|
14
14
|
<% end %>
|
15
|
-
<% table.column("Status") { |post| render Panda::
|
15
|
+
<% table.column("Status") { |post| render Panda::Core::Admin::TagComponent.new(status: post.status) } %>
|
16
16
|
<% table.column("Published") { |post| render Panda::CMS::Admin::UserActivityComponent.new(at: post.published_at, user: post.author)} %>
|
17
17
|
<% table.column("Last Updated") { |post| render Panda::CMS::Admin::UserActivityComponent.new(at: post.updated_at)} %>
|
18
18
|
<% end %>
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<%= render Panda::
|
1
|
+
<%= render Panda::Core::Admin::ContainerComponent.new do |component| %>
|
2
2
|
<% component.with_heading(text: "Settings", level: 1) %>
|
3
3
|
|
4
|
-
<%= render Panda::
|
4
|
+
<%= render Panda::Core::Admin::PanelComponent.new do |panel| %>
|
5
5
|
<% panel.with_heading(text: "System Status") %>
|
6
6
|
|
7
7
|
<p class="text-base leading-loose"><i class="mr-2 text-active fa fa-check-circle"></i> <span class="font-medium">Panda CMS:</span> v<%= Panda::CMS::VERSION %></p>
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<p class="text-base leading-loose"><i class="mr-2 text-active fa fa-check-circle"></i> <span class="font-medium">Environment:</span> <%= Rails.env.titleize %></p>
|
11
11
|
<% end %>
|
12
12
|
|
13
|
-
<%= render Panda::
|
13
|
+
<%= render Panda::Core::Admin::PanelComponent.new do |panel| %>
|
14
14
|
<% panel.with_heading(text: "Integrations") %>
|
15
15
|
|
16
16
|
<p class="text-base leading-loose"><i class="mr-2 text-active fa-brands fa-instagram"></i> <span class="font-medium">Instagram:</span> <%= Panda::CMS.config.instagram[:enabled] ? "Connected (@#{Panda::CMS.config.instagram[:username]})" : "Not Connected" %></p>
|
@@ -18,6 +18,6 @@
|
|
18
18
|
|
19
19
|
<div class="text-center mt-6 space-y-2">
|
20
20
|
<p class="text-sm font-semibold">🐼 Panda CMS version: <%= Panda::CMS::VERSION %></p>
|
21
|
-
<p class="text-sm">© <%= Date.current.year %>
|
21
|
+
<p class="text-sm">© <%= Date.current.year %> Otaina Limited. All rights reserved.</p>
|
22
22
|
</div>
|
23
23
|
<% end %>
|
@@ -19,10 +19,10 @@
|
|
19
19
|
</nav>
|
20
20
|
|
21
21
|
<% if content_for :sidebar %>
|
22
|
-
<div class="pt-4 pr-8 text-black/80" tabindex="-1">
|
23
|
-
<
|
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
24
|
<i class="mr-1 fa-light fa-gear"></i> <%= yield :sidebar_title %>
|
25
|
-
</
|
25
|
+
</button>
|
26
26
|
</div>
|
27
27
|
<% end %>
|
28
28
|
</div>
|
@@ -2,12 +2,12 @@
|
|
2
2
|
<ul role="list" class="flex flex-col flex-1">
|
3
3
|
<a class="block p-0 mt-4 mb-4 ml-2 text-xl font-medium text-white"><%= Panda::CMS.config.title %></a>
|
4
4
|
<% [
|
5
|
-
{ path:
|
6
|
-
{ path:
|
7
|
-
{ path:
|
8
|
-
{ path:
|
9
|
-
{ path:
|
10
|
-
{ path:
|
5
|
+
{ path: admin_cms_dashboard_path, text: "Dashboard", icon: "fa-house", matcher: :exact },
|
6
|
+
{ path: admin_cms_pages_path, text: "Pages", icon: "fa-page", matcher: :starts_with },
|
7
|
+
{ path: admin_cms_posts_path, text: "Posts", icon: "fa-notebook", matcher: :starts_with },
|
8
|
+
{ path: admin_cms_forms_path, text: "Forms", icon: "fa-cabinet-filing", matcher: :starts_with },
|
9
|
+
{ path: admin_cms_menus_path, text: "Menus", icon: "fa-list-dropdown", matcher: :starts_with },
|
10
|
+
{ path: admin_cms_settings_path, text: "Settings", icon: "fa-cog", matcher: :starts_with },
|
11
11
|
].each do |link| %>
|
12
12
|
<li>
|
13
13
|
<%= link_to link[:path], class: "#{active_link?(link[:path], match: link[:matcher]) ? selected_nav_highlight_colour_classes(request) : nav_highlight_colour_classes(request)}" do %>
|
@@ -17,13 +17,13 @@
|
|
17
17
|
</li>
|
18
18
|
<% end %>
|
19
19
|
<li>
|
20
|
-
<%= button_to admin_logout_path, method: :delete, id: "logout-link", data: { turbo: false }, class: nav_highlight_colour_classes(request) + " w-full" do %>
|
20
|
+
<%= button_to panda_core.admin_logout_path, method: :delete, id: "logout-link", data: { turbo: false }, class: nav_highlight_colour_classes(request) + " w-full" do %>
|
21
21
|
<span class="text-center"><i class="text-xl fa-regular fa-door-open fa-fw"></i></span>
|
22
22
|
<span class="mt-1">Logout</span>
|
23
23
|
<% end %>
|
24
24
|
</li>
|
25
25
|
<li class="mt-auto">
|
26
|
-
<%= link_to edit_admin_my_profile_path, class: nav_highlight_colour_classes(request) + " w-full", title: "Edit my Profile" do %>
|
26
|
+
<%= link_to panda_core.edit_admin_my_profile_path, class: nav_highlight_colour_classes(request) + " w-full", title: "Edit my Profile" do %>
|
27
27
|
<% if !current_user.image_url.to_s.empty? %>
|
28
28
|
<span class="text-center"><img src="<%= current_user.image_url %>" class="w-auto h-7 rounded-full"></span>
|
29
29
|
<% else %>
|
@@ -7,9 +7,17 @@
|
|
7
7
|
<%= csrf_meta_tags %>
|
8
8
|
<%= csp_meta_tag %>
|
9
9
|
<script src="https://kit.fontawesome.com/7835d81e75.js" defer="true" crossorigin="anonymous"></script>
|
10
|
-
<script async src="https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js" defer="true" crossorigin="anonymous"></script>
|
11
10
|
<%= stylesheet_link_tag "panda.cms", "data-turbo-track": "reload", media: "all" %>
|
12
|
-
|
11
|
+
|
12
|
+
<% if Panda::CMS::AssetLoader.use_github_assets? || Rails.env.test? %>
|
13
|
+
<!-- Using compiled Panda CMS assets -->
|
14
|
+
<%= panda_cms_complete_assets %>
|
15
|
+
<% else %>
|
16
|
+
<!-- Using development importmap assets -->
|
17
|
+
<script async src="https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js" defer="true" crossorigin="anonymous"></script>
|
18
|
+
<%= render "panda/cms/shared/importmap" %>
|
19
|
+
<% end %>
|
20
|
+
|
13
21
|
<%= render "panda/cms/shared/favicons" %>
|
14
22
|
<%= yield :head %>
|
15
23
|
</head>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
# Vendored
|
9
9
|
"@hotwired/turbo": asset_path("panda/cms/@hotwired--turbo.js"),
|
10
10
|
"@hotwired/stimulus": asset_path("panda/cms/@hotwired--stimulus.js"),
|
11
|
-
"@hotwired/stimulus-loading": asset_path("stimulus-loading.js"),
|
11
|
+
"@hotwired/stimulus-loading": asset_path("panda_cms/stimulus-loading.js"),
|
12
12
|
"@editorjs/editorjs": asset_path("panda/cms/@editorjs--editorjs.js"),
|
13
13
|
"tailwindcss-stimulus-components": asset_path("panda/cms/tailwindcss-stimulus-components.js"),
|
14
14
|
# Our page editor
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Panda CMS Page</title>
|
5
|
+
<% if params[:embed_id].present? %>
|
6
|
+
<!-- Include Panda CMS assets for editor functionality when in edit mode -->
|
7
|
+
<%= panda_cms_complete_assets %>
|
8
|
+
<% end %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<h1>Test Header</h1>
|
data/config/importmap.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
ActionView::Base.field_error_proc = proc do |html_tag, instance|
|
2
4
|
html = ""
|
3
5
|
form_fields = %w[input select textarea trix-editor label].join(", ")
|
@@ -6,30 +8,27 @@ ActionView::Base.field_error_proc = proc do |html_tag, instance|
|
|
6
8
|
autofocused = false
|
7
9
|
|
8
10
|
Nokogiri::HTML::DocumentFragment.parse(html_tag).css(form_fields).each do |element|
|
9
|
-
|
10
|
-
if !autofocused
|
11
|
-
# element.attribute("autofocus", "true")
|
12
|
-
autofocused = true
|
13
|
-
end
|
11
|
+
next unless form_fields.include?(element.node_name)
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
autofocused ||= true
|
14
|
+
|
15
|
+
message = "#{instance.object.class.human_attribute_name(instance.send(:sanitized_method_name))} "
|
16
|
+
message += if instance.error_message.respond_to?(:each)
|
17
|
+
"#{instance.error_message.uniq.to_sentence}."
|
18
|
+
else
|
19
|
+
"#{instance.error_message}."
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
if element.node_name.eql?("label")
|
23
|
+
html = element.to_s
|
24
|
+
else
|
25
|
+
element.add_class(error_class)
|
26
|
+
html = if element.get_attribute("data-prefix")
|
27
|
+
"#{element}</div><div class=\"#{message_class}\">#{message}"
|
28
|
+
elsif element.get_attribute("type") != "checkbox"
|
29
|
+
"#{element}<div class=\"#{message_class}\">#{message}</div>"
|
24
30
|
else
|
25
|
-
element.
|
26
|
-
html = if element.get_attribute("data-prefix")
|
27
|
-
"#{element}</div><div class=\"#{message_class}\">#{message}"
|
28
|
-
elsif element.get_attribute("type") != "checkbox"
|
29
|
-
"#{element}<div class=\"#{message_class}\">#{message}</div>"
|
30
|
-
else
|
31
|
-
element.to_s
|
32
|
-
end
|
31
|
+
element.to_s
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -1,10 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Panda::CMS.configure do |config|
|
2
4
|
# The main title of your website
|
3
5
|
config.title = "Demo Site"
|
4
6
|
|
5
|
-
# The path to the administration panel
|
6
|
-
config.admin_path = "/admin"
|
7
|
-
|
8
7
|
# Site access control
|
9
8
|
config.require_login_to_view = false
|
10
9
|
end
|
10
|
+
|
11
|
+
# Admin path is now configured via Panda::Core
|
12
|
+
Panda::Core.configure do |config|
|
13
|
+
# The path to the administration panel
|
14
|
+
config.admin_path = "/admin"
|
15
|
+
end
|
data/config/puma/test.rb
CHANGED
data/config/routes.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Panda::CMS::Engine.routes.draw do
|
4
|
-
constraints Panda::
|
5
|
-
|
4
|
+
constraints Panda::Core::AdminConstraint.new(&:present?) do
|
5
|
+
# CMS-specific dashboard (using Core's admin_path)
|
6
|
+
admin_path = Panda::Core.configuration.admin_path
|
7
|
+
get "#{admin_path}/cms", to: "admin/dashboard#show", as: :admin_cms_dashboard
|
8
|
+
|
9
|
+
namespace admin_path.delete_prefix("/").to_sym, path: "#{admin_path}/cms", as: :admin_cms, module: :admin do
|
6
10
|
resources :files
|
7
11
|
resources :forms, only: %i[index show]
|
8
12
|
resources :menus
|
@@ -13,30 +17,18 @@ Panda::CMS::Engine.routes.draw do
|
|
13
17
|
|
14
18
|
get "settings", to: "settings#index"
|
15
19
|
|
16
|
-
|
20
|
+
# Profile management moved to panda-core at /admin/my_profile
|
17
21
|
|
18
22
|
namespace :settings, as: :settings do
|
19
23
|
get "bulk_editor", to: "bulk_editor#new"
|
20
24
|
post "bulk_editor", to: "bulk_editor#create"
|
21
25
|
end
|
22
|
-
|
23
|
-
if Rails.env.development?
|
24
|
-
mount Lookbook::Engine, at: "/lookbook"
|
25
|
-
end
|
26
26
|
end
|
27
|
-
|
28
|
-
get Panda::CMS.route_namespace, to: "admin/dashboard#show", as: :admin_dashboard
|
29
27
|
end
|
30
28
|
|
31
29
|
### PUBLIC ROUTES ###
|
32
30
|
|
33
|
-
# Authentication routes
|
34
|
-
get Panda::CMS.route_namespace, to: "admin/sessions#new", as: :admin_login
|
35
|
-
# Get and post options here are for OmniAuth coming back in, not going out
|
36
|
-
match "#{Panda::CMS.route_namespace}/auth/:provider/callback", to: "admin/sessions#create", as: :admin_login_callback, via: %i[get post]
|
37
|
-
match "#{Panda::CMS.route_namespace}/auth/failure", to: "admin/sessions#failure", as: :admin_login_failure, via: %i[get post]
|
38
|
-
# OmniAuth additionally adds a GET route for "#{Panda::CMS.route_namespace}/auth/:provider" but doesn't name it
|
39
|
-
delete Panda::CMS.route_namespace, to: "admin/sessions#destroy", as: :admin_logout
|
31
|
+
# Authentication routes are now handled by Panda::Core
|
40
32
|
|
41
33
|
### APPENDED ROUTES ###
|
42
34
|
|
@@ -51,7 +43,7 @@ Panda::CMS::Engine.routes.draw do
|
|
51
43
|
constraints: {
|
52
44
|
year: /\d{4}/,
|
53
45
|
month: /\d{2}/,
|
54
|
-
slug:
|
46
|
+
slug: %r{[^/]+},
|
55
47
|
format: /html|json|xml/
|
56
48
|
}
|
57
49
|
|
@@ -60,7 +52,7 @@ Panda::CMS::Engine.routes.draw do
|
|
60
52
|
to: "posts#show",
|
61
53
|
as: :post,
|
62
54
|
constraints: {
|
63
|
-
slug:
|
55
|
+
slug: %r{[^/]+},
|
64
56
|
format: /html|json|xml/
|
65
57
|
}
|
66
58
|
|