panda_cms 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of panda_cms might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/README.md +72 -0
- data/Rakefile +8 -0
- data/app/assets/builds/panda_cms.css +1 -0
- data/app/assets/config/panda_cms_manifest.js +1 -0
- data/app/assets/stylesheets/panda_cms/application.tailwind.css +30 -0
- data/app/builders/panda_cms/form_builder.rb +118 -0
- data/app/components/panda_cms/admin/button_component.rb +65 -0
- data/app/components/panda_cms/admin/container_component.html.erb +13 -0
- data/app/components/panda_cms/admin/container_component.rb +11 -0
- data/app/components/panda_cms/admin/flash_message_component.html.erb +30 -0
- data/app/components/panda_cms/admin/flash_message_component.rb +44 -0
- data/app/components/panda_cms/admin/heading_component.rb +38 -0
- data/app/components/panda_cms/admin/slideover_component.html.erb +9 -0
- data/app/components/panda_cms/admin/slideover_component.rb +13 -0
- data/app/components/panda_cms/admin/tab_bar_component.html.erb +35 -0
- data/app/components/panda_cms/admin/tab_bar_component.rb +13 -0
- data/app/components/panda_cms/grid_component.html.erb +6 -0
- data/app/components/panda_cms/grid_component.rb +13 -0
- data/app/components/panda_cms/menu_component.html.erb +3 -0
- data/app/components/panda_cms/menu_component.rb +18 -0
- data/app/components/panda_cms/page_menu_component.html.erb +24 -0
- data/app/components/panda_cms/page_menu_component.rb +24 -0
- data/app/components/panda_cms/rich_text_component.html.erb +40 -0
- data/app/components/panda_cms/rich_text_component.rb +35 -0
- data/app/components/panda_cms/text_component.rb +63 -0
- data/app/constraints/panda_cms/admin_constraint.rb +16 -0
- data/app/controllers/panda_cms/admin/block_contents_controller.rb +42 -0
- data/app/controllers/panda_cms/admin/dashboard_controller.rb +15 -0
- data/app/controllers/panda_cms/admin/files_controller.rb +17 -0
- data/app/controllers/panda_cms/admin/menus_controller.rb +81 -0
- data/app/controllers/panda_cms/admin/pages_controller.rb +88 -0
- data/app/controllers/panda_cms/admin/sessions_controller.rb +72 -0
- data/app/controllers/panda_cms/application_controller.rb +51 -0
- data/app/controllers/panda_cms/errors_controller.rb +31 -0
- data/app/controllers/panda_cms/pages_controller.rb +33 -0
- data/app/helpers/panda_cms/admin/files_helper.rb +4 -0
- data/app/helpers/panda_cms/admin/pages_helper.rb +4 -0
- data/app/helpers/panda_cms/application_helper.rb +91 -0
- data/app/helpers/panda_cms/pages_helper.rb +4 -0
- data/app/helpers/panda_cms/theme_helper.rb +16 -0
- data/app/javascript/panda_cms/base.js +37 -0
- data/app/javascript/panda_cms/controllers/menu_controller.js +19 -0
- data/app/javascript/panda_cms/controllers/rich_text_editor_controller.js +59 -0
- data/app/javascript/panda_cms/controllers/text_field_update_controller.js +23 -0
- data/app/javascript/panda_cms/vendor/stimulus-components-rails-nested-form.js +2 -0
- data/app/javascript/panda_cms/vendor/tailwindcss-stimulus-components.js +2 -0
- data/app/jobs/panda_cms/application_job.rb +4 -0
- data/app/lib/panda_cms/demo_site_generator.rb +70 -0
- data/app/lib/panda_cms/slug.rb +21 -0
- data/app/mailers/panda_cms/application_mailer.rb +6 -0
- data/app/models/panda_cms/application_record.rb +5 -0
- data/app/models/panda_cms/block.rb +32 -0
- data/app/models/panda_cms/block_content.rb +16 -0
- data/app/models/panda_cms/block_content_version.rb +6 -0
- data/app/models/panda_cms/breadcrumb.rb +10 -0
- data/app/models/panda_cms/current.rb +15 -0
- data/app/models/panda_cms/menu.rb +50 -0
- data/app/models/panda_cms/menu_item.rb +56 -0
- data/app/models/panda_cms/page.rb +86 -0
- data/app/models/panda_cms/page_version.rb +6 -0
- data/app/models/panda_cms/redirect.rb +9 -0
- data/app/models/panda_cms/template.rb +44 -0
- data/app/models/panda_cms/template_version.rb +6 -0
- data/app/models/panda_cms/user.rb +11 -0
- data/app/models/panda_cms/version.rb +6 -0
- data/app/models/panda_cms/visit.rb +7 -0
- data/app/views/layouts/panda_cms/application.html.erb +68 -0
- data/app/views/layouts/panda_cms/public.html.erb +3 -0
- data/app/views/panda_cms/admin/dashboard/show.html.erb +8 -0
- data/app/views/panda_cms/admin/files/index.html.erb +124 -0
- data/app/views/panda_cms/admin/files/show.html.erb +2 -0
- data/app/views/panda_cms/admin/menus/_form.html.erb +21 -0
- data/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb +7 -0
- data/app/views/panda_cms/admin/menus/edit.html.erb +58 -0
- data/app/views/panda_cms/admin/menus/index.html.erb +32 -0
- data/app/views/panda_cms/admin/menus/new.html.erb +5 -0
- data/app/views/panda_cms/admin/pages/edit.html.erb +35 -0
- data/app/views/panda_cms/admin/pages/index.html.erb +46 -0
- data/app/views/panda_cms/admin/pages/new.html.erb +16 -0
- data/app/views/panda_cms/admin/pages/show.html.erb +1 -0
- data/app/views/panda_cms/admin/sessions/new.html.erb +39 -0
- data/app/views/panda_cms/admin/shared/_breadcrumbs.html.erb +25 -0
- data/app/views/panda_cms/admin/shared/_flash.html.erb +5 -0
- data/app/views/panda_cms/admin/shared/_sidebar.html.erb +29 -0
- data/app/views/panda_cms/shared/_favicons.html.erb +9 -0
- data/app/views/panda_cms/shared/_footer.html.erb +2 -0
- data/app/views/panda_cms/shared/_header.html.erb +19 -0
- data/config/importmap.rb +7 -0
- data/config/initializers/panda_cms/form_errors.rb +38 -0
- data/config/initializers/panda_cms.rb +42 -0
- data/config/locales/en.yml +13 -0
- data/config/routes.rb +26 -0
- data/config/tailwind.config.js +31 -0
- data/config/tailwind.embed.config.js +20 -0
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +9 -0
- data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +14 -0
- data/db/migrate/20240303002805_create_panda_cms_templates.rb +11 -0
- data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +14 -0
- data/db/migrate/20240303022441_create_panda_cms_blocks.rb +13 -0
- data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +10 -0
- data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +14 -0
- data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +10 -0
- data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +12 -0
- data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +5 -0
- data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +16 -0
- data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +6 -0
- data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +5 -0
- data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +24 -0
- data/db/migrate/20240317010532_create_panda_cms_users.rb +12 -0
- data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +7 -0
- data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +5 -0
- data/db/migrate/20240317214827_create_panda_cms_redirects.rb +15 -0
- data/db/migrate/20240317230622_create_panda_cms_visits.rb +13 -0
- data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +58 -0
- data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +5 -0
- data/db/seeds.rb +4 -0
- data/lib/generators/panda_cms/install_generator.rb +32 -0
- data/lib/panda_cms/engine.rb +172 -0
- data/lib/panda_cms/exceptions_app.rb +24 -0
- data/lib/panda_cms/version.rb +3 -0
- data/lib/panda_cms.rb +14 -0
- data/lib/tasks/panda_cms.rake +67 -0
- data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
- data/lib/templates/erb/scaffold/edit.html.erb.tt +8 -0
- data/lib/templates/erb/scaffold/index.html.erb.tt +14 -0
- data/lib/templates/erb/scaffold/new.html.erb.tt +7 -0
- data/lib/templates/erb/scaffold/partial.html.erb.tt +22 -0
- data/lib/templates/erb/scaffold/show.html.erb.tt +15 -0
- data/public/panda-cms-assets/android-chrome-192x192.png +0 -0
- data/public/panda-cms-assets/android-chrome-512x512.png +0 -0
- data/public/panda-cms-assets/apple-touch-icon.png +0 -0
- data/public/panda-cms-assets/browserconfig.xml +9 -0
- data/public/panda-cms-assets/editable.js +212 -0
- data/public/panda-cms-assets/favicon-16x16.png +0 -0
- data/public/panda-cms-assets/favicon-32x32.png +0 -0
- data/public/panda-cms-assets/favicon.ico +0 -0
- data/public/panda-cms-assets/mstile-150x150.png +0 -0
- data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
- data/public/panda-cms-assets/panda-nav.png +0 -0
- data/public/panda-cms-assets/safari-pinned-tab.svg +61 -0
- data/public/panda-cms-assets/site.webmanifest +14 -0
- data/public/panda-cms-assets/stimulus-loading.js +113 -0
- metadata +845 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require "awesome_nested_set"
|
2
|
+
|
3
|
+
module PandaCms
|
4
|
+
class Page < ApplicationRecord
|
5
|
+
acts_as_nested_set counter_cache: :children_count
|
6
|
+
self.table_name = "panda_cms_pages"
|
7
|
+
self.implicit_order_column = "lft"
|
8
|
+
|
9
|
+
has_paper_trail versions: {
|
10
|
+
class_name: "PandaCms::PageVersion"
|
11
|
+
}
|
12
|
+
|
13
|
+
after_save :after_save
|
14
|
+
|
15
|
+
belongs_to :template, foreign_key: :panda_cms_template_id, class_name: "PandaCms::Template", inverse_of: :pages, optional: false, counter_cache: :pages_count
|
16
|
+
has_many :blocks, through: :template
|
17
|
+
has_many :block_contents, foreign_key: :panda_cms_page_id, class_name: "PandaCms::BlockContent", inverse_of: :page
|
18
|
+
has_many :menu_items, foreign_key: :panda_cms_page_id, class_name: "PandaCms::MenuItem", inverse_of: :page
|
19
|
+
has_many :menus, through: :menu_items
|
20
|
+
has_many :menus_of_parent, through: :parent, source: :menus
|
21
|
+
has_one :page_menu, foreign_key: :panda_cms_menu_id, class_name: "PandaCms::Menu", inverse_of: :start_page
|
22
|
+
|
23
|
+
validates :title, presence: true
|
24
|
+
validates :path,
|
25
|
+
presence: true,
|
26
|
+
uniqueness: true,
|
27
|
+
format: {with: /\A\/.*\z/, message: "must start with a forward slash"}
|
28
|
+
validates :parent, presence: true, unless: -> { path == "/" }
|
29
|
+
validates :panda_cms_template_id, presence: true
|
30
|
+
|
31
|
+
scope :ordered, -> { order(:lft) }
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
#
|
36
|
+
# After save callbacks
|
37
|
+
#
|
38
|
+
# @return nil
|
39
|
+
# @visibility private
|
40
|
+
#
|
41
|
+
def after_save
|
42
|
+
generate_content_blocks
|
43
|
+
update_existing_menu_items
|
44
|
+
update_auto_menus
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_content_blocks
|
48
|
+
template_block_ids = template.blocks.ids
|
49
|
+
page_existing_block_ids = block_contents.map { |bc| bc.block.id }
|
50
|
+
required_block_ids = template_block_ids - page_existing_block_ids
|
51
|
+
|
52
|
+
if required_block_ids.count > 0
|
53
|
+
required_block_ids.each do |block_id|
|
54
|
+
PandaCms::BlockContent.find_or_create_by!(page: self, panda_cms_block_id: block_id, content: "")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Update text of existing menu items if the title differs
|
61
|
+
#
|
62
|
+
# @return nil
|
63
|
+
# @todo Only run this if the page title has changed
|
64
|
+
# @visibility private
|
65
|
+
#
|
66
|
+
def update_existing_menu_items
|
67
|
+
menu_items.where.not(text: title).update_all(text: title)
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Update any menus which include this page or its parent as a menu item
|
72
|
+
#
|
73
|
+
# @return nil
|
74
|
+
# @visibility private
|
75
|
+
#
|
76
|
+
def update_auto_menus
|
77
|
+
menus.find_each do |menu|
|
78
|
+
menu.generate_auto_menu_items
|
79
|
+
end
|
80
|
+
|
81
|
+
menus_of_parent.find_each do |menu|
|
82
|
+
menu.generate_auto_menu_items
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module PandaCms
|
2
|
+
class Redirect < ApplicationRecord
|
3
|
+
belongs_to :origin_page, class_name: "PandaCms::Page", foreign_key: :origin_panda_cms_page_id
|
4
|
+
belongs_to :destination_page, class_name: "PandaCms::Page", foreign_key: :destination_panda_cms_page_id
|
5
|
+
|
6
|
+
validates :status_code, presence: true
|
7
|
+
validates :visits, presence: true
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module PandaCms
|
2
|
+
# Represents a template in the Panda CMS application.
|
3
|
+
class Template < ApplicationRecord
|
4
|
+
self.table_name = "panda_cms_templates"
|
5
|
+
|
6
|
+
# Enables versioning for the Template model using the `has_paper_trail` gem.
|
7
|
+
has_paper_trail versions: {
|
8
|
+
class_name: "PandaCms::TemplateVersion"
|
9
|
+
}
|
10
|
+
|
11
|
+
# Associations
|
12
|
+
has_many :pages, class_name: "PandaCms::Page", dependent: :restrict_with_error, inverse_of: :template, foreign_key: :panda_cms_template_id
|
13
|
+
has_many :blocks, class_name: "PandaCms::Block", dependent: :restrict_with_error, inverse_of: :template, foreign_key: :panda_cms_template_id
|
14
|
+
has_many :block_contents, through: :blocks
|
15
|
+
|
16
|
+
# Validations
|
17
|
+
validates :name, presence: true, uniqueness: true
|
18
|
+
|
19
|
+
validates :file_path,
|
20
|
+
presence: true,
|
21
|
+
uniqueness: true,
|
22
|
+
format: {with: /\Alayouts\/.*\z/, message: "must be a valid layout file path"}
|
23
|
+
|
24
|
+
validate :validate_template_file_exists
|
25
|
+
|
26
|
+
# Scopes
|
27
|
+
scope :ordered, -> { order(:sort_order) }
|
28
|
+
scope :available, -> { where("max_uses IS NULL OR (pages_count < max_uses)") }
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Custom validation method to check if the file_path is a valid layout file path
|
33
|
+
# NB: Currently only supports .html.erb templates, may want to expand in future?
|
34
|
+
# @return [void]
|
35
|
+
def validate_template_file_exists
|
36
|
+
# Remove any directory traversal attempts from the file_path
|
37
|
+
safe_file_path = file_path.to_s.gsub("../", "")
|
38
|
+
# Check if the file_path is an ERB template that exists in app/views
|
39
|
+
template_path = Rails.root.join("app", "views", "#{safe_file_path}.html.erb")
|
40
|
+
# NB: file? checks for files and excludes directories (unlike exist?)
|
41
|
+
errors.add(:file_path, "must be an existing layout file path") unless File.file?(template_path)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module PandaCms
|
2
|
+
class Visit < ApplicationRecord
|
3
|
+
belongs_to :page, class_name: "PandaCms::Page", foreign_key: :panda_cms_page_id, optional: true
|
4
|
+
belongs_to :user, class_name: "PandaCms::User", foreign_key: :panda_cms_user_id, optional: true
|
5
|
+
belongs_to :redirect, class_name: "PandaCms::Redirect", foreign_key: :panda_cms_redirect_id, optional: true
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
<%= render "panda_cms/shared/header", html_class: "h-full bg-gray-50" %>
|
2
|
+
<div class="flex h-full" id="panda-container">
|
3
|
+
<div class="lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-72 lg:flex-col top-0 -m-t-2 w-full absolute" data-controller="panda-cms-menu">
|
4
|
+
<div class="flex grow flex-col gap-y-5 overflow-y-auto bg-panda-cms-dark px-4 pb-4 lg:max-h-full max-h-16" data-panda-cms-menu-target="menu" 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 partial: "panda_cms/admin/shared/sidebar" %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="flex flex-col flex-1 ml-0 lg:ml-72 mt-16 lg:mt-0" id="panda-inner-container" <% if content_for :sidebar %> data-controller="toggle" data-action="keydown.esc->modal#close" tabindex="-1"<% end %>>
|
10
|
+
<header class="w-full" id="panda-action-bar">
|
11
|
+
<div class="flex relative z-10 flex-shrink-0 h-16 bg-white border-b border-gray-200 shadow-sm">
|
12
|
+
<div class="flex flex-1 justify-between px-4 sm:px-6">
|
13
|
+
<div class="flex flex-1">
|
14
|
+
<form class="flex w-full md:ml-0" action="#" method="GET">
|
15
|
+
<label for="search-field" class="sr-only">Search</label>
|
16
|
+
<div class="relative w-full text-gray-400 focus-within:text-gray-600">
|
17
|
+
<div class="flex absolute inset-y-0 left-0 items-center pointer-events-none">
|
18
|
+
<svg class="flex-shrink-0 w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
19
|
+
<path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd" />
|
20
|
+
</svg>
|
21
|
+
</div>
|
22
|
+
<input name="search-field" autocomplete="off" id="search-field" class="py-2 pr-3 pl-8 w-full h-full text-gray-900 border-0 sm:text-sm focus:ring-0 focus:outline-none focus:placeholder:text-gray-400" placeholder="Search" type="search">
|
23
|
+
</div>
|
24
|
+
<% if content_for :sidebar %>
|
25
|
+
<a href="#" id="slideover-toggle" data-action="click->toggle#toggle touch->toggle#toggle" class="block relative right-0 py-4 pr-0 mt-1 w-32 font-semibold text-right text-gray-500 hover:text-gray-700 min-w-32 px-auto"><i class="fa-light fa-gear"></i> <%= yield :sidebar_title %></a>
|
26
|
+
<% end %>
|
27
|
+
</form>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</header>
|
32
|
+
|
33
|
+
<%= render "panda_cms/admin/shared/breadcrumbs" %>
|
34
|
+
|
35
|
+
<section id="panda-main" class="flex flex-row h-full">
|
36
|
+
<div class="flex-1 h-full" id="panda-cms-primary-content">
|
37
|
+
<%= yield %>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<% if content_for :sidebar %>
|
41
|
+
<div data-toggle-target="toggleable" class="flex hidden flex-col h-full bg-white divide-y divide-gray-200 shadow-xl basis-3/12 absolute right-0"
|
42
|
+
data-transition-enter="transform transition ease-in-out duration-500"
|
43
|
+
data-transition-enter-from="translate-x-full"
|
44
|
+
data-transition-enter-to="translate-x-0"
|
45
|
+
data-transition-leave="transform transition ease-in-out duration-500"
|
46
|
+
data-transition-leave-from="translate-x-full"
|
47
|
+
data-transition-leave-to="translate-x-0"
|
48
|
+
id="slideover">
|
49
|
+
<div class="overflow-y-auto flex-1 h-0">
|
50
|
+
<div class="py-3 px-4 bg-panda-cms-dark">
|
51
|
+
<div class="flex justify-between items-center">
|
52
|
+
<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>
|
53
|
+
<a href="#" data-action="click->toggle#toggle touch->toggle#toggle"><i class="font-bold text-white fa-regular fa-xmark right"></i></a>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
<div class="flex flex-col flex-1 justify-between">
|
57
|
+
<div class="px-4 space-y-6">
|
58
|
+
<%= yield :sidebar %>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
</div>
|
63
|
+
<% end %>
|
64
|
+
</section>
|
65
|
+
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
<%= render "panda_cms/shared/footer" %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div data-controller='toggle' class="m-2">
|
2
|
+
<div data-action='click->toggle#toggle touch->toggle#toggle' class="bg-gray-900 text-white p-6">
|
3
|
+
What is the question? (Click to play with toggle!)
|
4
|
+
</div>
|
5
|
+
<div data-toggle-target='toggleable' class="m-4 hidden">
|
6
|
+
<p>This is the answer</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,124 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "Files", level: 1) %>
|
3
|
+
|
4
|
+
<% component.with_slideover(title: "File Details") do %>
|
5
|
+
<div class="pt-4 pb-16 space-y-6">
|
6
|
+
<div>
|
7
|
+
<div class="block overflow-hidden w-full rounded-lg aspect-h-7 aspect-w-10">
|
8
|
+
<img src="https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80" alt="" class="object-cover">
|
9
|
+
</div>
|
10
|
+
<div class="flex justify-between items-start mt-4">
|
11
|
+
<div>
|
12
|
+
<h2 class="text-lg font-medium text-gray-900"><span class="sr-only">Details for </span>IMG_4985.HEIC</h2>
|
13
|
+
<p class="text-sm font-medium text-gray-500">3.9 MB</p>
|
14
|
+
</div>
|
15
|
+
<button type="button" class="flex relative justify-center items-center ml-4 w-8 h-8 text-gray-400 bg-white rounded-full hover:text-gray-500 hover:bg-gray-100 focus:ring-2 focus:outline-none focus:ring-panda-dark">
|
16
|
+
<span class="absolute -inset-1.5"></span>
|
17
|
+
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
18
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
|
19
|
+
</svg>
|
20
|
+
<span class="sr-only">Favorite</span>
|
21
|
+
</button>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<div>
|
25
|
+
<h3 class="font-medium text-gray-900">Information</h3>
|
26
|
+
<dl class="mt-2 border-t border-b border-gray-200 divide-y divide-gray-200">
|
27
|
+
<div class="flex justify-between py-3 text-sm font-medium">
|
28
|
+
<dt class="text-gray-500">Uploaded by</dt>
|
29
|
+
<dd class="text-gray-900 whitespace-nowrap">Marie Culver</dd>
|
30
|
+
</div>
|
31
|
+
<div class="flex justify-between py-3 text-sm font-medium">
|
32
|
+
<dt class="text-gray-500">Created</dt>
|
33
|
+
<dd class="text-gray-900 whitespace-nowrap">June 8, 2020</dd>
|
34
|
+
</div>
|
35
|
+
<div class="flex justify-between py-3 text-sm font-medium">
|
36
|
+
<dt class="text-gray-500">Last modified</dt>
|
37
|
+
<dd class="text-gray-900 whitespace-nowrap">June 8, 2020</dd>
|
38
|
+
</div>
|
39
|
+
<div class="flex justify-between py-3 text-sm font-medium">
|
40
|
+
<dt class="text-gray-500">Dimensions</dt>
|
41
|
+
<dd class="text-gray-900 whitespace-nowrap">4032 x 3024</dd>
|
42
|
+
</div>
|
43
|
+
<div class="flex justify-between py-3 text-sm font-medium">
|
44
|
+
<dt class="text-gray-500">Resolution</dt>
|
45
|
+
<dd class="text-gray-900 whitespace-nowrap">72 x 72</dd>
|
46
|
+
</div>
|
47
|
+
</dl>
|
48
|
+
</div>
|
49
|
+
<div>
|
50
|
+
<h3 class="font-medium text-gray-900">Description</h3>
|
51
|
+
<div class="flex justify-between items-center mt-2">
|
52
|
+
<p class="text-sm italic text-gray-500">Add a description to this image.</p>
|
53
|
+
<button type="button" class="flex relative justify-center items-center w-8 h-8 text-gray-400 bg-white rounded-full hover:text-gray-500 hover:bg-gray-100 focus:ring-2 focus:outline-none focus:ring-panda-dark">
|
54
|
+
<span class="absolute -inset-1.5"></span>
|
55
|
+
<svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
56
|
+
<path d="M2.695 14.763l-1.262 3.154a.5.5 0 00.65.65l3.155-1.262a4 4 0 001.343-.885L17.5 5.5a2.121 2.121 0 00-3-3L3.58 13.42a4 4 0 00-.885 1.343z" />
|
57
|
+
</svg>
|
58
|
+
<span class="sr-only">Add description</span>
|
59
|
+
</button>
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
<div>
|
63
|
+
<h3 class="font-medium text-gray-900">Shared with</h3>
|
64
|
+
<ul role="list" class="mt-2 border-t border-b border-gray-200 divide-y divide-gray-200">
|
65
|
+
<li class="flex justify-between items-center py-3">
|
66
|
+
<div class="flex items-center">
|
67
|
+
<img src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=3&w=1024&h=1024&q=80" alt="" class="w-8 h-8 rounded-full">
|
68
|
+
<p class="ml-4 text-sm font-medium text-gray-900">Aimee Douglas</p>
|
69
|
+
</div>
|
70
|
+
<button type="button" class="ml-6 text-sm font-medium bg-white rounded-md focus:ring-2 focus:ring-offset-2 focus:outline-none text-panda-dark hover:text-panda-dark focus:ring-panda-dark">Remove<span class="sr-only"> Aimee Douglas</span></button>
|
71
|
+
</li>
|
72
|
+
<li class="flex justify-between items-center py-3">
|
73
|
+
<div class="flex items-center">
|
74
|
+
<img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixqx=oilqXxSqey&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" class="w-8 h-8 rounded-full">
|
75
|
+
<p class="ml-4 text-sm font-medium text-gray-900">Andrea McMillan</p>
|
76
|
+
</div>
|
77
|
+
<button type="button" class="ml-6 text-sm font-medium bg-white rounded-md focus:ring-2 focus:ring-offset-2 focus:outline-none text-panda-dark hover:text-panda-dark focus:ring-panda-dark">Remove<span class="sr-only"> Andrea McMillan</span></button>
|
78
|
+
</li>
|
79
|
+
|
80
|
+
<li class="flex justify-between items-center py-2">
|
81
|
+
<button type="button" class="flex items-center p-1 -ml-1 bg-white rounded-md focus:ring-2 focus:outline-none group focus:ring-panda-dark">
|
82
|
+
<span class="flex justify-center items-center w-8 h-8 text-gray-400 rounded-full border-2 border-gray-300 border-dashed">
|
83
|
+
<svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
84
|
+
<path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z" />
|
85
|
+
</svg>
|
86
|
+
</span>
|
87
|
+
<span class="ml-4 text-sm font-medium text-panda-dark group-hover:text-panda-dark">Share</span>
|
88
|
+
</button>
|
89
|
+
</li>
|
90
|
+
</ul>
|
91
|
+
</div>
|
92
|
+
<div class="flex gap-x-3">
|
93
|
+
<button type="button" class="flex-1 py-2 px-3 text-sm font-semibold text-white rounded-md shadow-sm bg-panda-cms-dark hover:bg-panda-cms-dark focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-panda-dark">Download</button>
|
94
|
+
<button type="button" class="flex-1 py-2 px-3 text-sm font-semibold text-gray-900 bg-white rounded-md ring-1 ring-inset ring-gray-300 shadow-sm hover:bg-gray-50">Delete</button>
|
95
|
+
</div>
|
96
|
+
</div>
|
97
|
+
<% end %>
|
98
|
+
|
99
|
+
<% component.with_tab_bar do %>
|
100
|
+
<%= component.with_tab(name: "Recently Viewed", active: true) %>
|
101
|
+
<%= component.with_tab(name: "Recently Added") %>
|
102
|
+
<%= component.with_tab(name: "Favourited") %>
|
103
|
+
<% end %>
|
104
|
+
|
105
|
+
<section>
|
106
|
+
<h2 id="gallery-heading" class="sr-only">Recently viewed</h2>
|
107
|
+
<ul role="list" class="grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 md:grid-cols-4 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
108
|
+
<li class="relative">
|
109
|
+
<!-- Current: "ring-2 ring-panda-dark ring-offset-2", Default: "focus-within:ring-2 focus-within:ring-panda-dark focus-within:ring-offset-2 focus-within:ring-offset-gray-100" -->
|
110
|
+
<div class="block overflow-hidden w-full bg-gray-100 rounded-lg ring-2 ring-offset-2 ring-panda-dark aspect-w-10 aspect-h-7 group">
|
111
|
+
<!-- Current: "", Default: "group-hover:opacity-75" -->
|
112
|
+
<img src="https://images.unsplash.com/photo-1582053433976-25c00369fc93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=512&q=80" alt="" class="object-cover pointer-events-none">
|
113
|
+
<button type="button" class="absolute inset-0 focus:outline-none">
|
114
|
+
<span class="sr-only">View details for IMG_4985.HEIC</span>
|
115
|
+
</button>
|
116
|
+
</div>
|
117
|
+
<p class="block mt-2 text-sm font-medium text-gray-900 pointer-events-none truncate">IMG_4985.HEIC</p>
|
118
|
+
<p class="block text-sm font-medium text-gray-500 pointer-events-none">3.9 MB</p>
|
119
|
+
</li>
|
120
|
+
|
121
|
+
<!-- More files... -->
|
122
|
+
</ul>
|
123
|
+
</section>
|
124
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%= panda_cms_form_with model: menu, url: admin_menus_path, method: :post do |form| %>
|
2
|
+
<%= form.text_field :name %>
|
3
|
+
|
4
|
+
<div data-controller="nested-form" nested_form_wrapper_selector_value=".nested-form-wrapper">
|
5
|
+
<template data-nested-form-target="template">
|
6
|
+
<%= form.fields_for :menu_items, PandaCms::MenuItem.new, child_index: 'NEW_RECORD' do |item| %>
|
7
|
+
<%= render "menu_item_fields", form: item %>
|
8
|
+
<% end %>
|
9
|
+
</template>
|
10
|
+
|
11
|
+
<%= form.fields_for :menu_items do |item| %>
|
12
|
+
<%= render "menu_item_fields", form: item %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div data-nested-form-target="target"></div>
|
16
|
+
|
17
|
+
<%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<%= form.submit "Create" %>
|
21
|
+
<% end %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<div class="nested-form-wrapper border mt-2 mb-4 rounded-md border-grey-900 p-4" data-new-record="<%= form.object.new_record? %>">
|
2
|
+
<%= form.text_field :text %>
|
3
|
+
<%= form.text_field :external_url %>
|
4
|
+
<%= form.collection_select :panda_cms_page_id, PandaCms::Page.all, :id, :title, include_blank: true %>
|
5
|
+
<%= render PandaCms::Admin::ButtonComponent.new(text: "Remove Menu Item", action: :delete, data: {action: "nested-form#remove"}, size: :small) %>
|
6
|
+
<%= form.hidden_field :_destroy %>
|
7
|
+
</div>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "Edit Menu", level: 1) %>
|
3
|
+
|
4
|
+
<%= panda_cms_form_with model: @menu, url: admin_menu_path, method: :put do |form| %>
|
5
|
+
<%= form.text_field :name %>
|
6
|
+
|
7
|
+
<% if @menu.kind == "static" %>
|
8
|
+
<div data-controller="nested-form" data-nested-form-wrapper-selector-value=".nested-form-wrapper">
|
9
|
+
<template data-nested-form-target="template">
|
10
|
+
<%= form.fields_for :menu_items, PandaCms::MenuItem.new, child_index: "NEW_RECORD" do |item| %>
|
11
|
+
<%= render "menu_item_fields", form: item %>
|
12
|
+
<% end %>
|
13
|
+
</template>
|
14
|
+
|
15
|
+
<% if @menu.menu_items.count > 0 %>
|
16
|
+
<%= form.fields_for :menu_items, @menu.menu_items.sort_by(&:lft) do |item| %>
|
17
|
+
<%= render "menu_item_fields", form: item %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<div data-nested-form-target="target"></div>
|
22
|
+
|
23
|
+
<%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %>
|
24
|
+
</div>
|
25
|
+
<% else %>
|
26
|
+
<table class="-mx-3 min-w-full divide-y divide-gray-300">
|
27
|
+
<thead>
|
28
|
+
<tr>
|
29
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Text</th>
|
30
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Page</th>
|
31
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">External Link</th>
|
32
|
+
</tr>
|
33
|
+
</thead>
|
34
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
35
|
+
<% @menu.menu_items.root.self_and_descendants.each do |menu_item| %>
|
36
|
+
<tr>
|
37
|
+
<td class="py-5 pr-3 pl-3 text-sm whitespace-nowrap">
|
38
|
+
<div class="flex items-center">
|
39
|
+
<div class="<%= table_indent(menu_item) %>">
|
40
|
+
<div class="font-medium text-gray-900"><%= menu_item.text %></div>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
</td>
|
44
|
+
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
45
|
+
<div class="text-gray-900"><%= menu_item.page.title %></div>
|
46
|
+
</td>
|
47
|
+
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
48
|
+
<div class="text-gray-900"><%= menu_item.external_url %></div>
|
49
|
+
</td>
|
50
|
+
</tr>
|
51
|
+
<% end %>
|
52
|
+
</tbody>
|
53
|
+
</table>
|
54
|
+
<% end %>
|
55
|
+
|
56
|
+
<%= form.button %>
|
57
|
+
<% end %>
|
58
|
+
<% end %>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "Menus", level: 1) do |heading| %>
|
3
|
+
<% heading.with_button(action: :add, text: "Add Menu", link: new_admin_menu_path) %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<table class="-mx-3 min-w-full divide-y divide-gray-300">
|
7
|
+
<thead>
|
8
|
+
<tr>
|
9
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Name</th>
|
10
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Kind</th>
|
11
|
+
<th scope="col" class="relative py-3.5 pr-4 pl-3 sm:pr-0">
|
12
|
+
<span class="sr-only">Edit</span>
|
13
|
+
</th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
17
|
+
<% @menus.each do |menu| %>
|
18
|
+
<tr>
|
19
|
+
<td class="py-5 px-3 whitespace-nowrap font-medium text-gray-900">
|
20
|
+
<%= menu.name %>
|
21
|
+
</td>
|
22
|
+
<td class="py-5 px-3 whitespace-nowrap text-gray-900">
|
23
|
+
<%= menu.kind.titleize %>
|
24
|
+
</td>
|
25
|
+
<td class="py-5 pr-4 pl-3 text-sm font-medium text-right whitespace-nowrap">
|
26
|
+
<%= link_to "Edit", edit_admin_menu_path(menu), class: "text-panda-dark hover:text-indigo-900" %>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "#{page.title}", level: 1) do |heading| %>
|
3
|
+
<%# heading.with_button(action: :secondary, text: "Save Draft", link: "#", icon: "clipboard-check") %>
|
4
|
+
<%# heading.with_button(action: :save, text: "Publish Page", link: "#") %>
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
<% component.with_slideover(title: "Page Details") do %>
|
8
|
+
<%= form_with model: page, url: admin_page_path, method: :put do |f| %>
|
9
|
+
<div class="col-span-3 mb-2 sm:col-span-2">
|
10
|
+
<%= f.label :title, class: "mt-2 block text-sm font-medium leading-6 text-gray-900" %>
|
11
|
+
<div class="flex mt-2 rounded-md shadow-sm">
|
12
|
+
<%= f.text_field :title, class: "block w-full rounded-md border-0 p-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-300 focus:ring-1 focus:ring-inset focus:ring-gray-500 sm:text-sm sm:leading-6 hover:pointer" %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<%= f.label :template, class: "mt-2 block text-sm font-medium leading-6 text-gray-900" %>
|
16
|
+
<div class="flex mt-2 rounded-md shadow-sm">
|
17
|
+
<%= 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-gray-300 placeholder:text-gray-300 focus:ring-1 focus:ring-inset focus:ring-gray-500 sm:text-sm sm:leading-6 hover:pointer" %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<%= f.submit "Save", class: "mt-4 inline-flex justify-center rounded-md bg-panda-cms-dark px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-panda-cms-dark focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-panda-dark" %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<a class="text-sm text-gray-400 block -mt-4 mb-2" target="_blank" href="<%= @page.path %>"><%= @page.path %> <i class="fa-solid fa-arrow-up-right-from-square ml-2"></i></a>
|
26
|
+
|
27
|
+
<iframe id="editablePageFrame" src="<%= page.path %>?embed_id=<%= page.id %>" class="w-full h-full m-0 p-0 border border-slate-200"></iframe>
|
28
|
+
|
29
|
+
<script src="/panda-cms-assets/editable.js"></script>
|
30
|
+
<script>
|
31
|
+
document.addEventListener("DOMContentLoaded", function() {
|
32
|
+
const editable = new EditableController("<%= page.id %>", document.getElementById("editablePageFrame"));
|
33
|
+
});
|
34
|
+
</script>
|
35
|
+
<% end %>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "Pages", level: 1) do |heading| %>
|
3
|
+
<% heading.with_button(action: :add, text: "Add Page", link: new_admin_page_path) %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<table class="-mx-3 min-w-full divide-y divide-gray-300">
|
7
|
+
<thead>
|
8
|
+
<tr>
|
9
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Name</th>
|
10
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Status</th>
|
11
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Last Updated</th>
|
12
|
+
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Checks</th>
|
13
|
+
<th scope="col" class="relative py-3.5 pr-4 pl-3 sm:pr-0">
|
14
|
+
<span class="sr-only">Edit</span>
|
15
|
+
</th>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
19
|
+
<% root_page.self_and_descendants.each do |page| %>
|
20
|
+
<tr>
|
21
|
+
<td class="py-5 pr-3 pl-3 text-sm whitespace-nowrap">
|
22
|
+
<div class="flex items-center">
|
23
|
+
<div class="<%= table_indent(page) %>">
|
24
|
+
<div class="font-medium text-gray-900"><%= page.title %></div>
|
25
|
+
<div class="mt-1 text-gray-500"><%= link_to page.path, page.path, target: "_blank" %></div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</td>
|
29
|
+
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
30
|
+
<span class="inline-flex items-center py-1 px-2 text-xs font-medium text-green-700 bg-green-50 rounded-md ring-1 ring-inset ring-green-600/20">Active</span>
|
31
|
+
</td>
|
32
|
+
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
33
|
+
<div class="text-gray-900"><%#= page.versions.last.whodunnit %></div>
|
34
|
+
<div class="mt-1 text-gray-500"><%= time_ago_in_words(page.updated_at) %> ago</div>
|
35
|
+
</td>
|
36
|
+
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
37
|
+
<div class="text-gray-900"><i class="text-gray-500 fa fa-fw fa-paint-brush"></i> <%= page.template.name %></div>
|
38
|
+
</td>
|
39
|
+
<td class="py-5 pr-4 pl-3 text-sm font-medium text-right whitespace-nowrap">
|
40
|
+
<%= link_to "Edit", edit_admin_page_path(page), class: "text-panda-dark hover:text-indigo-900" %>
|
41
|
+
</td>
|
42
|
+
</tr>
|
43
|
+
<% end %>
|
44
|
+
</tbody>
|
45
|
+
</table>
|
46
|
+
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
+
<% component.with_heading(text: "Add Page", level: 1) do |heading| %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= panda_cms_form_with model: page, url: admin_pages_path, method: :post do |f| %>
|
6
|
+
<% options = nested_set_options(PandaCms::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %>
|
7
|
+
<div data-controller="text-field-update">
|
8
|
+
<input type="hidden" value="<%= PandaCms::Current.root %>" data-text-field-update-target="existing_root">
|
9
|
+
<%= f.select :parent_id, options, {}, { "data-text-field-update-target": "input_select", "data-action": "change->text-field-update#setPrePath" } %>
|
10
|
+
<%= f.text_field :title, { data: { "text-field-update-target": "input_text", action: "focusout->text-field-update#generatePath" } } %>
|
11
|
+
<%= f.text_field :path, { data: { prefix: PandaCms::Current.root, "text-field-update-target": "output_text" } } %>
|
12
|
+
<%= f.collection_select :panda_cms_template_id, PandaCms::Template.available, :id, :name %>
|
13
|
+
<%= f.button %>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
Show page
|