plum-cms 0.1.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 +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +252 -0
- data/app/assets/builds/tailwind.css +2 -0
- data/app/assets/images/plum-mark.svg +7 -0
- data/app/assets/images/table-needs-logo.svg +83 -0
- data/app/assets/javascripts/plum/application.js +15 -0
- data/app/assets/stylesheets/application.css +10 -0
- data/app/assets/stylesheets/plum/control_panel.css +2 -0
- data/app/assets/tailwind/application.css +47 -0
- data/app/controllers/plum/application_controller.rb +34 -0
- data/app/controllers/plum/cp/assets_controller.rb +84 -0
- data/app/controllers/plum/cp/base_controller.rb +45 -0
- data/app/controllers/plum/cp/content_types_controller.rb +59 -0
- data/app/controllers/plum/cp/dashboard_controller.rb +10 -0
- data/app/controllers/plum/cp/entries_controller.rb +240 -0
- data/app/controllers/plum/cp/form_definitions_controller.rb +105 -0
- data/app/controllers/plum/cp/form_submissions_controller.rb +26 -0
- data/app/controllers/plum/cp/globals_controller.rb +84 -0
- data/app/controllers/plum/cp/nav_items_controller.rb +68 -0
- data/app/controllers/plum/cp/nav_menus_controller.rb +56 -0
- data/app/controllers/plum/cp/site_settings_controller.rb +87 -0
- data/app/controllers/plum/cp/taxonomies_controller.rb +56 -0
- data/app/controllers/plum/cp/terms_controller.rb +55 -0
- data/app/controllers/plum/cp/theme_previews_controller.rb +27 -0
- data/app/controllers/plum/cp/themes_controller.rb +98 -0
- data/app/controllers/plum/form_submissions_controller.rb +44 -0
- data/app/controllers/plum/pages_controller.rb +161 -0
- data/app/controllers/plum/sessions_controller.rb +25 -0
- data/app/controllers/plum/theme_assets_controller.rb +14 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/markdown_helper.rb +21 -0
- data/app/helpers/plum/cp/assets_helper.rb +21 -0
- data/app/helpers/plum/cp/theme_settings_helper.rb +26 -0
- data/app/javascript/application.js +18 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/index.js +4 -0
- data/app/javascript/controllers/plum/blocks_editor_controller.js +275 -0
- data/app/javascript/controllers/plum/blueprint_controller.js +120 -0
- data/app/javascript/controllers/plum/form_fields_controller.js +84 -0
- data/app/javascript/controllers/plum/image_picker_controller.js +143 -0
- data/app/javascript/controllers/plum/theme_settings_controller.js +17 -0
- data/app/models/plum/application_record.rb +5 -0
- data/app/models/plum/asset.rb +69 -0
- data/app/models/plum/content_type.rb +35 -0
- data/app/models/plum/entry.rb +67 -0
- data/app/models/plum/entry_term.rb +8 -0
- data/app/models/plum/form_definition.rb +68 -0
- data/app/models/plum/form_submission.rb +76 -0
- data/app/models/plum/global.rb +24 -0
- data/app/models/plum/nav_item.rb +58 -0
- data/app/models/plum/nav_menu.rb +24 -0
- data/app/models/plum/site.rb +112 -0
- data/app/models/plum/site_scoped.rb +17 -0
- data/app/models/plum/site_setting.rb +35 -0
- data/app/models/plum/taxonomy.rb +24 -0
- data/app/models/plum/term.rb +23 -0
- data/app/models/plum/user.rb +16 -0
- data/app/services/plum/base_blocks.rb +161 -0
- data/app/services/plum/block_editor_config.rb +65 -0
- data/app/services/plum/block_library.rb +31 -0
- data/app/services/plum/builder_renderer.rb +63 -0
- data/app/services/plum/field_expander.rb +78 -0
- data/app/services/plum/form_renderer.rb +110 -0
- data/app/services/plum/liquid_context.rb +335 -0
- data/app/services/plum/liquid_filters.rb +58 -0
- data/app/services/plum/liquid_renderer.rb +49 -0
- data/app/services/plum/theme.rb +160 -0
- data/app/services/plum/theme_asset_path.rb +31 -0
- data/app/services/plum/theme_package_installer.rb +287 -0
- data/app/services/plum/theme_registry.rb +63 -0
- data/app/services/plum/theme_resolver.rb +55 -0
- data/app/services/plum/theme_settings_params.rb +54 -0
- data/app/themes/bagel-boy/assets/screenshot.svg +92 -0
- data/app/themes/bagel-boy/assets/theme.css +184 -0
- data/app/themes/bagel-boy/blocks/hours.liquid +4 -0
- data/app/themes/bagel-boy/blocks/menu_item.liquid +7 -0
- data/app/themes/bagel-boy/layouts/base.liquid +64 -0
- data/app/themes/bagel-boy/templates/collections/posts.liquid +32 -0
- data/app/themes/bagel-boy/templates/entries/_default.liquid +13 -0
- data/app/themes/bagel-boy/templates/entries/landing.liquid +4 -0
- data/app/themes/bagel-boy/templates/entries/pages.liquid +18 -0
- data/app/themes/bagel-boy/templates/entries/posts.liquid +8 -0
- data/app/themes/bagel-boy/templates/index.liquid +10 -0
- data/app/themes/bagel-boy/templates/search.liquid +28 -0
- data/app/themes/bagel-boy/theme.yml +47 -0
- data/app/themes/bagel-shop/assets/screenshot.svg +28 -0
- data/app/themes/bagel-shop/assets/theme.css +7 -0
- data/app/themes/bagel-shop/layouts/base.liquid +507 -0
- data/app/themes/bagel-shop/templates/entries/_default.liquid +15 -0
- data/app/themes/bagel-shop/templates/entries/pages.liquid +12 -0
- data/app/themes/bagel-shop/templates/entries/posts.liquid +19 -0
- data/app/themes/bagel-shop/templates/index.liquid +55 -0
- data/app/themes/bagel-shop/theme.yml +30 -0
- data/app/themes/default/assets/screenshot.svg +24 -0
- data/app/themes/default/assets/theme.css +89 -0
- data/app/themes/default/layouts/base.liquid +117 -0
- data/app/themes/default/templates/collections/_default.liquid +16 -0
- data/app/themes/default/templates/collections/posts.liquid +27 -0
- data/app/themes/default/templates/entries/_default.liquid +26 -0
- data/app/themes/default/templates/entries/landing.liquid +5 -0
- data/app/themes/default/templates/entries/pages.liquid +17 -0
- data/app/themes/default/templates/entries/posts.liquid +20 -0
- data/app/themes/default/templates/index.liquid +22 -0
- data/app/themes/default/templates/search.liquid +28 -0
- data/app/themes/default/templates/taxonomies/_default.liquid +25 -0
- data/app/themes/default/templates/taxonomies/_default_index.liquid +14 -0
- data/app/themes/default/theme.yml +23 -0
- data/app/views/layouts/plum/cp.html.erb +138 -0
- data/app/views/layouts/plum/session.html.erb +43 -0
- data/app/views/plum/cp/assets/_form.html.erb +44 -0
- data/app/views/plum/cp/assets/edit.html.erb +14 -0
- data/app/views/plum/cp/assets/index.html.erb +52 -0
- data/app/views/plum/cp/assets/new.html.erb +9 -0
- data/app/views/plum/cp/content_types/_form.html.erb +113 -0
- data/app/views/plum/cp/content_types/edit.html.erb +8 -0
- data/app/views/plum/cp/content_types/index.html.erb +48 -0
- data/app/views/plum/cp/content_types/new.html.erb +5 -0
- data/app/views/plum/cp/content_types/show.html.erb +59 -0
- data/app/views/plum/cp/dashboard/show.html.erb +50 -0
- data/app/views/plum/cp/entries/_form.html.erb +196 -0
- data/app/views/plum/cp/entries/edit.html.erb +9 -0
- data/app/views/plum/cp/entries/index.html.erb +51 -0
- data/app/views/plum/cp/entries/new.html.erb +5 -0
- data/app/views/plum/cp/form_definitions/_form.html.erb +90 -0
- data/app/views/plum/cp/form_definitions/edit.html.erb +11 -0
- data/app/views/plum/cp/form_definitions/index.html.erb +43 -0
- data/app/views/plum/cp/form_definitions/new.html.erb +5 -0
- data/app/views/plum/cp/form_definitions/show.html.erb +70 -0
- data/app/views/plum/cp/form_submissions/show.html.erb +20 -0
- data/app/views/plum/cp/globals/_form.html.erb +44 -0
- data/app/views/plum/cp/globals/edit.html.erb +11 -0
- data/app/views/plum/cp/globals/index.html.erb +41 -0
- data/app/views/plum/cp/globals/new.html.erb +5 -0
- data/app/views/plum/cp/globals/show.html.erb +14 -0
- data/app/views/plum/cp/nav_items/_form.html.erb +56 -0
- data/app/views/plum/cp/nav_items/edit.html.erb +11 -0
- data/app/views/plum/cp/nav_items/new.html.erb +6 -0
- data/app/views/plum/cp/nav_menus/_form.html.erb +33 -0
- data/app/views/plum/cp/nav_menus/_nav_item.html.erb +24 -0
- data/app/views/plum/cp/nav_menus/edit.html.erb +11 -0
- data/app/views/plum/cp/nav_menus/index.html.erb +41 -0
- data/app/views/plum/cp/nav_menus/new.html.erb +5 -0
- data/app/views/plum/cp/nav_menus/show.html.erb +24 -0
- data/app/views/plum/cp/shared/_icon.html.erb +39 -0
- data/app/views/plum/cp/shared/_image_picker.html.erb +38 -0
- data/app/views/plum/cp/site_settings/edit.html.erb +145 -0
- data/app/views/plum/cp/site_settings/show.html.erb +62 -0
- data/app/views/plum/cp/taxonomies/_form.html.erb +38 -0
- data/app/views/plum/cp/taxonomies/edit.html.erb +2 -0
- data/app/views/plum/cp/taxonomies/index.html.erb +38 -0
- data/app/views/plum/cp/taxonomies/new.html.erb +2 -0
- data/app/views/plum/cp/taxonomies/show.html.erb +46 -0
- data/app/views/plum/cp/terms/_form.html.erb +30 -0
- data/app/views/plum/cp/terms/edit.html.erb +2 -0
- data/app/views/plum/cp/terms/new.html.erb +2 -0
- data/app/views/plum/cp/themes/index.html.erb +160 -0
- data/app/views/plum/form_mailer/submission_notification.html.erb +13 -0
- data/app/views/plum/form_mailer/submission_notification.text.erb +7 -0
- data/app/views/plum/sessions/new.html.erb +20 -0
- data/compat/plum-cms.rb +1 -0
- data/config/locales/en.yml +31 -0
- data/config/plum_importmap.rb +4 -0
- data/config/plum_routes.rb +34 -0
- data/db/engine_migrate/20260101000001_create_plum_tables.rb +154 -0
- data/lib/generators/plum/install/install_generator.rb +54 -0
- data/lib/generators/plum/install/templates/plum_initializer.rb +37 -0
- data/lib/plum/configuration.rb +88 -0
- data/lib/plum/content_source.rb +45 -0
- data/lib/plum/content_source_context.rb +30 -0
- data/lib/plum/content_source_registry.rb +120 -0
- data/lib/plum/engine.rb +30 -0
- data/lib/plum/liquid_tags/form_tag.rb +17 -0
- data/lib/plum/version.rb +7 -0
- data/lib/plum.rb +11 -0
- data/vendor/javascript/lexxy.js +11859 -0
- metadata +405 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<div class="flex items-center justify-between gap-6 mb-8">
|
|
2
|
+
<div>
|
|
3
|
+
<h1 class="text-2xl font-bold text-gray-900"><%= @nav_menu.name %></h1>
|
|
4
|
+
<p class="mt-1 text-sm text-gray-500">
|
|
5
|
+
Liquid: <span class="font-mono">nav.<%= @nav_menu.handle %>.items</span>
|
|
6
|
+
</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="flex items-center gap-3">
|
|
9
|
+
<%= link_to "Edit Menu", edit_cp_nav_menu_path(@nav_menu),
|
|
10
|
+
class: "px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
11
|
+
<%= link_to "Add Item", new_cp_nav_menu_nav_item_path(@nav_menu),
|
|
12
|
+
class: "inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700" %>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<% if @nav_items.any? %>
|
|
17
|
+
<ol class="space-y-3">
|
|
18
|
+
<%= render partial: "nav_item", collection: @nav_items, as: :item, locals: { nav_menu: @nav_menu } %>
|
|
19
|
+
</ol>
|
|
20
|
+
<% else %>
|
|
21
|
+
<div class="bg-white shadow rounded-lg p-6">
|
|
22
|
+
<p class="text-sm text-gray-500">No navigation items yet.</p>
|
|
23
|
+
</div>
|
|
24
|
+
<% end %>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<%# Inline SVG icons (Heroicons outline style, 24x24) %>
|
|
2
|
+
<% case name %>
|
|
3
|
+
<% when "document" %>
|
|
4
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" /></svg>
|
|
5
|
+
<% when "newspaper" %>
|
|
6
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6V7.5Z" /></svg>
|
|
7
|
+
<% when "photo" %>
|
|
8
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" /></svg>
|
|
9
|
+
<% when "calendar" %>
|
|
10
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" /></svg>
|
|
11
|
+
<% when "star" %>
|
|
12
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" /></svg>
|
|
13
|
+
<% when "folder" %>
|
|
14
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" /></svg>
|
|
15
|
+
<% when "tag" %>
|
|
16
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z" /></svg>
|
|
17
|
+
<% when "bookmark" %>
|
|
18
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M17.593 3.322c1.1.128 1.907 1.077 1.907 2.185V21L12 17.25 4.5 21V5.507c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0 1 11.186 0Z" /></svg>
|
|
19
|
+
<% when "shopping-bag" %>
|
|
20
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5V6a3.75 3.75 0 1 0-7.5 0v4.5m11.356-1.993 1.263 12c.07.665-.45 1.243-1.119 1.243H4.25a1.125 1.125 0 0 1-1.12-1.243l1.264-12A1.125 1.125 0 0 1 5.513 7.5h12.974c.576 0 1.059.435 1.119 1.007ZM8.625 10.5a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm7.5 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" /></svg>
|
|
21
|
+
<% when "briefcase" %>
|
|
22
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M20.25 14.15v4.25c0 1.094-.787 2.036-1.872 2.18-2.087.277-4.216.42-6.378.42s-4.291-.143-6.378-.42c-1.085-.144-1.872-1.086-1.872-2.18v-4.25m16.5 0a2.18 2.18 0 0 0 .75-1.661V8.706c0-1.081-.768-2.015-1.837-2.175a48.114 48.114 0 0 0-3.413-.387m4.5 8.006c-.194.165-.42.295-.673.38A23.978 23.978 0 0 1 12 15.75c-2.648 0-5.195-.429-7.577-1.22a2.016 2.016 0 0 1-.673-.38m0 0A2.18 2.18 0 0 1 3 12.489V8.706c0-1.081.768-2.015 1.837-2.175a48.111 48.111 0 0 1 3.413-.387m7.5 0V5.25A2.25 2.25 0 0 0 13.5 3h-3a2.25 2.25 0 0 0-2.25 2.25v.894m7.5 0a48.667 48.667 0 0 0-7.5 0" /></svg>
|
|
23
|
+
<% when "megaphone" %>
|
|
24
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M10.34 15.84c-.688-.06-1.386-.09-2.09-.09H7.5a4.5 4.5 0 1 1 0-9h.75c.704 0 1.402-.03 2.09-.09m0 9.18c.253.962.584 1.892.985 2.783.247.55.06 1.21-.463 1.511l-.657.38c-.551.318-1.26.117-1.527-.461a20.845 20.845 0 0 1-1.44-4.282m3.102.069a18.03 18.03 0 0 1-.59-4.59c0-1.586.205-3.124.59-4.59m0 9.18a23.848 23.848 0 0 1 8.835 2.535M10.34 6.66a23.847 23.847 0 0 0 8.835-2.535m0 0A23.74 23.74 0 0 0 18.795 3m.38 1.125a23.91 23.91 0 0 1 1.014 5.395m-1.014 8.855c-.118.38-.245.754-.38 1.125m.38-1.125a23.91 23.91 0 0 0 1.014-5.395m0-3.46c.495.413.811 1.035.811 1.73 0 .695-.316 1.317-.811 1.73m0-3.46a24.347 24.347 0 0 1 0 3.46" /></svg>
|
|
25
|
+
<% when "chat" %>
|
|
26
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M8.625 12a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 0 1-2.555-.337A5.972 5.972 0 0 1 5.41 20.97a5.969 5.969 0 0 1-.474-.065 4.48 4.48 0 0 0 .978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25Z" /></svg>
|
|
27
|
+
<% when "globe" %>
|
|
28
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5a17.92 17.92 0 0 1-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418" /></svg>
|
|
29
|
+
<% when "heart" %>
|
|
30
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><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" /></svg>
|
|
31
|
+
<% when "music" %>
|
|
32
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="m9 9 10.5-3m0 6.553v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 1 1-.99-3.467l2.31-.66a2.25 2.25 0 0 0 1.632-2.163Zm0 0V4.846a1.125 1.125 0 0 0-1.49-1.065L9 5.63v3.37M9 9v10.114a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 1 1-.99-3.467l2.31-.66A2.25 2.25 0 0 0 9 15.464V9Z" /></svg>
|
|
33
|
+
<% when "film" %>
|
|
34
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h1.5C5.496 19.5 6 18.996 6 18.375m-3.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-1.5A1.125 1.125 0 0 1 18 18.375M20.625 4.5H3.375m17.25 0c.621 0 1.125.504 1.125 1.125M20.625 4.5h-1.5C18.504 4.5 18 5.004 18 5.625m3.75 0v1.5c0 .621-.504 1.125-1.125 1.125M3.375 4.5c-.621 0-1.125.504-1.125 1.125M3.375 4.5h1.5C5.496 4.5 6 5.004 6 5.625m-3.75 0v1.5c0 .621.504 1.125 1.125 1.125m0 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m1.5-3.75C5.496 8.25 6 7.746 6 7.125v-1.5M4.875 8.25C5.496 8.25 6 8.754 6 9.375v1.5m0-5.25v5.25m0-5.25C6 5.004 6.504 4.5 7.125 4.5h9.75c.621 0 1.125.504 1.125 1.125m1.125 2.625h1.5m-1.5 0A1.125 1.125 0 0 1 18 7.125v-1.5m1.125 2.625c-.621 0-1.125.504-1.125 1.125v1.5m2.625-2.625c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125M18 5.625v5.25M7.125 12h9.75m-9.75 0A1.125 1.125 0 0 1 6 10.875M7.125 12C6.504 12 6 12.504 6 13.125m0-2.25C6 11.496 5.496 12 4.875 12M18 10.875c0 .621-.504 1.125-1.125 1.125M18 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m-12 5.25v-5.25m0 5.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125m-12 0v-1.5c0-.621-.504-1.125-1.125-1.125M18 18.375v-5.25m0 5.25v-1.5c0-.621.504-1.125 1.125-1.125M18 13.125v1.5c0 .621.504 1.125 1.125 1.125M18 13.125c0-.621.504-1.125 1.125-1.125M6 13.125v1.5c0 .621-.504 1.125-1.125 1.125M6 13.125C6 12.504 5.496 12 4.875 12m-1.5 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M19.125 12h1.5m0 0c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h1.5m14.25 0h1.5" /></svg>
|
|
35
|
+
<% when "code" %>
|
|
36
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5" /></svg>
|
|
37
|
+
<% else %>
|
|
38
|
+
<svg class="h-5 w-5" style="color: inherit;" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" /></svg>
|
|
39
|
+
<% end %>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Reusable image picker.
|
|
3
|
+
locals:
|
|
4
|
+
input_name - the form field name (stores the selected asset id)
|
|
5
|
+
value - currently selected asset id (optional)
|
|
6
|
+
field_id - dom id for the hidden input (optional)
|
|
7
|
+
%>
|
|
8
|
+
<div class="mt-1 space-y-2"
|
|
9
|
+
data-controller="plum--image-picker"
|
|
10
|
+
data-plum--image-picker-assets-url-value="<%= cp_assets_path(format: :json) %>"
|
|
11
|
+
data-plum--image-picker-upload-url-value="<%= cp_assets_path %>">
|
|
12
|
+
<%= hidden_field_tag input_name, value, id: field_id,
|
|
13
|
+
data: { "plum--image-picker-target": "input" } %>
|
|
14
|
+
|
|
15
|
+
<div data-plum--image-picker-target="preview"></div>
|
|
16
|
+
|
|
17
|
+
<div class="flex items-center gap-2">
|
|
18
|
+
<button type="button" data-action="plum--image-picker#toggle"
|
|
19
|
+
class="rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50">Choose image</button>
|
|
20
|
+
<button type="button" data-action="plum--image-picker#clear"
|
|
21
|
+
class="text-sm text-gray-500 hover:text-gray-700">Remove</button>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="hidden rounded-lg border border-gray-200 bg-gray-50 p-3" data-plum--image-picker-target="panel">
|
|
25
|
+
<div class="mb-2 flex items-center justify-between">
|
|
26
|
+
<span class="text-xs font-medium text-gray-500" data-plum--image-picker-target="status"></span>
|
|
27
|
+
<button type="button" data-action="plum--image-picker#close" class="text-xs text-gray-500 hover:text-gray-700">Close</button>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="grid grid-cols-3 gap-2 sm:grid-cols-4" data-plum--image-picker-target="grid"></div>
|
|
30
|
+
<div class="mt-3 border-t border-gray-200 pt-3">
|
|
31
|
+
<label class="block text-xs font-medium text-gray-500">Upload a new image</label>
|
|
32
|
+
<input type="file" accept="image/*"
|
|
33
|
+
data-plum--image-picker-target="file"
|
|
34
|
+
data-action="change->plum--image-picker#upload"
|
|
35
|
+
class="mt-1 block w-full text-sm text-gray-700">
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<div class="mb-8">
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900">Edit Site Settings</h1>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<%= form_with model: [:cp, @site_settings], url: cp_site_settings_path, method: :patch,
|
|
6
|
+
class: "space-y-6", data: { controller: "plum--theme-settings" } do |f| %>
|
|
7
|
+
<% if @site_settings.errors.any? %>
|
|
8
|
+
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded">
|
|
9
|
+
<ul class="list-disc list-inside">
|
|
10
|
+
<% @site_settings.errors.full_messages.each do |msg| %>
|
|
11
|
+
<li><%= msg %></li>
|
|
12
|
+
<% end %>
|
|
13
|
+
</ul>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<div class="bg-white shadow rounded-lg p-6 space-y-6">
|
|
18
|
+
<h3 class="text-lg font-medium text-gray-900">General</h3>
|
|
19
|
+
|
|
20
|
+
<div>
|
|
21
|
+
<%= f.label :name, "Site Name", class: "block text-sm font-medium text-gray-700" %>
|
|
22
|
+
<%= f.text_field :name, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div>
|
|
26
|
+
<%= f.label :tagline, class: "block text-sm font-medium text-gray-700" %>
|
|
27
|
+
<%= f.text_field :tagline, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div>
|
|
31
|
+
<label class="block text-sm font-medium text-gray-700">Logo</label>
|
|
32
|
+
<%= render "plum/cp/shared/image_picker",
|
|
33
|
+
input_name: "site_setting[logo]",
|
|
34
|
+
value: @site_settings.logo.to_s,
|
|
35
|
+
field_id: "site_setting_logo" %>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div>
|
|
39
|
+
<%= f.label :theme_name, "Theme", class: "block text-sm font-medium text-gray-700" %>
|
|
40
|
+
<%= f.select :theme_name,
|
|
41
|
+
@themes.map { |theme| ["#{theme.name} (#{theme.handle})", theme.handle] },
|
|
42
|
+
{},
|
|
43
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500",
|
|
44
|
+
data: { "plum--theme-settings-target": "select", action: "plum--theme-settings#update" } %>
|
|
45
|
+
<% if @current_theme&.description.present? %>
|
|
46
|
+
<p class="mt-1 text-sm text-gray-500"><%= @current_theme.description %></p>
|
|
47
|
+
<% end %>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div>
|
|
51
|
+
<%= f.label :primary_color, "Primary Color", class: "block text-sm font-medium text-gray-700" %>
|
|
52
|
+
<%= f.color_field :primary_color,
|
|
53
|
+
class: "mt-1 h-10 w-16 rounded-md border border-gray-300 bg-white p-1" %>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div>
|
|
57
|
+
<%= f.label :support_email, "Support Email", class: "block text-sm font-medium text-gray-700" %>
|
|
58
|
+
<%= f.email_field :support_email,
|
|
59
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="bg-white shadow rounded-lg p-6 space-y-6">
|
|
64
|
+
<div class="flex items-center justify-between gap-4">
|
|
65
|
+
<h3 class="text-lg font-medium text-gray-900">Theme Settings</h3>
|
|
66
|
+
<div class="flex flex-wrap justify-end gap-2">
|
|
67
|
+
<% @themes.each do |theme| %>
|
|
68
|
+
<%= link_to "Preview #{theme.name}", cp_theme_preview_path(theme.handle),
|
|
69
|
+
target: "_blank", rel: "noopener",
|
|
70
|
+
class: "px-3 py-1.5 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
71
|
+
<% end %>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<% @themes.each do |theme| %>
|
|
76
|
+
<div data-plum--theme-settings-target="panel"
|
|
77
|
+
data-plum--theme-settings-handle="<%= theme.handle %>"
|
|
78
|
+
<%= "hidden" unless theme.handle == @site_settings.theme_name %>>
|
|
79
|
+
<% if theme.settings_fields.any? %>
|
|
80
|
+
<div class="space-y-4">
|
|
81
|
+
<% theme.settings_fields.each do |field| %>
|
|
82
|
+
<% field_id = theme_setting_input_id(theme, field) %>
|
|
83
|
+
<% field_name = theme_setting_input_name(theme, field) %>
|
|
84
|
+
<% field_value = theme_setting_value(field) %>
|
|
85
|
+
<div>
|
|
86
|
+
<label for="<%= field_id %>" class="block text-sm font-medium text-gray-700"><%= theme_setting_label(field) %></label>
|
|
87
|
+
|
|
88
|
+
<% case field["type"].to_s %>
|
|
89
|
+
<% when "color" %>
|
|
90
|
+
<%= color_field_tag field_name, field_value.presence || @site_settings.primary_color,
|
|
91
|
+
id: field_id,
|
|
92
|
+
class: "mt-1 h-10 w-16 rounded-md border border-gray-300 bg-white p-1" %>
|
|
93
|
+
<% when "textarea" %>
|
|
94
|
+
<%= text_area_tag field_name, field_value, id: field_id, rows: 3,
|
|
95
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
96
|
+
<% when "boolean" %>
|
|
97
|
+
<div class="mt-2 flex items-center gap-2">
|
|
98
|
+
<%= hidden_field_tag field_name, "0" %>
|
|
99
|
+
<%= check_box_tag field_name, "1", theme_setting_checked?(field),
|
|
100
|
+
id: field_id,
|
|
101
|
+
class: "h-4 w-4 rounded border-gray-300 text-purple-600 focus:ring-purple-500" %>
|
|
102
|
+
</div>
|
|
103
|
+
<% when "select" %>
|
|
104
|
+
<%= select_tag field_name,
|
|
105
|
+
options_for_select(theme_setting_options(field), field_value),
|
|
106
|
+
id: field_id,
|
|
107
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
108
|
+
<% else %>
|
|
109
|
+
<%= text_field_tag field_name, field_value, id: field_id,
|
|
110
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
111
|
+
<% end %>
|
|
112
|
+
<% if field["help"].present? %>
|
|
113
|
+
<p class="mt-1 text-sm text-gray-500"><%= field["help"] %></p>
|
|
114
|
+
<% end %>
|
|
115
|
+
</div>
|
|
116
|
+
<% end %>
|
|
117
|
+
</div>
|
|
118
|
+
<% else %>
|
|
119
|
+
<p class="text-sm text-gray-500">This theme does not define editable settings.</p>
|
|
120
|
+
<% end %>
|
|
121
|
+
</div>
|
|
122
|
+
<% end %>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div class="bg-white shadow rounded-lg p-6 space-y-6">
|
|
126
|
+
<h3 class="text-lg font-medium text-gray-900">SEO</h3>
|
|
127
|
+
|
|
128
|
+
<div>
|
|
129
|
+
<%= f.label :seo_title, "SEO Title", class: "block text-sm font-medium text-gray-700" %>
|
|
130
|
+
<%= f.text_field :seo_title, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div>
|
|
134
|
+
<%= f.label :seo_description, "SEO Description", class: "block text-sm font-medium text-gray-700" %>
|
|
135
|
+
<%= f.text_area :seo_description, rows: 3,
|
|
136
|
+
class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div class="flex justify-end space-x-3">
|
|
141
|
+
<%= link_to "Cancel", cp_site_settings_path,
|
|
142
|
+
class: "px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
143
|
+
<%= f.submit "Save Settings", class: "px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700 cursor-pointer" %>
|
|
144
|
+
</div>
|
|
145
|
+
<% end %>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<div class="flex items-center justify-between mb-8">
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900">Site Settings</h1>
|
|
3
|
+
<%= link_to "Edit", edit_cp_site_settings_path,
|
|
4
|
+
class: "inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700" %>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="bg-white shadow rounded-lg p-6">
|
|
8
|
+
<dl class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
|
9
|
+
<div>
|
|
10
|
+
<dt class="text-sm font-medium text-gray-500">Site Name</dt>
|
|
11
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.name %></dd>
|
|
12
|
+
</div>
|
|
13
|
+
<div>
|
|
14
|
+
<dt class="text-sm font-medium text-gray-500">Tagline</dt>
|
|
15
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.tagline || "—" %></dd>
|
|
16
|
+
</div>
|
|
17
|
+
<div>
|
|
18
|
+
<dt class="text-sm font-medium text-gray-500">SEO Title</dt>
|
|
19
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.seo_title || "—" %></dd>
|
|
20
|
+
</div>
|
|
21
|
+
<div>
|
|
22
|
+
<dt class="text-sm font-medium text-gray-500">SEO Description</dt>
|
|
23
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.seo_description || "—" %></dd>
|
|
24
|
+
</div>
|
|
25
|
+
<div>
|
|
26
|
+
<dt class="text-sm font-medium text-gray-500">Theme</dt>
|
|
27
|
+
<dd class="mt-1 text-sm text-gray-900">
|
|
28
|
+
<%= @current_theme&.name || @site_settings.theme_name || "default" %>
|
|
29
|
+
<span class="text-gray-500">(<%= @site_settings.theme_name || "default" %>)</span>
|
|
30
|
+
</dd>
|
|
31
|
+
</div>
|
|
32
|
+
<div>
|
|
33
|
+
<dt class="text-sm font-medium text-gray-500">Primary Color</dt>
|
|
34
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.primary_color || "—" %></dd>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
<dt class="text-sm font-medium text-gray-500">Support Email</dt>
|
|
38
|
+
<dd class="mt-1 text-sm text-gray-900"><%= @site_settings.support_email || "—" %></dd>
|
|
39
|
+
</div>
|
|
40
|
+
</dl>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<% if @current_theme&.settings_fields&.any? %>
|
|
44
|
+
<div class="mt-6 bg-white shadow rounded-lg p-6">
|
|
45
|
+
<h2 class="text-lg font-medium text-gray-900">Theme Settings</h2>
|
|
46
|
+
<dl class="mt-4 grid grid-cols-1 gap-6 sm:grid-cols-2">
|
|
47
|
+
<% @current_theme.settings_fields.each do |field| %>
|
|
48
|
+
<% value = current_site.theme_settings[field["handle"].to_s] %>
|
|
49
|
+
<div>
|
|
50
|
+
<dt class="text-sm font-medium text-gray-500"><%= theme_setting_label(field) %></dt>
|
|
51
|
+
<dd class="mt-1 text-sm text-gray-900">
|
|
52
|
+
<% if field["type"] == "boolean" %>
|
|
53
|
+
<%= ActiveModel::Type::Boolean.new.cast(value) ? "Yes" : "No" %>
|
|
54
|
+
<% else %>
|
|
55
|
+
<%= value.presence || "—" %>
|
|
56
|
+
<% end %>
|
|
57
|
+
</dd>
|
|
58
|
+
</div>
|
|
59
|
+
<% end %>
|
|
60
|
+
</dl>
|
|
61
|
+
</div>
|
|
62
|
+
<% end %>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<%= form_with model: [:cp, taxonomy], url: taxonomy.persisted? ? "#{cp_prefix}/taxonomies/#{taxonomy.id}" : "#{cp_prefix}/taxonomies", method: taxonomy.persisted? ? :patch : :post, class: "space-y-6" do |f| %>
|
|
2
|
+
<% if taxonomy.errors.any? %>
|
|
3
|
+
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded">
|
|
4
|
+
<ul class="list-disc list-inside">
|
|
5
|
+
<% taxonomy.errors.full_messages.each do |msg| %>
|
|
6
|
+
<li><%= msg %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div class="bg-white shadow rounded-lg p-6 space-y-6">
|
|
13
|
+
<div>
|
|
14
|
+
<%= f.label :name, class: "block text-sm font-medium text-gray-700" %>
|
|
15
|
+
<%= f.text_field :name, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<%= f.label :handle, class: "block text-sm font-medium text-gray-700" %>
|
|
20
|
+
<%= f.text_field :handle, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 font-mono",
|
|
21
|
+
placeholder: "auto-generated from name" %>
|
|
22
|
+
<p class="mt-1 text-sm text-gray-500">Used in templates. Lowercase letters, numbers, and underscores only.</p>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div>
|
|
26
|
+
<%= f.label :slug, class: "block text-sm font-medium text-gray-700" %>
|
|
27
|
+
<%= f.text_field :slug, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 font-mono",
|
|
28
|
+
placeholder: "auto-generated from name" %>
|
|
29
|
+
<p class="mt-1 text-sm text-gray-500">Used in URLs, e.g. /categories/breakfast.</p>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="flex justify-end space-x-3">
|
|
34
|
+
<%= link_to "Cancel", "#{cp_prefix}/taxonomies",
|
|
35
|
+
class: "px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
36
|
+
<%= f.submit class: "px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700 cursor-pointer" %>
|
|
37
|
+
</div>
|
|
38
|
+
<% end %>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<div class="flex items-center justify-between mb-6">
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900">Taxonomies</h1>
|
|
3
|
+
<%= link_to "New Taxonomy", "#{cp_prefix}/taxonomies/new",
|
|
4
|
+
class: "px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 text-sm font-medium" %>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="bg-white shadow rounded-lg overflow-hidden">
|
|
8
|
+
<% if @taxonomies.any? %>
|
|
9
|
+
<table class="min-w-full divide-y divide-gray-200">
|
|
10
|
+
<thead class="bg-gray-50">
|
|
11
|
+
<tr>
|
|
12
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th>
|
|
13
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Handle</th>
|
|
14
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Terms</th>
|
|
15
|
+
<th class="px-6 py-3"></th>
|
|
16
|
+
</tr>
|
|
17
|
+
</thead>
|
|
18
|
+
<tbody class="divide-y divide-gray-200">
|
|
19
|
+
<% @taxonomies.each do |taxonomy| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<td class="px-6 py-4">
|
|
22
|
+
<%= link_to taxonomy.name, "#{cp_prefix}/taxonomies/#{taxonomy.id}", class: "text-purple-600 hover:text-purple-900 font-medium" %>
|
|
23
|
+
</td>
|
|
24
|
+
<td class="px-6 py-4 text-sm text-gray-500 font-mono"><%= taxonomy.handle %></td>
|
|
25
|
+
<td class="px-6 py-4 text-sm text-gray-500"><%= taxonomy.terms.size %></td>
|
|
26
|
+
<td class="px-6 py-4 text-right text-sm">
|
|
27
|
+
<%= link_to "Edit", "#{cp_prefix}/taxonomies/#{taxonomy.id}/edit", class: "text-purple-600 hover:text-purple-900" %>
|
|
28
|
+
</td>
|
|
29
|
+
</tr>
|
|
30
|
+
<% end %>
|
|
31
|
+
</tbody>
|
|
32
|
+
</table>
|
|
33
|
+
<% else %>
|
|
34
|
+
<div class="p-6 text-center text-gray-500">
|
|
35
|
+
<p>No taxonomies yet. Create one to start categorizing your content.</p>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<div class="flex items-center justify-between mb-6">
|
|
2
|
+
<div>
|
|
3
|
+
<h1 class="text-2xl font-bold text-gray-900"><%= @taxonomy.name %></h1>
|
|
4
|
+
<p class="text-sm text-gray-500 font-mono mt-1"><%= @taxonomy.handle %></p>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="flex gap-3">
|
|
7
|
+
<%= link_to "Edit Taxonomy", "#{cp_prefix}/taxonomies/#{@taxonomy.id}/edit",
|
|
8
|
+
class: "px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
9
|
+
<%= link_to "Add Term", "#{cp_prefix}/taxonomies/#{@taxonomy.id}/terms/new",
|
|
10
|
+
class: "px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 text-sm font-medium" %>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div class="bg-white shadow rounded-lg overflow-hidden">
|
|
15
|
+
<% if @terms.any? %>
|
|
16
|
+
<table class="min-w-full divide-y divide-gray-200">
|
|
17
|
+
<thead class="bg-gray-50">
|
|
18
|
+
<tr>
|
|
19
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th>
|
|
20
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Slug</th>
|
|
21
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Entries</th>
|
|
22
|
+
<th class="px-6 py-3"></th>
|
|
23
|
+
</tr>
|
|
24
|
+
</thead>
|
|
25
|
+
<tbody class="divide-y divide-gray-200">
|
|
26
|
+
<% @terms.each do |term| %>
|
|
27
|
+
<tr>
|
|
28
|
+
<td class="px-6 py-4 font-medium text-gray-900"><%= term.name %></td>
|
|
29
|
+
<td class="px-6 py-4 text-sm text-gray-500 font-mono"><%= term.slug %></td>
|
|
30
|
+
<td class="px-6 py-4 text-sm text-gray-500"><%= term.entries.count %></td>
|
|
31
|
+
<td class="px-6 py-4 text-right text-sm space-x-3">
|
|
32
|
+
<%= link_to "Edit", "#{cp_prefix}/taxonomies/#{@taxonomy.id}/terms/#{term.id}/edit", class: "text-purple-600 hover:text-purple-900" %>
|
|
33
|
+
<%= button_to "Delete", "#{cp_prefix}/taxonomies/#{@taxonomy.id}/terms/#{term.id}", method: :delete,
|
|
34
|
+
data: { turbo_confirm: "Delete this term?" },
|
|
35
|
+
class: "text-red-600 hover:text-red-900" %>
|
|
36
|
+
</td>
|
|
37
|
+
</tr>
|
|
38
|
+
<% end %>
|
|
39
|
+
</tbody>
|
|
40
|
+
</table>
|
|
41
|
+
<% else %>
|
|
42
|
+
<div class="p-6 text-center text-gray-500">
|
|
43
|
+
<p>No terms yet. Add one to start tagging entries.</p>
|
|
44
|
+
</div>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%= form_with model: [:cp, @taxonomy, term], url: term.persisted? ? "#{cp_prefix}/taxonomies/#{@taxonomy.id}/terms/#{term.id}" : "#{cp_prefix}/taxonomies/#{@taxonomy.id}/terms", method: term.persisted? ? :patch : :post, class: "space-y-6" do |f| %>
|
|
2
|
+
<% if term.errors.any? %>
|
|
3
|
+
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded">
|
|
4
|
+
<ul class="list-disc list-inside">
|
|
5
|
+
<% term.errors.full_messages.each do |msg| %>
|
|
6
|
+
<li><%= msg %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div class="bg-white shadow rounded-lg p-6 space-y-6">
|
|
13
|
+
<div>
|
|
14
|
+
<%= f.label :name, class: "block text-sm font-medium text-gray-700" %>
|
|
15
|
+
<%= f.text_field :name, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500" %>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<%= f.label :slug, class: "block text-sm font-medium text-gray-700" %>
|
|
20
|
+
<%= f.text_field :slug, class: "mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 font-mono",
|
|
21
|
+
placeholder: "auto-generated from name" %>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="flex justify-end space-x-3">
|
|
26
|
+
<%= link_to "Cancel", "#{cp_prefix}/taxonomies/#{@taxonomy.id}",
|
|
27
|
+
class: "px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" %>
|
|
28
|
+
<%= f.submit class: "px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700 cursor-pointer" %>
|
|
29
|
+
</div>
|
|
30
|
+
<% end %>
|