panda_cms 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +71 -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 +61 -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 +43 -0
- data/app/components/panda_cms/admin/panel_component.html.erb +7 -0
- data/app/components/panda_cms/admin/panel_component.rb +11 -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/statistics_component.html.erb +4 -0
- data/app/components/panda_cms/admin/statistics_component.rb +15 -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/admin/table_component.html.erb +21 -0
- data/app/components/panda_cms/admin/table_component.rb +43 -0
- data/app/components/panda_cms/admin/tag_component.rb +33 -0
- data/app/components/panda_cms/admin/user_activity_component.html.erb +5 -0
- data/app/components/panda_cms/admin/user_activity_component.rb +19 -0
- data/app/components/panda_cms/admin/user_display_component.html.erb +11 -0
- data/app/components/panda_cms/admin/user_display_component.rb +19 -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 +67 -0
- data/app/constraints/panda_cms/admin_constraint.rb +16 -0
- data/app/controllers/panda_cms/admin/block_contents_controller.rb +44 -0
- data/app/controllers/panda_cms/admin/dashboard_controller.rb +31 -0
- data/app/controllers/panda_cms/admin/files_controller.rb +19 -0
- data/app/controllers/panda_cms/admin/forms_controller.rb +51 -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/posts_controller.rb +34 -0
- data/app/controllers/panda_cms/admin/sessions_controller.rb +83 -0
- data/app/controllers/panda_cms/admin/settings/bulk_editor_controller.rb +35 -0
- data/app/controllers/panda_cms/admin/settings_controller.rb +18 -0
- data/app/controllers/panda_cms/application_controller.rb +55 -0
- data/app/controllers/panda_cms/errors_controller.rb +31 -0
- data/app/controllers/panda_cms/form_submissions_controller.rb +21 -0
- data/app/controllers/panda_cms/pages_controller.rb +56 -0
- data/app/controllers/panda_cms/posts_controller.rb +17 -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 +96 -0
- data/app/helpers/panda_cms/pages_helper.rb +4 -0
- data/app/helpers/panda_cms/theme_helper.rb +16 -0
- data/app/javascript/base.js +37 -0
- data/app/javascript/controllers/menu_controller.js +19 -0
- data/app/javascript/controllers/text_controller.js +78 -0
- data/app/javascript/controllers/text_field_update_controller.js +23 -0
- data/app/javascript/vendor/stimulus-components-rails-nested-form.js +2 -0
- data/app/javascript/vendor/tailwindcss-stimulus-components.js +2 -0
- data/app/jobs/panda_cms/application_job.rb +4 -0
- data/app/jobs/panda_cms/record_visit_job.rb +29 -0
- data/app/lib/panda_cms/bulk_editor.rb +169 -0
- data/app/lib/panda_cms/demo_site_generator.rb +70 -0
- data/app/lib/panda_cms/slug.rb +22 -0
- data/app/mailers/panda_cms/application_mailer.rb +6 -0
- data/app/mailers/panda_cms/form_mailer.rb +19 -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/form.rb +7 -0
- data/app/models/panda_cms/form_submission.rb +5 -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 +81 -0
- data/app/models/panda_cms/page_version.rb +6 -0
- data/app/models/panda_cms/post.rb +25 -0
- data/app/models/panda_cms/post_version.rb +6 -0
- data/app/models/panda_cms/redirect.rb +9 -0
- data/app/models/panda_cms/template.rb +117 -0
- data/app/models/panda_cms/template_version.rb +6 -0
- data/app/models/panda_cms/user.rb +15 -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 +44 -0
- data/app/views/layouts/panda_cms/public.html.erb +3 -0
- data/app/views/panda_cms/admin/dashboard/show.html.erb +11 -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/forms/edit.html.erb +0 -0
- data/app/views/panda_cms/admin/forms/index.html.erb +13 -0
- data/app/views/panda_cms/admin/forms/new.html.erb +16 -0
- data/app/views/panda_cms/admin/forms/show.html.erb +35 -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 +10 -0
- data/app/views/panda_cms/admin/menus/new.html.erb +5 -0
- data/app/views/panda_cms/admin/pages/edit.html.erb +26 -0
- data/app/views/panda_cms/admin/pages/index.html.erb +16 -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/posts/index.html.erb +16 -0
- data/app/views/panda_cms/admin/sessions/new.html.erb +18 -0
- data/app/views/panda_cms/admin/settings/bulk_editor/new.html.erb +68 -0
- data/app/views/panda_cms/admin/settings/index.html.erb +19 -0
- data/app/views/panda_cms/admin/shared/_breadcrumbs.html.erb +28 -0
- data/app/views/panda_cms/admin/shared/_flash.html.erb +5 -0
- data/app/views/panda_cms/admin/shared/_sidebar.html.erb +45 -0
- data/app/views/panda_cms/form_mailer/notification_email.html.erb +11 -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 +15 -0
- data/config/importmap.rb +9 -0
- data/config/initializers/panda_cms/form_errors.rb +38 -0
- data/config/initializers/panda_cms/healthcheck_log_silencer.rb +11 -0
- data/config/initializers/panda_cms.rb +52 -0
- data/config/locales/en.yml +29 -0
- data/config/routes.rb +43 -0
- data/config/tailwind.config.js +35 -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 +14 -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/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +28 -0
- data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
- data/db/migrate/20240804110225_add_status_to_panda_cms_pages.rb +7 -0
- data/db/migrate/20240804235210_create_panda_cms_forms.rb +11 -0
- data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +9 -0
- data/db/migrate/20240805121123_create_panda_cms_posts.rb +27 -0
- data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +14 -0
- data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +13 -0
- data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +5 -0
- data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +5 -0
- data/db/seeds.rb +4 -0
- data/lib/generators/panda_cms/install_generator.rb +24 -0
- data/lib/panda_cms/engine.rb +167 -0
- data/lib/panda_cms/exceptions_app.rb +24 -0
- data/lib/panda_cms/version.rb +3 -0
- data/lib/panda_cms.rb +15 -0
- data/lib/tasks/panda_cms.rake +92 -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/favicons/android-chrome-192x192.png +0 -0
- data/public/panda-cms-assets/favicons/android-chrome-512x512.png +0 -0
- data/public/panda-cms-assets/favicons/apple-touch-icon.png +0 -0
- data/public/panda-cms-assets/favicons/browserconfig.xml +9 -0
- data/public/panda-cms-assets/favicons/favicon-16x16.png +0 -0
- data/public/panda-cms-assets/favicons/favicon-32x32.png +0 -0
- data/public/panda-cms-assets/favicons/favicon.ico +0 -0
- data/public/panda-cms-assets/favicons/mstile-150x150.png +0 -0
- data/public/panda-cms-assets/favicons/safari-pinned-tab.svg +61 -0
- data/public/panda-cms-assets/favicons/site.webmanifest +14 -0
- data/public/panda-cms-assets/javascripts/base.js +37 -0
- data/public/panda-cms-assets/javascripts/controllers/menu_controller.js +19 -0
- data/public/panda-cms-assets/javascripts/controllers/text_field_update_controller.js +23 -0
- data/public/panda-cms-assets/javascripts/embed/editable.js +308 -0
- data/public/panda-cms-assets/javascripts/vendor/stimulus-components-rails-nested-form.js +2 -0
- data/public/panda-cms-assets/javascripts/vendor/stimulus-loading.js +113 -0
- data/public/panda-cms-assets/javascripts/vendor/tailwindcss-stimulus-components.js +2 -0
- data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
- data/public/panda-cms-assets/panda-nav.png +0 -0
- metadata +1034 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
require "groupdate"
|
2
|
+
require "importmap-rails"
|
3
|
+
require "paper_trail"
|
4
|
+
require "view_component"
|
5
|
+
|
6
|
+
require "omniauth"
|
7
|
+
require "omniauth/rails_csrf_protection"
|
8
|
+
require "omniauth/strategies/microsoft_graph"
|
9
|
+
require "omniauth/strategies/google_oauth2"
|
10
|
+
require "omniauth/strategies/github"
|
11
|
+
|
12
|
+
require "panda_cms/exceptions_app"
|
13
|
+
|
14
|
+
module PandaCms
|
15
|
+
class Engine < ::Rails::Engine
|
16
|
+
isolate_namespace PandaCms
|
17
|
+
engine_name "panda_cms"
|
18
|
+
|
19
|
+
config.to_prepare do
|
20
|
+
ApplicationController.helper(::ApplicationHelper)
|
21
|
+
end
|
22
|
+
|
23
|
+
# We rely on ViewComponent here before we can continue
|
24
|
+
config.railties_order = [::ViewComponent::Engine, PandaCms::Engine, :main_app, :all]
|
25
|
+
|
26
|
+
# Set our generators
|
27
|
+
config.generators do |g|
|
28
|
+
g.orm :active_record, primary_key_type: :uuid
|
29
|
+
g.test_framework :rspec, fixture: true
|
30
|
+
g.fixture_replacement :factory_bot, dir: "spec/factories"
|
31
|
+
g.view_specs false
|
32
|
+
g.templates.unshift File.expand_path("../../templates", __FILE__)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Make files in public available to the main app (e.g. favicon.ico)
|
36
|
+
config.app_middleware.use(
|
37
|
+
Rack::Static,
|
38
|
+
urls: ["/panda-cms-assets"],
|
39
|
+
root: PandaCms::Engine.root.join("public")
|
40
|
+
)
|
41
|
+
|
42
|
+
config.exceptions_app = PandaCms::ExceptionsApp.new(exceptions_app: routes)
|
43
|
+
|
44
|
+
# Create an importmap for the engine's JS
|
45
|
+
initializer "panda_cms.importmap", before: "importmap" do |app|
|
46
|
+
app.config.importmap.cache_sweeper(watches: PandaCms::Engine.root.join("public/panda-cms-assets"))
|
47
|
+
app.config.importmap.paths << PandaCms::Engine.root.join("config/importmap.rb")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Append routes to the routes file
|
51
|
+
config.after_initialize do |app|
|
52
|
+
app.routes.append do
|
53
|
+
mount PandaCms::Engine => "/", :as => "panda_cms"
|
54
|
+
post "/_forms/:id", to: "panda_cms/form_submissions#create", as: :panda_cms_form_submit
|
55
|
+
get "/_maintenance", to: "panda_cms/errors#error_503", as: :panda_cms_maintenance
|
56
|
+
get "/*path", to: "panda_cms/pages#show", as: :panda_cms_page
|
57
|
+
root to: "panda_cms/pages#root"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add the migrations to the main app
|
62
|
+
initializer "panda_cms.migrations" do |app|
|
63
|
+
unless app.root.to_s.match root.to_s
|
64
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
65
|
+
app.config.paths["db/migrate"] << expanded_path
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set up authentication
|
71
|
+
initializer "panda_cms.omniauth", before: "omniauth" do |app|
|
72
|
+
app.config.session_store :cookie_store, key: "_panda_cms_session"
|
73
|
+
app.config.middleware.use ActionDispatch::Cookies
|
74
|
+
app.config.middleware.use ActionDispatch::Session::CookieStore, app.config.session_options
|
75
|
+
|
76
|
+
OmniAuth.config.logger = Rails.logger
|
77
|
+
auth_path = "#{PandaCms.admin_path}/auth"
|
78
|
+
callback_path = "/callback"
|
79
|
+
|
80
|
+
# TODO: Move this to somewhere more sensible
|
81
|
+
# Define the mapping of our provider "names" to the OmniAuth strategies and configuration
|
82
|
+
available_providers = {
|
83
|
+
microsoft: {
|
84
|
+
strategy: :microsoft_graph,
|
85
|
+
defaults: {
|
86
|
+
name: "microsoft",
|
87
|
+
# Setup at the following URL:
|
88
|
+
# https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade
|
89
|
+
client_id: Rails.application.credentials.dig(:microsoft, :client_id),
|
90
|
+
client_secret: Rails.application.credentials.dig(:microsoft, :client_secret),
|
91
|
+
# Don't change this or the sky will fall on your head
|
92
|
+
# https://github.com/synth/omniauth-microsoft_graph/tree/main?tab=readme-ov-file#domain-verification
|
93
|
+
skip_domain_verification: false,
|
94
|
+
# If your application is single-tenanted, replace "common" with your tenant (directory) ID
|
95
|
+
# from https://portal.azure.com/#settings/directory, otherwise you'll likely want to leave
|
96
|
+
# these settings unchanged
|
97
|
+
client_options: {
|
98
|
+
site: "https://login.microsoftonline.com/",
|
99
|
+
token_url: "common/oauth2/v2.0/token",
|
100
|
+
authorize_url: "common/oauth2/v2.0/authorize"
|
101
|
+
},
|
102
|
+
# If you assign specific users or groups, you will likely want to set this to
|
103
|
+
# true to enable auto-provisioning
|
104
|
+
create_account_on_first_login: false,
|
105
|
+
create_admin_account_on_first_login: false,
|
106
|
+
# Don't hide this provider from the login page
|
107
|
+
hidden: false
|
108
|
+
}
|
109
|
+
},
|
110
|
+
google: {
|
111
|
+
strategy: :google_oauth2,
|
112
|
+
defaults: {
|
113
|
+
name: "google",
|
114
|
+
# Setup at the following URL: https://console.developers.google.com/
|
115
|
+
client_id: Rails.application.credentials.dig(:google, :client_id),
|
116
|
+
client_secret: Rails.application.credentials.dig(:google, :client_secret),
|
117
|
+
# If you assign specific users or groups, you will likely want to set this to
|
118
|
+
# true to enable auto-provisioning
|
119
|
+
create_account_on_first_login: false,
|
120
|
+
create_admin_account_on_first_login: false,
|
121
|
+
# Options we need
|
122
|
+
scope: "email, profile",
|
123
|
+
image_aspect_ratio: "square",
|
124
|
+
image_size: 150,
|
125
|
+
# Worth setting select_account as default, as many people have multiple Google accounts now:
|
126
|
+
prompt: "select_account",
|
127
|
+
# You should probably also set the 'hd' option, huh?,
|
128
|
+
# Don't hide this provider from the login page
|
129
|
+
hidden: false
|
130
|
+
}
|
131
|
+
},
|
132
|
+
github: {
|
133
|
+
strategy: :github,
|
134
|
+
defaults: {
|
135
|
+
name: "github",
|
136
|
+
# Setup at the following URL: https://github.com/settings/applications/new
|
137
|
+
# with a callback of
|
138
|
+
# In the meantime, as long as you're set to /admin as your login path, and on
|
139
|
+
# http://localhost:3000, you can use these for a first login :)
|
140
|
+
client_id: Rails.application.credentials.dig(:github, :client_id),
|
141
|
+
client_secret: Rails.application.credentials.dig(:github, :client_secret),
|
142
|
+
scope: "user:email,read:user",
|
143
|
+
create_account_on_first_login: false,
|
144
|
+
create_admin_account_on_first_login: false,
|
145
|
+
# Don't hide this provider from the login page
|
146
|
+
hidden: false
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
available_providers.each do |provider, options|
|
152
|
+
if PandaCms.authentication.dig(provider, :enabled)
|
153
|
+
options[:defaults][:path_prefix] = auth_path
|
154
|
+
options[:defaults][:redirect_uri] = "#{PandaCms.url}#{auth_path}/#{provider}#{callback_path}"
|
155
|
+
|
156
|
+
provider_config = options[:defaults].merge(PandaCms.authentication[provider])
|
157
|
+
|
158
|
+
Rails.logger.info("Configuring OmniAuth for #{provider} with #{provider_config}")
|
159
|
+
|
160
|
+
app.config.middleware.use OmniAuth::Builder do
|
161
|
+
provider options[:strategy], provider_config
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# https://guides.rubyonrails.org/configuring.html#config-exceptions-app
|
2
|
+
module PandaCms
|
3
|
+
class ExceptionsApp
|
4
|
+
def initialize(exceptions_app:)
|
5
|
+
@exceptions_app = exceptions_app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
request = ActionDispatch::Request.new(env)
|
10
|
+
|
11
|
+
fallback_to_html_format_if_invalid_mime_type(request)
|
12
|
+
|
13
|
+
@exceptions_app.call(env)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def fallback_to_html_format_if_invalid_mime_type(request)
|
19
|
+
request.formats
|
20
|
+
rescue ActionDispatch::Http::MimeNegotiation::InvalidType
|
21
|
+
request.set_header "CONTENT_TYPE", "text/html"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/panda_cms.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "panda_cms/version"
|
2
|
+
require "panda_cms/engine"
|
3
|
+
|
4
|
+
module PandaCms
|
5
|
+
mattr_accessor :admin_path
|
6
|
+
mattr_accessor :authentication
|
7
|
+
mattr_accessor :require_login_to_view
|
8
|
+
mattr_accessor :title
|
9
|
+
mattr_accessor :url
|
10
|
+
mattr_accessor :posts
|
11
|
+
|
12
|
+
def self.admin_path_symbol
|
13
|
+
@@admin_path.delete_prefix("/")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "tailwindcss-rails"
|
2
|
+
require "shellwords"
|
3
|
+
|
4
|
+
require "panda_cms/engine"
|
5
|
+
|
6
|
+
ENV["TAILWIND_PATH"] ||= Tailwindcss::Engine.root.join("exe/tailwindcss").to_s
|
7
|
+
|
8
|
+
namespace :panda_cms do
|
9
|
+
desc "Generate missing blocks from template files"
|
10
|
+
task generate_missing_blocks: [:environment] do
|
11
|
+
PandaCms::Template.generate_missing_blocks
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :export do
|
15
|
+
desc "Generate a .json export and output to stdout"
|
16
|
+
task json: [:environment] do
|
17
|
+
puts PandaCms::BulkEditor.export
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :assets do
|
22
|
+
desc "Compile assets for release"
|
23
|
+
task :compile do
|
24
|
+
# Copy all the JS files into public
|
25
|
+
admin_js_path = PandaCms::Engine.root.join("app/javascript/panda_cms")
|
26
|
+
FileUtils.cp_r "#{admin_js_path}/.", PandaCms::Engine.root.join("public/panda-cms-assets/javascripts")
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Build admin assets for Panda CMS"
|
30
|
+
task :admin do
|
31
|
+
# This is enough for development
|
32
|
+
run_tailwind(
|
33
|
+
root_path: PandaCms::Engine.root,
|
34
|
+
input_path: "app/assets/stylesheets/panda_cms/application.tailwind.css",
|
35
|
+
output_path: "app/assets/builds/panda_cms.css"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Build dummy assets for Panda CMS"
|
40
|
+
# We only care about this in development
|
41
|
+
task :dummy do
|
42
|
+
run_tailwind(
|
43
|
+
root_path: Rails.application.root,
|
44
|
+
input_path: "app/assets/stylesheets/application.tailwind.css",
|
45
|
+
output_path: "app/assets/builds/application.css",
|
46
|
+
config_path: "config/tailwind.config.js"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Watch admin assets for Panda CMS"
|
51
|
+
# We only care about this in development
|
52
|
+
task :watch_admin do
|
53
|
+
run_tailwind(
|
54
|
+
root_path: PandaCms::Engine.root,
|
55
|
+
input_path: "app/assets/stylesheets/panda_cms/application.tailwind.css",
|
56
|
+
output_path: "app/assets/builds/panda_cms.css",
|
57
|
+
watch: true
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Watch dummy assets for Panda CMS"
|
62
|
+
# We only care about this in development
|
63
|
+
task :watch_dummy do
|
64
|
+
run_tailwind(
|
65
|
+
root_path: Rails.application.root,
|
66
|
+
input_path: "app/assets/stylesheets/application.tailwind.css",
|
67
|
+
output_path: "app/assets/builds/application.css",
|
68
|
+
config_path: "config/tailwind.config.js",
|
69
|
+
watch: true
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
task default: [:spec, :panda_cms]
|
76
|
+
|
77
|
+
def run_tailwind(root_path:, input_path: nil, output_path: nil, config_path: nil, watch: false)
|
78
|
+
Rails.logger = Logger.new($stdout)
|
79
|
+
config_path ||= root_path.join("config/tailwind.config.js")
|
80
|
+
|
81
|
+
command = [
|
82
|
+
ENV["TAILWIND_PATH"],
|
83
|
+
"-i #{root_path.join(input_path)}",
|
84
|
+
"-o #{root_path.join(output_path)}",
|
85
|
+
"-c #{root_path.join(config_path)}",
|
86
|
+
"-m"
|
87
|
+
]
|
88
|
+
|
89
|
+
command << "-w" if watch
|
90
|
+
|
91
|
+
exec command.join(" ")
|
92
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<%%= form_with(model: <%= model_resource_name %>, class: "contents") do |form| %>
|
2
|
+
<%% if <%= singular_table_name %>.errors.any? %>
|
3
|
+
<div id="error_explanation" class="py-2 px-3 mt-3 font-medium text-red-500 bg-red-50 rounded-lg">
|
4
|
+
<h2><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<%% <%= singular_table_name %>.errors.each do |error| %>
|
8
|
+
<li><%%= error.full_message %></li>
|
9
|
+
<%% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<%% end %>
|
13
|
+
|
14
|
+
<% attributes.each do |attribute| -%>
|
15
|
+
<div class="my-5">
|
16
|
+
<% if attribute.password_digest? -%>
|
17
|
+
<%%= form.label :password %>
|
18
|
+
<%%= form.password_field :password, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="my-5">
|
22
|
+
<%%= form.label :password_confirmation %>
|
23
|
+
<%%= form.password_field :password_confirmation, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
24
|
+
<% elsif attribute.attachments? -%>
|
25
|
+
<%%= form.label :<%= attribute.column_name %> %>
|
26
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, multiple: true, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
27
|
+
<% else -%>
|
28
|
+
<%%= form.label :<%= attribute.column_name %> %>
|
29
|
+
<% if attribute.field_type == :text_area -%>
|
30
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, rows: 4, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
31
|
+
<% elsif attribute.field_type == :check_box -%>
|
32
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "block mt-2 h-5 w-5" %>
|
33
|
+
<% else -%>
|
34
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
35
|
+
<% end -%>
|
36
|
+
<% end -%>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<% end -%>
|
40
|
+
<div class="inline">
|
41
|
+
<%%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
42
|
+
</div>
|
43
|
+
<%% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="mx-auto w-full md:w-2/3">
|
2
|
+
<h1 class="text-4xl font-bold">Editing <%= human_name.downcase %></h1>
|
3
|
+
|
4
|
+
<%%= render "form", <%= singular_table_name %>: @<%= singular_table_name %> %>
|
5
|
+
|
6
|
+
<%%= link_to "Show this <%= human_name.downcase %>", @<%= singular_table_name %>, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
7
|
+
<%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper %>_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
8
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class="w-full">
|
2
|
+
<%% if notice.present? %>
|
3
|
+
<p class="inline-block py-2 px-3 mb-5 font-medium text-green-500 bg-green-50 rounded-lg" id="notice"><%%= notice %></p>
|
4
|
+
<%% end %>
|
5
|
+
|
6
|
+
<div class="flex justify-between items-center">
|
7
|
+
<h1 class="text-4xl font-bold"><%= human_name.pluralize %></h1>
|
8
|
+
<%%= link_to "New <%= human_name.downcase %>", new_<%= singular_route_name %>_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div id="<%= plural_table_name %>" class="min-w-full">
|
12
|
+
<%%= render @<%= plural_table_name %> %>
|
13
|
+
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<div class="mx-auto w-full md:w-2/3">
|
2
|
+
<h1 class="text-4xl font-bold">New <%= human_name.downcase %></h1>
|
3
|
+
|
4
|
+
<%%= render "form", <%= singular_table_name %>: @<%= singular_table_name %> %>
|
5
|
+
|
6
|
+
<%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper %>_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
7
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<div id="<%%= dom_id <%= singular_name %> %>">
|
2
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
3
|
+
<p class="my-5">
|
4
|
+
<strong class="block mb-1 font-medium"><%= attribute.human_name %>:</strong>
|
5
|
+
<% if attribute.attachment? -%>
|
6
|
+
<%%= link_to <%= singular_name %>.<%= attribute.column_name %>.filename, <%= singular_name %>.<%= attribute.column_name %> if <%= singular_name %>.<%= attribute.column_name %>.attached? %>
|
7
|
+
<% elsif attribute.attachments? -%>
|
8
|
+
<%% <%= singular_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
9
|
+
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
|
10
|
+
<%% end %>
|
11
|
+
<% else -%>
|
12
|
+
<%%= <%= singular_name %>.<%= attribute.column_name %> %>
|
13
|
+
<% end -%>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<% end -%>
|
17
|
+
<%% if action_name != "show" %>
|
18
|
+
<%%= link_to "Show this <%= human_name.downcase %>", <%= singular_name %>, class: "rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
19
|
+
<%%= link_to "Edit this <%= human_name.downcase %>", edit_<%= singular_name %>_path(<%= singular_name %>), class: "rounded-lg py-3 ml-2 px-5 bg-gray-100 inline-block font-medium" %>
|
20
|
+
<hr class="mt-6">
|
21
|
+
<%% end %>
|
22
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class="flex mx-auto w-full md:w-2/3">
|
2
|
+
<div class="mx-auto">
|
3
|
+
<%% if notice.present? %>
|
4
|
+
<p class="inline-block py-2 px-3 mb-5 font-medium text-green-500 bg-green-50 rounded-lg" id="notice"><%%= notice %></p>
|
5
|
+
<%% end %>
|
6
|
+
|
7
|
+
<%%= render @<%= singular_table_name %> %>
|
8
|
+
|
9
|
+
<%%= link_to "Edit this <%= singular_table_name %>", edit_<%= singular_table_name %>_path(@<%= singular_table_name %>), class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
10
|
+
<div class="inline-block ml-2">
|
11
|
+
<%%= button_to "Destroy this <%= singular_table_name %>", <%= singular_table_name %>_path(@<%= singular_table_name %>), method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %>
|
12
|
+
</div>
|
13
|
+
<%%= link_to "Back to <%= plural_table_name %>", <%= index_helper %>_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
14
|
+
</div>
|
15
|
+
</div>
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
3
|
+
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
4
|
+
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
5
|
+
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
6
|
+
preserveAspectRatio="xMidYMid meet">
|
7
|
+
<metadata>
|
8
|
+
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
9
|
+
</metadata>
|
10
|
+
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
11
|
+
fill="#000000" stroke="none">
|
12
|
+
<path d="M565 1803 c-42 -22 -65 -43 -83 -78 -42 -82 -32 -165 29 -226 36 -36
|
13
|
+
39 -43 33 -75 l-6 -34 -28 42 c-49 77 -190 192 -210 172 -5 -5 -17 -38 -26
|
14
|
+
-74 -26 -102 -3 -238 55 -319 l19 -26 -61 3 c-67 4 -137 -12 -137 -31 0 -24
|
15
|
+
56 -102 100 -139 46 -40 115 -68 166 -68 32 0 32 -1 23 -32 -21 -74 -7 -156
|
16
|
+
37 -215 29 -39 33 -89 7 -78 -59 25 -73 27 -105 21 -24 -4 -47 -19 -67 -42
|
17
|
+
-26 -29 -31 -43 -31 -87 0 -63 25 -120 76 -176 84 -93 183 -120 272 -73 44 23
|
18
|
+
78 26 156 16 35 -5 46 -11 46 -25 0 -19 44 -59 65 -59 7 0 23 8 36 19 18 14
|
19
|
+
46 19 110 23 65 3 95 10 123 26 50 30 164 31 227 2 118 -53 240 5 305 144 15
|
20
|
+
33 24 70 24 103 0 44 -5 58 -31 87 -45 51 -85 56 -171 21 -29 -12 -22 38 12
|
21
|
+
87 67 96 53 232 -35 353 -13 19 -8 30 72 150 75 113 90 143 114 230 33 117 36
|
22
|
+
145 13 145 -23 0 -185 -155 -208 -199 l-20 -36 -11 50 c-11 50 -11 50 22 81
|
23
|
+
125 119 48 334 -120 334 -55 0 -79 -10 -122 -51 l-31 -29 -59 22 c-83 30 -208
|
24
|
+
29 -288 -2 l-59 -22 -31 30 c-18 17 -45 36 -60 41 -41 16 -107 13 -142 -6z
|
25
|
+
m557 -83 c74 -23 159 -80 206 -139 42 -52 92 -158 92 -194 0 -33 -41 -161 -70
|
26
|
+
-217 -39 -77 -217 -136 -385 -127 -188 10 -313 97 -375 263 -19 53 -19 54 0
|
27
|
+
116 73 236 308 367 532 298z m-437 -49 c3 -5 -4 -12 -14 -16 -11 -3 -32 -20
|
28
|
+
-46 -36 l-25 -31 0 36 c0 23 6 39 18 45 22 13 59 14 67 2z m698 -3 c16 -13 35
|
29
|
+
-68 22 -68 -16 0 -95 62 -90 71 9 13 48 11 68 -3z m66 -442 c-50 -81 -93 -145
|
30
|
+
-96 -142 -5 4 22 49 154 259 14 22 26 37 29 34 3 -2 -37 -70 -87 -151z m-171
|
31
|
+
-273 c-74 -117 -67 -107 -72 -102 -7 7 114 199 124 199 5 0 -18 -44 -52 -97z
|
32
|
+
m-378 -72 c63 -15 156 -13 218 3 29 7 52 9 52 4 0 -21 -21 -46 -44 -52 -13 -3
|
33
|
+
-38 -22 -56 -43 -30 -34 -32 -40 -27 -91 6 -54 5 -56 -53 -143 -33 -48 -69
|
34
|
+
-90 -80 -94 -11 -3 -25 -15 -30 -26 -11 -19 -11 -19 -53 2 -54 27 -144 94
|
35
|
+
-156 117 -8 16 -1 17 82 17 75 0 99 4 127 21 48 28 80 78 80 127 0 53 -56 111
|
36
|
+
-117 121 -40 7 -41 9 -31 32 7 15 17 23 27 20 9 -3 36 -10 61 -15z m174 -288
|
37
|
+
c-64 -99 -87 -133 -91 -129 -6 5 91 156 101 156 4 0 0 -12 -10 -27z m235 -45
|
38
|
+
c-32 -44 -90 -87 -148 -109 -30 -11 -58 -18 -62 -17 -5 2 13 37 39 78 l48 75
|
39
|
+
71 0 71 0 -19 -27z m-864 -22 c67 -28 119 -138 83 -174 -34 -34 -124 11 -159
|
40
|
+
79 -29 58 -16 96 39 108 1 1 18 -5 37 -13z m1199 -28 c13 -36 -24 -112 -66
|
41
|
+
-138 -46 -28 -82 -26 -107 6 l-21 27 27 49 c51 93 142 124 167 56z m-649 -93
|
42
|
+
c14 -13 25 -34 25 -47 0 -19 -3 -18 -18 12 -11 24 -28 39 -52 47 -34 11 -34
|
43
|
+
12 -7 12 17 1 38 -9 52 -24z"/>
|
44
|
+
<path d="M765 1496 c-71 -31 -115 -122 -95 -198 23 -83 91 -119 158 -84 57 30
|
45
|
+
122 119 122 168 0 37 -34 90 -71 110 -40 21 -72 22 -114 4z m121 -98 c19 -23
|
46
|
+
19 -23 -2 -5 -11 9 -29 17 -39 17 -27 0 -55 -30 -55 -59 0 -31 8 -44 35 -59
|
47
|
+
11 -6 15 -12 9 -12 -26 0 -57 37 -57 68 0 65 70 96 109 50z m-31 -26 c0 -18
|
48
|
+
-20 -15 -23 4 -3 10 1 15 10 12 7 -3 13 -10 13 -16z"/>
|
49
|
+
<path d="M1119 1487 c-94 -63 -83 -180 24 -258 75 -54 149 -32 182 56 31 80
|
50
|
+
-5 172 -79 206 -54 25 -86 24 -127 -4z m84 -79 c9 -7 20 -27 23 -45 5 -26 1
|
51
|
+
-37 -19 -57 -15 -14 -34 -26 -44 -26 -11 1 -6 6 14 15 36 15 48 42 34 78 -14
|
52
|
+
35 -53 45 -89 22 l-27 -18 19 21 c21 24 63 29 89 10z m-23 -38 c0 -11 -4 -20
|
53
|
+
-10 -20 -5 0 -10 9 -10 20 0 11 5 20 10 20 6 0 10 -9 10 -20z"/>
|
54
|
+
<path d="M948 1249 c-14 -6 -29 -16 -32 -24 -6 -18 40 -75 61 -75 13 0 13 -3
|
55
|
+
3 -15 -17 -21 -48 -19 -62 5 -17 26 -30 26 -26 -1 2 -12 15 -31 30 -42 23 -17
|
56
|
+
31 -19 53 -9 19 9 32 9 47 1 28 -15 65 -3 84 27 13 19 14 28 5 37 -8 8 -15 6
|
57
|
+
-27 -11 -17 -24 -46 -29 -62 -9 -8 10 -4 16 19 26 57 25 61 72 7 90 -37 13
|
58
|
+
-64 13 -100 0z m42 -23 c0 -2 -9 -6 -20 -9 -11 -3 -20 -1 -20 4 0 5 9 9 20 9
|
59
|
+
11 0 20 -2 20 -4z"/>
|
60
|
+
</g>
|
61
|
+
</svg>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"name": "",
|
3
|
+
"short_name": "",
|
4
|
+
"icons": [
|
5
|
+
{
|
6
|
+
"src": "/panda-cms-assets/favicons/android-chrome-192x192.png",
|
7
|
+
"sizes": "192x192",
|
8
|
+
"type": "image/png"
|
9
|
+
}
|
10
|
+
],
|
11
|
+
"theme_color": "#ffffff",
|
12
|
+
"background_color": "#ffffff",
|
13
|
+
"display": "standalone"
|
14
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Application as PandaCmsApplication } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
const panda_cms = PandaCmsApplication.start();
|
4
|
+
|
5
|
+
// Configure Stimulus development experience
|
6
|
+
panda_cms.debug = location.hostname === "localhost";
|
7
|
+
window.pandaStimulus = panda_cms;
|
8
|
+
|
9
|
+
export { panda_cms };
|
10
|
+
|
11
|
+
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
12
|
+
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
|
13
|
+
eagerLoadControllersFrom("panda_cms/controllers", panda_cms);
|
14
|
+
|
15
|
+
import {
|
16
|
+
Alert,
|
17
|
+
Autosave,
|
18
|
+
ColorPreview,
|
19
|
+
Dropdown,
|
20
|
+
Modal,
|
21
|
+
Tabs,
|
22
|
+
Popover,
|
23
|
+
Toggle,
|
24
|
+
Slideover,
|
25
|
+
} from "panda_cms/vendor/tailwindcss-stimulus-components";
|
26
|
+
panda_cms.register("alert", Alert);
|
27
|
+
panda_cms.register("autosave", Autosave);
|
28
|
+
panda_cms.register("color-preview", ColorPreview);
|
29
|
+
panda_cms.register("dropdown", Dropdown);
|
30
|
+
panda_cms.register("modal", Modal);
|
31
|
+
panda_cms.register("popover", Popover);
|
32
|
+
panda_cms.register("slideover", Slideover);
|
33
|
+
panda_cms.register("tabs", Tabs);
|
34
|
+
panda_cms.register("toggle", Toggle);
|
35
|
+
|
36
|
+
import RailsNestedForm from "panda_cms/vendor/stimulus-components-rails-nested-form";
|
37
|
+
panda_cms.register("nested-form", RailsNestedForm);
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Controller as PandaCmsController } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends PandaCmsController {
|
4
|
+
static targets = ["pandaCmsMenu"]
|
5
|
+
static values = {
|
6
|
+
open: { type: Boolean, default: false }
|
7
|
+
}
|
8
|
+
|
9
|
+
toggle(event) {
|
10
|
+
this.openValue = !this.openValue
|
11
|
+
this.animate()
|
12
|
+
}
|
13
|
+
|
14
|
+
animate() {
|
15
|
+
this.toggleableTargets.forEach(target => {
|
16
|
+
transition(target, this.openValue)
|
17
|
+
})
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { Controller as PandaCmsController } from "@hotwired/stimulus"
|
2
|
+
export default class extends PandaCmsController {
|
3
|
+
static targets = [ "existing_root", "input_select", "input_text", "output_text" ]
|
4
|
+
|
5
|
+
connect() {
|
6
|
+
}
|
7
|
+
|
8
|
+
generatePath() {
|
9
|
+
this.output_textTarget.value = "/" + this.createSlug(this.input_textTarget.value);
|
10
|
+
}
|
11
|
+
|
12
|
+
setPrePath() {
|
13
|
+
this.parent_slugs = this.input_selectTarget.options[this.input_selectTarget.selectedIndex].text.match(/.*\((.*)\)$/)[1];
|
14
|
+
this.output_textTarget.previousSibling.innerHTML = (this.existing_rootTarget.value + this.parent_slugs).replace(/\/$/, '');;
|
15
|
+
}
|
16
|
+
|
17
|
+
createSlug(input) {
|
18
|
+
return input.toLowerCase().trim()
|
19
|
+
.replace(/[^\w\s-]/g, "-")
|
20
|
+
.replace(/&/, "and")
|
21
|
+
.replace(/[\s_-]+/g, "-");
|
22
|
+
}
|
23
|
+
}
|